]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/main.c
BootX-81.tar.gz
[apple/bootx.git] / bootx.tproj / sl.subproj / main.c
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * main.c - Main functions for BootX.
31 *
32 * Copyright (c) 1998-2004 Apple Computer, Inc.
33 *
34 * DRI: Josh de Cesare
35 */
36
37
38 #include <sl.h>
39 #include "aes.h"
40 #include <IOKit/IOHibernatePrivate.h>
41 #include <bootfiles.h>
42
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);
56
57 const unsigned long StartTVector[2] = {(unsigned long)Start, 0};
58
59 char gStackBaseAddr[0x8000];
60
61 char *gVectorSaveAddr;
62 long gImageLastKernelAddr = 0;
63 long gImageFirstBootXAddr = kLoadAddr;
64 long gKernelEntryPoint;
65 long gDeviceTreeAddr;
66 long gDeviceTreeSize;
67 long gBootArgsAddr;
68 long gBootArgsSize;
69 long gSymbolTableAddr;
70 long gSymbolTableSize;
71
72 long gBootSourceNumber = -1;
73 long gBootSourceNumberMax;
74 long gBootMode = kBootModeNormal;
75 long gBootDeviceType;
76 long gBootFileType;
77 char gHaveKernelCache = 0;
78 char gBootDevice[256];
79 char gBootFile[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;
85
86 char gTempStr[4096];
87
88 long *gDeviceTreeMMTmp = 0;
89
90 long gOFVersion = 0;
91
92 char *gKeyMap;
93 char gHibernateBoot;
94 unsigned long gHibernateKeySizeBytes;
95
96 long gRootAddrCells;
97 long gRootSizeCells;
98
99 CICell gChosenPH;
100 CICell gOptionsPH;
101 CICell gScreenPH;
102 CICell gMemoryMapPH;
103 CICell gStdOutPH;
104
105 CICell gMMUIH;
106 CICell gMemoryIH;
107 CICell gStdOutIH;
108 CICell gKeyboardIH;
109
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;
116
117 //int gDebugCount = 0;
118
119 // Private Functions
120
121 static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr)
122 {
123 long newSP;
124
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));
128
129 Main(ciPtr);
130 }
131
132 static long WakeKernel(void *p1, void *p2, void *p3, void *p4)
133 {
134 IOHibernateImageHeader * header = (IOHibernateImageHeader *) p1;
135 unsigned long msr;
136 typedef void (*Proc)(void *, void *, void *, void *);
137 Proc proc;
138 unsigned long cnt, newSP;
139 unsigned long *src, *dst;
140 unsigned int count;
141 unsigned int page;
142 unsigned int compressedSize;
143 unsigned int uncompressedPages;
144 int32_t byteCnt;
145 u_int32_t lowHalf, highHalf;
146 u_int32_t sum;
147
148 Quiesce();
149 printf("\nWake Kernel!\n");
150
151 // Save SPRs for OF
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));
157
158 // Turn off translations
159 msr = 0x00001000;
160 __asm__ volatile("sync");
161 __asm__ volatile("mtmsr %0" : : "r" (msr));
162 __asm__ volatile("isync");
163
164 // Save OF's Exceptions Vectors
165 bcopy(0x0, gOFVectorSave, kVectorSize);
166
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);
171
172 src = (unsigned long *) (((u_int32_t) &header->fileExtentMap[0])
173 + header->fileExtentMapSize);
174 sum = 0;
175
176 for (page = 0; page < count; page++)
177 {
178 compressedSize = 4096;
179
180 lowHalf = 1;
181 highHalf = 0;
182
183 for (cnt = 0; cnt < compressedSize; cnt += 0x20) {
184 dst[0] = src[0];
185 dst[1] = src[1];
186 dst[2] = src[2];
187 dst[3] = src[3];
188 dst[4] = src[4];
189 dst[5] = src[5];
190 dst[6] = src[6];
191 dst[7] = src[7];
192 for (byteCnt = 0; byteCnt < 0x20; byteCnt++) {
193 lowHalf += ((u_int8_t *) dst)[byteCnt];
194 highHalf += lowHalf;
195 }
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");
201 src += 8;
202 dst += 8;
203 }
204
205 lowHalf %= 65521L;
206 highHalf %= 65521L;
207 sum += (highHalf << 16) | lowHalf;
208 }
209 uncompressedPages = count;
210 header->actualRestore1Sum = sum;
211
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");
219
220 // Make sure everything get sync'd up.
221 __asm__ volatile("isync");
222 __asm__ volatile("sync");
223 __asm__ volatile("eieio");
224
225 // Move the Stack
226 __asm__ volatile("mr r1, %0" : : "r" (newSP));
227 __asm__ volatile("ori 0, 0, 0" : : );
228 proc(p1, p2, p3, p4);
229
230 return -1;
231 }
232
233 void HibernateBoot(void)
234 {
235 CICell dev, size, maxRead, imageSize, codeSize, allocSize, bytesToRead;
236 CICell memoryPH;
237 CICell available[2*16];
238 long mem_base;
239 IOHibernateImageHeader _header;
240 IOHibernateImageHeader * header = &_header;
241 volatile IOPolledFileExtent * currentExtent;
242 long long extentStart;
243 long long extentLength;
244 long long position, positionMax;
245 long buffer;
246 char c;
247 int havePreview, readingPreview;
248 char * tail;
249 Boot_Video videoInfo;
250 hibernate_graphics_t * graphicsInfo;
251 uint32_t machineSignature;
252 int32_t blob, lastBlob = 0;
253 // decryption data
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;
260
261 do {
262 tail = &gBootDevice[0];
263 while ((c = *++tail) && (c != ','))
264 {}
265 if (!c)
266 break;
267
268 *tail++ = 0;
269 extentStart = strtouq(tail, 0, 16);
270
271 printf("extentStart %s, %qx\n", gBootDevice, extentStart);
272
273 dev = Open(gBootDevice);
274 Seek(dev, extentStart);
275
276 size = Read(dev, (CICell) header, sizeof(IOHibernateImageHeader));
277 printf("header read size %x\n", size);
278
279 imageSize = header->image1Size;
280 codeSize = header->restore1PageCount << 12;
281 if (kIOHibernateHeaderSignature != header->signature)
282 break;
283
284 size = GetProp(gChosenPH, kIOHibernateMachineSignatureKey,
285 (char *)&machineSignature, sizeof(machineSignature));
286 if (size != sizeof(machineSignature)) machineSignature = 0;
287 if (machineSignature != header->machineSignature)
288 break;
289
290 allocSize = imageSize + ((4095 + sizeof(hibernate_graphics_t) + sizeof(hibernate_cryptwakevars_t)) & ~4095);
291
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;
299
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))
307 break;
308 }
309 }
310
311 printf("mem_base %x\n", mem_base);
312
313 graphicsInfo = (hibernate_graphics_t *) mem_base;
314 cryptwakevars = (hibernate_cryptwakevars_t *) (graphicsInfo + 1);
315 mem_base += (allocSize - imageSize);
316
317 bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader));
318 header = (IOHibernateImageHeader *) mem_base;
319
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);
326
327 position = 0;
328 maxRead = 0;
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;
335 } else {
336 bytesToRead = imageSize;
337 positionMax = header->imageSize;
338 maxRead = positionMax / kIOHibernateProgressCount;
339 SplashPreview(NULL, &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
340 }
341
342 while (bytesToRead) {
343
344 if (!extentLength) {
345 currentExtent++;
346 extentStart = currentExtent->start;
347 extentLength = currentExtent->length;
348 }
349 if (extentLength < bytesToRead)
350 size = extentLength;
351 else
352 size = bytesToRead;
353
354 if (maxRead && (size > maxRead))
355 size = maxRead;
356
357 if (-1 == Seek(dev, extentStart)) {
358 printf("seek fail\n");
359 break;
360 }
361 if (size != Read(dev, buffer, size)) {
362 printf("read fail\n");
363 break;
364 }
365
366 bytesToRead -= size;
367
368 if (!bytesToRead && readingPreview) {
369 uint8_t * src = (uint8_t *) (
370 ((uint32_t) &header->fileExtentMap[0])
371 + header->fileExtentMapSize
372 + codeSize
373 + header->previewPageListSize);
374
375 SplashPreview(src, &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
376 readingPreview = 0;
377 bytesToRead = imageSize;
378 maxRead = positionMax / kIOHibernateProgressCount;
379 } else if (!readingPreview) {
380 // progress
381 position += size;
382 blob = (position * kIOHibernateProgressCount) / positionMax;
383 if (blob != lastBlob)
384 {
385 SplashProgress(&graphicsInfo->progressSaveUnder[0][0], lastBlob, blob);
386 lastBlob = blob;
387 }
388 }
389
390 if (bytesToRead) {
391 extentStart += size;
392 extentLength -= size;
393 buffer += size;
394 }
395 }
396 if (bytesToRead)
397 break;
398
399 if (header->encryptStart) {
400 aes_decrypt_key(&gExtensionsSpec[0],
401 gHibernateKeySizeBytes,
402 &cryptvars->ctx.decrypt);
403
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);
407
408 // decrypt the buffer
409 uint32_t len = (uint32_t)(header->image1Size - header->encryptStart);
410 aes_decrypt_cbc(((uint8_t *) header) + header->encryptStart,
411 &first_iv[0],
412 len >> 4,
413 ((uint8_t *) header) + header->encryptStart,
414 &cryptvars->ctx.decrypt);
415 }
416
417 bcopy(&cryptvars->aes_iv[0], &cryptwakevars->aes_iv[0], sizeof(cryptwakevars->aes_iv));
418
419 bzero(&cryptvars->aes_iv[0], sizeof(cryptvars));
420 bzero(&gExtensionsSpec[0], sizeof(gExtensionsSpec));
421
422 Close(dev);
423
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;
433
434 WakeKernel(header, graphicsInfo, cryptwakevars, 0);
435 break;
436 }
437 while (0);
438
439 // failures reboot
440 Interpret(0, 0, " reset-all");
441 }
442
443 static void Main(ClientInterfacePtr ciPtr)
444 {
445 long ret;
446 int trycache;
447 long flags, cachetime, kerneltime, exttime = 0;
448 void *binary = (void *)kLoadAddr;
449
450 ret = InitEverything(ciPtr);
451 if (ret != 0) Exit();
452
453 if (gHibernateBoot) {
454 HibernateBoot();
455 }
456
457 // Get or infer the boot paths.
458 ret = GetBootPaths();
459 if (ret != 0) FailToBoot(1);
460
461 #if kFailToBoot
462 DrawSplashScreen(0);
463 #endif
464
465 while (ret == 0) {
466 trycache = (0 == (gBootMode & kBootModeSafe))
467 && (gBootKernelCacheFile[0] != 0);
468
469 if (trycache && (gBootFileType == kBlockDeviceType)) do {
470
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)) {
474 trycache = 0;
475 break;
476 }
477 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
478 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
479 || (cachetime < kerneltime)) {
480 trycache = 0;
481 break;
482 }
483 ret = GetFileInfo(gExtensionsSpec, "Extensions", &flags, &exttime);
484 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
485 && (cachetime < exttime)) {
486 trycache = 0;
487 break;
488 }
489 if (kerneltime > exttime)
490 exttime = kerneltime;
491 if (cachetime != (exttime + 1)) {
492 trycache = 0;
493 break;
494 }
495 } while (0);
496
497 if (trycache) {
498 ret = LoadFile(gBootKernelCacheFile);
499 if (ret != -1) {
500 ret = DecodeKernel(binary);
501 if (ret != -1) break;
502 }
503 }
504 ret = LoadThinFatFile(gBootFile, &binary);
505 if (ret != -1) ret = DecodeKernel(binary);
506 if (ret != -1) break;
507
508 ret = GetBootPaths();
509 if (ret != 0) FailToBoot(2);
510 }
511
512 if (ret != 0) FailToBoot(3);
513
514 if (!gHaveKernelCache) {
515 ret = LoadDrivers(gExtensionsSpec);
516 if (ret != 0) FailToBoot(4);
517 }
518
519 #if kFailToBoot
520 DrawSplashScreen(1);
521 #endif
522
523 ret = SetUpBootArgs();
524 if (ret != 0) FailToBoot(5);
525
526 ret = CallKernel();
527
528 FailToBoot(6);
529 }
530
531 static uint32_t UnescapeData(const uint8_t * src,
532 uint32_t srcLen,
533 uint8_t * dst,
534 uint32_t dstMaxLen)
535 {
536 uint32_t cnt, cnt2, dstLen = 0;
537 uint8_t byte;
538
539 for (cnt = 0; cnt < srcLen;) {
540 byte = src[cnt++];
541 if (byte == 0xFF) {
542 byte = src[cnt++];
543 cnt2 = byte & 0x7F;
544 byte = (byte & 0x80) ? 0xFF : 0x00;
545 } else
546 cnt2 = 1;
547 while (cnt2--) {
548 if (dstLen >= dstMaxLen)
549 return (-1);
550 dst[dstLen++] = byte;
551 }
552 }
553 return (dstLen);
554 }
555
556 static long InitEverything(ClientInterfacePtr ciPtr)
557 {
558 long ret, mem_base, mem_base2, size;
559 CICell keyboardPH;
560 char name[32], securityMode[33];
561 long length;
562 char *compatible;
563
564 // Init the OF Client Interface.
565 ret = InitCI(ciPtr);
566 if (ret != 0) return -1;
567
568 // Get the OF Version
569 gOFVersion = GetOFVersion();
570 if (gOFVersion == 0) return -1;
571
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;
576
577 // Init the SL Words package.
578 ret = InitSLWords();
579 if (ret != 0) return -1;
580
581 // Get the phandle for /options
582 gOptionsPH = FindDevice("/options");
583 if (gOptionsPH == -1) return -1;
584
585 // Get the phandle for /chosen
586 gChosenPH = FindDevice("/chosen");
587 if (gChosenPH == -1) return -1;
588
589 // Init the Memory Map.
590 ret = InitMemoryMap();
591 if (ret != 0) return -1;
592
593 // Get IHandles for the MMU and Memory
594 size = GetProp(gChosenPH, "mmu", (char *)&gMMUIH, 4);
595 if (size != 4) {
596 printf("Failed to get the IH for the MMU.\n");
597 return -1;
598 }
599 size = GetProp(gChosenPH, "memory", (char *)&gMemoryIH, 4);
600 if (size != 4) {
601 printf("Failed to get the IH for the Memory.\n");
602 return -1;
603 }
604
605 // Get first element of root's compatible property.
606 ret = GetPackageProperty(Peer(0), "compatible", &compatible, &length);
607 if (ret != -1)
608 strcpy(gPlatformName, compatible);
609
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;
614
615 // Try to find the keyboard using chosen
616 ret = GetProp(gChosenPH, "stdin", (char *)&gKeyboardIH, 4);
617 if (ret != 4) gKeyboardIH = 0;
618 else {
619 keyboardPH = InstanceToPackage(gKeyboardIH);
620 ret = GetProp(keyboardPH, "name", name, 31);
621 if (ret != -1) {
622 name[ret] = '\0';
623 if (strcmp(name, "keyboard") && strcmp(name, "kbd")) gKeyboardIH = 0;
624 } else gKeyboardIH = 0;
625 }
626
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");
630
631 // Get the key map set up, and make it up to date.
632 gKeyMap = InitKeyMap(gKeyboardIH);
633 if (gKeyMap == NULL) return -1;
634 UpdateKeyMap();
635
636 // Test for Secure Boot Mode.
637 size = GetProp(gOptionsPH, "security-mode", securityMode, 32);
638 if (size != -1) {
639 securityMode[size] = '\0';
640 if (strcmp(securityMode, "none")) gBootMode |= kBootModeSecure;
641 }
642
643 #if kFailToBoot
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);
648 } else {
649 SetOutputLevel(kOutputLevelOff);
650 }
651 #else
652 SetOutputLevel(kOutputLevelFull);
653 #endif
654
655 // printf now works.
656 printf("\n\nMac OS X Loader\n");
657
658 // Test for Safe Boot Mode; Shift and not Delete.
659 if (((gBootMode & kBootModeSecure) == 0)
660 && TestForKey(kShiftKey) && !TestForKey(kDeleteKey)) {
661 gBootMode |= kBootModeSafe;
662 }
663
664 size = GetProp(gOptionsPH, kIOHibernateBootImageKey, gBootDevice, 255);
665 if (size && (-1 != size)) do {
666 gBootDevice[size] = '\0';
667
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);
675
676 // always clear the boot-image variable
677 #if kFailToBoot
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");
681 #endif
682
683 // safe mode means no hibernate
684 if (kBootModeSafe & gBootMode) break;
685
686 #if kFailToBoot
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';
691
692 if (FindDevice(gBootFile) != FindDevice(gBootDevice)) break;
693 #endif
694
695 gHibernateBoot = 1;
696 } while (0);
697
698 if (gHibernateBoot)
699 {
700 // Claim memory for malloc.
701 if (Claim(kMallocAddr_H, kMallocSize_H, 0) == 0) {
702 printf("Claim for malloc failed.\n");
703 return -1;
704 }
705 malloc_init((char *)kMallocAddr_H, kMallocSize_H);
706 gImageFirstBootXAddr = kMallocAddr_H + kMallocSize_H;
707 } else {
708 // Claim memory for the FS Cache.
709 if (Claim(kFSCacheAddr, kFSCacheSize, 0) == 0) {
710 printf("Claim for fs cache failed.\n");
711 return -1;
712 }
713
714 // Claim memory for malloc.
715 if (Claim(kMallocAddr, kMallocSize, 0) == 0) {
716 printf("Claim for malloc failed.\n");
717 return -1;
718 }
719 malloc_init((char *)kMallocAddr, kMallocSize);
720
721 // Claim memory for the Load Addr.
722 mem_base = Claim(kLoadAddr, kLoadSize, 0);
723 if (mem_base == 0) {
724 printf("Claim for Load Area failed.\n");
725 return -1;
726 }
727
728 // Claim the memory for the Image Addr
729 if (gOFVersion >= kOFVersion3x) {
730 mem_base = Claim(kImageAddr, kImageSize, 0);
731 if (mem_base == 0) {
732 printf("Claim for Image Area failed.\n");
733 return -1;
734 }
735 } else {
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");
741 return -1;
742 }
743
744 // Unmap the old xcoff stack.
745 CallMethod(2, 0, gMMUIH, "unmap", 0x00380000, 0x00080000);
746
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");
754 return -1;
755 }
756
757 // Map them together.
758 CallMethod(4, 0, gMMUIH, "map",
759 kImageAddr1Phys, kImageAddr1, kImageSize1, 0);
760 }
761
762 bzero((char *)kImageAddr, kImageSize);
763
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");
768 return -1;
769 }
770 // Find all the displays and set them up.
771 ret = InitDisplays(1);
772 if (ret != 0) {
773 printf("InitDisplays failed.\n");
774 return -1;
775 }
776 }
777
778 return 0;
779 }
780
781
782 long ThinFatBinary(void **binary, unsigned long *length)
783 {
784 long ret;
785
786 ret = ThinFatBinaryMachO(binary, length);
787 if (ret == -1) ret = ThinFatBinaryElf(binary, length);
788
789 return ret;
790 }
791
792 static long DecodeKernel(void *binary)
793 {
794 long ret;
795 compressed_kernel_header *kernel_header = (compressed_kernel_header *)binary;
796 u_int32_t size;
797
798 if (kernel_header->signature == 'comp') {
799 if (kernel_header->compress_type != 'lzss')
800 return -1;
801 if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
802 return -1;
803 if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
804 return -1;
805
806 binary = AllocateBootXMemory(kernel_header->uncompressed_size);
807
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);
811 return -1;
812 }
813 if (kernel_header->adler32 !=
814 Adler32(binary, kernel_header->uncompressed_size)) {
815 printf("adler mismatch\n");
816 return -1;
817 }
818 }
819
820 ThinFatBinary(&binary, 0);
821
822 ret = DecodeMachO(binary);
823 if (ret == -1) ret = DecodeElf(binary);
824
825 return ret;
826 }
827
828
829 static long SetUpBootArgs(void)
830 {
831 boot_args_ptr args;
832 CICell memoryPH;
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;
839
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);
844
845 // Allocate some memory for the BootArgs.
846 gBootArgsSize = sizeof(boot_args);
847 gBootArgsAddr = AllocateKernelMemory(gBootArgsSize);
848
849 // Add the BootArgs to the memory-map.
850 AllocateMemoryRange("BootArgs", gBootArgsAddr, gBootArgsSize);
851
852 args = (boot_args_ptr)gBootArgsAddr;
853
854 args->Revision = kBootArgsRevision;
855 args->Version = kBootArgsVersion1;
856 args->machineType = 0;
857
858 // Check the Keyboard for 'cmd-s' and 'cmd-v'
859 UpdateKeyMap();
860 if ((gBootMode & kBootModeSecure) == 0) {
861 sKey = TestForKey(kCommandKey) && TestForKey('s');
862 vKey = TestForKey(kCommandKey) && TestForKey('v');
863 } else {
864 sKey = 0;
865 vKey = 0;
866 }
867
868 // if 'cmd-s' or 'cmd-v' was pressed do a text boot.
869 if (sKey || vKey) graphicsBoot = 0;
870
871 // Create the command line.
872 if (gOFVersion < kOFVersion3x) {
873 ofBootArgs[0] = ' ';
874 size = GetProp(gChosenPH, "machargs", ofBootArgs + 1, (sizeof(ofBootArgs) - 2));
875 if (size == -1) {
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));
888 } else {
889 size = GetProp(gOptionsPH, "boot-args", ofBootArgs, (sizeof(ofBootArgs) - 1));
890 if (size == -1) ofBootArgs[0] = '\0';
891 else ofBootArgs[size] = '\0';
892 }
893
894 if (ofBootArgs[0] != '\0') {
895 // Look for special options and copy the rest.
896 dash = 0;
897 ofArgs = ofBootArgs;
898 while ((tc = *ofArgs) != '\0') {
899 tc = tolower(tc);
900
901 // Check for entering a dash arg.
902 if (tc == '-') {
903 dash = 1;
904 ofArgs++;
905 continue;
906 }
907
908 // Do special stuff if in a dash arg.
909 if (dash) {
910 if (tc == 's') {
911 graphicsBoot = 0;
912 ofArgs++;
913 sKey = 0;
914 } else if (tc == 'v') {
915 graphicsBoot = 0;
916 ofArgs++;
917 vKey = 0;
918 } else {
919 // Check for exiting dash arg
920 if (isspace(tc)) dash = 0;
921
922 // Copy any non 's' or 'v'
923 ofArgs++;
924 }
925 } else {
926 // Not a dash arg so just copy it.
927 ofArgs++;
928 }
929 }
930 }
931
932 // Add any pressed keys (s, v, shift) to the command line
933 keyPos = 0;
934 if (sKey || vKey || (gBootMode & kBootModeSafe)) {
935 keyStr[keyPos++] = '-';
936
937 if (sKey) keyStr[keyPos++] = 's';
938 if (vKey) keyStr[keyPos++] = 'v';
939 if (gBootMode & kBootModeSafe) keyStr[keyPos++] = 'x';
940
941 keyStr[keyPos++] = ' ';
942 }
943 keyStr[keyPos++] = '\0';
944
945 sprintf(args->CommandLine, "%s%s", keyStr, ofBootArgs);
946
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;
950 else {
951 bank_shift = 12;
952 args->Version = kBootArgsVersion2;
953 }
954
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;
962
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;
968 } else {
969 args->PhysicalDRAM[cnt].base =
970 *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift;
971
972 }
973
974 if (gRootSizeCells == 1) {
975 args->PhysicalDRAM[cnt].size =
976 *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift;
977 } else {
978 args->PhysicalDRAM[cnt].size =
979 *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift;
980
981 }
982 }
983
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;
989
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));
992 mem_banks--;
993 cnt--;
994 }
995 bzero(args->PhysicalDRAM + mem_banks, (kMaxDRAMBanks - mem_banks) * sizeof(DRAMBank));
996
997 // Get the video info
998 GetMainScreenPH(&args->Video, 1);
999 args->Video.v_display = graphicsBoot;
1000
1001 // Add the DeviceTree to the memory-map.
1002 // The actuall address and size must be filled in later.
1003 AllocateMemoryRange("DeviceTree", 0, 0);
1004
1005 ret = FlattenDeviceTree();
1006 if (ret != 0) return -1;
1007
1008 // Fill in the address and size of the device tree.
1009 if (gDeviceTreeAddr) {
1010 gDeviceTreeMMTmp[0] = gDeviceTreeAddr;
1011 gDeviceTreeMMTmp[1] = gDeviceTreeSize;
1012 }
1013
1014 args->deviceTreeP = (void *)gDeviceTreeAddr;
1015 args->deviceTreeLength = gDeviceTreeSize;
1016 args->topOfKernelData = AllocateKernelMemory(0);
1017
1018 return 0;
1019 }
1020
1021
1022 static long CallKernel(void)
1023 {
1024 unsigned long msr, cnt;
1025
1026 Quiesce();
1027
1028 printf("\nCall Kernel!\n");
1029
1030 // Save SPRs for OF
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));
1036
1037 // Turn off translations
1038 msr = 0x00001000;
1039 __asm__ volatile("sync");
1040 __asm__ volatile("mtmsr %0" : : "r" (msr));
1041 __asm__ volatile("isync");
1042
1043 // Save the OF's Exceptions Vectors
1044 bcopy(0x0, gOFVectorSave, kVectorSize);
1045
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));
1051 }
1052
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));
1059 }
1060 }
1061
1062 // Make sure everything get sync'd up.
1063 __asm__ volatile("isync");
1064 __asm__ volatile("sync");
1065 __asm__ volatile("eieio");
1066
1067 // Call the Kernel's entry point
1068 (*(void (*)())gKernelEntryPoint)(gBootArgsAddr, kMacOSXSignature);
1069
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));
1075 }
1076
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));
1082
1083 // Restore translations
1084 __asm__ volatile("sync");
1085 __asm__ volatile("mtmsr %0" : : "r" (gOFMSRSave));
1086 __asm__ volatile("isync");
1087
1088 return -1;
1089 }
1090
1091
1092 static void FailToBoot(long num)
1093 {
1094 // useful for those holding down command-v ...
1095 printf("FailToBoot: %d\n", num);
1096 #if kFailToBoot
1097 DrawFailedBootPicture();
1098 while (1);
1099 num = 0;
1100 #else
1101 Enter(); // For debugging
1102 #endif
1103 }
1104
1105
1106 static long InitMemoryMap(void)
1107 {
1108 long result;
1109
1110 result = Interpret(0, 1,
1111 " dev /chosen"
1112 " new-device"
1113 " \" memory-map\" device-name"
1114 " active-package"
1115 " device-end"
1116 , &gMemoryMapPH);
1117
1118 return result;
1119 }
1120
1121
1122 static long GetOFVersion(void)
1123 {
1124 CICell ph;
1125 char versStr[256], *tmpStr;
1126 long vers, size;
1127
1128 // Get the openprom package
1129 ph = FindDevice("/openprom");
1130 if (ph == -1) return 0;
1131
1132 // Get it's model property
1133 size = GetProp(ph, "model", versStr, 255);
1134 if (size == -1) return -1;
1135 versStr[size] = '\0';
1136
1137 // Find the start of the number.
1138 tmpStr = NULL;
1139 if (!strncmp(versStr, "Open Firmware, ", 15)) {
1140 tmpStr = versStr + 15;
1141 } else if (!strncmp(versStr, "OpenFirmware ", 13)) {
1142 tmpStr = versStr + 13;
1143 } else return -1;
1144
1145 // Clasify by each instance as needed...
1146 switch (*tmpStr) {
1147 case '1' :
1148 vers = kOFVersion1x;
1149 break;
1150
1151 case '2' :
1152 vers = kOFVersion2x;
1153 break;
1154
1155 case '3' :
1156 vers = kOFVersion3x;
1157 break;
1158
1159 case '4' :
1160 vers = kOFVersion4x;
1161 break;
1162
1163 default :
1164 vers = 0;
1165 break;
1166 }
1167
1168 return vers;
1169 }
1170
1171
1172 static long TestForKey(long key)
1173 {
1174 long keyNum;
1175 long bp;
1176 char tc;
1177
1178 if (gOFVersion < kOFVersion3x) {
1179 switch(key) {
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;
1189 }
1190 } else {
1191 switch(key) {
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;
1202 }
1203
1204 // Map the right modifier keys on to the left.
1205 gKeyMap[28] |= gKeyMap[28] << 4;
1206 }
1207
1208 if (keyNum == -1) return 0;
1209
1210 bp = keyNum & 7;
1211 tc = gKeyMap[keyNum >> 3];
1212
1213 return (tc & (1 << bp)) != 0;
1214 }
1215
1216
1217 #define kBootpBootFileOffset (108)
1218 #define UUIDLEN 63
1219 static long GetBootPaths(void)
1220 {
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]"
1225
1226 /*
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]);
1231 */
1232
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';
1241 }
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
1252
1253
1254 // check for Boot != Root
1255 ret = FindRPSDir(gBootDevice, &rpsDir); // rpsDir set on success
1256 if (ret == 0) {
1257 SetProp(gChosenPH, kBootRootActiveKey, NULL, 0); // crumb for the OS
1258 // would be nice to set gBootSourceNumberMax = 1, but overridden below
1259 }
1260
1261 // Load any Boot.plist data (for Tiger RAID, BootRoot, etc)
1262 ret = ReadBootPlist(gBootDevice, rpsDir); // sets gBootDict on success
1263 if (ret == 0) {
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"
1270 }
1271 }
1272
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);
1277 return -1;
1278 }
1279
1280
1281 // Get the boot file (e.g. mach_kernel)
1282 size = GetProp(gChosenPH, "bootargs", gBootFile, 256);
1283 gBootFile[size] = '\0';
1284
1285 if (gBootFile[0] != '\0') {
1286 gBootFileType = GetDeviceType(gBootFile);
1287 gBootSourceNumberMax = 0;
1288 } else {
1289 gBootSourceNumber = 0;
1290 gBootFileType = gBootDeviceType;
1291 if (gBootFileType == kNetworkDeviceType) gBootSourceNumberMax = 1;
1292 else {
1293 if (gOFVersion < kOFVersion3x) {
1294 gBootSourceNumberMax = 4;
1295 } else {
1296 gBootSourceNumberMax = 6;
1297 }
1298 }
1299 }
1300 // gBootSourceNumberMax = 2; // helpful to prevent lots of probing
1301
1302 if (gBootFileType == kNetworkDeviceType) {
1303 SetProp(Peer(0), "net-boot", NULL, 0);
1304 }
1305 }
1306
1307 if (gBootSourceNumber >= gBootSourceNumberMax) return -1;
1308
1309 if (gBootSourceNumberMax != 0) {
1310 switch (gBootFileType) {
1311 case kNetworkDeviceType :
1312 // Find the end of the device spec.
1313 cnt = 0;
1314 while (gBootDevice[cnt] != ':') cnt++;
1315
1316 // Copy the device spec with the ':'.
1317 strncpy(gBootFile, gBootDevice, cnt + 1);
1318
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)) {
1323 if (bootplen > 0) {
1324 buffer = malloc(bootplen);
1325 GetProp(gChosenPH, "bootp-response", buffer, bootplen);
1326 } else {
1327 buffer = malloc(bsdplen);
1328 GetProp(gChosenPH, "bsdp-response", buffer, bsdplen);
1329 }
1330
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] == '/') {
1335 buffer[cnt] = '\\';
1336 cnt2 = cnt + 1;
1337 }
1338 cnt++;
1339 }
1340
1341 // Add a comma at the front.
1342 buffer[kBootpBootFileOffset - 1] = ',';
1343
1344 // Append the the root dir to the device spec.
1345 strncat(gBootFile, buffer + kBootpBootFileOffset - 1,
1346 cnt2 - kBootpBootFileOffset + 1);
1347
1348 free(buffer);
1349 } else {
1350 // Look for the start of the root dir path.
1351 cnt3 = cnt;
1352 while (gBootDevice[cnt3] != ',') cnt3++;
1353
1354 // Find the end of the path. Look for a comma or null.
1355 cnt2 = cnt3 + 1;
1356 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt2] != ',')) cnt2++;
1357
1358 // Find the last back slash or comma in the path
1359 cnt4 = cnt2 - 1;
1360 while ((gBootDevice[cnt4] != ',') && (gBootDevice[cnt4] != '\\')) cnt4--;
1361
1362 // Copy the IP addresses if needed.
1363 if (gOFVersion < kOFVersion3x) {
1364 strncat(gBootFile, gBootDevice + cnt + 1, cnt3 - cnt - 1);
1365 }
1366
1367 // Add on the directory path
1368 strncat(gBootFile, gBootDevice + cnt3, cnt4 - cnt3 + 1);
1369 }
1370
1371 // Add on the kernel name
1372 strcat(gBootFile, "mach.macosx");
1373
1374 // Add on postfix
1375 strcat(gBootFile, gBootDevice + cnt2);
1376 break;
1377
1378 case kBlockDeviceType :
1379 // Find the first ':'.
1380 cnt = 0;
1381 while ((gBootDevice[cnt] != '\0') && (gBootDevice[cnt] != ':')) cnt++;
1382 if (gBootDevice[cnt] == '\0') return -1;
1383
1384 // Find the comma after the ':'.
1385 cnt2 = cnt + 1;
1386 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt] != ',')) cnt2++;
1387
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);
1392
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;
1396
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);
1401
1402 // and the cache file name
1403
1404 bzero(gCacheNameAdler + 64, sizeof(gBootFile));
1405 strcpy(gCacheNameAdler + 64, gBootFile);
1406 adler32 = Adler32(gCacheNameAdler, sizeof(gCacheNameAdler));
1407
1408 strncpy(gBootKernelCacheFile, gBootDevice, cnt + 1);
1409 sprintf(gBootKernelCacheFile + cnt + 1,
1410 "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum, adler32);
1411 break;
1412
1413 default:
1414 printf("Failed to infer Boot Device Type.\n");
1415 return -1;
1416 break;
1417 }
1418 }
1419
1420 // Figure out the root dir.
1421 ret = ConvertFileSpec(gBootFile, gExtensionsSpec, &filePath);
1422 if (ret == -1) {
1423 printf("Failed to determine root directory\n");
1424 return -1;
1425 }
1426
1427 strcat(gExtensionsSpec, ",");
1428
1429 // Add in any extra path to gRootDir (handles com.apple.boot.[RPS]).
1430 cnt = 0;
1431 while (filePath[cnt] != '\0') cnt++;
1432
1433 if (cnt != 0) {
1434 for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) {
1435 if (filePath[cnt2] == '\\') {
1436 strncat(gExtensionsSpec, filePath, cnt2 + 1);
1437 break;
1438 }
1439 }
1440 }
1441
1442 // Figure out the extensions dir.
1443 if (gBootFileType == kBlockDeviceType) {
1444 cnt = strlen(gExtensionsSpec);
1445 if ((cnt > 2) && (gExtensionsSpec[cnt-1] == '\\') && (gExtensionsSpec[cnt-2] == '\\'))
1446 cnt--;
1447 strcpy(gExtensionsSpec + cnt, "System\\Library\\");
1448 }
1449
1450 // technically could just do this once at the end
1451 SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1);
1452
1453 if (gBootDict && gBootDict->type == kTagTypeDict) {
1454 TagPtr prop = GetProperty(gBootDict, kRootUUIDKey);
1455 if (prop && prop->type == kTagTypeString)
1456 strncpy(uuidStr, prop->string, UUIDLEN);
1457 }
1458
1459 if (uuidStr[0] == '\0') {
1460 (void)GetFSUUID(gBootFile, uuidStr);
1461 }
1462
1463 if (uuidStr[0]) {
1464 printf("setting boot-uuid to: %s\n", uuidStr);
1465 SetProp(gChosenPH, "boot-uuid", uuidStr, strlen(uuidStr) + 1);
1466 }
1467
1468 gBootSourceNumber++;
1469
1470 return 0;
1471 }
1472
1473 /*
1474 * FindRPSDir looks for a "rock," "paper," or "scissors" directory
1475 * - handle all permutations: 3 dirs, any 2 dirs, any 1 dir
1476 */
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)
1480 {
1481 long rval = 0;
1482 long flags, time;
1483 char haveR, haveP, haveS;
1484
1485 unsigned long index = 0;
1486 char *curName;
1487
1488 haveR = haveP = haveS = 0;
1489
1490 // strip any file specifier and start at the root
1491 if (ConvertFileSpec(bootDevice, rootDirSpec, NULL)) return -1;
1492 strncat(rootDirSpec, ",\\", SPECLEN-strlen(rootDirSpec));
1493
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; }
1499 }
1500
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
1505 // p wins
1506 *rpsDir = kBootDirP;
1507 } else if (haveR && haveS) {
1508 // r wins
1509 *rpsDir = kBootDirR;
1510 } else if (haveP && haveS) {
1511 // s wins
1512 *rpsDir = kBootDirS;
1513 } else if (haveR) { // NComb(3,1) = 3
1514 // wins by default
1515 *rpsDir = kBootDirR;
1516 } else if (haveP) {
1517 // wins by default
1518 *rpsDir = kBootDirP;
1519 } else if (haveS) {
1520 // wins by default
1521 *rpsDir = kBootDirS;
1522 } else { // NComb(3,0) = 0
1523 rval = -1;
1524 }
1525
1526 return rval;
1527 }
1528
1529 /*
1530 * ReadBootPlist looks around for com.apple.Boot.plist, populates gBootDict
1531 * could live elsewhere
1532 */
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\\" \
1537 BOOTPLIST_NAME
1538 static char plistSpec[SPECLEN+1]; // save stack space
1539 static long ReadBootPlist(char *devSpec, char *rpsDir)
1540 {
1541 int len;
1542
1543 do {
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));
1548
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));
1554
1555 // and try to load again
1556 if ((len = LoadFile(plistSpec)) < 0) {
1557 printf("couldn't load %s\n", BOOTPLIST_NAME);
1558 break;
1559 }
1560 }
1561 *((char*)kLoadAddr + len) = '\0'; // terminate for parser safety
1562
1563 if (ParseXML((char*)kLoadAddr, &gBootDict) < 0 || !gBootDict) {
1564 printf("couldn't parse %s\n", BOOTPLIST_NAME);
1565 break;
1566 }
1567
1568 return 0;
1569 } while(0);
1570
1571 return -1;
1572 }
1573
1574 // Public Functions
1575
1576 long GetDeviceType(char *devSpec)
1577 {
1578 CICell ph;
1579 long size;
1580 char deviceType[32];
1581
1582 if (isRAIDPath(devSpec))
1583 return kBlockDeviceType;
1584
1585 ph = FindDevice(devSpec);
1586 if (ph == -1) return -1;
1587
1588 size = GetProp(ph, "device_type", deviceType, 31);
1589 if (size != -1) deviceType[size] = '\0';
1590 else deviceType[0] = '\0';
1591
1592 if (strcmp(deviceType, "network") == 0) return kNetworkDeviceType;
1593 if (strcmp(deviceType, "block") == 0) return kBlockDeviceType;
1594
1595 return kUnknownDeviceType;
1596 }
1597
1598
1599 long ConvertFileSpec(char *fileSpec, char *devSpec, char **filePath)
1600 {
1601 long cnt;
1602
1603 // Find the first ':' in the fileSpec.
1604 cnt = 0;
1605 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ':')) cnt++;
1606 if (fileSpec[cnt] == '\0') return -1;
1607
1608 // Find the next ',' in the fileSpec.
1609 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ',')) cnt++;
1610
1611 // Copy the string to devSpec.
1612 strncpy(devSpec, fileSpec, cnt);
1613 devSpec[cnt] = '\0';
1614
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;
1619 } else {
1620 *filePath = NULL;
1621 }
1622 }
1623
1624 return 0;
1625 }
1626
1627
1628 long MatchThis(CICell phandle, char *string)
1629 {
1630 long ret, length;
1631 char *name, *model, *compatible;
1632
1633 ret = GetPackageProperty(phandle, "name", &name, &length);
1634 if ((ret == -1) || (length == 0)) name = NULL;
1635
1636 ret = GetPackageProperty(phandle, "model", &model, &length);
1637 if ((ret == -1) || (length == 0)) model = NULL;
1638
1639 ret = GetPackageProperty(phandle, "compatible", &compatible, &length);
1640 if ((ret == -1) || (length == 0)) model = NULL;
1641
1642 if ((name != NULL) && strcmp(name, string) == 0) return 0;
1643 if ((model != NULL) && strcmp(model, string) == 0) return 0;
1644
1645 if (compatible != NULL) {
1646 while (*compatible != '\0') {
1647 if (strcmp(compatible, string) == 0) return 0;
1648
1649 compatible += strlen(compatible) + 1;
1650 }
1651 }
1652
1653 return -1;
1654 }
1655
1656
1657 void *AllocateBootXMemory(long size)
1658 {
1659 long addr = gImageFirstBootXAddr - size;
1660
1661 if (addr < gImageLastKernelAddr) return 0;
1662
1663 gImageFirstBootXAddr = addr;
1664
1665 return (void *)addr;
1666 }
1667
1668
1669 long AllocateKernelMemory(long size)
1670 {
1671 long addr = gImageLastKernelAddr;
1672
1673 gImageLastKernelAddr += (size + 0xFFF) & ~0xFFF;
1674
1675 if (gImageLastKernelAddr > gImageFirstBootXAddr)
1676 FailToBoot(-1);
1677
1678 return addr;
1679 }
1680
1681
1682 long AllocateMemoryRange(char *rangeName, long start, long length)
1683 {
1684 long result, *buffer;
1685
1686 buffer = AllocateBootXMemory(2 * sizeof(long));
1687 if (buffer == 0) return -1;
1688
1689 buffer[0] = start;
1690 buffer[1] = length;
1691
1692 result = SetProp(gMemoryMapPH, rangeName, (char *)buffer, 2 * sizeof(long));
1693 if (result == -1) return -1;
1694
1695 return 0;
1696 }
1697
1698 #define BASE 65521L /* largest prime smaller than 65536 */
1699 #define NMAX 5000
1700 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
1701
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);
1707
1708 unsigned long Adler32(unsigned char *buf, long len)
1709 {
1710 unsigned long s1 = 1; // adler & 0xffff;
1711 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
1712 int k;
1713
1714 while (len > 0) {
1715 k = len < NMAX ? len : NMAX;
1716 len -= k;
1717 while (k >= 16) {
1718 DO16(buf);
1719 buf += 16;
1720 k -= 16;
1721 }
1722 if (k != 0) do {
1723 s1 += *buf++;
1724 s2 += s1;
1725 } while (--k);
1726 s1 %= BASE;
1727 s2 %= BASE;
1728 }
1729 return (s2 << 16) | s1;
1730 }