]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/main.c
BootX-74.1.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / main.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * main.c - Main functions for BootX.
24 *
25 * Copyright (c) 1998-2004 Apple Computer, Inc.
26 *
27 * DRI: Josh de Cesare
28 */
29
30
31 #include <sl.h>
32 #include "aes.h"
33
34 static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr);
35 static void Main(ClientInterfacePtr ciPtr);
36 static long InitEverything(ClientInterfacePtr ciPtr);
37 static long DecodeKernel(void *binary);
38 static long SetUpBootArgs(void);
39 static long CallKernel(void);
40 static void FailToBoot(long num);
41 static long InitMemoryMap(void);
42 static long GetOFVersion(void);
43 static long TestForKey(long key);
44 static long GetBootPaths(void);
45 static long ReadBootPlist(char *devSpec);
46
47 const unsigned long StartTVector[2] = {(unsigned long)Start, 0};
48
49 char gStackBaseAddr[0x8000];
50
51 char *gVectorSaveAddr;
52 long gImageLastKernelAddr = 0;
53 long gImageFirstBootXAddr = kLoadAddr;
54 long gKernelEntryPoint;
55 long gDeviceTreeAddr;
56 long gDeviceTreeSize;
57 long gBootArgsAddr;
58 long gBootArgsSize;
59 long gSymbolTableAddr;
60 long gSymbolTableSize;
61
62 long gBootSourceNumber = -1;
63 long gBootSourceNumberMax;
64 long gBootMode = kBootModeNormal;
65 long gBootDeviceType;
66 long gBootFileType;
67 char gHaveKernelCache = 0;
68 char gBootDevice[256];
69 char gBootFile[256];
70 TagPtr gBootDict = NULL;
71 static char gBootKernelCacheFile[512];
72 static char gExtensionsSpec[4096];
73 static char gCacheNameAdler[64 + sizeof(gBootFile)];
74 static char *gPlatformName = gCacheNameAdler;
75
76 char gTempStr[4096];
77
78 long *gDeviceTreeMMTmp = 0;
79
80 long gOFVersion = 0;
81
82 char *gKeyMap;
83
84 long gRootAddrCells;
85 long gRootSizeCells;
86
87 CICell gChosenPH;
88 CICell gOptionsPH;
89 CICell gScreenPH;
90 CICell gMemoryMapPH;
91 CICell gStdOutPH;
92
93 CICell gMMUIH;
94 CICell gMemoryIH;
95 CICell gStdOutIH;
96 CICell gKeyboardIH;
97
98 static char gOFVectorSave[kVectorSize];
99 static unsigned long gOFMSRSave;
100 static unsigned long gOFSPRG0Save;
101 static unsigned long gOFSPRG1Save;
102 static unsigned long gOFSPRG2Save;
103 static unsigned long gOFSPRG3Save;
104
105 //int gDebugCount = 0;
106
107 // Private Functions
108
109 static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr)
110 {
111 long newSP;
112
113 // Move the Stack to a chunk of the BSS
114 newSP = (long)gStackBaseAddr + sizeof(gStackBaseAddr) - 0x100;
115 __asm__ volatile("mr r1, %0" : : "r" (newSP));
116
117 Main(ciPtr);
118 }
119
120
121
122 static void Main(ClientInterfacePtr ciPtr)
123 {
124 long ret;
125 int trycache;
126 long flags, cachetime, kerneltime, exttime = 0;
127 void *binary = (void *)kLoadAddr;
128
129 ret = InitEverything(ciPtr);
130 if (ret != 0) Exit();
131
132
133 // Get or infer the boot paths.
134 ret = GetBootPaths();
135 if (ret != 0) FailToBoot(1);
136
137 #if kFailToBoot
138 DrawSplashScreen(0);
139 #endif
140
141 while (ret == 0) {
142 trycache = (0 == (gBootMode & kBootModeSafe))
143 && (gBootKernelCacheFile[0] != 0);
144
145 if (trycache && (gBootFileType == kBlockDeviceType)) do {
146
147 // if we haven't found the kernel yet, don't use the cache
148 ret = GetFileInfo(NULL, gBootFile, &flags, &kerneltime);
149 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
150 trycache = 0;
151 break;
152 }
153 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
154 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
155 || (cachetime < kerneltime)) {
156 trycache = 0;
157 break;
158 }
159 ret = GetFileInfo(gExtensionsSpec, "Extensions", &flags, &exttime);
160 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
161 && (cachetime < exttime)) {
162 trycache = 0;
163 break;
164 }
165 if (kerneltime > exttime)
166 exttime = kerneltime;
167 if (cachetime != (exttime + 1)) {
168 trycache = 0;
169 break;
170 }
171 } while (0);
172
173 if (trycache) {
174 ret = LoadFile(gBootKernelCacheFile);
175 if (ret != -1) {
176 ret = DecodeKernel(binary);
177 if (ret != -1) break;
178 }
179 }
180 ret = LoadThinFatFile(gBootFile, &binary);
181 if (ret != -1) ret = DecodeKernel(binary);
182 if (ret != -1) break;
183
184 ret = GetBootPaths();
185 if (ret != 0) FailToBoot(2);
186 }
187
188 if (ret != 0) FailToBoot(3);
189
190 if (!gHaveKernelCache) {
191 ret = LoadDrivers(gExtensionsSpec);
192 if (ret != 0) FailToBoot(4);
193 }
194
195 #if kFailToBoot
196 DrawSplashScreen(1);
197 #endif
198
199 ret = SetUpBootArgs();
200 if (ret != 0) FailToBoot(5);
201
202 ret = CallKernel();
203
204 FailToBoot(6);
205 }
206
207 static uint32_t UnescapeData(const uint8_t * src,
208 uint32_t srcLen,
209 uint8_t * dst,
210 uint32_t dstMaxLen)
211 {
212 uint32_t cnt, cnt2, dstLen = 0;
213 uint8_t byte;
214
215 for (cnt = 0; cnt < srcLen;) {
216 byte = src[cnt++];
217 if (byte == 0xFF) {
218 byte = src[cnt++];
219 cnt2 = byte & 0x7F;
220 byte = (byte & 0x80) ? 0xFF : 0x00;
221 } else
222 cnt2 = 1;
223 while (cnt2--) {
224 if (dstLen >= dstMaxLen)
225 return (-1);
226 dst[dstLen++] = byte;
227 }
228 }
229 return (dstLen);
230 }
231
232 static long InitEverything(ClientInterfacePtr ciPtr)
233 {
234 long ret, mem_base, mem_base2, size;
235 CICell keyboardPH;
236 char name[32], securityMode[33];
237 long length;
238 char *compatible;
239
240 // Init the OF Client Interface.
241 ret = InitCI(ciPtr);
242 if (ret != 0) return -1;
243
244 // Get the OF Version
245 gOFVersion = GetOFVersion();
246 if (gOFVersion == 0) return -1;
247
248 // Get the address and size cells for the root.
249 GetProp(Peer(0), "#address-cells", (char *)&gRootAddrCells, 4);
250 GetProp(Peer(0), "#size-cells", (char *)&gRootSizeCells, 4);
251 if ((gRootAddrCells > 2) || (gRootAddrCells > 2)) return -1;
252
253 // Init the SL Words package.
254 ret = InitSLWords();
255 if (ret != 0) return -1;
256
257 // Get the phandle for /options
258 gOptionsPH = FindDevice("/options");
259 if (gOptionsPH == -1) return -1;
260
261 // Get the phandle for /chosen
262 gChosenPH = FindDevice("/chosen");
263 if (gChosenPH == -1) return -1;
264
265 // Init the Memory Map.
266 ret = InitMemoryMap();
267 if (ret != 0) return -1;
268
269 // Get IHandles for the MMU and Memory
270 size = GetProp(gChosenPH, "mmu", (char *)&gMMUIH, 4);
271 if (size != 4) {
272 printf("Failed to get the IH for the MMU.\n");
273 return -1;
274 }
275 size = GetProp(gChosenPH, "memory", (char *)&gMemoryIH, 4);
276 if (size != 4) {
277 printf("Failed to get the IH for the Memory.\n");
278 return -1;
279 }
280
281 // Get first element of root's compatible property.
282 ret = GetPackageProperty(Peer(0), "compatible", &compatible, &length);
283 if (ret != -1)
284 strcpy(gPlatformName, compatible);
285
286 // Get stdout's IH, so that the boot display can be found.
287 ret = GetProp(gChosenPH, "stdout", (char *)&gStdOutIH, 4);
288 if (ret == 4) gStdOutPH = InstanceToPackage(gStdOutIH);
289 else gStdOutPH = gStdOutIH = 0;
290
291 // Try to find the keyboard using chosen
292 ret = GetProp(gChosenPH, "stdin", (char *)&gKeyboardIH, 4);
293 if (ret != 4) gKeyboardIH = 0;
294 else {
295 keyboardPH = InstanceToPackage(gKeyboardIH);
296 ret = GetProp(keyboardPH, "name", name, 31);
297 if (ret != -1) {
298 name[ret] = '\0';
299 if (strcmp(name, "keyboard") && strcmp(name, "kbd")) gKeyboardIH = 0;
300 } else gKeyboardIH = 0;
301 }
302
303 // Try to the find the keyboard using open if chosen did not work.
304 if (gKeyboardIH == 0) gKeyboardIH = Open("keyboard");
305 if (gKeyboardIH == 0) gKeyboardIH = Open("kbd");
306
307 // Get the key map set up, and make it up to date.
308 gKeyMap = InitKeyMap(gKeyboardIH);
309 if (gKeyMap == NULL) return -1;
310 UpdateKeyMap();
311
312 // Test for Secure Boot Mode.
313 size = GetProp(gOptionsPH, "security-mode", securityMode, 32);
314 if (size != -1) {
315 securityMode[size] = '\0';
316 if (strcmp(securityMode, "none")) gBootMode |= kBootModeSecure;
317 }
318
319 #if kFailToBoot
320 // 'cmd-s' or 'cmd-v' is pressed set outputLevel to kOutputLevelFull
321 if (((gBootMode & kBootModeSecure) == 0) && TestForKey(kCommandKey) &&
322 (TestForKey('s') || TestForKey('v'))) {
323 SetOutputLevel(kOutputLevelFull);
324 } else {
325 SetOutputLevel(kOutputLevelOff);
326 }
327 #else
328 SetOutputLevel(kOutputLevelFull);
329 #endif
330
331 // printf now works.
332 printf("\n\nMac OS X Loader\n");
333
334 // Test for Safe Boot Mode; Shift and not Delete.
335 if (((gBootMode & kBootModeSecure) == 0)
336 && TestForKey(kShiftKey) && !TestForKey(kDeleteKey)) {
337 gBootMode |= kBootModeSafe;
338 }
339
340 {
341 // Claim memory for the FS Cache.
342 if (Claim(kFSCacheAddr, kFSCacheSize, 0) == 0) {
343 printf("Claim for fs cache failed.\n");
344 return -1;
345 }
346
347 // Claim memory for malloc.
348 if (Claim(kMallocAddr, kMallocSize, 0) == 0) {
349 printf("Claim for malloc failed.\n");
350 return -1;
351 }
352 malloc_init((char *)kMallocAddr, kMallocSize);
353
354 // Claim memory for the Load Addr.
355 mem_base = Claim(kLoadAddr, kLoadSize, 0);
356 if (mem_base == 0) {
357 printf("Claim for Load Area failed.\n");
358 return -1;
359 }
360
361 // Claim the memory for the Image Addr
362 if (gOFVersion >= kOFVersion3x) {
363 mem_base = Claim(kImageAddr, kImageSize, 0);
364 if (mem_base == 0) {
365 printf("Claim for Image Area failed.\n");
366 return -1;
367 }
368 } else {
369 // Claim the 1:1 mapped chunks first.
370 mem_base = Claim(kImageAddr0, kImageSize0, 0);
371 mem_base2 = Claim(kImageAddr2, kImageSize2, 0);
372 if ((mem_base == 0) || (mem_base2 == 0)) {
373 printf("Claim for Image Area failed.\n");
374 return -1;
375 }
376
377 // Unmap the old xcoff stack.
378 CallMethod(2, 0, gMMUIH, "unmap", 0x00380000, 0x00080000);
379
380 // Grab the physical memory then the logical.
381 CallMethod(3, 1, gMemoryIH, "claim",
382 kImageAddr1Phys, kImageSize1, 0, &mem_base);
383 CallMethod(3, 1, gMMUIH, "claim",
384 kImageAddr1, kImageSize1, 0, &mem_base2);
385 if ((mem_base == 0) || (mem_base2 == 0)) {
386 printf("Claim for Image Area failed.\n");
387 return -1;
388 }
389
390 // Map them together.
391 CallMethod(4, 0, gMMUIH, "map",
392 kImageAddr1Phys, kImageAddr1, kImageSize1, 0);
393 }
394
395 bzero((char *)kImageAddr, kImageSize);
396
397 // Allocate some space for the Vector Save area.
398 gVectorSaveAddr = AllocateBootXMemory(kVectorSize);
399 if (gVectorSaveAddr == 0) {
400 printf("Allocation for the Vector Save Area failed.\n");
401 return -1;
402 }
403 // Find all the displays and set them up.
404 ret = InitDisplays(1);
405 if (ret != 0) {
406 printf("InitDisplays failed.\n");
407 return -1;
408 }
409 }
410
411 return 0;
412 }
413
414
415 long ThinFatBinary(void **binary, unsigned long *length)
416 {
417 long ret;
418
419 ret = ThinFatBinaryMachO(binary, length);
420 if (ret == -1) ret = ThinFatBinaryElf(binary, length);
421
422 return ret;
423 }
424
425 static long DecodeKernel(void *binary)
426 {
427 long ret;
428 compressed_kernel_header *kernel_header = (compressed_kernel_header *)binary;
429 u_int32_t size;
430
431 if (kernel_header->signature == 'comp') {
432 if (kernel_header->compress_type != 'lzss')
433 return -1;
434 if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
435 return -1;
436 if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
437 return -1;
438
439 binary = AllocateBootXMemory(kernel_header->uncompressed_size);
440
441 size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0], kernel_header->compressed_size);
442 if (kernel_header->uncompressed_size != size) {
443 printf("size mismatch from lzss %x\n", size);
444 return -1;
445 }
446 if (kernel_header->adler32 !=
447 Adler32(binary, kernel_header->uncompressed_size)) {
448 printf("adler mismatch\n");
449 return -1;
450 }
451 }
452
453 ThinFatBinary(&binary, 0);
454
455 ret = DecodeMachO(binary);
456 if (ret == -1) ret = DecodeElf(binary);
457
458 return ret;
459 }
460
461
462 static long SetUpBootArgs(void)
463 {
464 boot_args_ptr args;
465 CICell memoryPH;
466 long graphicsBoot = 1;
467 long ret, cnt, size, dash;
468 long sKey, vKey, keyPos;
469 char ofBootArgs[240], *ofArgs, tc, keyStr[8];
470 unsigned char mem_regs[kMaxDRAMBanks*16];
471 unsigned long mem_banks, bank_shift;
472
473 // Save file system cache statistics.
474 SetProp(gChosenPH, "BootXCacheHits", (char *)&gCacheHits, 4);
475 SetProp(gChosenPH, "BootXCacheMisses", (char *)&gCacheMisses, 4);
476 SetProp(gChosenPH, "BootXCacheEvicts", (char *)&gCacheEvicts, 4);
477
478 // Allocate some memory for the BootArgs.
479 gBootArgsSize = sizeof(boot_args);
480 gBootArgsAddr = AllocateKernelMemory(gBootArgsSize);
481
482 // Add the BootArgs to the memory-map.
483 AllocateMemoryRange("BootArgs", gBootArgsAddr, gBootArgsSize);
484
485 args = (boot_args_ptr)gBootArgsAddr;
486
487 args->Revision = kBootArgsRevision;
488 args->Version = kBootArgsVersion1;
489 args->machineType = 0;
490
491 // Check the Keyboard for 'cmd-s' and 'cmd-v'
492 UpdateKeyMap();
493 if ((gBootMode & kBootModeSecure) == 0) {
494 sKey = TestForKey(kCommandKey) && TestForKey('s');
495 vKey = TestForKey(kCommandKey) && TestForKey('v');
496 } else {
497 sKey = 0;
498 vKey = 0;
499 }
500
501 // if 'cmd-s' or 'cmd-v' was pressed do a text boot.
502 if (sKey || vKey) graphicsBoot = 0;
503
504 // Create the command line.
505 if (gOFVersion < kOFVersion3x) {
506 ofBootArgs[0] = ' ';
507 size = GetProp(gChosenPH, "machargs", ofBootArgs + 1, (sizeof(ofBootArgs) - 2));
508 if (size == -1) {
509 size = GetProp(gOptionsPH, "boot-command", ofBootArgs, (sizeof(ofBootArgs) - 1));
510 if (size == -1) ofBootArgs[0] = '\0';
511 else ofBootArgs[size] = '\0';
512 // Look for " bootr" but skip the number.
513 if (!strncmp(ofBootArgs + 1, " bootr", 6)) {
514 strcpy(ofBootArgs, ofBootArgs + 7);
515 } else ofBootArgs[0] = '\0';
516 SetProp(gChosenPH, "machargs", ofBootArgs, strlen(ofBootArgs) + 1);
517 } else ofBootArgs[size] = '\0';
518 // Force boot-command to start with 0 bootr.
519 sprintf(gTempStr, "0 bootr%s", ofBootArgs);
520 SetProp(gOptionsPH, "boot-command", gTempStr, strlen(gTempStr));
521 } else {
522 size = GetProp(gOptionsPH, "boot-args", ofBootArgs, (sizeof(ofBootArgs) - 1));
523 if (size == -1) ofBootArgs[0] = '\0';
524 else ofBootArgs[size] = '\0';
525 }
526
527 if (ofBootArgs[0] != '\0') {
528 // Look for special options and copy the rest.
529 dash = 0;
530 ofArgs = ofBootArgs;
531 while ((tc = *ofArgs) != '\0') {
532 tc = tolower(tc);
533
534 // Check for entering a dash arg.
535 if (tc == '-') {
536 dash = 1;
537 ofArgs++;
538 continue;
539 }
540
541 // Do special stuff if in a dash arg.
542 if (dash) {
543 if (tc == 's') {
544 graphicsBoot = 0;
545 ofArgs++;
546 sKey = 0;
547 } else if (tc == 'v') {
548 graphicsBoot = 0;
549 ofArgs++;
550 vKey = 0;
551 } else {
552 // Check for exiting dash arg
553 if (isspace(tc)) dash = 0;
554
555 // Copy any non 's' or 'v'
556 ofArgs++;
557 }
558 } else {
559 // Not a dash arg so just copy it.
560 ofArgs++;
561 }
562 }
563 }
564
565 // Add any pressed keys (s, v, shift) to the command line
566 keyPos = 0;
567 if (sKey || vKey || (gBootMode & kBootModeSafe)) {
568 keyStr[keyPos++] = '-';
569
570 if (sKey) keyStr[keyPos++] = 's';
571 if (vKey) keyStr[keyPos++] = 'v';
572 if (gBootMode & kBootModeSafe) keyStr[keyPos++] = 'x';
573
574 keyStr[keyPos++] = ' ';
575 }
576 keyStr[keyPos++] = '\0';
577
578 sprintf(args->CommandLine, "%s%s", keyStr, ofBootArgs);
579
580 // If the address or size cells are larger than 1, use page numbers
581 // and signify Boot Args Version 2.
582 if ((gRootAddrCells == 1) && (gRootSizeCells == 1)) bank_shift = 0;
583 else {
584 bank_shift = 12;
585 args->Version = kBootArgsVersion2;
586 }
587
588 // Get the information about the memory banks
589 memoryPH = FindDevice("/memory");
590 if (memoryPH == -1) return -1;
591 size = GetProp(memoryPH, "reg", mem_regs, kMaxDRAMBanks * 16);
592 if (size == 0) return -1;
593 mem_banks = size / (4 * (gRootAddrCells + gRootSizeCells));
594 if (mem_banks > kMaxDRAMBanks) mem_banks = kMaxDRAMBanks;
595
596 // Convert the reg properties to 32 bit values
597 for (cnt = 0; cnt < mem_banks; cnt++) {
598 if (gRootAddrCells == 1) {
599 args->PhysicalDRAM[cnt].base =
600 *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift;
601 } else {
602 args->PhysicalDRAM[cnt].base =
603 *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift;
604
605 }
606
607 if (gRootSizeCells == 1) {
608 args->PhysicalDRAM[cnt].size =
609 *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift;
610 } else {
611 args->PhysicalDRAM[cnt].size =
612 *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift;
613
614 }
615 }
616
617 // Collapse the memory banks into contiguous chunks
618 for (cnt = 0; cnt < mem_banks - 1; cnt++) {
619 if ((args->PhysicalDRAM[cnt + 1].base != 0) &&
620 ((args->PhysicalDRAM[cnt].base + args->PhysicalDRAM[cnt].size) !=
621 args->PhysicalDRAM[cnt + 1].base)) continue;
622
623 args->PhysicalDRAM[cnt].size += args->PhysicalDRAM[cnt + 1].size;
624 bcopy(args->PhysicalDRAM + cnt + 2, args->PhysicalDRAM + cnt + 1, (mem_banks - cnt - 2) * sizeof(DRAMBank));
625 mem_banks--;
626 cnt--;
627 }
628 bzero(args->PhysicalDRAM + mem_banks, (kMaxDRAMBanks - mem_banks) * sizeof(DRAMBank));
629
630 // Get the video info
631 GetMainScreenPH(&args->Video, 1);
632 args->Video.v_display = graphicsBoot;
633
634 // Add the DeviceTree to the memory-map.
635 // The actuall address and size must be filled in later.
636 AllocateMemoryRange("DeviceTree", 0, 0);
637
638 ret = FlattenDeviceTree();
639 if (ret != 0) return -1;
640
641 // Fill in the address and size of the device tree.
642 if (gDeviceTreeAddr) {
643 gDeviceTreeMMTmp[0] = gDeviceTreeAddr;
644 gDeviceTreeMMTmp[1] = gDeviceTreeSize;
645 }
646
647 args->deviceTreeP = (void *)gDeviceTreeAddr;
648 args->deviceTreeLength = gDeviceTreeSize;
649 args->topOfKernelData = AllocateKernelMemory(0);
650
651 return 0;
652 }
653
654
655 static long CallKernel(void)
656 {
657 unsigned long msr, cnt;
658
659 Quiesce();
660
661 printf("\nCall Kernel!\n");
662
663 // Save SPRs for OF
664 __asm__ volatile("mfmsr %0" : "=r" (gOFMSRSave));
665 __asm__ volatile("mfsprg %0, 0" : "=r" (gOFSPRG0Save));
666 __asm__ volatile("mfsprg %0, 1" : "=r" (gOFSPRG1Save));
667 __asm__ volatile("mfsprg %0, 2" : "=r" (gOFSPRG2Save));
668 __asm__ volatile("mfsprg %0, 3" : "=r" (gOFSPRG3Save));
669
670 // Turn off translations
671 msr = 0x00001000;
672 __asm__ volatile("sync");
673 __asm__ volatile("mtmsr %0" : : "r" (msr));
674 __asm__ volatile("isync");
675
676 // Save the OF's Exceptions Vectors
677 bcopy(0x0, gOFVectorSave, kVectorSize);
678
679 // Move the Exception Vectors
680 bcopy(gVectorSaveAddr, 0x0, kVectorSize);
681 for (cnt = 0; cnt < kVectorSize; cnt += 0x20) {
682 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
683 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
684 }
685
686 // Move the Image1 save area for OF 1.x / 2.x
687 if (gOFVersion < kOFVersion3x) {
688 bcopy((char *)kImageAddr1Phys, (char *)kImageAddr1, kImageSize1);
689 for (cnt = kImageAddr1; cnt < kImageSize1; cnt += 0x20) {
690 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
691 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
692 }
693 }
694
695 // Make sure everything get sync'd up.
696 __asm__ volatile("isync");
697 __asm__ volatile("sync");
698 __asm__ volatile("eieio");
699
700 // Call the Kernel's entry point
701 (*(void (*)())gKernelEntryPoint)(gBootArgsAddr, kMacOSXSignature);
702
703 // Restore OF's Exception Vectors
704 bcopy(gOFVectorSave, 0x0, 0x3000);
705 for (cnt = 0; cnt < kVectorSize; cnt += 0x20) {
706 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
707 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
708 }
709
710 // Restore SPRs for OF
711 __asm__ volatile("mtsprg 0, %0" : : "r" (gOFSPRG0Save));
712 __asm__ volatile("mtsprg 1, %0" : : "r" (gOFSPRG1Save));
713 __asm__ volatile("mtsprg 2, %0" : : "r" (gOFSPRG2Save));
714 __asm__ volatile("mtsprg 3, %0" : : "r" (gOFSPRG3Save));
715
716 // Restore translations
717 __asm__ volatile("sync");
718 __asm__ volatile("mtmsr %0" : : "r" (gOFMSRSave));
719 __asm__ volatile("isync");
720
721 return -1;
722 }
723
724
725 static void FailToBoot(long num)
726 {
727 // useful for those holding down command-v ...
728 printf("FailToBoot: %d\n", num);
729 #if kFailToBoot
730 DrawFailedBootPicture();
731 while (1);
732 num = 0;
733 #else
734 Enter(); // For debugging
735 #endif
736 }
737
738
739 static long InitMemoryMap(void)
740 {
741 long result;
742
743 result = Interpret(0, 1,
744 " dev /chosen"
745 " new-device"
746 " \" memory-map\" device-name"
747 " active-package"
748 " device-end"
749 , &gMemoryMapPH);
750
751 return result;
752 }
753
754
755 static long GetOFVersion(void)
756 {
757 CICell ph;
758 char versStr[256], *tmpStr;
759 long vers, size;
760
761 // Get the openprom package
762 ph = FindDevice("/openprom");
763 if (ph == -1) return 0;
764
765 // Get it's model property
766 size = GetProp(ph, "model", versStr, 255);
767 if (size == -1) return -1;
768 versStr[size] = '\0';
769
770 // Find the start of the number.
771 tmpStr = NULL;
772 if (!strncmp(versStr, "Open Firmware, ", 15)) {
773 tmpStr = versStr + 15;
774 } else if (!strncmp(versStr, "OpenFirmware ", 13)) {
775 tmpStr = versStr + 13;
776 } else return -1;
777
778 // Clasify by each instance as needed...
779 switch (*tmpStr) {
780 case '1' :
781 vers = kOFVersion1x;
782 break;
783
784 case '2' :
785 vers = kOFVersion2x;
786 break;
787
788 case '3' :
789 vers = kOFVersion3x;
790 break;
791
792 case '4' :
793 vers = kOFVersion4x;
794 break;
795
796 default :
797 vers = 0;
798 break;
799 }
800
801 return vers;
802 }
803
804
805 static long TestForKey(long key)
806 {
807 long keyNum;
808 long bp;
809 char tc;
810
811 if (gOFVersion < kOFVersion3x) {
812 switch(key) {
813 case 'a' : keyNum = 7; break;
814 case 's' : keyNum = 6; break;
815 case 'v' : keyNum = 14; break;
816 case 'y' : keyNum = 23; break;
817 case kCommandKey : keyNum = 48; break;
818 case kOptKey : keyNum = 61; break;
819 case kShiftKey : keyNum = 63; break;
820 case kControlKey : keyNum = 49; break;
821 default : keyNum = -1; break;
822 }
823 } else {
824 switch(key) {
825 case 'a' : keyNum = 3; break;
826 case 's' : keyNum = 17; break;
827 case 'v' : keyNum = 30; break;
828 case 'y' : keyNum = 27; break;
829 case kCommandKey : keyNum = 228; break;
830 case kOptKey : keyNum = 229; break;
831 case kShiftKey : keyNum = 230; break;
832 case kControlKey : keyNum = 231; break;
833 case kDeleteKey : keyNum = 45; break;
834 default : keyNum = -1; break;
835 }
836
837 // Map the right modifier keys on to the left.
838 gKeyMap[28] |= gKeyMap[28] << 4;
839 }
840
841 if (keyNum == -1) return 0;
842
843 bp = keyNum & 7;
844 tc = gKeyMap[keyNum >> 3];
845
846 return (tc & (1 << bp)) != 0;
847 }
848
849
850 #define kBootpBootFileOffset (108)
851
852 static long GetBootPaths(void)
853 {
854 long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen;
855 unsigned long adler32;
856 char *filePath, *buffer, uuidStr[64];
857
858 if (gBootSourceNumber == -1) {
859 // Get the boot device and derive its type
860 // (try chosen "bootpath", then boot-device in the options)
861 size = GetProp(gChosenPH, "bootpath", gBootDevice, 255);
862 gBootDevice[size] = '\0';
863 if (gBootDevice[0] == '\0') {
864 size = GetProp(gOptionsPH, "boot-device", gBootDevice, 255);
865 gBootDevice[size] = '\0';
866 }
867 // hardcode to my Apple_Boot before my Apple_RAID
868 // debug: override boot device to boot from disk even if OF used TFTP
869 //printf("old gBootDevice: %s\n", gBootDevice);
870 //strcpy(gBootDevice, "fw/node@d0010100007a9d/sbp-2@c000/@0:12"); // SmartDisk
871 //strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:9"); // mconcatI
872 //strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:11"); // mconcatI
873 //strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:2"); // mconcatII
874 //strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:4"); // mconcatII
875 //strcpy(gBootDevice, "fw/node@50770e0000676f/sbp-2@4000/@0:3"); // m120
876 //strcpy(gBootDevice, "fw/node@50770e0000725b/sbp-2@4000/@0:3"); // m120
877
878
879 // Look for Boot.plist-based booter stuff (like RAID :)
880 ret = ReadBootPlist(gBootDevice);
881 if (ret == 0) {
882 // success -> gBootDevice = "AppleRAID/#:0,\\\\:tbxi"
883 (void)LookForRAID(gBootDict); // could take gBootDevice?
884 }
885
886
887 // note RAID itself is of "block" type like members
888 gBootDeviceType = GetDeviceType(gBootDevice);
889 if(gBootDeviceType == -1) {
890 printf("Could not find boot device %s\n", gBootDevice);
891 return -1;
892 }
893
894
895 // Get the boot file (e.g. mach_kernel)
896 size = GetProp(gChosenPH, "bootargs", gBootFile, 256);
897 gBootFile[size] = '\0';
898
899 if (gBootFile[0] != '\0') {
900 gBootFileType = GetDeviceType(gBootFile);
901 gBootSourceNumberMax = 0;
902 } else {
903 gBootSourceNumber = 0;
904 gBootFileType = gBootDeviceType;
905 if (gBootFileType == kNetworkDeviceType) gBootSourceNumberMax = 1;
906 else {
907 if (gOFVersion < kOFVersion3x) {
908 gBootSourceNumberMax = 4;
909 } else {
910 gBootSourceNumberMax = 6;
911 }
912 }
913 }
914 // gBootSourceNumberMax = 2; // helpful to prevent lots of probing
915
916 if (gBootFileType == kNetworkDeviceType) {
917 SetProp(Peer(0), "net-boot", NULL, 0);
918 }
919 }
920
921 if (gBootSourceNumber >= gBootSourceNumberMax) return -1;
922
923 if (gBootSourceNumberMax != 0) {
924 switch (gBootFileType) {
925 case kNetworkDeviceType :
926 // Find the end of the device spec.
927 cnt = 0;
928 while (gBootDevice[cnt] != ':') cnt++;
929
930 // Copy the device spec with the ':'.
931 strncpy(gBootFile, gBootDevice, cnt + 1);
932
933 // Check for bootp-responce or bsdp-responce.
934 bootplen = GetPropLen(gChosenPH, "bootp-response");
935 bsdplen = GetPropLen(gChosenPH, "bsdp-response");
936 if ((bootplen > 0) || (bsdplen > 0)) {
937 if (bootplen > 0) {
938 buffer = malloc(bootplen);
939 GetProp(gChosenPH, "bootp-response", buffer, bootplen);
940 } else {
941 buffer = malloc(bsdplen);
942 GetProp(gChosenPH, "bsdp-response", buffer, bsdplen);
943 }
944
945 // Flip the slash's to back slash's while looking for the last one.
946 cnt = cnt2 = kBootpBootFileOffset;
947 while (buffer[cnt] != '\0') {
948 if (buffer[cnt] == '/') {
949 buffer[cnt] = '\\';
950 cnt2 = cnt + 1;
951 }
952 cnt++;
953 }
954
955 // Add a comma at the front.
956 buffer[kBootpBootFileOffset - 1] = ',';
957
958 // Append the the root dir to the device spec.
959 strncat(gBootFile, buffer + kBootpBootFileOffset - 1,
960 cnt2 - kBootpBootFileOffset + 1);
961
962 free(buffer);
963 } else {
964 // Look for the start of the root dir path.
965 cnt3 = cnt;
966 while (gBootDevice[cnt3] != ',') cnt3++;
967
968 // Find the end of the path. Look for a comma or null.
969 cnt2 = cnt3 + 1;
970 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt2] != ',')) cnt2++;
971
972 // Find the last back slash or comma in the path
973 cnt4 = cnt2 - 1;
974 while ((gBootDevice[cnt4] != ',') && (gBootDevice[cnt4] != '\\')) cnt4--;
975
976 // Copy the IP addresses if needed.
977 if (gOFVersion < kOFVersion3x) {
978 strncat(gBootFile, gBootDevice + cnt + 1, cnt3 - cnt - 1);
979 }
980
981 // Add on the directory path
982 strncat(gBootFile, gBootDevice + cnt3, cnt4 - cnt3 + 1);
983 }
984
985 // Add on the kernel name
986 strcat(gBootFile, "mach.macosx");
987
988 // Add on postfix
989 strcat(gBootFile, gBootDevice + cnt2);
990 break;
991
992 case kBlockDeviceType :
993 // Find the first ':'.
994 cnt = 0;
995 while ((gBootDevice[cnt] != '\0') && (gBootDevice[cnt] != ':')) cnt++;
996 if (gBootDevice[cnt] == '\0') return -1;
997
998 // Find the comma after the ':'.
999 cnt2 = cnt + 1;
1000 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt] != ',')) cnt2++;
1001
1002 // Get just the partition number
1003 strncpy(gBootFile, gBootDevice + cnt + 1, cnt2 - cnt - 1);
1004 partNum = strtol(gBootFile, 0, 10);
1005 if (partNum == 0) partNum = strtol(gBootFile, 0, 16);
1006
1007 // Adjust the partition number.
1008 // Pass 0 & 1, no offset. Pass 2 & 3, offset 1, Pass 4 & 5, offset 2.
1009 partNum += gBootSourceNumber / 2;
1010
1011 // Construct the boot-file
1012 strncpy(gBootFile, gBootDevice, cnt + 1);
1013 sprintf(gBootFile + cnt + 1, "%d,%s\\mach_kernel",
1014 partNum, ((gBootSourceNumber & 1) ? "" : "\\"));
1015
1016 // and the cache file name
1017
1018 bzero(gCacheNameAdler + 64, sizeof(gBootFile));
1019 strcpy(gCacheNameAdler + 64, gBootFile);
1020 adler32 = Adler32(gCacheNameAdler, sizeof(gCacheNameAdler));
1021
1022 strncpy(gBootKernelCacheFile, gBootDevice, cnt + 1);
1023 sprintf(gBootKernelCacheFile + cnt + 1,
1024 "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum, adler32);
1025 break;
1026
1027 default:
1028 printf("Failed to infer Boot Device Type.\n");
1029 return -1;
1030 break;
1031 }
1032 }
1033
1034 // Figure out the root dir.
1035 ret = ConvertFileSpec(gBootFile, gExtensionsSpec, &filePath);
1036 if (ret == -1) {
1037 printf("Failed to determine root directory\n");
1038 return -1;
1039 }
1040
1041 strcat(gExtensionsSpec, ",");
1042
1043 // Add in any extra path to gRootDir.
1044 cnt = 0;
1045 while (filePath[cnt] != '\0') cnt++;
1046
1047 if (cnt != 0) {
1048 for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) {
1049 if (filePath[cnt2] == '\\') {
1050 strncat(gExtensionsSpec, filePath, cnt2 + 1);
1051 break;
1052 }
1053 }
1054 }
1055
1056 // Figure out the extensions dir.
1057 if (gBootFileType == kBlockDeviceType) {
1058 cnt = strlen(gExtensionsSpec);
1059 if ((cnt > 2) && (gExtensionsSpec[cnt-1] == '\\') && (gExtensionsSpec[cnt-2] == '\\'))
1060 cnt--;
1061 strcpy(gExtensionsSpec + cnt, "System\\Library\\");
1062 }
1063
1064 // technically could just do this once at the end
1065 SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1);
1066
1067 if (GetFSUUID(gBootFile, uuidStr) == 0) {
1068 printf("setting boot-uuid to: %s\n", uuidStr);
1069 SetProp(gChosenPH, "boot-uuid", uuidStr, strlen(uuidStr) + 1);
1070 }
1071
1072 gBootSourceNumber++;
1073
1074 return 0;
1075 }
1076
1077 #define BOOTPLIST_PATH "com.apple.Boot.plist"
1078
1079 // ReadBootPlist could live elsewhere
1080 static long ReadBootPlist(char *devSpec)
1081 {
1082 char plistSpec[256];
1083 int len;
1084
1085 do {
1086 // construct the Boot.plist spec
1087 if (ConvertFileSpec(devSpec, plistSpec, NULL)) break;
1088 strncat(plistSpec, ",\\\\", 255-strlen(plistSpec));
1089 strncat(plistSpec, BOOTPLIST_PATH, 255-strlen(plistSpec));
1090
1091 // load the contents
1092 if ((len = LoadFile(plistSpec)) < 0) break;
1093 // we could try for the root as well as the blessed folder
1094 *((char*)kLoadAddr + len) = '\0'; // terminate for parser safety
1095
1096 if (ParseXML((char*)kLoadAddr, &gBootDict) < 0 || !gBootDict) {
1097 printf("couldn't parse %s\n", BOOTPLIST_PATH);
1098 break;
1099 }
1100
1101 return 0;
1102 } while(0);
1103
1104 return -1;
1105 }
1106
1107 // Public Functions
1108
1109 long GetDeviceType(char *devSpec)
1110 {
1111 CICell ph;
1112 long size;
1113 char deviceType[32];
1114
1115 if (isRAIDPath(devSpec))
1116 return kBlockDeviceType;
1117
1118 ph = FindDevice(devSpec);
1119 if (ph == -1) return -1;
1120
1121 size = GetProp(ph, "device_type", deviceType, 31);
1122 if (size != -1) deviceType[size] = '\0';
1123 else deviceType[0] = '\0';
1124
1125 if (strcmp(deviceType, "network") == 0) return kNetworkDeviceType;
1126 if (strcmp(deviceType, "block") == 0) return kBlockDeviceType;
1127
1128 return kUnknownDeviceType;
1129 }
1130
1131
1132 long ConvertFileSpec(char *fileSpec, char *devSpec, char **filePath)
1133 {
1134 long cnt;
1135
1136 // Find the first ':' in the fileSpec.
1137 cnt = 0;
1138 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ':')) cnt++;
1139 if (fileSpec[cnt] == '\0') return -1;
1140
1141 // Find the next ',' in the fileSpec.
1142 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ',')) cnt++;
1143
1144 // Copy the string to devSpec.
1145 strncpy(devSpec, fileSpec, cnt);
1146 devSpec[cnt] = '\0';
1147
1148 // If there is a filePath start it after the ',', otherwise NULL.
1149 if (filePath != NULL) {
1150 if (fileSpec[cnt] != '\0') {
1151 *filePath = fileSpec + cnt + 1;
1152 } else {
1153 *filePath = NULL;
1154 }
1155 }
1156
1157 return 0;
1158 }
1159
1160
1161 long MatchThis(CICell phandle, char *string)
1162 {
1163 long ret, length;
1164 char *name, *model, *compatible;
1165
1166 ret = GetPackageProperty(phandle, "name", &name, &length);
1167 if ((ret == -1) || (length == 0)) name = NULL;
1168
1169 ret = GetPackageProperty(phandle, "model", &model, &length);
1170 if ((ret == -1) || (length == 0)) model = NULL;
1171
1172 ret = GetPackageProperty(phandle, "compatible", &compatible, &length);
1173 if ((ret == -1) || (length == 0)) model = NULL;
1174
1175 if ((name != NULL) && strcmp(name, string) == 0) return 0;
1176 if ((model != NULL) && strcmp(model, string) == 0) return 0;
1177
1178 if (compatible != NULL) {
1179 while (*compatible != '\0') {
1180 if (strcmp(compatible, string) == 0) return 0;
1181
1182 compatible += strlen(compatible) + 1;
1183 }
1184 }
1185
1186 return -1;
1187 }
1188
1189
1190 void *AllocateBootXMemory(long size)
1191 {
1192 long addr = gImageFirstBootXAddr - size;
1193
1194 if (addr < gImageLastKernelAddr) return 0;
1195
1196 gImageFirstBootXAddr = addr;
1197
1198 return (void *)addr;
1199 }
1200
1201
1202 long AllocateKernelMemory(long size)
1203 {
1204 long addr = gImageLastKernelAddr;
1205
1206 gImageLastKernelAddr += (size + 0xFFF) & ~0xFFF;
1207
1208 if (gImageLastKernelAddr > gImageFirstBootXAddr)
1209 FailToBoot(-1);
1210
1211 return addr;
1212 }
1213
1214
1215 long AllocateMemoryRange(char *rangeName, long start, long length)
1216 {
1217 long result, *buffer;
1218
1219 buffer = AllocateBootXMemory(2 * sizeof(long));
1220 if (buffer == 0) return -1;
1221
1222 buffer[0] = start;
1223 buffer[1] = length;
1224
1225 result = SetProp(gMemoryMapPH, rangeName, (char *)buffer, 2 * sizeof(long));
1226 if (result == -1) return -1;
1227
1228 return 0;
1229 }
1230
1231 #define BASE 65521L /* largest prime smaller than 65536 */
1232 #define NMAX 5000
1233 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
1234
1235 #define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
1236 #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
1237 #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
1238 #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
1239 #define DO16(buf) DO8(buf,0); DO8(buf,8);
1240
1241 unsigned long Adler32(unsigned char *buf, long len)
1242 {
1243 unsigned long s1 = 1; // adler & 0xffff;
1244 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
1245 int k;
1246
1247 while (len > 0) {
1248 k = len < NMAX ? len : NMAX;
1249 len -= k;
1250 while (k >= 16) {
1251 DO16(buf);
1252 buf += 16;
1253 k -= 16;
1254 }
1255 if (k != 0) do {
1256 s1 += *buf++;
1257 s2 += s1;
1258 } while (--k);
1259 s1 %= BASE;
1260 s2 %= BASE;
1261 }
1262 return (s2 << 16) | s1;
1263 }