]>
git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/main.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * main.c - Main functions for BootX.
25 * Copyright (c) 1998-2004 Apple Computer, Inc.
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
);
47 const unsigned long StartTVector
[2] = {(unsigned long)Start
, 0};
49 char gStackBaseAddr
[0x8000];
51 char *gVectorSaveAddr
;
52 long gImageLastKernelAddr
= 0;
53 long gImageFirstBootXAddr
= kLoadAddr
;
54 long gKernelEntryPoint
;
59 long gSymbolTableAddr
;
60 long gSymbolTableSize
;
62 long gBootSourceNumber
= -1;
63 long gBootSourceNumberMax
;
64 long gBootMode
= kBootModeNormal
;
67 char gHaveKernelCache
= 0;
68 char gBootDevice
[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
;
78 long *gDeviceTreeMMTmp
= 0;
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
;
105 //int gDebugCount = 0;
109 static void Start(void *unused1
, void *unused2
, ClientInterfacePtr ciPtr
)
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
));
122 static void Main(ClientInterfacePtr ciPtr
)
126 long flags
, cachetime
, kerneltime
, exttime
= 0;
127 void *binary
= (void *)kLoadAddr
;
129 ret
= InitEverything(ciPtr
);
130 if (ret
!= 0) Exit();
133 // Get or infer the boot paths.
134 ret
= GetBootPaths();
135 if (ret
!= 0) FailToBoot(1);
142 trycache
= (0 == (gBootMode
& kBootModeSafe
))
143 && (gBootKernelCacheFile
[0] != 0);
145 if (trycache
&& (gBootFileType
== kBlockDeviceType
)) do {
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
)) {
153 ret
= GetFileInfo(NULL
, gBootKernelCacheFile
, &flags
, &cachetime
);
154 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)
155 || (cachetime
< kerneltime
)) {
159 ret
= GetFileInfo(gExtensionsSpec
, "Extensions", &flags
, &exttime
);
160 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeDirectory
)
161 && (cachetime
< exttime
)) {
165 if (kerneltime
> exttime
)
166 exttime
= kerneltime
;
167 if (cachetime
!= (exttime
+ 1)) {
174 ret
= LoadFile(gBootKernelCacheFile
);
176 ret
= DecodeKernel(binary
);
177 if (ret
!= -1) break;
180 ret
= LoadThinFatFile(gBootFile
, &binary
);
181 if (ret
!= -1) ret
= DecodeKernel(binary
);
182 if (ret
!= -1) break;
184 ret
= GetBootPaths();
185 if (ret
!= 0) FailToBoot(2);
188 if (ret
!= 0) FailToBoot(3);
190 if (!gHaveKernelCache
) {
191 ret
= LoadDrivers(gExtensionsSpec
);
192 if (ret
!= 0) FailToBoot(4);
199 ret
= SetUpBootArgs();
200 if (ret
!= 0) FailToBoot(5);
207 static uint32_t UnescapeData(const uint8_t * src
,
212 uint32_t cnt
, cnt2
, dstLen
= 0;
215 for (cnt
= 0; cnt
< srcLen
;) {
220 byte
= (byte
& 0x80) ? 0xFF : 0x00;
224 if (dstLen
>= dstMaxLen
)
226 dst
[dstLen
++] = byte
;
232 static long InitEverything(ClientInterfacePtr ciPtr
)
234 long ret
, mem_base
, mem_base2
, size
;
236 char name
[32], securityMode
[33];
240 // Init the OF Client Interface.
242 if (ret
!= 0) return -1;
244 // Get the OF Version
245 gOFVersion
= GetOFVersion();
246 if (gOFVersion
== 0) return -1;
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;
253 // Init the SL Words package.
255 if (ret
!= 0) return -1;
257 // Get the phandle for /options
258 gOptionsPH
= FindDevice("/options");
259 if (gOptionsPH
== -1) return -1;
261 // Get the phandle for /chosen
262 gChosenPH
= FindDevice("/chosen");
263 if (gChosenPH
== -1) return -1;
265 // Init the Memory Map.
266 ret
= InitMemoryMap();
267 if (ret
!= 0) return -1;
269 // Get IHandles for the MMU and Memory
270 size
= GetProp(gChosenPH
, "mmu", (char *)&gMMUIH
, 4);
272 printf("Failed to get the IH for the MMU.\n");
275 size
= GetProp(gChosenPH
, "memory", (char *)&gMemoryIH
, 4);
277 printf("Failed to get the IH for the Memory.\n");
281 // Get first element of root's compatible property.
282 ret
= GetPackageProperty(Peer(0), "compatible", &compatible
, &length
);
284 strcpy(gPlatformName
, compatible
);
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;
291 // Try to find the keyboard using chosen
292 ret
= GetProp(gChosenPH
, "stdin", (char *)&gKeyboardIH
, 4);
293 if (ret
!= 4) gKeyboardIH
= 0;
295 keyboardPH
= InstanceToPackage(gKeyboardIH
);
296 ret
= GetProp(keyboardPH
, "name", name
, 31);
299 if (strcmp(name
, "keyboard") && strcmp(name
, "kbd")) gKeyboardIH
= 0;
300 } else gKeyboardIH
= 0;
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");
307 // Get the key map set up, and make it up to date.
308 gKeyMap
= InitKeyMap(gKeyboardIH
);
309 if (gKeyMap
== NULL
) return -1;
312 // Test for Secure Boot Mode.
313 size
= GetProp(gOptionsPH
, "security-mode", securityMode
, 32);
315 securityMode
[size
] = '\0';
316 if (strcmp(securityMode
, "none")) gBootMode
|= kBootModeSecure
;
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
);
325 SetOutputLevel(kOutputLevelOff
);
328 SetOutputLevel(kOutputLevelFull
);
332 printf("\n\nMac OS X Loader\n");
334 // Test for Safe Boot Mode; Shift and not Delete.
335 if (((gBootMode
& kBootModeSecure
) == 0)
336 && TestForKey(kShiftKey
) && !TestForKey(kDeleteKey
)) {
337 gBootMode
|= kBootModeSafe
;
341 // Claim memory for the FS Cache.
342 if (Claim(kFSCacheAddr
, kFSCacheSize
, 0) == 0) {
343 printf("Claim for fs cache failed.\n");
347 // Claim memory for malloc.
348 if (Claim(kMallocAddr
, kMallocSize
, 0) == 0) {
349 printf("Claim for malloc failed.\n");
352 malloc_init((char *)kMallocAddr
, kMallocSize
);
354 // Claim memory for the Load Addr.
355 mem_base
= Claim(kLoadAddr
, kLoadSize
, 0);
357 printf("Claim for Load Area failed.\n");
361 // Claim the memory for the Image Addr
362 if (gOFVersion
>= kOFVersion3x
) {
363 mem_base
= Claim(kImageAddr
, kImageSize
, 0);
365 printf("Claim for Image Area failed.\n");
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");
377 // Unmap the old xcoff stack.
378 CallMethod(2, 0, gMMUIH
, "unmap", 0x00380000, 0x00080000);
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");
390 // Map them together.
391 CallMethod(4, 0, gMMUIH
, "map",
392 kImageAddr1Phys
, kImageAddr1
, kImageSize1
, 0);
395 bzero((char *)kImageAddr
, kImageSize
);
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");
403 // Find all the displays and set them up.
404 ret
= InitDisplays(1);
406 printf("InitDisplays failed.\n");
415 long ThinFatBinary(void **binary
, unsigned long *length
)
419 ret
= ThinFatBinaryMachO(binary
, length
);
420 if (ret
== -1) ret
= ThinFatBinaryElf(binary
, length
);
425 static long DecodeKernel(void *binary
)
428 compressed_kernel_header
*kernel_header
= (compressed_kernel_header
*)binary
;
431 if (kernel_header
->signature
== 'comp') {
432 if (kernel_header
->compress_type
!= 'lzss')
434 if (kernel_header
->platform_name
[0] && strcmp(gPlatformName
, kernel_header
->platform_name
))
436 if (kernel_header
->root_path
[0] && strcmp(gBootFile
, kernel_header
->root_path
))
439 binary
= AllocateBootXMemory(kernel_header
->uncompressed_size
);
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
);
446 if (kernel_header
->adler32
!=
447 Adler32(binary
, kernel_header
->uncompressed_size
)) {
448 printf("adler mismatch\n");
453 ThinFatBinary(&binary
, 0);
455 ret
= DecodeMachO(binary
);
456 if (ret
== -1) ret
= DecodeElf(binary
);
462 static long SetUpBootArgs(void)
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
;
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);
478 // Allocate some memory for the BootArgs.
479 gBootArgsSize
= sizeof(boot_args
);
480 gBootArgsAddr
= AllocateKernelMemory(gBootArgsSize
);
482 // Add the BootArgs to the memory-map.
483 AllocateMemoryRange("BootArgs", gBootArgsAddr
, gBootArgsSize
);
485 args
= (boot_args_ptr
)gBootArgsAddr
;
487 args
->Revision
= kBootArgsRevision
;
488 args
->Version
= kBootArgsVersion1
;
489 args
->machineType
= 0;
491 // Check the Keyboard for 'cmd-s' and 'cmd-v'
493 if ((gBootMode
& kBootModeSecure
) == 0) {
494 sKey
= TestForKey(kCommandKey
) && TestForKey('s');
495 vKey
= TestForKey(kCommandKey
) && TestForKey('v');
501 // if 'cmd-s' or 'cmd-v' was pressed do a text boot.
502 if (sKey
|| vKey
) graphicsBoot
= 0;
504 // Create the command line.
505 if (gOFVersion
< kOFVersion3x
) {
507 size
= GetProp(gChosenPH
, "machargs", ofBootArgs
+ 1, (sizeof(ofBootArgs
) - 2));
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
));
522 size
= GetProp(gOptionsPH
, "boot-args", ofBootArgs
, (sizeof(ofBootArgs
) - 1));
523 if (size
== -1) ofBootArgs
[0] = '\0';
524 else ofBootArgs
[size
] = '\0';
527 if (ofBootArgs
[0] != '\0') {
528 // Look for special options and copy the rest.
531 while ((tc
= *ofArgs
) != '\0') {
534 // Check for entering a dash arg.
541 // Do special stuff if in a dash arg.
547 } else if (tc
== 'v') {
552 // Check for exiting dash arg
553 if (isspace(tc
)) dash
= 0;
555 // Copy any non 's' or 'v'
559 // Not a dash arg so just copy it.
565 // Add any pressed keys (s, v, shift) to the command line
567 if (sKey
|| vKey
|| (gBootMode
& kBootModeSafe
)) {
568 keyStr
[keyPos
++] = '-';
570 if (sKey
) keyStr
[keyPos
++] = 's';
571 if (vKey
) keyStr
[keyPos
++] = 'v';
572 if (gBootMode
& kBootModeSafe
) keyStr
[keyPos
++] = 'x';
574 keyStr
[keyPos
++] = ' ';
576 keyStr
[keyPos
++] = '\0';
578 sprintf(args
->CommandLine
, "%s%s", keyStr
, ofBootArgs
);
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;
585 args
->Version
= kBootArgsVersion2
;
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
;
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
;
602 args
->PhysicalDRAM
[cnt
].base
=
603 *(unsigned long long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
)) >> bank_shift
;
607 if (gRootSizeCells
== 1) {
608 args
->PhysicalDRAM
[cnt
].size
=
609 *(unsigned long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
) + 4 * gRootAddrCells
) >> bank_shift
;
611 args
->PhysicalDRAM
[cnt
].size
=
612 *(unsigned long long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
) + 4 * gRootAddrCells
) >> bank_shift
;
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;
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
));
628 bzero(args
->PhysicalDRAM
+ mem_banks
, (kMaxDRAMBanks
- mem_banks
) * sizeof(DRAMBank
));
630 // Get the video info
631 GetMainScreenPH(&args
->Video
, 1);
632 args
->Video
.v_display
= graphicsBoot
;
634 // Add the DeviceTree to the memory-map.
635 // The actuall address and size must be filled in later.
636 AllocateMemoryRange("DeviceTree", 0, 0);
638 ret
= FlattenDeviceTree();
639 if (ret
!= 0) return -1;
641 // Fill in the address and size of the device tree.
642 if (gDeviceTreeAddr
) {
643 gDeviceTreeMMTmp
[0] = gDeviceTreeAddr
;
644 gDeviceTreeMMTmp
[1] = gDeviceTreeSize
;
647 args
->deviceTreeP
= (void *)gDeviceTreeAddr
;
648 args
->deviceTreeLength
= gDeviceTreeSize
;
649 args
->topOfKernelData
= AllocateKernelMemory(0);
655 static long CallKernel(void)
657 unsigned long msr
, cnt
;
661 printf("\nCall Kernel!\n");
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
));
670 // Turn off translations
672 __asm__
volatile("sync");
673 __asm__
volatile("mtmsr %0" : : "r" (msr
));
674 __asm__
volatile("isync");
676 // Save the OF's Exceptions Vectors
677 bcopy(0x0, gOFVectorSave
, kVectorSize
);
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
));
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
));
695 // Make sure everything get sync'd up.
696 __asm__
volatile("isync");
697 __asm__
volatile("sync");
698 __asm__
volatile("eieio");
700 // Call the Kernel's entry point
701 (*(void (*)())gKernelEntryPoint
)(gBootArgsAddr
, kMacOSXSignature
);
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
));
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
));
716 // Restore translations
717 __asm__
volatile("sync");
718 __asm__
volatile("mtmsr %0" : : "r" (gOFMSRSave
));
719 __asm__
volatile("isync");
725 static void FailToBoot(long num
)
727 // useful for those holding down command-v ...
728 printf("FailToBoot: %d\n", num
);
730 DrawFailedBootPicture();
734 Enter(); // For debugging
739 static long InitMemoryMap(void)
743 result
= Interpret(0, 1,
746 " \" memory-map\" device-name"
755 static long GetOFVersion(void)
758 char versStr
[256], *tmpStr
;
761 // Get the openprom package
762 ph
= FindDevice("/openprom");
763 if (ph
== -1) return 0;
765 // Get it's model property
766 size
= GetProp(ph
, "model", versStr
, 255);
767 if (size
== -1) return -1;
768 versStr
[size
] = '\0';
770 // Find the start of the number.
772 if (!strncmp(versStr
, "Open Firmware, ", 15)) {
773 tmpStr
= versStr
+ 15;
774 } else if (!strncmp(versStr
, "OpenFirmware ", 13)) {
775 tmpStr
= versStr
+ 13;
778 // Clasify by each instance as needed...
805 static long TestForKey(long key
)
811 if (gOFVersion
< kOFVersion3x
) {
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;
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;
837 // Map the right modifier keys on to the left.
838 gKeyMap
[28] |= gKeyMap
[28] << 4;
841 if (keyNum
== -1) return 0;
844 tc
= gKeyMap
[keyNum
>> 3];
846 return (tc
& (1 << bp
)) != 0;
850 #define kBootpBootFileOffset (108)
852 static long GetBootPaths(void)
854 long ret
, cnt
, cnt2
, cnt3
, cnt4
, size
, partNum
, bootplen
, bsdplen
;
855 unsigned long adler32
;
856 char *filePath
, *buffer
, uuidStr
[64];
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';
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
879 // Look for Boot.plist-based booter stuff (like RAID :)
880 ret
= ReadBootPlist(gBootDevice
);
882 // success -> gBootDevice = "AppleRAID/#:0,\\\\:tbxi"
883 (void)LookForRAID(gBootDict
); // could take gBootDevice?
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
);
895 // Get the boot file (e.g. mach_kernel)
896 size
= GetProp(gChosenPH
, "bootargs", gBootFile
, 256);
897 gBootFile
[size
] = '\0';
899 if (gBootFile
[0] != '\0') {
900 gBootFileType
= GetDeviceType(gBootFile
);
901 gBootSourceNumberMax
= 0;
903 gBootSourceNumber
= 0;
904 gBootFileType
= gBootDeviceType
;
905 if (gBootFileType
== kNetworkDeviceType
) gBootSourceNumberMax
= 1;
907 if (gOFVersion
< kOFVersion3x
) {
908 gBootSourceNumberMax
= 4;
910 gBootSourceNumberMax
= 6;
914 // gBootSourceNumberMax = 2; // helpful to prevent lots of probing
916 if (gBootFileType
== kNetworkDeviceType
) {
917 SetProp(Peer(0), "net-boot", NULL
, 0);
921 if (gBootSourceNumber
>= gBootSourceNumberMax
) return -1;
923 if (gBootSourceNumberMax
!= 0) {
924 switch (gBootFileType
) {
925 case kNetworkDeviceType
:
926 // Find the end of the device spec.
928 while (gBootDevice
[cnt
] != ':') cnt
++;
930 // Copy the device spec with the ':'.
931 strncpy(gBootFile
, gBootDevice
, cnt
+ 1);
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)) {
938 buffer
= malloc(bootplen
);
939 GetProp(gChosenPH
, "bootp-response", buffer
, bootplen
);
941 buffer
= malloc(bsdplen
);
942 GetProp(gChosenPH
, "bsdp-response", buffer
, bsdplen
);
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
] == '/') {
955 // Add a comma at the front.
956 buffer
[kBootpBootFileOffset
- 1] = ',';
958 // Append the the root dir to the device spec.
959 strncat(gBootFile
, buffer
+ kBootpBootFileOffset
- 1,
960 cnt2
- kBootpBootFileOffset
+ 1);
964 // Look for the start of the root dir path.
966 while (gBootDevice
[cnt3
] != ',') cnt3
++;
968 // Find the end of the path. Look for a comma or null.
970 while ((gBootDevice
[cnt2
] != '\0') && (gBootDevice
[cnt2
] != ',')) cnt2
++;
972 // Find the last back slash or comma in the path
974 while ((gBootDevice
[cnt4
] != ',') && (gBootDevice
[cnt4
] != '\\')) cnt4
--;
976 // Copy the IP addresses if needed.
977 if (gOFVersion
< kOFVersion3x
) {
978 strncat(gBootFile
, gBootDevice
+ cnt
+ 1, cnt3
- cnt
- 1);
981 // Add on the directory path
982 strncat(gBootFile
, gBootDevice
+ cnt3
, cnt4
- cnt3
+ 1);
985 // Add on the kernel name
986 strcat(gBootFile
, "mach.macosx");
989 strcat(gBootFile
, gBootDevice
+ cnt2
);
992 case kBlockDeviceType
:
993 // Find the first ':'.
995 while ((gBootDevice
[cnt
] != '\0') && (gBootDevice
[cnt
] != ':')) cnt
++;
996 if (gBootDevice
[cnt
] == '\0') return -1;
998 // Find the comma after the ':'.
1000 while ((gBootDevice
[cnt2
] != '\0') && (gBootDevice
[cnt
] != ',')) cnt2
++;
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);
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;
1011 // Construct the boot-file
1012 strncpy(gBootFile
, gBootDevice
, cnt
+ 1);
1013 sprintf(gBootFile
+ cnt
+ 1, "%d,%s\\mach_kernel",
1014 partNum
, ((gBootSourceNumber
& 1) ? "" : "\\"));
1016 // and the cache file name
1018 bzero(gCacheNameAdler
+ 64, sizeof(gBootFile
));
1019 strcpy(gCacheNameAdler
+ 64, gBootFile
);
1020 adler32
= Adler32(gCacheNameAdler
, sizeof(gCacheNameAdler
));
1022 strncpy(gBootKernelCacheFile
, gBootDevice
, cnt
+ 1);
1023 sprintf(gBootKernelCacheFile
+ cnt
+ 1,
1024 "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum
, adler32
);
1028 printf("Failed to infer Boot Device Type.\n");
1034 // Figure out the root dir.
1035 ret
= ConvertFileSpec(gBootFile
, gExtensionsSpec
, &filePath
);
1037 printf("Failed to determine root directory\n");
1041 strcat(gExtensionsSpec
, ",");
1043 // Add in any extra path to gRootDir.
1045 while (filePath
[cnt
] != '\0') cnt
++;
1048 for (cnt2
= cnt
- 1; cnt2
>= 0; cnt2
--) {
1049 if (filePath
[cnt2
] == '\\') {
1050 strncat(gExtensionsSpec
, filePath
, cnt2
+ 1);
1056 // Figure out the extensions dir.
1057 if (gBootFileType
== kBlockDeviceType
) {
1058 cnt
= strlen(gExtensionsSpec
);
1059 if ((cnt
> 2) && (gExtensionsSpec
[cnt
-1] == '\\') && (gExtensionsSpec
[cnt
-2] == '\\'))
1061 strcpy(gExtensionsSpec
+ cnt
, "System\\Library\\");
1064 // technically could just do this once at the end
1065 SetProp(gChosenPH
, "rootpath", gBootFile
, strlen(gBootFile
) + 1);
1067 if (GetFSUUID(gBootFile
, uuidStr
) == 0) {
1068 printf("setting boot-uuid to: %s\n", uuidStr
);
1069 SetProp(gChosenPH
, "boot-uuid", uuidStr
, strlen(uuidStr
) + 1);
1072 gBootSourceNumber
++;
1077 #define BOOTPLIST_PATH "com.apple.Boot.plist"
1079 // ReadBootPlist could live elsewhere
1080 static long ReadBootPlist(char *devSpec
)
1082 char plistSpec
[256];
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
));
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
1096 if (ParseXML((char*)kLoadAddr
, &gBootDict
) < 0 || !gBootDict
) {
1097 printf("couldn't parse %s\n", BOOTPLIST_PATH
);
1109 long GetDeviceType(char *devSpec
)
1113 char deviceType
[32];
1115 if (isRAIDPath(devSpec
))
1116 return kBlockDeviceType
;
1118 ph
= FindDevice(devSpec
);
1119 if (ph
== -1) return -1;
1121 size
= GetProp(ph
, "device_type", deviceType
, 31);
1122 if (size
!= -1) deviceType
[size
] = '\0';
1123 else deviceType
[0] = '\0';
1125 if (strcmp(deviceType
, "network") == 0) return kNetworkDeviceType
;
1126 if (strcmp(deviceType
, "block") == 0) return kBlockDeviceType
;
1128 return kUnknownDeviceType
;
1132 long ConvertFileSpec(char *fileSpec
, char *devSpec
, char **filePath
)
1136 // Find the first ':' in the fileSpec.
1138 while ((fileSpec
[cnt
] != '\0') && (fileSpec
[cnt
] != ':')) cnt
++;
1139 if (fileSpec
[cnt
] == '\0') return -1;
1141 // Find the next ',' in the fileSpec.
1142 while ((fileSpec
[cnt
] != '\0') && (fileSpec
[cnt
] != ',')) cnt
++;
1144 // Copy the string to devSpec.
1145 strncpy(devSpec
, fileSpec
, cnt
);
1146 devSpec
[cnt
] = '\0';
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;
1161 long MatchThis(CICell phandle
, char *string
)
1164 char *name
, *model
, *compatible
;
1166 ret
= GetPackageProperty(phandle
, "name", &name
, &length
);
1167 if ((ret
== -1) || (length
== 0)) name
= NULL
;
1169 ret
= GetPackageProperty(phandle
, "model", &model
, &length
);
1170 if ((ret
== -1) || (length
== 0)) model
= NULL
;
1172 ret
= GetPackageProperty(phandle
, "compatible", &compatible
, &length
);
1173 if ((ret
== -1) || (length
== 0)) model
= NULL
;
1175 if ((name
!= NULL
) && strcmp(name
, string
) == 0) return 0;
1176 if ((model
!= NULL
) && strcmp(model
, string
) == 0) return 0;
1178 if (compatible
!= NULL
) {
1179 while (*compatible
!= '\0') {
1180 if (strcmp(compatible
, string
) == 0) return 0;
1182 compatible
+= strlen(compatible
) + 1;
1190 void *AllocateBootXMemory(long size
)
1192 long addr
= gImageFirstBootXAddr
- size
;
1194 if (addr
< gImageLastKernelAddr
) return 0;
1196 gImageFirstBootXAddr
= addr
;
1198 return (void *)addr
;
1202 long AllocateKernelMemory(long size
)
1204 long addr
= gImageLastKernelAddr
;
1206 gImageLastKernelAddr
+= (size
+ 0xFFF) & ~0xFFF;
1208 if (gImageLastKernelAddr
> gImageFirstBootXAddr
)
1215 long AllocateMemoryRange(char *rangeName
, long start
, long length
)
1217 long result
, *buffer
;
1219 buffer
= AllocateBootXMemory(2 * sizeof(long));
1220 if (buffer
== 0) return -1;
1225 result
= SetProp(gMemoryMapPH
, rangeName
, (char *)buffer
, 2 * sizeof(long));
1226 if (result
== -1) return -1;
1231 #define BASE 65521L /* largest prime smaller than 65536 */
1233 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
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);
1241 unsigned long Adler32(unsigned char *buf
, long len
)
1243 unsigned long s1
= 1; // adler & 0xffff;
1244 unsigned long s2
= 0; // (adler >> 16) & 0xffff;
1248 k
= len
< NMAX
? len
: NMAX
;
1262 return (s2
<< 16) | s1
;