]> git.saurik.com Git - apple/bootx.git/blob - bootx.tproj/sl.subproj/main.c
d9a6767d5569fe8206fe46c9d7dec17c70a7cd72
[apple/bootx.git] / bootx.tproj / sl.subproj / main.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * main.c - Main functions for BootX.
27 *
28 * Copyright (c) 1998-2002 Apple Computer, Inc.
29 *
30 * DRI: Josh de Cesare
31 */
32
33
34 #include <sl.h>
35
36 static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr);
37 static void Main(ClientInterfacePtr ciPtr);
38 static long InitEverything(ClientInterfacePtr ciPtr);
39 static long DecodeKernel(void);
40 static long SetUpBootArgs(void);
41 static long CallKernel(void);
42 static void FailToBoot(long num);
43 static long InitMemoryMap(void);
44 static long GetOFVersion(void);
45 static long TestForKey(long key);
46 static long GetBootPaths(void);
47
48 const unsigned long StartTVector[2] = {(unsigned long)Start, 0};
49
50 char gStackBaseAddr[0x8000];
51
52 char *gVectorSaveAddr;
53 long gImageLastKernelAddr = 0;
54 long gImageFirstBootXAddr = kLoadAddr;
55 long gKernelEntryPoint;
56 long gDeviceTreeAddr;
57 long gDeviceTreeSize;
58 long gBootArgsAddr;
59 long gBootArgsSize;
60 long gSymbolTableAddr;
61 long gSymbolTableSize;
62
63 long gBootSourceNumber = -1;
64 long gBootSourceNumberMax;
65 long gBootMode = kBootModeNormal;
66 long gBootDeviceType;
67 long gBootFileType;
68 char gBootDevice[256];
69 char gBootFile[256];
70 char gRootDir[256];
71
72 char gTempStr[4096];
73
74 long *gDeviceTreeMMTmp = 0;
75
76 long gOFVersion;
77
78 char *gKeyMap;
79
80 CICell gChosenPH;
81 CICell gOptionsPH;
82 CICell gScreenPH;
83 CICell gMemoryMapPH;
84 CICell gStdOutPH;
85
86 CICell gMMUIH;
87 CICell gMemoryIH;
88 CICell gStdOutIH;
89 CICell gKeyboardIH;
90
91 // Private Functions
92
93 static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr)
94 {
95 long newSP;
96
97 // Move the Stack to a chunk of the BSS
98 newSP = (long)gStackBaseAddr + sizeof(gStackBaseAddr) - 0x100;
99 __asm__ volatile("mr r1, %0" : : "r" (newSP));
100
101 Main(ciPtr);
102 }
103
104
105 static void Main(ClientInterfacePtr ciPtr)
106 {
107 long ret;
108
109 ret = InitEverything(ciPtr);
110 if (ret != 0) Exit();
111
112 // Get or infer the boot paths.
113 ret = GetBootPaths();
114 if (ret != 0) FailToBoot(1);
115
116 DrawSplashScreen(0);
117
118 while (ret == 0) {
119 ret = LoadFile(gBootFile);
120 if (ret != -1) break;
121
122 ret = GetBootPaths();
123 if (ret != 0) FailToBoot(2);
124 }
125
126 ret = DecodeKernel();
127 if (ret != 0) FailToBoot(3);
128
129 ret = LoadDrivers(gRootDir);
130 if (ret != 0) FailToBoot(4);
131
132 DrawSplashScreen(1);
133
134 ret = SetUpBootArgs();
135 if (ret != 0) FailToBoot(5);
136
137 ret = CallKernel();
138
139 FailToBoot(6);
140 }
141
142
143 static long InitEverything(ClientInterfacePtr ciPtr)
144 {
145 long ret, mem_base, mem_base2, size;
146 CICell keyboardPH;
147 char name[32], securityMode[33];
148
149 // Init the OF Client Interface.
150 ret = InitCI(ciPtr);
151 if (ret != 0) return -1;
152
153 // Get the OF Version
154 gOFVersion = GetOFVersion();
155 if (gOFVersion == 0) return -1;
156
157 // Init the SL Words package.
158 ret = InitSLWords();
159 if (ret != 0) return -1;
160
161 // Get the phandle for /options
162 gOptionsPH = FindDevice("/options");
163 if (gOptionsPH == -1) return -1;
164
165 // Get the phandle for /chosen
166 gChosenPH = FindDevice("/chosen");
167 if (gChosenPH == -1) return -1;
168
169 // Init the Memory Map.
170 ret = InitMemoryMap();
171 if (ret != 0) return -1;
172
173 // Get IHandles for the MMU and Memory
174 size = GetProp(gChosenPH, "mmu", (char *)&gMMUIH, 4);
175 if (size != 4) {
176 printf("Failed to get the IH for the MMU.\n");
177 return -1;
178 }
179 size = GetProp(gChosenPH, "memory", (char *)&gMemoryIH, 4);
180 if (size != 4) {
181 printf("Failed to get the IH for the Memory.\n");
182 return -1;
183 }
184
185 // Get stdout's IH, so that the boot display can be found.
186 ret = GetProp(gChosenPH, "stdout", (char *)&gStdOutIH, 4);
187 if (ret == 4) gStdOutPH = InstanceToPackage(gStdOutIH);
188 else gStdOutPH = gStdOutIH = 0;
189
190 // Try to find the keyboard using chosen
191 ret = GetProp(gChosenPH, "stdin", (char *)&gKeyboardIH, 4);
192 if (ret != 4) gKeyboardIH = 0;
193 else {
194 keyboardPH = InstanceToPackage(gKeyboardIH);
195 ret = GetProp(keyboardPH, "name", name, 31);
196 if (ret != -1) {
197 name[ret] = '\0';
198 if (strcmp(name, "keyboard") && strcmp(name, "kbd")) gKeyboardIH = 0;
199 } else gKeyboardIH = 0;
200 }
201
202 // Try to the find the keyboard using open if chosen did not work.
203 if (gKeyboardIH == 0) gKeyboardIH = Open("keyboard");
204 if (gKeyboardIH == 0) gKeyboardIH = Open("kbd");
205
206 // Get the key map set up, and make it up to date.
207 gKeyMap = InitKeyMap(gKeyboardIH);
208 if (gKeyMap == NULL) return -1;
209 UpdateKeyMap();
210
211 // Test for Secure Boot Mode.
212 size = GetProp(gOptionsPH, "security-mode", securityMode, 32);
213 if (size != -1) {
214 securityMode[size] = '\0';
215 if (strcmp(securityMode, "none")) gBootMode |= kBootModeSecure;
216 }
217
218 #if kFailToBoot
219 // 'cmd-s' or 'cmd-v' is pressed set outputLevel to kOutputLevelFull
220 if (((gBootMode & kBootModeSecure) == 0) && TestForKey(kCommandKey) &&
221 (TestForKey('s') || TestForKey('v'))) {
222 SetOutputLevel(kOutputLevelFull);
223 } else {
224 SetOutputLevel(kOutputLevelOff);
225 }
226 #else
227 SetOutputLevel(kOutputLevelFull);
228 #endif
229
230 // printf now works.
231 printf("\n\nMac OS X Loader\n");
232
233 // Test for Safe Boot Mode.
234 if (((gBootMode & kBootModeSecure) == 0) && TestForKey(kShiftKey)) {
235 gBootMode |= kBootModeSafe;
236 }
237
238 if (Claim(kMallocAddr, kMallocSize, 0) == 0) {
239 printf("Claim for malloc failed.\n");
240 return -1;
241 }
242 malloc_init((char *)kMallocAddr, kMallocSize);
243
244 // malloc now works.
245
246 // Claim the memory for the Load Addr
247 mem_base = Claim(kLoadAddr, kLoadSize, 0);
248 if (mem_base == 0) {
249 printf("Claim for Load Area failed.\n");
250 return -1;
251 }
252
253 // Claim the memory for the Image Addr
254 if (gOFVersion >= kOFVersion3x) {
255 mem_base = Claim(kImageAddr, kImageSize, 0);
256 if (mem_base == 0) {
257 printf("Claim for Image Area failed.\n");
258 return -1;
259 }
260 } else {
261 // Claim the 1:1 mapped chunks first.
262 mem_base = Claim(kImageAddr0, kImageSize0, 0);
263 mem_base2 = Claim(kImageAddr2, kImageSize2, 0);
264 if ((mem_base == 0) || (mem_base2 == 0)) {
265 printf("Claim for Image Area failed.\n");
266 return -1;
267 }
268
269 // Unmap the old xcoff stack.
270 CallMethod(2, 0, gMMUIH, "unmap", 0x00380000, 0x00080000);
271
272 // Grap the physical memory then the logical.
273 CallMethod(3, 1, gMemoryIH, "claim",
274 kImageAddr1Phys, kImageSize1, 0, &mem_base);
275 CallMethod(3, 1, gMMUIH, "claim",
276 kImageAddr1, kImageSize1, 0, &mem_base2);
277 if ((mem_base == 0) || (mem_base2 == 0)) {
278 printf("Claim for Image Area failed.\n");
279 return -1;
280 }
281
282 // Map them together.
283 CallMethod(4, 0, gMMUIH, "map",
284 kImageAddr1Phys, kImageAddr1, kImageSize1, 0);
285 }
286
287 bzero((char *)kImageAddr, kImageSize);
288
289 // Allocate some space for the Vector Save area.
290 gVectorSaveAddr = AllocateBootXMemory(kVectorSize);
291 if (gVectorSaveAddr == 0) {
292 printf("Allocation for the Vector Save Area failed.\n");
293 return -1;
294 }
295
296 // Find all the displays and set them up.
297 ret = InitDisplays();
298 if (ret != 0) {
299 printf("InitDisplays failed.\n");
300 return -1;
301 }
302
303 return 0;
304 }
305
306
307 static long DecodeKernel(void)
308 {
309 long ret;
310
311 ret = DecodeMachO();
312 if (ret == -1) ret = DecodeElf();
313
314 return ret;
315 }
316
317
318 static long SetUpBootArgs(void)
319 {
320 boot_args_ptr args;
321 CICell memoryPH;
322 long graphicsBoot = 1;
323 long ret, cnt, mem_size, size, dash;
324 long sKey, vKey, keyPos;
325 char ofBootArgs[128], *ofArgs, tc, keyStr[8];
326
327 // Save file system cache statistics.
328 SetProp(gChosenPH, "BootXCacheHits", (char *)&gCacheHits, 4);
329 SetProp(gChosenPH, "BootXCacheMisses", (char *)&gCacheMisses, 4);
330 SetProp(gChosenPH, "BootXCacheEvicts", (char *)&gCacheEvicts, 4);
331
332 // Allocate some memory for the BootArgs.
333 gBootArgsSize = sizeof(boot_args);
334 gBootArgsAddr = AllocateKernelMemory(gBootArgsSize);
335
336 // Add the BootArgs to the memory-map.
337 AllocateMemoryRange("BootArgs", gBootArgsAddr, gBootArgsSize);
338
339 args = (boot_args_ptr)gBootArgsAddr;
340
341 args->Revision = kBootArgsRevision;
342 args->Version = kBootArgsVersion;
343 args->machineType = 0;
344
345 // Check the Keyboard for 'cmd-s' and 'cmd-v'
346 UpdateKeyMap();
347 if ((gBootMode & kBootModeSecure) == 0) {
348 sKey = TestForKey(kCommandKey) && TestForKey('s');
349 vKey = TestForKey(kCommandKey) && TestForKey('v');
350 } else {
351 sKey = 0;
352 vKey = 0;
353 }
354
355 // if 'cmd-s' or 'cmd-v' was pressed do a text boot.
356 if (sKey || vKey) graphicsBoot = 0;
357
358 // Create the command line.
359 if (gOFVersion < kOFVersion3x) {
360 ofBootArgs[0] = ' ';
361 size = GetProp(gChosenPH, "machargs", ofBootArgs + 1, 126);
362 if (size == -1) {
363 size = GetProp(gOptionsPH, "boot-command", ofBootArgs, 127);
364 if (size == -1) ofBootArgs[0] = '\0';
365 else ofBootArgs[size] = '\0';
366 // Look for " bootr" but skip the number.
367 if (!strncmp(ofBootArgs + 1, " bootr", 6)) {
368 strcpy(ofBootArgs, ofBootArgs + 7);
369 } else ofBootArgs[0] = '\0';
370 SetProp(gChosenPH, "machargs", ofBootArgs, strlen(ofBootArgs) + 1);
371 } else ofBootArgs[size] = '\0';
372 // Force boot-command to start with 0 bootr.
373 sprintf(gTempStr, "0 bootr%s", ofBootArgs);
374 SetProp(gOptionsPH, "boot-command", gTempStr, strlen(gTempStr));
375 } else {
376 size = GetProp(gOptionsPH, "boot-args", ofBootArgs, 127);
377 if (size == -1) ofBootArgs[0] = '\0';
378 else ofBootArgs[size] = '\0';
379 }
380
381 if (ofBootArgs[0] != '\0') {
382 // Look for special options and copy the rest.
383 dash = 0;
384 ofArgs = ofBootArgs;
385 while ((tc = *ofArgs) != '\0') {
386 tc = tolower(tc);
387
388 // Check for entering a dash arg.
389 if (tc == '-') {
390 dash = 1;
391 ofArgs++;
392 continue;
393 }
394
395 // Do special stuff if in a dash arg.
396 if (dash) {
397 if (tc == 's') {
398 graphicsBoot = 0;
399 ofArgs++;
400 sKey = 0;
401 } else if (tc == 'v') {
402 graphicsBoot = 0;
403 ofArgs++;
404 vKey = 0;
405 } else {
406 // Check for exiting dash arg
407 if (isspace(tc)) dash = 0;
408
409 // Copy any non 's' or 'v'
410 ofArgs++;
411 }
412 } else {
413 // Not a dash arg so just copy it.
414 ofArgs++;
415 }
416 }
417 }
418
419 // Add any pressed keys (s, v, shift) to the command line
420 keyPos = 0;
421 if (sKey || vKey || (gBootMode & kBootModeSafe)) {
422 keyStr[keyPos++] = '-';
423
424 if (sKey) keyStr[keyPos++] = 's';
425 if (vKey) keyStr[keyPos++] = 'v';
426 if (gBootMode & kBootModeSafe) keyStr[keyPos++] = 'x';
427
428 keyStr[keyPos++] = ' ';
429 }
430 keyStr[keyPos++] = '\0';
431
432 sprintf(args->CommandLine, "%s%s", keyStr, ofBootArgs);
433
434 // Get the memory info
435 memoryPH = FindDevice("/memory");
436 if (memoryPH == -1) return -1;
437 size = GetProp(memoryPH, "reg", (char *)(args->PhysicalDRAM),
438 kMaxDRAMBanks * sizeof(DRAMBank));
439 if (size == 0) return -1;
440
441 // This is a hack to make the memory look like its all
442 // in one big bank.
443 mem_size = 0;
444 for (cnt = 0; cnt < kMaxDRAMBanks; cnt++) {
445 mem_size += args->PhysicalDRAM[cnt].size;
446 args->PhysicalDRAM[cnt].base = 0;
447 args->PhysicalDRAM[cnt].size = 0;
448 }
449 args->PhysicalDRAM[0].size = mem_size;
450
451 // Get the video info
452 GetMainScreenPH(&args->Video);
453 args->Video.v_display = graphicsBoot;
454
455 // Add the DeviceTree to the memory-map.
456 // The actuall address and size must be filled in later.
457 AllocateMemoryRange("DeviceTree", 0, 0);
458
459 ret = FlattenDeviceTree();
460 if (ret != 0) return -1;
461
462 // Fill in the address and size of the device tree.
463 if (gDeviceTreeAddr) {
464 gDeviceTreeMMTmp[0] = gDeviceTreeAddr;
465 gDeviceTreeMMTmp[1] = gDeviceTreeSize;
466 }
467
468 args->deviceTreeP = (void *)gDeviceTreeAddr;
469 args->deviceTreeLength = gDeviceTreeSize;
470 args->topOfKernelData = AllocateKernelMemory(0);
471
472 return 0;
473 }
474
475
476 static long CallKernel(void)
477 {
478 long msr, cnt;
479
480 Quiesce();
481
482 printf("\nCall Kernel!\n");
483
484 msr = 0x00001000;
485 __asm__ volatile("mtmsr %0" : : "r" (msr));
486 __asm__ volatile("isync");
487
488 // Move the Execption Vectors
489 bcopy(gVectorSaveAddr, 0x0, kVectorSize);
490 for (cnt = 0; cnt < kVectorSize; cnt += 0x20) {
491 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
492 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
493 }
494
495 // Move the Image1 save area for OF 1.x / 2.x
496 if (gOFVersion < kOFVersion3x) {
497 bcopy((char *)kImageAddr1Phys, (char *)kImageAddr1, kImageSize1);
498 for (cnt = kImageAddr1; cnt < kImageSize1; cnt += 0x20) {
499 __asm__ volatile("dcbf 0, %0" : : "r" (cnt));
500 __asm__ volatile("icbi 0, %0" : : "r" (cnt));
501 }
502 }
503
504 // Make sure everything get sync'd up.
505 __asm__ volatile("isync");
506 __asm__ volatile("sync");
507 __asm__ volatile("eieio");
508
509 (*(void (*)())gKernelEntryPoint)(gBootArgsAddr, kMacOSXSignature);
510
511 return -1;
512 }
513
514
515 static void FailToBoot(long num)
516 {
517 #if kFailToBoot
518 DrawFailedBootPicture();
519 while (1);
520 num = 0;
521 #else
522 printf("FailToBoot: %d\n", num);
523 Enter(); // For debugging
524 #endif
525 }
526
527
528 static long InitMemoryMap(void)
529 {
530 long result;
531
532 result = Interpret(0, 1,
533 " dev /chosen"
534 " new-device"
535 " \" memory-map\" device-name"
536 " active-package"
537 " device-end"
538 , &gMemoryMapPH);
539
540 return result;
541 }
542
543
544 static long GetOFVersion(void)
545 {
546 CICell ph;
547 char versStr[256], *tmpStr;
548 long vers, size;
549
550 // Get the openprom package
551 ph = FindDevice("/openprom");
552 if (ph == -1) return 0;
553
554 // Get it's model property
555 size = GetProp(ph, "model", versStr, 255);
556 if (size == -1) return -1;
557 versStr[size] = '\0';
558
559 // Find the start of the number.
560 tmpStr = NULL;
561 if (!strncmp(versStr, "Open Firmware, ", 15)) {
562 tmpStr = versStr + 15;
563 } else if (!strncmp(versStr, "OpenFirmware ", 13)) {
564 tmpStr = versStr + 13;
565 } else return -1;
566
567 // Clasify by each instance as needed...
568 switch (*tmpStr) {
569 case '1' :
570 vers = kOFVersion1x;
571 break;
572
573 case '2' :
574 vers = kOFVersion2x;
575 break;
576
577 case '3' :
578 vers = kOFVersion3x;
579 break;
580
581 default :
582 vers = 0;
583 break;
584 }
585
586 return vers;
587 }
588
589
590 static long TestForKey(long key)
591 {
592 long keyNum;
593 long bp;
594 char tc;
595
596 if (gOFVersion < kOFVersion3x) {
597 switch(key) {
598 case 'a' : keyNum = 7; break;
599 case 's' : keyNum = 6; break;
600 case 'v' : keyNum = 14; break;
601 case 'y' : keyNum = 23; break;
602 case kCommandKey : keyNum = 48; break;
603 case kOptKey : keyNum = 61; break;
604 case kShiftKey : keyNum = 63; break;
605 case kControlKey : keyNum = 49; break;
606 default : keyNum = -1; break;
607 }
608 } else {
609 switch(key) {
610 case 'a' : keyNum = 3; break;
611 case 's' : keyNum = 17; break;
612 case 'v' : keyNum = 30; break;
613 case 'y' : keyNum = 27; break;
614 case kCommandKey : keyNum = 228; break;
615 case kOptKey : keyNum = 229; break;
616 case kShiftKey : keyNum = 230; break;
617 case kControlKey : keyNum = 231; break;
618 default : keyNum = -1; break;
619 }
620
621 // Map the right modifier keys on to the left.
622 gKeyMap[28] |= gKeyMap[28] << 4;
623 }
624
625 if (keyNum == -1) return 0;
626
627 bp = keyNum & 7;
628 tc = gKeyMap[keyNum >> 3];
629
630 return (tc & (1 << bp)) != 0;
631 }
632
633
634 #define kBootpBootFileOffset (108)
635
636 static long GetBootPaths(void)
637 {
638 long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen;
639 char *filePath, *buffer;
640
641 if (gBootSourceNumber == -1) {
642 // Get the boot-device
643 size = GetProp(gChosenPH, "bootpath", gBootDevice, 255);
644 gBootDevice[size] = '\0';
645 if (gBootDevice[0] == '\0') {
646 size = GetProp(gOptionsPH, "boot-device", gBootDevice, 255);
647 gBootDevice[size] = '\0';
648 }
649 gBootDeviceType = GetDeviceType(gBootDevice);
650
651 // Get the boot-file
652 size = GetProp(gChosenPH, "bootargs", gBootFile, 256);
653 gBootFile[size] = '\0';
654
655 if (gBootFile[0] != '\0') {
656 gBootFileType = GetDeviceType(gBootFile);
657 gBootSourceNumberMax = 0;
658 } else {
659 gBootSourceNumber = 0;
660 gBootFileType = gBootDeviceType;
661 if (gBootFileType == kNetworkDeviceType) gBootSourceNumberMax = 1;
662 else {
663 if (gOFVersion < kOFVersion3x) {
664 gBootSourceNumberMax = 4;
665 } else {
666 gBootSourceNumberMax = 6;
667 }
668 }
669 }
670
671 if (gBootFileType == kNetworkDeviceType) {
672 SetProp(Peer(0), "net-boot", NULL, 0);
673 }
674 }
675
676 if (gBootSourceNumber >= gBootSourceNumberMax) return -1;
677
678 if (gBootSourceNumberMax != 0) {
679 switch (gBootFileType) {
680 case kNetworkDeviceType :
681 // Find the end of the device spec.
682 cnt = 0;
683 while (gBootDevice[cnt] != ':') cnt++;
684
685 // Copy the device spec with the ':'.
686 strncpy(gBootFile, gBootDevice, cnt + 1);
687
688 // Check for bootp-responce or bsdp-responce.
689 bootplen = GetPropLen(gChosenPH, "bootp-response");
690 bsdplen = GetPropLen(gChosenPH, "bsdp-response");
691 if ((bootplen > 0) || (bsdplen > 0)) {
692 if (bootplen > 0) {
693 buffer = malloc(bootplen);
694 GetProp(gChosenPH, "bootp-response", buffer, bootplen);
695 } else {
696 buffer = malloc(bsdplen);
697 GetProp(gChosenPH, "bsdp-response", buffer, bsdplen);
698 }
699
700 // Flip the slash's to back slash's while looking for the last one.
701 cnt = cnt2 = kBootpBootFileOffset;
702 while (buffer[cnt] != '\0') {
703 if (buffer[cnt] == '/') {
704 buffer[cnt] = '\\';
705 cnt2 = cnt + 1;
706 }
707 cnt++;
708 }
709
710 // Add a comma at the front.
711 buffer[kBootpBootFileOffset - 1] = ',';
712
713 // Append the the root dir to the device spec.
714 strncat(gBootFile, buffer + kBootpBootFileOffset - 1,
715 cnt2 - kBootpBootFileOffset + 1);
716
717 free(buffer);
718 } else {
719 // Look for the start of the root dir path.
720 cnt3 = cnt;
721 while (gBootDevice[cnt3] != ',') cnt3++;
722
723 // Find the end of the path. Look for a comma or null.
724 cnt2 = cnt3 + 1;
725 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt2] != ',')) cnt2++;
726
727 // Find the last back slash or comma in the path
728 cnt4 = cnt2 - 1;
729 while ((gBootDevice[cnt4] != ',') && (gBootDevice[cnt4] != '\\')) cnt4--;
730
731 // Copy the IP addresses if needed.
732 if (gOFVersion < kOFVersion3x) {
733 strncat(gBootFile, gBootDevice + cnt + 1, cnt3 - cnt - 1);
734 }
735
736 // Add on the directory path
737 strncat(gBootFile, gBootDevice + cnt3, cnt4 - cnt3 + 1);
738 }
739
740 // Add on the kernel name
741 strcat(gBootFile, "mach.macosx");
742
743 // Add on postfix
744 strcat(gBootFile, gBootDevice + cnt2);
745 break;
746
747 case kBlockDeviceType :
748 // Find the first ':'.
749 cnt = 0;
750 while ((gBootDevice[cnt] != '\0') && (gBootDevice[cnt] != ':')) cnt++;
751 if (gBootDevice[cnt] == '\0') return -1;
752
753 // Find the comma after the ':'.
754 cnt2 = cnt + 1;
755 while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt] != ',')) cnt2++;
756
757 // Get just the partition number
758 strncpy(gBootFile, gBootDevice + cnt + 1, cnt2 - cnt - 1);
759 partNum = atoi(gBootFile);
760
761 // Adjust the partition number.
762 // Pass 0 & 1, no offset. Pass 2 & 3, offset 1, Pass 4 & 5, offset 2.
763 partNum += gBootSourceNumber / 2;
764
765 // Construct the boot-file
766 strncpy(gBootFile, gBootDevice, cnt + 1);
767 sprintf(gBootFile + cnt + 1, "%d,%s\\mach_kernel",
768 partNum, ((gBootSourceNumber & 1) ? "" : "\\"));
769 break;
770
771 default:
772 printf("Failed to infer Boot Device Type.\n");
773 return -1;
774 break;
775 }
776 }
777
778 // Figure out the root dir.
779 ret = ConvertFileSpec(gBootFile, gRootDir, &filePath);
780 if (ret == -1) return -1;
781
782 strcat(gRootDir, ",");
783
784 // Add in any extra path to gRootDir.
785 cnt = 0;
786 while (filePath[cnt] != '\0') cnt++;
787
788 if (cnt != 0) {
789 for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) {
790 if (filePath[cnt2] == '\\') {
791 strncat(gRootDir, filePath, cnt2 + 1);
792 break;
793 }
794 }
795 }
796
797 SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1);
798
799 gBootSourceNumber++;
800
801 return 0;
802 }
803
804 // Public Functions
805
806 long GetDeviceType(char *devSpec)
807 {
808 CICell ph;
809 long size;
810 char deviceType[32];
811
812 ph = FindDevice(devSpec);
813 if (ph == -1) return -1;
814
815 size = GetProp(ph, "device_type", deviceType, 31);
816 if (size != -1) deviceType[size] = '\0';
817 else deviceType[0] = '\0';
818
819 if (strcmp(deviceType, "network") == 0) return kNetworkDeviceType;
820 if (strcmp(deviceType, "block") == 0) return kBlockDeviceType;
821
822 return kUnknownDeviceType;
823 }
824
825
826 long ConvertFileSpec(char *fileSpec, char *devSpec, char **filePath)
827 {
828 long cnt;
829
830 // Find the first ':' in the fileSpec.
831 cnt = 0;
832 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ':')) cnt++;
833 if (fileSpec[cnt] == '\0') return -1;
834
835 // Find the next ',' in the fileSpec.
836 while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ',')) cnt++;
837
838 // Copy the string to devSpec.
839 strncpy(devSpec, fileSpec, cnt);
840 devSpec[cnt] = '\0';
841
842 // If there is a filePath start it after the ',', otherwise NULL.
843 if (filePath != NULL) {
844 if (fileSpec[cnt] != '\0') {
845 *filePath = fileSpec + cnt + 1;
846 } else {
847 *filePath = NULL;
848 }
849 }
850
851 return 0;
852 }
853
854
855 long MatchThis(CICell phandle, char *string)
856 {
857 long ret, length;
858 char *name, *model, *compatible;
859
860 ret = GetPackageProperty(phandle, "name", &name, &length);
861 if ((ret == -1) || (length == 0)) name = NULL;
862
863 ret = GetPackageProperty(phandle, "model", &model, &length);
864 if ((ret == -1) || (length == 0)) model = NULL;
865
866 ret = GetPackageProperty(phandle, "compatible", &compatible, &length);
867 if ((ret == -1) || (length == 0)) model = NULL;
868
869 if ((name != NULL) && strcmp(name, string) == 0) return 0;
870 if ((model != NULL) && strcmp(model, string) == 0) return 0;
871
872 if (compatible != NULL) {
873 while (*compatible != '\0') {
874 if (strcmp(compatible, string) == 0) return 0;
875
876 compatible += strlen(compatible) + 1;
877 }
878 }
879
880 return -1;
881 }
882
883
884 void *AllocateBootXMemory(long size)
885 {
886 long addr = gImageFirstBootXAddr - size;
887
888 if (addr < gImageLastKernelAddr) return 0;
889
890 gImageFirstBootXAddr = addr;
891
892 return (void *)addr;
893 }
894
895
896 long AllocateKernelMemory(long size)
897 {
898 long addr = gImageLastKernelAddr;
899
900 gImageLastKernelAddr += (size + 0xFFF) & ~0xFFF;
901
902 if (gImageLastKernelAddr > gImageFirstBootXAddr)
903 FailToBoot(-1);
904
905 return addr;
906 }
907
908
909 long AllocateMemoryRange(char *rangeName, long start, long length)
910 {
911 long result, *buffer;
912
913 buffer = AllocateBootXMemory(2 * sizeof(long));
914 if (buffer == 0) return -1;
915
916 buffer[0] = start;
917 buffer[1] = length;
918
919 result = SetProp(gMemoryMapPH, rangeName, (char *)buffer, 2 * sizeof(long));
920 if (result == -1) return -1;
921
922 return 0;
923 }
924
925
926 unsigned long Alder32(unsigned char *buffer, long length)
927 {
928 long cnt;
929 unsigned long result, lowHalf, highHalf;
930
931 lowHalf = 1;
932 highHalf = 0;
933
934 for (cnt = 0; cnt < length; cnt++) {
935 if ((cnt % 5000) == 0) {
936 lowHalf %= 65521L;
937 highHalf %= 65521L;
938 }
939
940 lowHalf += buffer[cnt];
941 highHalf += lowHalf;
942 }
943
944 lowHalf %= 65521L;
945 highHalf %= 65521L;
946
947 result = (highHalf << 16) | lowHalf;
948
949 return result;
950 }