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