2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 * main.c - Main functions for BootX.
32 * Copyright (c) 1998-2004 Apple Computer, Inc.
40 #include <IOKit/IOHibernatePrivate.h>
41 #include <bootfiles.h>
43 static void Start(void *unused1
, void *unused2
, ClientInterfacePtr ciPtr
);
44 static void Main(ClientInterfacePtr ciPtr
);
45 static long InitEverything(ClientInterfacePtr ciPtr
);
46 static long DecodeKernel(void *binary
);
47 static long SetUpBootArgs(void);
48 static long CallKernel(void);
49 static void FailToBoot(long num
);
50 static long InitMemoryMap(void);
51 static long GetOFVersion(void);
52 static long TestForKey(long key
);
53 static long GetBootPaths(void);
54 static long ReadBootPlist(char *devSpec
, char *rpsDir
);
55 static long FindRPSDir(char *bootDevice
, char **rpsDir
);
57 const unsigned long StartTVector
[2] = {(unsigned long)Start
, 0};
59 char gStackBaseAddr
[0x8000];
61 char *gVectorSaveAddr
;
62 long gImageLastKernelAddr
= 0;
63 long gImageFirstBootXAddr
= kLoadAddr
;
64 long gKernelEntryPoint
;
69 long gSymbolTableAddr
;
70 long gSymbolTableSize
;
72 long gBootSourceNumber
= -1;
73 long gBootSourceNumberMax
;
74 long gBootMode
= kBootModeNormal
;
77 char gHaveKernelCache
= 0;
78 char gBootDevice
[256];
80 TagPtr gBootDict
= NULL
;
81 static char gBootKernelCacheFile
[512];
82 static char gExtensionsSpec
[4096];
83 static char gCacheNameAdler
[64 + sizeof(gBootFile
)];
84 static char *gPlatformName
= gCacheNameAdler
;
88 long *gDeviceTreeMMTmp
= 0;
94 unsigned long gHibernateKeySizeBytes
;
110 static char gOFVectorSave
[kVectorSize
];
111 static unsigned long gOFMSRSave
;
112 static unsigned long gOFSPRG0Save
;
113 static unsigned long gOFSPRG1Save
;
114 static unsigned long gOFSPRG2Save
;
115 static unsigned long gOFSPRG3Save
;
117 //int gDebugCount = 0;
121 static void Start(void *unused1
, void *unused2
, ClientInterfacePtr ciPtr
)
125 // Move the Stack to a chunk of the BSS
126 newSP
= (long)gStackBaseAddr
+ sizeof(gStackBaseAddr
) - 0x100;
127 __asm__
volatile("mr r1, %0" : : "r" (newSP
));
132 static long WakeKernel(void *p1
, void *p2
, void *p3
, void *p4
)
134 IOHibernateImageHeader
* header
= (IOHibernateImageHeader
*) p1
;
136 typedef void (*Proc
)(void *, void *, void *, void *);
138 unsigned long cnt
, newSP
;
139 unsigned long *src
, *dst
;
142 unsigned int compressedSize
;
143 unsigned int uncompressedPages
;
145 u_int32_t lowHalf
, highHalf
;
149 printf("\nWake Kernel!\n");
152 __asm__
volatile("mfmsr %0" : "=r" (gOFMSRSave
));
153 __asm__
volatile("mfsprg %0, 0" : "=r" (gOFSPRG0Save
));
154 __asm__
volatile("mfsprg %0, 1" : "=r" (gOFSPRG1Save
));
155 __asm__
volatile("mfsprg %0, 2" : "=r" (gOFSPRG2Save
));
156 __asm__
volatile("mfsprg %0, 3" : "=r" (gOFSPRG3Save
));
158 // Turn off translations
160 __asm__
volatile("sync");
161 __asm__
volatile("mtmsr %0" : : "r" (msr
));
162 __asm__
volatile("isync");
164 // Save OF's Exceptions Vectors
165 bcopy(0x0, gOFVectorSave
, kVectorSize
);
167 dst
= (unsigned long *) (header
->restore1CodePage
<< 12);
168 count
= header
->restore1PageCount
;
169 proc
= (Proc
) (header
->restore1CodeOffset
+ ((uint32_t) dst
));
170 newSP
= header
->restore1StackOffset
+ (header
->restore1CodePage
<< 12);
172 src
= (unsigned long *) (((u_int32_t
) &header
->fileExtentMap
[0])
173 + header
->fileExtentMapSize
);
176 for (page
= 0; page
< count
; page
++)
178 compressedSize
= 4096;
183 for (cnt
= 0; cnt
< compressedSize
; cnt
+= 0x20) {
192 for (byteCnt
= 0; byteCnt
< 0x20; byteCnt
++) {
193 lowHalf
+= ((u_int8_t
*) dst
)[byteCnt
];
196 __asm__
volatile("dcbf 0, %0" : : "r" (dst
));
197 __asm__
volatile("sync");
198 __asm__
volatile("icbi 0, %0" : : "r" (dst
));
199 __asm__
volatile("isync");
200 __asm__
volatile("sync");
207 sum
+= (highHalf
<< 16) | lowHalf
;
209 uncompressedPages
= count
;
210 header
->actualRestore1Sum
= sum
;
212 __asm__
volatile("dcbf 0, %0" : : "r" (dst
));
213 __asm__
volatile("dcbf 0, %0" : : "r" (dst
+32));
214 __asm__
volatile("sync");
215 __asm__
volatile("icbi 0, %0" : : "r" (dst
));
216 __asm__
volatile("icbi 0, %0" : : "r" (dst
+32));
217 __asm__
volatile("isync");
218 __asm__
volatile("sync");
220 // Make sure everything get sync'd up.
221 __asm__
volatile("isync");
222 __asm__
volatile("sync");
223 __asm__
volatile("eieio");
226 __asm__
volatile("mr r1, %0" : : "r" (newSP
));
227 __asm__
volatile("ori 0, 0, 0" : : );
228 proc(p1
, p2
, p3
, p4
);
233 void HibernateBoot(void)
235 CICell dev
, size
, maxRead
, imageSize
, codeSize
, allocSize
, bytesToRead
;
237 CICell available
[2*16];
239 IOHibernateImageHeader _header
;
240 IOHibernateImageHeader
* header
= &_header
;
241 volatile IOPolledFileExtent
* currentExtent
;
242 long long extentStart
;
243 long long extentLength
;
244 long long position
, positionMax
;
247 int havePreview
, readingPreview
;
249 Boot_Video videoInfo
;
250 hibernate_graphics_t
* graphicsInfo
;
251 uint32_t machineSignature
;
252 int32_t blob
, lastBlob
= 0;
254 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
255 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
256 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
257 hibernate_cryptvars_t _cryptvars
;
258 hibernate_cryptvars_t
* cryptvars
= &_cryptvars
;
259 hibernate_cryptwakevars_t
* cryptwakevars
;
262 tail
= &gBootDevice
[0];
263 while ((c
= *++tail
) && (c
!= ','))
269 extentStart
= strtouq(tail
, 0, 16);
271 printf("extentStart %s, %qx\n", gBootDevice
, extentStart
);
273 dev
= Open(gBootDevice
);
274 Seek(dev
, extentStart
);
276 size
= Read(dev
, (CICell
) header
, sizeof(IOHibernateImageHeader
));
277 printf("header read size %x\n", size
);
279 imageSize
= header
->image1Size
;
280 codeSize
= header
->restore1PageCount
<< 12;
281 if (kIOHibernateHeaderSignature
!= header
->signature
)
284 size
= GetProp(gChosenPH
, kIOHibernateMachineSignatureKey
,
285 (char *)&machineSignature
, sizeof(machineSignature
));
286 if (size
!= sizeof(machineSignature
)) machineSignature
= 0;
287 if (machineSignature
!= header
->machineSignature
)
290 allocSize
= imageSize
+ ((4095 + sizeof(hibernate_graphics_t
) + sizeof(hibernate_cryptwakevars_t
)) & ~4095);
292 // try to allocate the image as high as possible - end of available memory
293 memoryPH
= FindDevice("/memory");
294 if (memoryPH
== -1) break;
295 size
= GetProp(memoryPH
, "available", (char *) &available
[0], sizeof(available
));
296 if (size
== 0) break;
297 size
/= sizeof(CICell
);
298 mem_base
= available
[size
- 2] + available
[size
- 1] - allocSize
;
300 if (-1 == Claim(mem_base
, allocSize
, 0)) {
301 // else try above BootX's image
302 mem_base
= kImageAddr_H
;
303 if (-1 == Claim(mem_base
, allocSize
, 0)) {
304 // else try below BootX's image
305 mem_base
= (header
->restore1CodePage
<< 12) + codeSize
;
306 if (-1 == Claim(mem_base
, allocSize
, 0))
311 printf("mem_base %x\n", mem_base
);
313 graphicsInfo
= (hibernate_graphics_t
*) mem_base
;
314 cryptwakevars
= (hibernate_cryptwakevars_t
*) (graphicsInfo
+ 1);
315 mem_base
+= (allocSize
- imageSize
);
317 bcopy(header
, (void *) mem_base
, sizeof(IOHibernateImageHeader
));
318 header
= (IOHibernateImageHeader
*) mem_base
;
320 imageSize
-= sizeof(IOHibernateImageHeader
);
321 // imageSize -= codeSize;
322 currentExtent
= &header
->fileExtentMap
[0];
323 extentLength
= currentExtent
->length
- sizeof(IOHibernateImageHeader
);
324 extentStart
= currentExtent
->start
+ sizeof(IOHibernateImageHeader
);
325 buffer
= (long)(header
+ 1);
329 bytesToRead
= header
->previewSize
;
330 havePreview
= readingPreview
= (bytesToRead
!= 0);
331 if (readingPreview
) {
332 bytesToRead
+= header
->fileExtentMapSize
- sizeof(header
->fileExtentMap
) + codeSize
;
333 positionMax
= header
->imageSize
- bytesToRead
;
334 imageSize
-= bytesToRead
;
336 bytesToRead
= imageSize
;
337 positionMax
= header
->imageSize
;
338 maxRead
= positionMax
/ kIOHibernateProgressCount
;
339 SplashPreview(NULL
, &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
342 while (bytesToRead
) {
346 extentStart
= currentExtent
->start
;
347 extentLength
= currentExtent
->length
;
349 if (extentLength
< bytesToRead
)
354 if (maxRead
&& (size
> maxRead
))
357 if (-1 == Seek(dev
, extentStart
)) {
358 printf("seek fail\n");
361 if (size
!= Read(dev
, buffer
, size
)) {
362 printf("read fail\n");
368 if (!bytesToRead
&& readingPreview
) {
369 uint8_t * src
= (uint8_t *) (
370 ((uint32_t) &header
->fileExtentMap
[0])
371 + header
->fileExtentMapSize
373 + header
->previewPageListSize
);
375 SplashPreview(src
, &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
377 bytesToRead
= imageSize
;
378 maxRead
= positionMax
/ kIOHibernateProgressCount
;
379 } else if (!readingPreview
) {
382 blob
= (position
* kIOHibernateProgressCount
) / positionMax
;
383 if (blob
!= lastBlob
)
385 SplashProgress(&graphicsInfo
->progressSaveUnder
[0][0], lastBlob
, blob
);
392 extentLength
-= size
;
399 if (header
->encryptStart
) {
400 aes_decrypt_key(&gExtensionsSpec
[0],
401 gHibernateKeySizeBytes
,
402 &cryptvars
->ctx
.decrypt
);
404 // set the vector for the following decryptions
405 bcopy(((uint8_t *) header
) + header
->image1Size
- AES_BLOCK_SIZE
,
406 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
408 // decrypt the buffer
409 uint32_t len
= (uint32_t)(header
->image1Size
- header
->encryptStart
);
410 aes_decrypt_cbc(((uint8_t *) header
) + header
->encryptStart
,
413 ((uint8_t *) header
) + header
->encryptStart
,
414 &cryptvars
->ctx
.decrypt
);
417 bcopy(&cryptvars
->aes_iv
[0], &cryptwakevars
->aes_iv
[0], sizeof(cryptwakevars
->aes_iv
));
419 bzero(&cryptvars
->aes_iv
[0], sizeof(cryptvars
));
420 bzero(&gExtensionsSpec
[0], sizeof(gExtensionsSpec
));
424 // Get the video info
425 GetMainScreenPH(&videoInfo
, 0);
426 videoInfo
.v_display
= 1;
427 graphicsInfo
->physicalAddress
= videoInfo
.v_baseAddr
;
428 graphicsInfo
->mode
= videoInfo
.v_display
;
429 graphicsInfo
->rowBytes
= videoInfo
.v_rowBytes
;
430 graphicsInfo
->width
= videoInfo
.v_width
;
431 graphicsInfo
->height
= videoInfo
.v_height
;
432 graphicsInfo
->depth
= videoInfo
.v_depth
;
434 WakeKernel(header
, graphicsInfo
, cryptwakevars
, 0);
440 Interpret(0, 0, " reset-all");
443 static void Main(ClientInterfacePtr ciPtr
)
447 long flags
, cachetime
, kerneltime
, exttime
= 0;
448 void *binary
= (void *)kLoadAddr
;
450 ret
= InitEverything(ciPtr
);
451 if (ret
!= 0) Exit();
453 if (gHibernateBoot
) {
457 // Get or infer the boot paths.
458 ret
= GetBootPaths();
459 if (ret
!= 0) FailToBoot(1);
466 trycache
= (0 == (gBootMode
& kBootModeSafe
))
467 && (gBootKernelCacheFile
[0] != 0);
469 if (trycache
&& (gBootFileType
== kBlockDeviceType
)) do {
471 // if we haven't found the kernel yet, don't use the cache
472 ret
= GetFileInfo(NULL
, gBootFile
, &flags
, &kerneltime
);
473 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)) {
477 ret
= GetFileInfo(NULL
, gBootKernelCacheFile
, &flags
, &cachetime
);
478 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)
479 || (cachetime
< kerneltime
)) {
483 ret
= GetFileInfo(gExtensionsSpec
, "Extensions", &flags
, &exttime
);
484 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeDirectory
)
485 && (cachetime
< exttime
)) {
489 if (kerneltime
> exttime
)
490 exttime
= kerneltime
;
491 if (cachetime
!= (exttime
+ 1)) {
498 ret
= LoadFile(gBootKernelCacheFile
);
500 ret
= DecodeKernel(binary
);
501 if (ret
!= -1) break;
504 ret
= LoadThinFatFile(gBootFile
, &binary
);
505 if (ret
!= -1) ret
= DecodeKernel(binary
);
506 if (ret
!= -1) break;
508 ret
= GetBootPaths();
509 if (ret
!= 0) FailToBoot(2);
512 if (ret
!= 0) FailToBoot(3);
514 if (!gHaveKernelCache
) {
515 ret
= LoadDrivers(gExtensionsSpec
);
516 if (ret
!= 0) FailToBoot(4);
523 ret
= SetUpBootArgs();
524 if (ret
!= 0) FailToBoot(5);
531 static uint32_t UnescapeData(const uint8_t * src
,
536 uint32_t cnt
, cnt2
, dstLen
= 0;
539 for (cnt
= 0; cnt
< srcLen
;) {
544 byte
= (byte
& 0x80) ? 0xFF : 0x00;
548 if (dstLen
>= dstMaxLen
)
550 dst
[dstLen
++] = byte
;
556 static long InitEverything(ClientInterfacePtr ciPtr
)
558 long ret
, mem_base
, mem_base2
, size
;
560 char name
[32], securityMode
[33];
564 // Init the OF Client Interface.
566 if (ret
!= 0) return -1;
568 // Get the OF Version
569 gOFVersion
= GetOFVersion();
570 if (gOFVersion
== 0) return -1;
572 // Get the address and size cells for the root.
573 GetProp(Peer(0), "#address-cells", (char *)&gRootAddrCells
, 4);
574 GetProp(Peer(0), "#size-cells", (char *)&gRootSizeCells
, 4);
575 if ((gRootAddrCells
> 2) || (gRootAddrCells
> 2)) return -1;
577 // Init the SL Words package.
579 if (ret
!= 0) return -1;
581 // Get the phandle for /options
582 gOptionsPH
= FindDevice("/options");
583 if (gOptionsPH
== -1) return -1;
585 // Get the phandle for /chosen
586 gChosenPH
= FindDevice("/chosen");
587 if (gChosenPH
== -1) return -1;
589 // Init the Memory Map.
590 ret
= InitMemoryMap();
591 if (ret
!= 0) return -1;
593 // Get IHandles for the MMU and Memory
594 size
= GetProp(gChosenPH
, "mmu", (char *)&gMMUIH
, 4);
596 printf("Failed to get the IH for the MMU.\n");
599 size
= GetProp(gChosenPH
, "memory", (char *)&gMemoryIH
, 4);
601 printf("Failed to get the IH for the Memory.\n");
605 // Get first element of root's compatible property.
606 ret
= GetPackageProperty(Peer(0), "compatible", &compatible
, &length
);
608 strcpy(gPlatformName
, compatible
);
610 // Get stdout's IH, so that the boot display can be found.
611 ret
= GetProp(gChosenPH
, "stdout", (char *)&gStdOutIH
, 4);
612 if (ret
== 4) gStdOutPH
= InstanceToPackage(gStdOutIH
);
613 else gStdOutPH
= gStdOutIH
= 0;
615 // Try to find the keyboard using chosen
616 ret
= GetProp(gChosenPH
, "stdin", (char *)&gKeyboardIH
, 4);
617 if (ret
!= 4) gKeyboardIH
= 0;
619 keyboardPH
= InstanceToPackage(gKeyboardIH
);
620 ret
= GetProp(keyboardPH
, "name", name
, 31);
623 if (strcmp(name
, "keyboard") && strcmp(name
, "kbd")) gKeyboardIH
= 0;
624 } else gKeyboardIH
= 0;
627 // Try to the find the keyboard using open if chosen did not work.
628 if (gKeyboardIH
== 0) gKeyboardIH
= Open("keyboard");
629 if (gKeyboardIH
== 0) gKeyboardIH
= Open("kbd");
631 // Get the key map set up, and make it up to date.
632 gKeyMap
= InitKeyMap(gKeyboardIH
);
633 if (gKeyMap
== NULL
) return -1;
636 // Test for Secure Boot Mode.
637 size
= GetProp(gOptionsPH
, "security-mode", securityMode
, 32);
639 securityMode
[size
] = '\0';
640 if (strcmp(securityMode
, "none")) gBootMode
|= kBootModeSecure
;
644 // 'cmd-s' or 'cmd-v' is pressed set outputLevel to kOutputLevelFull
645 if (((gBootMode
& kBootModeSecure
) == 0) && TestForKey(kCommandKey
) &&
646 (TestForKey('s') || TestForKey('v'))) {
647 SetOutputLevel(kOutputLevelFull
);
649 SetOutputLevel(kOutputLevelOff
);
652 SetOutputLevel(kOutputLevelFull
);
656 printf("\n\nMac OS X Loader\n");
658 // Test for Safe Boot Mode; Shift and not Delete.
659 if (((gBootMode
& kBootModeSecure
) == 0)
660 && TestForKey(kShiftKey
) && !TestForKey(kDeleteKey
)) {
661 gBootMode
|= kBootModeSafe
;
664 size
= GetProp(gOptionsPH
, kIOHibernateBootImageKey
, gBootDevice
, 255);
665 if (size
&& (-1 != size
)) do {
666 gBootDevice
[size
] = '\0';
668 // reuse gExtensionsSpec
669 #define keyBufSize (sizeof(gExtensionsSpec) / 2)
670 size
= GetProp(gOptionsPH
, kIOHibernateBootImageKeyKey
,
671 gExtensionsSpec
+ keyBufSize
, keyBufSize
);
672 if (size
&& (-1 != size
))
673 gHibernateKeySizeBytes
= UnescapeData(gExtensionsSpec
+ keyBufSize
, size
,
674 gExtensionsSpec
, keyBufSize
);
676 // always clear the boot-image variable
678 Interpret(0, 0, " setenv " kIOHibernateBootImageKey
);
679 Interpret(0, 0, " setenv " kIOHibernateBootImageKeyKey
); // (will need to be done by OF)
680 Interpret(0, 0, " sync-nvram");
683 // safe mode means no hibernate
684 if (kBootModeSafe
& gBootMode
) break;
687 // check we booted from nvram-set device
688 size
= GetProp(gChosenPH
, "bootpath", gBootFile
, 255);
689 if (!size
|| (-1 == size
)) break;
690 gBootFile
[size
] = '\0';
692 if (FindDevice(gBootFile
) != FindDevice(gBootDevice
)) break;
700 // Claim memory for malloc.
701 if (Claim(kMallocAddr_H
, kMallocSize_H
, 0) == 0) {
702 printf("Claim for malloc failed.\n");
705 malloc_init((char *)kMallocAddr_H
, kMallocSize_H
);
706 gImageFirstBootXAddr
= kMallocAddr_H
+ kMallocSize_H
;
708 // Claim memory for the FS Cache.
709 if (Claim(kFSCacheAddr
, kFSCacheSize
, 0) == 0) {
710 printf("Claim for fs cache failed.\n");
714 // Claim memory for malloc.
715 if (Claim(kMallocAddr
, kMallocSize
, 0) == 0) {
716 printf("Claim for malloc failed.\n");
719 malloc_init((char *)kMallocAddr
, kMallocSize
);
721 // Claim memory for the Load Addr.
722 mem_base
= Claim(kLoadAddr
, kLoadSize
, 0);
724 printf("Claim for Load Area failed.\n");
728 // Claim the memory for the Image Addr
729 if (gOFVersion
>= kOFVersion3x
) {
730 mem_base
= Claim(kImageAddr
, kImageSize
, 0);
732 printf("Claim for Image Area failed.\n");
736 // Claim the 1:1 mapped chunks first.
737 mem_base
= Claim(kImageAddr0
, kImageSize0
, 0);
738 mem_base2
= Claim(kImageAddr2
, kImageSize2
, 0);
739 if ((mem_base
== 0) || (mem_base2
== 0)) {
740 printf("Claim for Image Area failed.\n");
744 // Unmap the old xcoff stack.
745 CallMethod(2, 0, gMMUIH
, "unmap", 0x00380000, 0x00080000);
747 // Grab the physical memory then the logical.
748 CallMethod(3, 1, gMemoryIH
, "claim",
749 kImageAddr1Phys
, kImageSize1
, 0, &mem_base
);
750 CallMethod(3, 1, gMMUIH
, "claim",
751 kImageAddr1
, kImageSize1
, 0, &mem_base2
);
752 if ((mem_base
== 0) || (mem_base2
== 0)) {
753 printf("Claim for Image Area failed.\n");
757 // Map them together.
758 CallMethod(4, 0, gMMUIH
, "map",
759 kImageAddr1Phys
, kImageAddr1
, kImageSize1
, 0);
762 bzero((char *)kImageAddr
, kImageSize
);
764 // Allocate some space for the Vector Save area.
765 gVectorSaveAddr
= AllocateBootXMemory(kVectorSize
);
766 if (gVectorSaveAddr
== 0) {
767 printf("Allocation for the Vector Save Area failed.\n");
770 // Find all the displays and set them up.
771 ret
= InitDisplays(1);
773 printf("InitDisplays failed.\n");
782 long ThinFatBinary(void **binary
, unsigned long *length
)
786 ret
= ThinFatBinaryMachO(binary
, length
);
787 if (ret
== -1) ret
= ThinFatBinaryElf(binary
, length
);
792 static long DecodeKernel(void *binary
)
795 compressed_kernel_header
*kernel_header
= (compressed_kernel_header
*)binary
;
798 if (kernel_header
->signature
== 'comp') {
799 if (kernel_header
->compress_type
!= 'lzss')
801 if (kernel_header
->platform_name
[0] && strcmp(gPlatformName
, kernel_header
->platform_name
))
803 if (kernel_header
->root_path
[0] && strcmp(gBootFile
, kernel_header
->root_path
))
806 binary
= AllocateBootXMemory(kernel_header
->uncompressed_size
);
808 size
= decompress_lzss((u_int8_t
*) binary
, &kernel_header
->data
[0], kernel_header
->compressed_size
);
809 if (kernel_header
->uncompressed_size
!= size
) {
810 printf("size mismatch from lzss %x\n", size
);
813 if (kernel_header
->adler32
!=
814 Adler32(binary
, kernel_header
->uncompressed_size
)) {
815 printf("adler mismatch\n");
820 ThinFatBinary(&binary
, 0);
822 ret
= DecodeMachO(binary
);
823 if (ret
== -1) ret
= DecodeElf(binary
);
829 static long SetUpBootArgs(void)
833 long graphicsBoot
= 1;
834 long ret
, cnt
, size
, dash
;
835 long sKey
, vKey
, keyPos
;
836 char ofBootArgs
[240], *ofArgs
, tc
, keyStr
[8];
837 unsigned char mem_regs
[kMaxDRAMBanks
*16];
838 unsigned long mem_banks
, bank_shift
;
840 // Save file system cache statistics.
841 SetProp(gChosenPH
, "BootXCacheHits", (char *)&gCacheHits
, 4);
842 SetProp(gChosenPH
, "BootXCacheMisses", (char *)&gCacheMisses
, 4);
843 SetProp(gChosenPH
, "BootXCacheEvicts", (char *)&gCacheEvicts
, 4);
845 // Allocate some memory for the BootArgs.
846 gBootArgsSize
= sizeof(boot_args
);
847 gBootArgsAddr
= AllocateKernelMemory(gBootArgsSize
);
849 // Add the BootArgs to the memory-map.
850 AllocateMemoryRange("BootArgs", gBootArgsAddr
, gBootArgsSize
);
852 args
= (boot_args_ptr
)gBootArgsAddr
;
854 args
->Revision
= kBootArgsRevision
;
855 args
->Version
= kBootArgsVersion1
;
856 args
->machineType
= 0;
858 // Check the Keyboard for 'cmd-s' and 'cmd-v'
860 if ((gBootMode
& kBootModeSecure
) == 0) {
861 sKey
= TestForKey(kCommandKey
) && TestForKey('s');
862 vKey
= TestForKey(kCommandKey
) && TestForKey('v');
868 // if 'cmd-s' or 'cmd-v' was pressed do a text boot.
869 if (sKey
|| vKey
) graphicsBoot
= 0;
871 // Create the command line.
872 if (gOFVersion
< kOFVersion3x
) {
874 size
= GetProp(gChosenPH
, "machargs", ofBootArgs
+ 1, (sizeof(ofBootArgs
) - 2));
876 size
= GetProp(gOptionsPH
, "boot-command", ofBootArgs
, (sizeof(ofBootArgs
) - 1));
877 if (size
== -1) ofBootArgs
[0] = '\0';
878 else ofBootArgs
[size
] = '\0';
879 // Look for " bootr" but skip the number.
880 if (!strncmp(ofBootArgs
+ 1, " bootr", 6)) {
881 strcpy(ofBootArgs
, ofBootArgs
+ 7);
882 } else ofBootArgs
[0] = '\0';
883 SetProp(gChosenPH
, "machargs", ofBootArgs
, strlen(ofBootArgs
) + 1);
884 } else ofBootArgs
[size
] = '\0';
885 // Force boot-command to start with 0 bootr.
886 sprintf(gTempStr
, "0 bootr%s", ofBootArgs
);
887 SetProp(gOptionsPH
, "boot-command", gTempStr
, strlen(gTempStr
));
889 size
= GetProp(gOptionsPH
, "boot-args", ofBootArgs
, (sizeof(ofBootArgs
) - 1));
890 if (size
== -1) ofBootArgs
[0] = '\0';
891 else ofBootArgs
[size
] = '\0';
894 if (ofBootArgs
[0] != '\0') {
895 // Look for special options and copy the rest.
898 while ((tc
= *ofArgs
) != '\0') {
901 // Check for entering a dash arg.
908 // Do special stuff if in a dash arg.
914 } else if (tc
== 'v') {
919 // Check for exiting dash arg
920 if (isspace(tc
)) dash
= 0;
922 // Copy any non 's' or 'v'
926 // Not a dash arg so just copy it.
932 // Add any pressed keys (s, v, shift) to the command line
934 if (sKey
|| vKey
|| (gBootMode
& kBootModeSafe
)) {
935 keyStr
[keyPos
++] = '-';
937 if (sKey
) keyStr
[keyPos
++] = 's';
938 if (vKey
) keyStr
[keyPos
++] = 'v';
939 if (gBootMode
& kBootModeSafe
) keyStr
[keyPos
++] = 'x';
941 keyStr
[keyPos
++] = ' ';
943 keyStr
[keyPos
++] = '\0';
945 sprintf(args
->CommandLine
, "%s%s", keyStr
, ofBootArgs
);
947 // If the address or size cells are larger than 1, use page numbers
948 // and signify Boot Args Version 2.
949 if ((gRootAddrCells
== 1) && (gRootSizeCells
== 1)) bank_shift
= 0;
952 args
->Version
= kBootArgsVersion2
;
955 // Get the information about the memory banks
956 memoryPH
= FindDevice("/memory");
957 if (memoryPH
== -1) return -1;
958 size
= GetProp(memoryPH
, "reg", mem_regs
, kMaxDRAMBanks
* 16);
959 if (size
== 0) return -1;
960 mem_banks
= size
/ (4 * (gRootAddrCells
+ gRootSizeCells
));
961 if (mem_banks
> kMaxDRAMBanks
) mem_banks
= kMaxDRAMBanks
;
963 // Convert the reg properties to 32 bit values
964 for (cnt
= 0; cnt
< mem_banks
; cnt
++) {
965 if (gRootAddrCells
== 1) {
966 args
->PhysicalDRAM
[cnt
].base
=
967 *(unsigned long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
)) >> bank_shift
;
969 args
->PhysicalDRAM
[cnt
].base
=
970 *(unsigned long long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
)) >> bank_shift
;
974 if (gRootSizeCells
== 1) {
975 args
->PhysicalDRAM
[cnt
].size
=
976 *(unsigned long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
) + 4 * gRootAddrCells
) >> bank_shift
;
978 args
->PhysicalDRAM
[cnt
].size
=
979 *(unsigned long long *)(mem_regs
+ cnt
* 4 * (gRootAddrCells
+ gRootSizeCells
) + 4 * gRootAddrCells
) >> bank_shift
;
984 // Collapse the memory banks into contiguous chunks
985 for (cnt
= 0; cnt
< mem_banks
- 1; cnt
++) {
986 if ((args
->PhysicalDRAM
[cnt
+ 1].base
!= 0) &&
987 ((args
->PhysicalDRAM
[cnt
].base
+ args
->PhysicalDRAM
[cnt
].size
) !=
988 args
->PhysicalDRAM
[cnt
+ 1].base
)) continue;
990 args
->PhysicalDRAM
[cnt
].size
+= args
->PhysicalDRAM
[cnt
+ 1].size
;
991 bcopy(args
->PhysicalDRAM
+ cnt
+ 2, args
->PhysicalDRAM
+ cnt
+ 1, (mem_banks
- cnt
- 2) * sizeof(DRAMBank
));
995 bzero(args
->PhysicalDRAM
+ mem_banks
, (kMaxDRAMBanks
- mem_banks
) * sizeof(DRAMBank
));
997 // Get the video info
998 GetMainScreenPH(&args
->Video
, 1);
999 args
->Video
.v_display
= graphicsBoot
;
1001 // Add the DeviceTree to the memory-map.
1002 // The actuall address and size must be filled in later.
1003 AllocateMemoryRange("DeviceTree", 0, 0);
1005 ret
= FlattenDeviceTree();
1006 if (ret
!= 0) return -1;
1008 // Fill in the address and size of the device tree.
1009 if (gDeviceTreeAddr
) {
1010 gDeviceTreeMMTmp
[0] = gDeviceTreeAddr
;
1011 gDeviceTreeMMTmp
[1] = gDeviceTreeSize
;
1014 args
->deviceTreeP
= (void *)gDeviceTreeAddr
;
1015 args
->deviceTreeLength
= gDeviceTreeSize
;
1016 args
->topOfKernelData
= AllocateKernelMemory(0);
1022 static long CallKernel(void)
1024 unsigned long msr
, cnt
;
1028 printf("\nCall Kernel!\n");
1031 __asm__
volatile("mfmsr %0" : "=r" (gOFMSRSave
));
1032 __asm__
volatile("mfsprg %0, 0" : "=r" (gOFSPRG0Save
));
1033 __asm__
volatile("mfsprg %0, 1" : "=r" (gOFSPRG1Save
));
1034 __asm__
volatile("mfsprg %0, 2" : "=r" (gOFSPRG2Save
));
1035 __asm__
volatile("mfsprg %0, 3" : "=r" (gOFSPRG3Save
));
1037 // Turn off translations
1039 __asm__
volatile("sync");
1040 __asm__
volatile("mtmsr %0" : : "r" (msr
));
1041 __asm__
volatile("isync");
1043 // Save the OF's Exceptions Vectors
1044 bcopy(0x0, gOFVectorSave
, kVectorSize
);
1046 // Move the Exception Vectors
1047 bcopy(gVectorSaveAddr
, 0x0, kVectorSize
);
1048 for (cnt
= 0; cnt
< kVectorSize
; cnt
+= 0x20) {
1049 __asm__
volatile("dcbf 0, %0" : : "r" (cnt
));
1050 __asm__
volatile("icbi 0, %0" : : "r" (cnt
));
1053 // Move the Image1 save area for OF 1.x / 2.x
1054 if (gOFVersion
< kOFVersion3x
) {
1055 bcopy((char *)kImageAddr1Phys
, (char *)kImageAddr1
, kImageSize1
);
1056 for (cnt
= kImageAddr1
; cnt
< kImageSize1
; cnt
+= 0x20) {
1057 __asm__
volatile("dcbf 0, %0" : : "r" (cnt
));
1058 __asm__
volatile("icbi 0, %0" : : "r" (cnt
));
1062 // Make sure everything get sync'd up.
1063 __asm__
volatile("isync");
1064 __asm__
volatile("sync");
1065 __asm__
volatile("eieio");
1067 // Call the Kernel's entry point
1068 (*(void (*)())gKernelEntryPoint
)(gBootArgsAddr
, kMacOSXSignature
);
1070 // Restore OF's Exception Vectors
1071 bcopy(gOFVectorSave
, 0x0, 0x3000);
1072 for (cnt
= 0; cnt
< kVectorSize
; cnt
+= 0x20) {
1073 __asm__
volatile("dcbf 0, %0" : : "r" (cnt
));
1074 __asm__
volatile("icbi 0, %0" : : "r" (cnt
));
1077 // Restore SPRs for OF
1078 __asm__
volatile("mtsprg 0, %0" : : "r" (gOFSPRG0Save
));
1079 __asm__
volatile("mtsprg 1, %0" : : "r" (gOFSPRG1Save
));
1080 __asm__
volatile("mtsprg 2, %0" : : "r" (gOFSPRG2Save
));
1081 __asm__
volatile("mtsprg 3, %0" : : "r" (gOFSPRG3Save
));
1083 // Restore translations
1084 __asm__
volatile("sync");
1085 __asm__
volatile("mtmsr %0" : : "r" (gOFMSRSave
));
1086 __asm__
volatile("isync");
1092 static void FailToBoot(long num
)
1094 // useful for those holding down command-v ...
1095 printf("FailToBoot: %d\n", num
);
1097 DrawFailedBootPicture();
1101 Enter(); // For debugging
1106 static long InitMemoryMap(void)
1110 result
= Interpret(0, 1,
1113 " \" memory-map\" device-name"
1122 static long GetOFVersion(void)
1125 char versStr
[256], *tmpStr
;
1128 // Get the openprom package
1129 ph
= FindDevice("/openprom");
1130 if (ph
== -1) return 0;
1132 // Get it's model property
1133 size
= GetProp(ph
, "model", versStr
, 255);
1134 if (size
== -1) return -1;
1135 versStr
[size
] = '\0';
1137 // Find the start of the number.
1139 if (!strncmp(versStr
, "Open Firmware, ", 15)) {
1140 tmpStr
= versStr
+ 15;
1141 } else if (!strncmp(versStr
, "OpenFirmware ", 13)) {
1142 tmpStr
= versStr
+ 13;
1145 // Clasify by each instance as needed...
1148 vers
= kOFVersion1x
;
1152 vers
= kOFVersion2x
;
1156 vers
= kOFVersion3x
;
1160 vers
= kOFVersion4x
;
1172 static long TestForKey(long key
)
1178 if (gOFVersion
< kOFVersion3x
) {
1180 case 'a' : keyNum
= 7; break;
1181 case 's' : keyNum
= 6; break;
1182 case 'v' : keyNum
= 14; break;
1183 case 'y' : keyNum
= 23; break;
1184 case kCommandKey
: keyNum
= 48; break;
1185 case kOptKey
: keyNum
= 61; break;
1186 case kShiftKey
: keyNum
= 63; break;
1187 case kControlKey
: keyNum
= 49; break;
1188 default : keyNum
= -1; break;
1192 case 'a' : keyNum
= 3; break;
1193 case 's' : keyNum
= 17; break;
1194 case 'v' : keyNum
= 30; break;
1195 case 'y' : keyNum
= 27; break;
1196 case kCommandKey
: keyNum
= 228; break;
1197 case kOptKey
: keyNum
= 229; break;
1198 case kShiftKey
: keyNum
= 230; break;
1199 case kControlKey
: keyNum
= 231; break;
1200 case kDeleteKey
: keyNum
= 45; break;
1201 default : keyNum
= -1; break;
1204 // Map the right modifier keys on to the left.
1205 gKeyMap
[28] |= gKeyMap
[28] << 4;
1208 if (keyNum
== -1) return 0;
1211 tc
= gKeyMap
[keyNum
>> 3];
1213 return (tc
& (1 << bp
)) != 0;
1217 #define kBootpBootFileOffset (108)
1219 static long GetBootPaths(void)
1221 long ret
, cnt
, cnt2
, cnt3
, cnt4
, size
, partNum
, bootplen
, bsdplen
;
1222 unsigned long adler32
;
1223 char *filePath
, *buffer
, uuidStr
[UUIDLEN
+1] = { '\0' };
1224 char *rpsDir
= ""; // perhaps to be one of "com.apple.Boot.[RPS]"
1227 printf("accessing the first few bytes of memory...\n");
1228 unsigned *mem = NULL;
1229 for(cnt=0; cnt<10; cnt++)
1230 printf("mem[%d]: %x ('%c')\n", cnt, mem[cnt], mem[cnt]);
1233 if (gBootSourceNumber
== -1) {
1234 // Get the boot device and derive its type
1235 // (try chosen "bootpath", then boot-device in the options)
1236 size
= GetProp(gChosenPH
, "bootpath", gBootDevice
, 255);
1237 gBootDevice
[size
] = '\0';
1238 if (gBootDevice
[0] == '\0') {
1239 size
= GetProp(gOptionsPH
, "boot-device", gBootDevice
, 255);
1240 gBootDevice
[size
] = '\0';
1242 // hardcode to my Apple_Boot before my Apple_RAID
1243 // debug: override boot device to boot from disk even if OF used TFTP
1244 //printf("old gBootDevice: %s\n", gBootDevice);
1245 //strcpy(gBootDevice, "fw/node@d0010100007a9d/sbp-2@c000/@0:12"); // SmartDisk
1246 //strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:9"); // mconcatI
1247 //strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:11"); // mconcatI
1248 //strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:2"); // mconcatII
1249 //strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:4"); // mconcatII
1250 //strcpy(gBootDevice, "fw/node@50770e0000676f/sbp-2@4000/@0:3"); // m120
1251 //strcpy(gBootDevice, "fw/node@50770e0000725b/sbp-2@4000/@0:3"); // m120
1254 // check for Boot != Root
1255 ret
= FindRPSDir(gBootDevice
, &rpsDir
); // rpsDir set on success
1257 SetProp(gChosenPH
, kBootRootActiveKey
, NULL
, 0); // crumb for the OS
1258 // would be nice to set gBootSourceNumberMax = 1, but overridden below
1261 // Load any Boot.plist data (for Tiger RAID, BootRoot, etc)
1262 ret
= ReadBootPlist(gBootDevice
, rpsDir
); // sets gBootDict on success
1264 // XX until we decide to be rid of the RAID implementation, short-
1265 // circuit common 10.5 case (Boot.plist exists but doesn't mean RAID)
1266 if (gBootDict
->type
!= kTagTypeDict
||
1267 GetProperty(gBootDict
, kKernelNameKey
) == NULL
) {
1268 (void)LookForRAID(gBootDict
); // might change gBootDevice
1269 // LFR() success -> gBootDevice = "AppleRAID/#:0,\\:tbxi"
1273 // note RAID itself is of "block" type like members
1274 gBootDeviceType
= GetDeviceType(gBootDevice
);
1275 if(gBootDeviceType
== -1) {
1276 printf("Could not find boot device %s\n", gBootDevice
);
1281 // Get the boot file (e.g. mach_kernel)
1282 size
= GetProp(gChosenPH
, "bootargs", gBootFile
, 256);
1283 gBootFile
[size
] = '\0';
1285 if (gBootFile
[0] != '\0') {
1286 gBootFileType
= GetDeviceType(gBootFile
);
1287 gBootSourceNumberMax
= 0;
1289 gBootSourceNumber
= 0;
1290 gBootFileType
= gBootDeviceType
;
1291 if (gBootFileType
== kNetworkDeviceType
) gBootSourceNumberMax
= 1;
1293 if (gOFVersion
< kOFVersion3x
) {
1294 gBootSourceNumberMax
= 4;
1296 gBootSourceNumberMax
= 6;
1300 // gBootSourceNumberMax = 2; // helpful to prevent lots of probing
1302 if (gBootFileType
== kNetworkDeviceType
) {
1303 SetProp(Peer(0), "net-boot", NULL
, 0);
1307 if (gBootSourceNumber
>= gBootSourceNumberMax
) return -1;
1309 if (gBootSourceNumberMax
!= 0) {
1310 switch (gBootFileType
) {
1311 case kNetworkDeviceType
:
1312 // Find the end of the device spec.
1314 while (gBootDevice
[cnt
] != ':') cnt
++;
1316 // Copy the device spec with the ':'.
1317 strncpy(gBootFile
, gBootDevice
, cnt
+ 1);
1319 // Check for bootp-responce or bsdp-responce.
1320 bootplen
= GetPropLen(gChosenPH
, "bootp-response");
1321 bsdplen
= GetPropLen(gChosenPH
, "bsdp-response");
1322 if ((bootplen
> 0) || (bsdplen
> 0)) {
1324 buffer
= malloc(bootplen
);
1325 GetProp(gChosenPH
, "bootp-response", buffer
, bootplen
);
1327 buffer
= malloc(bsdplen
);
1328 GetProp(gChosenPH
, "bsdp-response", buffer
, bsdplen
);
1331 // Flip the slash's to back slash's while looking for the last one.
1332 cnt
= cnt2
= kBootpBootFileOffset
;
1333 while (buffer
[cnt
] != '\0') {
1334 if (buffer
[cnt
] == '/') {
1341 // Add a comma at the front.
1342 buffer
[kBootpBootFileOffset
- 1] = ',';
1344 // Append the the root dir to the device spec.
1345 strncat(gBootFile
, buffer
+ kBootpBootFileOffset
- 1,
1346 cnt2
- kBootpBootFileOffset
+ 1);
1350 // Look for the start of the root dir path.
1352 while (gBootDevice
[cnt3
] != ',') cnt3
++;
1354 // Find the end of the path. Look for a comma or null.
1356 while ((gBootDevice
[cnt2
] != '\0') && (gBootDevice
[cnt2
] != ',')) cnt2
++;
1358 // Find the last back slash or comma in the path
1360 while ((gBootDevice
[cnt4
] != ',') && (gBootDevice
[cnt4
] != '\\')) cnt4
--;
1362 // Copy the IP addresses if needed.
1363 if (gOFVersion
< kOFVersion3x
) {
1364 strncat(gBootFile
, gBootDevice
+ cnt
+ 1, cnt3
- cnt
- 1);
1367 // Add on the directory path
1368 strncat(gBootFile
, gBootDevice
+ cnt3
, cnt4
- cnt3
+ 1);
1371 // Add on the kernel name
1372 strcat(gBootFile
, "mach.macosx");
1375 strcat(gBootFile
, gBootDevice
+ cnt2
);
1378 case kBlockDeviceType
:
1379 // Find the first ':'.
1381 while ((gBootDevice
[cnt
] != '\0') && (gBootDevice
[cnt
] != ':')) cnt
++;
1382 if (gBootDevice
[cnt
] == '\0') return -1;
1384 // Find the comma after the ':'.
1386 while ((gBootDevice
[cnt2
] != '\0') && (gBootDevice
[cnt
] != ',')) cnt2
++;
1388 // Get just the partition number
1389 strncpy(gBootFile
, gBootDevice
+ cnt
+ 1, cnt2
- cnt
- 1);
1390 partNum
= strtol(gBootFile
, 0, 10);
1391 if (partNum
== 0) partNum
= strtol(gBootFile
, 0, 16);
1393 // Adjust the partition number.
1394 // Pass 0 & 1, no offset. Pass 2 & 3, offset 1, Pass 4 & 5, offset 2.
1395 partNum
+= gBootSourceNumber
/ 2;
1397 // Construct the boot-file
1398 strncpy(gBootFile
, gBootDevice
, cnt
+ 1);
1399 sprintf(gBootFile
+ cnt
+ 1, "%d,%s%s\\mach_kernel",
1400 partNum
, ((gBootSourceNumber
& 1) ? "" : "\\"), rpsDir
);
1402 // and the cache file name
1404 bzero(gCacheNameAdler
+ 64, sizeof(gBootFile
));
1405 strcpy(gCacheNameAdler
+ 64, gBootFile
);
1406 adler32
= Adler32(gCacheNameAdler
, sizeof(gCacheNameAdler
));
1408 strncpy(gBootKernelCacheFile
, gBootDevice
, cnt
+ 1);
1409 sprintf(gBootKernelCacheFile
+ cnt
+ 1,
1410 "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum
, adler32
);
1414 printf("Failed to infer Boot Device Type.\n");
1420 // Figure out the root dir.
1421 ret
= ConvertFileSpec(gBootFile
, gExtensionsSpec
, &filePath
);
1423 printf("Failed to determine root directory\n");
1427 strcat(gExtensionsSpec
, ",");
1429 // Add in any extra path to gRootDir (handles com.apple.boot.[RPS]).
1431 while (filePath
[cnt
] != '\0') cnt
++;
1434 for (cnt2
= cnt
- 1; cnt2
>= 0; cnt2
--) {
1435 if (filePath
[cnt2
] == '\\') {
1436 strncat(gExtensionsSpec
, filePath
, cnt2
+ 1);
1442 // Figure out the extensions dir.
1443 if (gBootFileType
== kBlockDeviceType
) {
1444 cnt
= strlen(gExtensionsSpec
);
1445 if ((cnt
> 2) && (gExtensionsSpec
[cnt
-1] == '\\') && (gExtensionsSpec
[cnt
-2] == '\\'))
1447 strcpy(gExtensionsSpec
+ cnt
, "System\\Library\\");
1450 // technically could just do this once at the end
1451 SetProp(gChosenPH
, "rootpath", gBootFile
, strlen(gBootFile
) + 1);
1453 if (gBootDict
&& gBootDict
->type
== kTagTypeDict
) {
1454 TagPtr prop
= GetProperty(gBootDict
, kRootUUIDKey
);
1455 if (prop
&& prop
->type
== kTagTypeString
)
1456 strncpy(uuidStr
, prop
->string
, UUIDLEN
);
1459 if (uuidStr
[0] == '\0') {
1460 (void)GetFSUUID(gBootFile
, uuidStr
);
1464 printf("setting boot-uuid to: %s\n", uuidStr
);
1465 SetProp(gChosenPH
, "boot-uuid", uuidStr
, strlen(uuidStr
) + 1);
1468 gBootSourceNumber
++;
1474 * FindRPSDir looks for a "rock," "paper," or "scissors" directory
1475 * - handle all permutations: 3 dirs, any 2 dirs, any 1 dir
1477 #define SPECLEN 1024
1478 static char rootDirSpec
[SPECLEN
+1]; // not sure how big our stacks are
1479 static long FindRPSDir(char *bootDevice
, char **rpsDir
)
1483 char haveR
, haveP
, haveS
;
1485 unsigned long index
= 0;
1488 haveR
= haveP
= haveS
= 0;
1490 // strip any file specifier and start at the root
1491 if (ConvertFileSpec(bootDevice
, rootDirSpec
, NULL
)) return -1;
1492 strncat(rootDirSpec
, ",\\", SPECLEN
-strlen(rootDirSpec
));
1494 // walk the directory looking for com.apple.Boot.[RPS]
1495 while (GetDirEntry(rootDirSpec
, &index
, &curName
, &flags
, &time
) != -1) {
1496 if (!strcmp(curName
, kBootDirR
)) { haveR
= 1; continue; }
1497 if (!strcmp(curName
, kBootDirP
)) { haveP
= 1; continue; }
1498 if (!strcmp(curName
, kBootDirS
)) { haveS
= 1; continue; }
1501 if (haveR
&& haveP
&& haveS
) { // NComb(3,3) = 1
1502 printf("WARNING: all of R,P,S exist: booting from 'R'\n");
1503 *rpsDir
= kBootDirR
;
1504 } else if (haveR
&& haveP
) { // NComb(3,2) = 3
1506 *rpsDir
= kBootDirP
;
1507 } else if (haveR
&& haveS
) {
1509 *rpsDir
= kBootDirR
;
1510 } else if (haveP
&& haveS
) {
1512 *rpsDir
= kBootDirS
;
1513 } else if (haveR
) { // NComb(3,1) = 3
1515 *rpsDir
= kBootDirR
;
1518 *rpsDir
= kBootDirP
;
1521 *rpsDir
= kBootDirS
;
1522 } else { // NComb(3,0) = 0
1530 * ReadBootPlist looks around for com.apple.Boot.plist, populates gBootDict
1531 * could live elsewhere
1533 #define OF_BLESSEDDIR ",\\\\"
1534 #define BOOTPLIST_NAME "com.apple.Boot.plist"
1535 #define BOOTPLIST_PATH OF_BLESSEDDIR BOOTPLIST_NAME
1536 #define PREF_BOOTPLIST_PATH "\\Library\\Preferences\\SystemConfiguration\\" \
1538 static char plistSpec
[SPECLEN
+1]; // save stack space
1539 static long ReadBootPlist(char *devSpec
, char *rpsDir
)
1544 if (ConvertFileSpec(devSpec
, plistSpec
, NULL
)) break;
1545 strncat(plistSpec
, ",", SPECLEN
-strlen(plistSpec
));
1546 strncat(plistSpec
, rpsDir
, SPECLEN
-strlen(plistSpec
)); // may be ""
1547 strncat(plistSpec
, PREF_BOOTPLIST_PATH
, SPECLEN
-strlen(plistSpec
));
1549 // try to load the contents
1550 if ((len
= LoadFile(plistSpec
)) < 0) {
1551 // construct old-style spec for Boot.plist (in blessed folder == root)
1552 if (ConvertFileSpec(devSpec
, plistSpec
, NULL
)) break;
1553 strncat(plistSpec
, BOOTPLIST_PATH
, SPECLEN
-strlen(plistSpec
));
1555 // and try to load again
1556 if ((len
= LoadFile(plistSpec
)) < 0) {
1557 printf("couldn't load %s\n", BOOTPLIST_NAME
);
1561 *((char*)kLoadAddr
+ len
) = '\0'; // terminate for parser safety
1563 if (ParseXML((char*)kLoadAddr
, &gBootDict
) < 0 || !gBootDict
) {
1564 printf("couldn't parse %s\n", BOOTPLIST_NAME
);
1576 long GetDeviceType(char *devSpec
)
1580 char deviceType
[32];
1582 if (isRAIDPath(devSpec
))
1583 return kBlockDeviceType
;
1585 ph
= FindDevice(devSpec
);
1586 if (ph
== -1) return -1;
1588 size
= GetProp(ph
, "device_type", deviceType
, 31);
1589 if (size
!= -1) deviceType
[size
] = '\0';
1590 else deviceType
[0] = '\0';
1592 if (strcmp(deviceType
, "network") == 0) return kNetworkDeviceType
;
1593 if (strcmp(deviceType
, "block") == 0) return kBlockDeviceType
;
1595 return kUnknownDeviceType
;
1599 long ConvertFileSpec(char *fileSpec
, char *devSpec
, char **filePath
)
1603 // Find the first ':' in the fileSpec.
1605 while ((fileSpec
[cnt
] != '\0') && (fileSpec
[cnt
] != ':')) cnt
++;
1606 if (fileSpec
[cnt
] == '\0') return -1;
1608 // Find the next ',' in the fileSpec.
1609 while ((fileSpec
[cnt
] != '\0') && (fileSpec
[cnt
] != ',')) cnt
++;
1611 // Copy the string to devSpec.
1612 strncpy(devSpec
, fileSpec
, cnt
);
1613 devSpec
[cnt
] = '\0';
1615 // If there is a filePath start it after the ',', otherwise NULL.
1616 if (filePath
!= NULL
) {
1617 if (fileSpec
[cnt
] != '\0') {
1618 *filePath
= fileSpec
+ cnt
+ 1;
1628 long MatchThis(CICell phandle
, char *string
)
1631 char *name
, *model
, *compatible
;
1633 ret
= GetPackageProperty(phandle
, "name", &name
, &length
);
1634 if ((ret
== -1) || (length
== 0)) name
= NULL
;
1636 ret
= GetPackageProperty(phandle
, "model", &model
, &length
);
1637 if ((ret
== -1) || (length
== 0)) model
= NULL
;
1639 ret
= GetPackageProperty(phandle
, "compatible", &compatible
, &length
);
1640 if ((ret
== -1) || (length
== 0)) model
= NULL
;
1642 if ((name
!= NULL
) && strcmp(name
, string
) == 0) return 0;
1643 if ((model
!= NULL
) && strcmp(model
, string
) == 0) return 0;
1645 if (compatible
!= NULL
) {
1646 while (*compatible
!= '\0') {
1647 if (strcmp(compatible
, string
) == 0) return 0;
1649 compatible
+= strlen(compatible
) + 1;
1657 void *AllocateBootXMemory(long size
)
1659 long addr
= gImageFirstBootXAddr
- size
;
1661 if (addr
< gImageLastKernelAddr
) return 0;
1663 gImageFirstBootXAddr
= addr
;
1665 return (void *)addr
;
1669 long AllocateKernelMemory(long size
)
1671 long addr
= gImageLastKernelAddr
;
1673 gImageLastKernelAddr
+= (size
+ 0xFFF) & ~0xFFF;
1675 if (gImageLastKernelAddr
> gImageFirstBootXAddr
)
1682 long AllocateMemoryRange(char *rangeName
, long start
, long length
)
1684 long result
, *buffer
;
1686 buffer
= AllocateBootXMemory(2 * sizeof(long));
1687 if (buffer
== 0) return -1;
1692 result
= SetProp(gMemoryMapPH
, rangeName
, (char *)buffer
, 2 * sizeof(long));
1693 if (result
== -1) return -1;
1698 #define BASE 65521L /* largest prime smaller than 65536 */
1700 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
1702 #define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
1703 #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
1704 #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
1705 #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
1706 #define DO16(buf) DO8(buf,0); DO8(buf,8);
1708 unsigned long Adler32(unsigned char *buf
, long len
)
1710 unsigned long s1
= 1; // adler & 0xffff;
1711 unsigned long s2
= 0; // (adler >> 16) & 0xffff;
1715 k
= len
< NMAX
? len
: NMAX
;
1729 return (s2
<< 16) | s1
;