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