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