]>
Commit | Line | Data |
---|---|---|
04fee52e A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
8be739c0 A |
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. | |
04fee52e | 11 | * |
8be739c0 A |
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 | |
04fee52e A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
8be739c0 A |
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. | |
04fee52e A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * main.c - Main functions for BootX. | |
24 | * | |
8be739c0 | 25 | * Copyright (c) 1998-2004 Apple Computer, Inc. |
04fee52e A |
26 | * |
27 | * DRI: Josh de Cesare | |
28 | */ | |
29 | ||
30 | ||
31 | #include <sl.h> | |
8be739c0 | 32 | #include "aes.h" |
04fee52e A |
33 | |
34 | static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr); | |
35 | static void Main(ClientInterfacePtr ciPtr); | |
36 | static long InitEverything(ClientInterfacePtr ciPtr); | |
8be739c0 | 37 | static long DecodeKernel(void *binary); |
04fee52e A |
38 | static long SetUpBootArgs(void); |
39 | static long CallKernel(void); | |
40 | static void FailToBoot(long num); | |
41 | static long InitMemoryMap(void); | |
42 | static long GetOFVersion(void); | |
43 | static long TestForKey(long key); | |
44 | static long GetBootPaths(void); | |
8be739c0 | 45 | static long ReadBootPlist(char *devSpec); |
04fee52e A |
46 | |
47 | const unsigned long StartTVector[2] = {(unsigned long)Start, 0}; | |
48 | ||
49 | char gStackBaseAddr[0x8000]; | |
50 | ||
51 | char *gVectorSaveAddr; | |
52 | long gImageLastKernelAddr = 0; | |
53 | long gImageFirstBootXAddr = kLoadAddr; | |
54 | long gKernelEntryPoint; | |
55 | long gDeviceTreeAddr; | |
56 | long gDeviceTreeSize; | |
57 | long gBootArgsAddr; | |
58 | long gBootArgsSize; | |
59 | long gSymbolTableAddr; | |
60 | long gSymbolTableSize; | |
61 | ||
62 | long gBootSourceNumber = -1; | |
63 | long gBootSourceNumberMax; | |
366defd1 | 64 | long gBootMode = kBootModeNormal; |
04fee52e A |
65 | long gBootDeviceType; |
66 | long gBootFileType; | |
b1faa321 | 67 | char gHaveKernelCache = 0; |
04fee52e A |
68 | char gBootDevice[256]; |
69 | char gBootFile[256]; | |
8be739c0 | 70 | TagPtr gBootDict = NULL; |
b1faa321 A |
71 | static char gBootKernelCacheFile[512]; |
72 | static char gExtensionsSpec[4096]; | |
73 | static char gCacheNameAdler[64 + sizeof(gBootFile)]; | |
74 | static char *gPlatformName = gCacheNameAdler; | |
04fee52e A |
75 | |
76 | char gTempStr[4096]; | |
77 | ||
78 | long *gDeviceTreeMMTmp = 0; | |
79 | ||
8be739c0 | 80 | long gOFVersion = 0; |
04fee52e A |
81 | |
82 | char *gKeyMap; | |
83 | ||
71019aa0 A |
84 | long gRootAddrCells; |
85 | long gRootSizeCells; | |
86 | ||
04fee52e A |
87 | CICell gChosenPH; |
88 | CICell gOptionsPH; | |
89 | CICell gScreenPH; | |
90 | CICell gMemoryMapPH; | |
91 | CICell gStdOutPH; | |
92 | ||
93 | CICell gMMUIH; | |
94 | CICell gMemoryIH; | |
95 | CICell gStdOutIH; | |
96 | CICell gKeyboardIH; | |
97 | ||
71019aa0 A |
98 | static char gOFVectorSave[kVectorSize]; |
99 | static unsigned long gOFMSRSave; | |
100 | static unsigned long gOFSPRG0Save; | |
101 | static unsigned long gOFSPRG1Save; | |
102 | static unsigned long gOFSPRG2Save; | |
103 | static unsigned long gOFSPRG3Save; | |
104 | ||
8be739c0 A |
105 | //int gDebugCount = 0; |
106 | ||
04fee52e A |
107 | // Private Functions |
108 | ||
109 | static void Start(void *unused1, void *unused2, ClientInterfacePtr ciPtr) | |
110 | { | |
111 | long newSP; | |
112 | ||
113 | // Move the Stack to a chunk of the BSS | |
114 | newSP = (long)gStackBaseAddr + sizeof(gStackBaseAddr) - 0x100; | |
115 | __asm__ volatile("mr r1, %0" : : "r" (newSP)); | |
116 | ||
117 | Main(ciPtr); | |
118 | } | |
119 | ||
120 | ||
8be739c0 | 121 | |
04fee52e A |
122 | static void Main(ClientInterfacePtr ciPtr) |
123 | { | |
124 | long ret; | |
b1faa321 | 125 | int trycache; |
8be739c0 A |
126 | long flags, cachetime, kerneltime, exttime = 0; |
127 | void *binary = (void *)kLoadAddr; | |
04fee52e A |
128 | |
129 | ret = InitEverything(ciPtr); | |
130 | if (ret != 0) Exit(); | |
8be739c0 A |
131 | |
132 | ||
04fee52e A |
133 | // Get or infer the boot paths. |
134 | ret = GetBootPaths(); | |
135 | if (ret != 0) FailToBoot(1); | |
136 | ||
8be739c0 | 137 | #if kFailToBoot |
366defd1 | 138 | DrawSplashScreen(0); |
8be739c0 | 139 | #endif |
04fee52e A |
140 | |
141 | while (ret == 0) { | |
b1faa321 A |
142 | trycache = (0 == (gBootMode & kBootModeSafe)) |
143 | && (gBootKernelCacheFile[0] != 0); | |
144 | ||
145 | if (trycache && (gBootFileType == kBlockDeviceType)) do { | |
146 | ||
147 | // if we haven't found the kernel yet, don't use the cache | |
8be739c0 | 148 | ret = GetFileInfo(NULL, gBootFile, &flags, &kerneltime); |
b1faa321 A |
149 | if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) { |
150 | trycache = 0; | |
151 | break; | |
152 | } | |
153 | ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime); | |
154 | if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat) | |
8be739c0 | 155 | || (cachetime < kerneltime)) { |
b1faa321 A |
156 | trycache = 0; |
157 | break; | |
158 | } | |
8be739c0 | 159 | ret = GetFileInfo(gExtensionsSpec, "Extensions", &flags, &exttime); |
b1faa321 | 160 | if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory) |
8be739c0 A |
161 | && (cachetime < exttime)) { |
162 | trycache = 0; | |
163 | break; | |
164 | } | |
165 | if (kerneltime > exttime) | |
166 | exttime = kerneltime; | |
167 | if (cachetime != (exttime + 1)) { | |
b1faa321 A |
168 | trycache = 0; |
169 | break; | |
170 | } | |
171 | } while (0); | |
172 | ||
173 | if (trycache) { | |
174 | ret = LoadFile(gBootKernelCacheFile); | |
175 | if (ret != -1) { | |
8be739c0 | 176 | ret = DecodeKernel(binary); |
b1faa321 A |
177 | if (ret != -1) break; |
178 | } | |
179 | } | |
8be739c0 A |
180 | ret = LoadThinFatFile(gBootFile, &binary); |
181 | if (ret != -1) ret = DecodeKernel(binary); | |
04fee52e A |
182 | if (ret != -1) break; |
183 | ||
184 | ret = GetBootPaths(); | |
185 | if (ret != 0) FailToBoot(2); | |
186 | } | |
187 | ||
366defd1 | 188 | if (ret != 0) FailToBoot(3); |
04fee52e | 189 | |
b1faa321 A |
190 | if (!gHaveKernelCache) { |
191 | ret = LoadDrivers(gExtensionsSpec); | |
192 | if (ret != 0) FailToBoot(4); | |
193 | } | |
366defd1 | 194 | |
8be739c0 | 195 | #if kFailToBoot |
366defd1 | 196 | DrawSplashScreen(1); |
8be739c0 | 197 | #endif |
366defd1 | 198 | |
04fee52e | 199 | ret = SetUpBootArgs(); |
366defd1 | 200 | if (ret != 0) FailToBoot(5); |
04fee52e A |
201 | |
202 | ret = CallKernel(); | |
203 | ||
366defd1 | 204 | FailToBoot(6); |
04fee52e A |
205 | } |
206 | ||
8be739c0 A |
207 | static uint32_t UnescapeData(const uint8_t * src, |
208 | uint32_t srcLen, | |
209 | uint8_t * dst, | |
210 | uint32_t dstMaxLen) | |
211 | { | |
212 | uint32_t cnt, cnt2, dstLen = 0; | |
213 | uint8_t byte; | |
214 | ||
215 | for (cnt = 0; cnt < srcLen;) { | |
216 | byte = src[cnt++]; | |
217 | if (byte == 0xFF) { | |
218 | byte = src[cnt++]; | |
219 | cnt2 = byte & 0x7F; | |
220 | byte = (byte & 0x80) ? 0xFF : 0x00; | |
221 | } else | |
222 | cnt2 = 1; | |
223 | while (cnt2--) { | |
224 | if (dstLen >= dstMaxLen) | |
225 | return (-1); | |
226 | dst[dstLen++] = byte; | |
227 | } | |
228 | } | |
229 | return (dstLen); | |
230 | } | |
04fee52e A |
231 | |
232 | static long InitEverything(ClientInterfacePtr ciPtr) | |
233 | { | |
366defd1 | 234 | long ret, mem_base, mem_base2, size; |
04fee52e | 235 | CICell keyboardPH; |
366defd1 | 236 | char name[32], securityMode[33]; |
b1faa321 A |
237 | long length; |
238 | char *compatible; | |
04fee52e A |
239 | |
240 | // Init the OF Client Interface. | |
241 | ret = InitCI(ciPtr); | |
242 | if (ret != 0) return -1; | |
243 | ||
244 | // Get the OF Version | |
245 | gOFVersion = GetOFVersion(); | |
246 | if (gOFVersion == 0) return -1; | |
247 | ||
71019aa0 A |
248 | // Get the address and size cells for the root. |
249 | GetProp(Peer(0), "#address-cells", (char *)&gRootAddrCells, 4); | |
250 | GetProp(Peer(0), "#size-cells", (char *)&gRootSizeCells, 4); | |
251 | if ((gRootAddrCells > 2) || (gRootAddrCells > 2)) return -1; | |
252 | ||
04fee52e | 253 | // Init the SL Words package. |
366defd1 | 254 | ret = InitSLWords(); |
04fee52e A |
255 | if (ret != 0) return -1; |
256 | ||
257 | // Get the phandle for /options | |
258 | gOptionsPH = FindDevice("/options"); | |
259 | if (gOptionsPH == -1) return -1; | |
260 | ||
261 | // Get the phandle for /chosen | |
262 | gChosenPH = FindDevice("/chosen"); | |
263 | if (gChosenPH == -1) return -1; | |
264 | ||
265 | // Init the Memory Map. | |
266 | ret = InitMemoryMap(); | |
267 | if (ret != 0) return -1; | |
268 | ||
269 | // Get IHandles for the MMU and Memory | |
270 | size = GetProp(gChosenPH, "mmu", (char *)&gMMUIH, 4); | |
271 | if (size != 4) { | |
272 | printf("Failed to get the IH for the MMU.\n"); | |
273 | return -1; | |
274 | } | |
275 | size = GetProp(gChosenPH, "memory", (char *)&gMemoryIH, 4); | |
276 | if (size != 4) { | |
277 | printf("Failed to get the IH for the Memory.\n"); | |
278 | return -1; | |
279 | } | |
280 | ||
b1faa321 A |
281 | // Get first element of root's compatible property. |
282 | ret = GetPackageProperty(Peer(0), "compatible", &compatible, &length); | |
283 | if (ret != -1) | |
284 | strcpy(gPlatformName, compatible); | |
285 | ||
04fee52e A |
286 | // Get stdout's IH, so that the boot display can be found. |
287 | ret = GetProp(gChosenPH, "stdout", (char *)&gStdOutIH, 4); | |
288 | if (ret == 4) gStdOutPH = InstanceToPackage(gStdOutIH); | |
289 | else gStdOutPH = gStdOutIH = 0; | |
290 | ||
291 | // Try to find the keyboard using chosen | |
292 | ret = GetProp(gChosenPH, "stdin", (char *)&gKeyboardIH, 4); | |
293 | if (ret != 4) gKeyboardIH = 0; | |
294 | else { | |
295 | keyboardPH = InstanceToPackage(gKeyboardIH); | |
296 | ret = GetProp(keyboardPH, "name", name, 31); | |
297 | if (ret != -1) { | |
298 | name[ret] = '\0'; | |
299 | if (strcmp(name, "keyboard") && strcmp(name, "kbd")) gKeyboardIH = 0; | |
300 | } else gKeyboardIH = 0; | |
301 | } | |
302 | ||
303 | // Try to the find the keyboard using open if chosen did not work. | |
304 | if (gKeyboardIH == 0) gKeyboardIH = Open("keyboard"); | |
305 | if (gKeyboardIH == 0) gKeyboardIH = Open("kbd"); | |
306 | ||
307 | // Get the key map set up, and make it up to date. | |
308 | gKeyMap = InitKeyMap(gKeyboardIH); | |
309 | if (gKeyMap == NULL) return -1; | |
310 | UpdateKeyMap(); | |
311 | ||
366defd1 A |
312 | // Test for Secure Boot Mode. |
313 | size = GetProp(gOptionsPH, "security-mode", securityMode, 32); | |
314 | if (size != -1) { | |
315 | securityMode[size] = '\0'; | |
316 | if (strcmp(securityMode, "none")) gBootMode |= kBootModeSecure; | |
04fee52e | 317 | } |
04fee52e A |
318 | |
319 | #if kFailToBoot | |
320 | // 'cmd-s' or 'cmd-v' is pressed set outputLevel to kOutputLevelFull | |
366defd1 A |
321 | if (((gBootMode & kBootModeSecure) == 0) && TestForKey(kCommandKey) && |
322 | (TestForKey('s') || TestForKey('v'))) { | |
04fee52e | 323 | SetOutputLevel(kOutputLevelFull); |
366defd1 A |
324 | } else { |
325 | SetOutputLevel(kOutputLevelOff); | |
326 | } | |
04fee52e A |
327 | #else |
328 | SetOutputLevel(kOutputLevelFull); | |
329 | #endif | |
330 | ||
331 | // printf now works. | |
332 | printf("\n\nMac OS X Loader\n"); | |
333 | ||
8be739c0 A |
334 | // Test for Safe Boot Mode; Shift and not Delete. |
335 | if (((gBootMode & kBootModeSecure) == 0) | |
336 | && TestForKey(kShiftKey) && !TestForKey(kDeleteKey)) { | |
366defd1 A |
337 | gBootMode |= kBootModeSafe; |
338 | } | |
8be739c0 A |
339 | |
340 | { | |
341 | // Claim memory for the FS Cache. | |
342 | if (Claim(kFSCacheAddr, kFSCacheSize, 0) == 0) { | |
343 | printf("Claim for fs cache failed.\n"); | |
04fee52e A |
344 | return -1; |
345 | } | |
8be739c0 A |
346 | |
347 | // Claim memory for malloc. | |
348 | if (Claim(kMallocAddr, kMallocSize, 0) == 0) { | |
349 | printf("Claim for malloc failed.\n"); | |
04fee52e A |
350 | return -1; |
351 | } | |
8be739c0 | 352 | malloc_init((char *)kMallocAddr, kMallocSize); |
04fee52e | 353 | |
8be739c0 A |
354 | // Claim memory for the Load Addr. |
355 | mem_base = Claim(kLoadAddr, kLoadSize, 0); | |
356 | if (mem_base == 0) { | |
357 | printf("Claim for Load Area failed.\n"); | |
04fee52e A |
358 | return -1; |
359 | } | |
360 | ||
8be739c0 A |
361 | // Claim the memory for the Image Addr |
362 | if (gOFVersion >= kOFVersion3x) { | |
363 | mem_base = Claim(kImageAddr, kImageSize, 0); | |
364 | if (mem_base == 0) { | |
365 | printf("Claim for Image Area failed.\n"); | |
366 | return -1; | |
367 | } | |
368 | } else { | |
369 | // Claim the 1:1 mapped chunks first. | |
370 | mem_base = Claim(kImageAddr0, kImageSize0, 0); | |
371 | mem_base2 = Claim(kImageAddr2, kImageSize2, 0); | |
372 | if ((mem_base == 0) || (mem_base2 == 0)) { | |
373 | printf("Claim for Image Area failed.\n"); | |
374 | return -1; | |
375 | } | |
376 | ||
377 | // Unmap the old xcoff stack. | |
378 | CallMethod(2, 0, gMMUIH, "unmap", 0x00380000, 0x00080000); | |
379 | ||
380 | // Grab the physical memory then the logical. | |
381 | CallMethod(3, 1, gMemoryIH, "claim", | |
382 | kImageAddr1Phys, kImageSize1, 0, &mem_base); | |
383 | CallMethod(3, 1, gMMUIH, "claim", | |
384 | kImageAddr1, kImageSize1, 0, &mem_base2); | |
385 | if ((mem_base == 0) || (mem_base2 == 0)) { | |
386 | printf("Claim for Image Area failed.\n"); | |
387 | return -1; | |
388 | } | |
389 | ||
390 | // Map them together. | |
391 | CallMethod(4, 0, gMMUIH, "map", | |
392 | kImageAddr1Phys, kImageAddr1, kImageSize1, 0); | |
393 | } | |
394 | ||
395 | bzero((char *)kImageAddr, kImageSize); | |
396 | ||
397 | // Allocate some space for the Vector Save area. | |
398 | gVectorSaveAddr = AllocateBootXMemory(kVectorSize); | |
399 | if (gVectorSaveAddr == 0) { | |
400 | printf("Allocation for the Vector Save Area failed.\n"); | |
401 | return -1; | |
402 | } | |
403 | // Find all the displays and set them up. | |
404 | ret = InitDisplays(1); | |
405 | if (ret != 0) { | |
406 | printf("InitDisplays failed.\n"); | |
407 | return -1; | |
408 | } | |
409 | } | |
04fee52e A |
410 | |
411 | return 0; | |
412 | } | |
413 | ||
414 | ||
71019aa0 A |
415 | long ThinFatBinary(void **binary, unsigned long *length) |
416 | { | |
417 | long ret; | |
418 | ||
419 | ret = ThinFatBinaryMachO(binary, length); | |
420 | if (ret == -1) ret = ThinFatBinaryElf(binary, length); | |
421 | ||
422 | return ret; | |
423 | } | |
424 | ||
8be739c0 | 425 | static long DecodeKernel(void *binary) |
04fee52e A |
426 | { |
427 | long ret; | |
8be739c0 | 428 | compressed_kernel_header *kernel_header = (compressed_kernel_header *)binary; |
b1faa321 A |
429 | u_int32_t size; |
430 | ||
431 | if (kernel_header->signature == 'comp') { | |
432 | if (kernel_header->compress_type != 'lzss') | |
433 | return -1; | |
434 | if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name)) | |
435 | return -1; | |
436 | if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path)) | |
437 | return -1; | |
438 | ||
439 | binary = AllocateBootXMemory(kernel_header->uncompressed_size); | |
440 | ||
441 | size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0], kernel_header->compressed_size); | |
442 | if (kernel_header->uncompressed_size != size) { | |
443 | printf("size mismatch from lzss %x\n", size); | |
444 | return -1; | |
445 | } | |
446 | if (kernel_header->adler32 != | |
8be739c0 | 447 | Adler32(binary, kernel_header->uncompressed_size)) { |
b1faa321 A |
448 | printf("adler mismatch\n"); |
449 | return -1; | |
450 | } | |
451 | } | |
04fee52e | 452 | |
71019aa0 A |
453 | ThinFatBinary(&binary, 0); |
454 | ||
455 | ret = DecodeMachO(binary); | |
456 | if (ret == -1) ret = DecodeElf(binary); | |
04fee52e A |
457 | |
458 | return ret; | |
459 | } | |
460 | ||
461 | ||
462 | static long SetUpBootArgs(void) | |
463 | { | |
71019aa0 A |
464 | boot_args_ptr args; |
465 | CICell memoryPH; | |
466 | long graphicsBoot = 1; | |
467 | long ret, cnt, size, dash; | |
468 | long sKey, vKey, keyPos; | |
8be739c0 | 469 | char ofBootArgs[240], *ofArgs, tc, keyStr[8]; |
71019aa0 A |
470 | unsigned char mem_regs[kMaxDRAMBanks*16]; |
471 | unsigned long mem_banks, bank_shift; | |
04fee52e A |
472 | |
473 | // Save file system cache statistics. | |
474 | SetProp(gChosenPH, "BootXCacheHits", (char *)&gCacheHits, 4); | |
475 | SetProp(gChosenPH, "BootXCacheMisses", (char *)&gCacheMisses, 4); | |
476 | SetProp(gChosenPH, "BootXCacheEvicts", (char *)&gCacheEvicts, 4); | |
477 | ||
478 | // Allocate some memory for the BootArgs. | |
479 | gBootArgsSize = sizeof(boot_args); | |
480 | gBootArgsAddr = AllocateKernelMemory(gBootArgsSize); | |
481 | ||
482 | // Add the BootArgs to the memory-map. | |
483 | AllocateMemoryRange("BootArgs", gBootArgsAddr, gBootArgsSize); | |
484 | ||
485 | args = (boot_args_ptr)gBootArgsAddr; | |
486 | ||
487 | args->Revision = kBootArgsRevision; | |
71019aa0 | 488 | args->Version = kBootArgsVersion1; |
04fee52e A |
489 | args->machineType = 0; |
490 | ||
366defd1 | 491 | // Check the Keyboard for 'cmd-s' and 'cmd-v' |
04fee52e | 492 | UpdateKeyMap(); |
366defd1 | 493 | if ((gBootMode & kBootModeSecure) == 0) { |
04fee52e A |
494 | sKey = TestForKey(kCommandKey) && TestForKey('s'); |
495 | vKey = TestForKey(kCommandKey) && TestForKey('v'); | |
04fee52e | 496 | } else { |
04fee52e A |
497 | sKey = 0; |
498 | vKey = 0; | |
04fee52e | 499 | } |
04fee52e A |
500 | |
501 | // if 'cmd-s' or 'cmd-v' was pressed do a text boot. | |
502 | if (sKey || vKey) graphicsBoot = 0; | |
503 | ||
04fee52e A |
504 | // Create the command line. |
505 | if (gOFVersion < kOFVersion3x) { | |
506 | ofBootArgs[0] = ' '; | |
8be739c0 | 507 | size = GetProp(gChosenPH, "machargs", ofBootArgs + 1, (sizeof(ofBootArgs) - 2)); |
04fee52e | 508 | if (size == -1) { |
8be739c0 | 509 | size = GetProp(gOptionsPH, "boot-command", ofBootArgs, (sizeof(ofBootArgs) - 1)); |
04fee52e A |
510 | if (size == -1) ofBootArgs[0] = '\0'; |
511 | else ofBootArgs[size] = '\0'; | |
512 | // Look for " bootr" but skip the number. | |
513 | if (!strncmp(ofBootArgs + 1, " bootr", 6)) { | |
514 | strcpy(ofBootArgs, ofBootArgs + 7); | |
515 | } else ofBootArgs[0] = '\0'; | |
516 | SetProp(gChosenPH, "machargs", ofBootArgs, strlen(ofBootArgs) + 1); | |
517 | } else ofBootArgs[size] = '\0'; | |
518 | // Force boot-command to start with 0 bootr. | |
519 | sprintf(gTempStr, "0 bootr%s", ofBootArgs); | |
520 | SetProp(gOptionsPH, "boot-command", gTempStr, strlen(gTempStr)); | |
521 | } else { | |
8be739c0 | 522 | size = GetProp(gOptionsPH, "boot-args", ofBootArgs, (sizeof(ofBootArgs) - 1)); |
04fee52e A |
523 | if (size == -1) ofBootArgs[0] = '\0'; |
524 | else ofBootArgs[size] = '\0'; | |
525 | } | |
526 | ||
527 | if (ofBootArgs[0] != '\0') { | |
528 | // Look for special options and copy the rest. | |
529 | dash = 0; | |
530 | ofArgs = ofBootArgs; | |
531 | while ((tc = *ofArgs) != '\0') { | |
532 | tc = tolower(tc); | |
533 | ||
534 | // Check for entering a dash arg. | |
535 | if (tc == '-') { | |
536 | dash = 1; | |
537 | ofArgs++; | |
538 | continue; | |
539 | } | |
540 | ||
541 | // Do special stuff if in a dash arg. | |
542 | if (dash) { | |
366defd1 | 543 | if (tc == 's') { |
04fee52e A |
544 | graphicsBoot = 0; |
545 | ofArgs++; | |
546 | sKey = 0; | |
366defd1 | 547 | } else if (tc == 'v') { |
04fee52e A |
548 | graphicsBoot = 0; |
549 | ofArgs++; | |
550 | vKey = 0; | |
366defd1 | 551 | } else { |
04fee52e A |
552 | // Check for exiting dash arg |
553 | if (isspace(tc)) dash = 0; | |
554 | ||
366defd1 | 555 | // Copy any non 's' or 'v' |
04fee52e A |
556 | ofArgs++; |
557 | } | |
558 | } else { | |
559 | // Not a dash arg so just copy it. | |
560 | ofArgs++; | |
366defd1 | 561 | } |
04fee52e A |
562 | } |
563 | } | |
564 | ||
366defd1 | 565 | // Add any pressed keys (s, v, shift) to the command line |
04fee52e | 566 | keyPos = 0; |
366defd1 | 567 | if (sKey || vKey || (gBootMode & kBootModeSafe)) { |
04fee52e A |
568 | keyStr[keyPos++] = '-'; |
569 | ||
04fee52e A |
570 | if (sKey) keyStr[keyPos++] = 's'; |
571 | if (vKey) keyStr[keyPos++] = 'v'; | |
366defd1 | 572 | if (gBootMode & kBootModeSafe) keyStr[keyPos++] = 'x'; |
04fee52e A |
573 | |
574 | keyStr[keyPos++] = ' '; | |
575 | } | |
576 | keyStr[keyPos++] = '\0'; | |
577 | ||
366defd1 | 578 | sprintf(args->CommandLine, "%s%s", keyStr, ofBootArgs); |
04fee52e | 579 | |
71019aa0 A |
580 | // If the address or size cells are larger than 1, use page numbers |
581 | // and signify Boot Args Version 2. | |
582 | if ((gRootAddrCells == 1) && (gRootSizeCells == 1)) bank_shift = 0; | |
583 | else { | |
584 | bank_shift = 12; | |
585 | args->Version = kBootArgsVersion2; | |
586 | } | |
587 | ||
588 | // Get the information about the memory banks | |
04fee52e A |
589 | memoryPH = FindDevice("/memory"); |
590 | if (memoryPH == -1) return -1; | |
71019aa0 | 591 | size = GetProp(memoryPH, "reg", mem_regs, kMaxDRAMBanks * 16); |
04fee52e | 592 | if (size == 0) return -1; |
71019aa0 A |
593 | mem_banks = size / (4 * (gRootAddrCells + gRootSizeCells)); |
594 | if (mem_banks > kMaxDRAMBanks) mem_banks = kMaxDRAMBanks; | |
595 | ||
596 | // Convert the reg properties to 32 bit values | |
597 | for (cnt = 0; cnt < mem_banks; cnt++) { | |
598 | if (gRootAddrCells == 1) { | |
599 | args->PhysicalDRAM[cnt].base = | |
600 | *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift; | |
601 | } else { | |
602 | args->PhysicalDRAM[cnt].base = | |
603 | *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells)) >> bank_shift; | |
604 | ||
605 | } | |
606 | ||
607 | if (gRootSizeCells == 1) { | |
608 | args->PhysicalDRAM[cnt].size = | |
609 | *(unsigned long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift; | |
610 | } else { | |
611 | args->PhysicalDRAM[cnt].size = | |
612 | *(unsigned long long *)(mem_regs + cnt * 4 * (gRootAddrCells + gRootSizeCells) + 4 * gRootAddrCells) >> bank_shift; | |
613 | ||
614 | } | |
615 | } | |
04fee52e | 616 | |
71019aa0 A |
617 | // Collapse the memory banks into contiguous chunks |
618 | for (cnt = 0; cnt < mem_banks - 1; cnt++) { | |
619 | if ((args->PhysicalDRAM[cnt + 1].base != 0) && | |
620 | ((args->PhysicalDRAM[cnt].base + args->PhysicalDRAM[cnt].size) != | |
621 | args->PhysicalDRAM[cnt + 1].base)) continue; | |
622 | ||
623 | args->PhysicalDRAM[cnt].size += args->PhysicalDRAM[cnt + 1].size; | |
624 | bcopy(args->PhysicalDRAM + cnt + 2, args->PhysicalDRAM + cnt + 1, (mem_banks - cnt - 2) * sizeof(DRAMBank)); | |
625 | mem_banks--; | |
626 | cnt--; | |
04fee52e | 627 | } |
71019aa0 | 628 | bzero(args->PhysicalDRAM + mem_banks, (kMaxDRAMBanks - mem_banks) * sizeof(DRAMBank)); |
04fee52e A |
629 | |
630 | // Get the video info | |
8be739c0 | 631 | GetMainScreenPH(&args->Video, 1); |
366defd1 | 632 | args->Video.v_display = graphicsBoot; |
04fee52e A |
633 | |
634 | // Add the DeviceTree to the memory-map. | |
635 | // The actuall address and size must be filled in later. | |
636 | AllocateMemoryRange("DeviceTree", 0, 0); | |
637 | ||
638 | ret = FlattenDeviceTree(); | |
639 | if (ret != 0) return -1; | |
640 | ||
641 | // Fill in the address and size of the device tree. | |
642 | if (gDeviceTreeAddr) { | |
643 | gDeviceTreeMMTmp[0] = gDeviceTreeAddr; | |
644 | gDeviceTreeMMTmp[1] = gDeviceTreeSize; | |
645 | } | |
646 | ||
647 | args->deviceTreeP = (void *)gDeviceTreeAddr; | |
648 | args->deviceTreeLength = gDeviceTreeSize; | |
649 | args->topOfKernelData = AllocateKernelMemory(0); | |
650 | ||
651 | return 0; | |
652 | } | |
653 | ||
654 | ||
655 | static long CallKernel(void) | |
656 | { | |
71019aa0 | 657 | unsigned long msr, cnt; |
04fee52e A |
658 | |
659 | Quiesce(); | |
660 | ||
661 | printf("\nCall Kernel!\n"); | |
662 | ||
71019aa0 A |
663 | // Save SPRs for OF |
664 | __asm__ volatile("mfmsr %0" : "=r" (gOFMSRSave)); | |
665 | __asm__ volatile("mfsprg %0, 0" : "=r" (gOFSPRG0Save)); | |
666 | __asm__ volatile("mfsprg %0, 1" : "=r" (gOFSPRG1Save)); | |
667 | __asm__ volatile("mfsprg %0, 2" : "=r" (gOFSPRG2Save)); | |
668 | __asm__ volatile("mfsprg %0, 3" : "=r" (gOFSPRG3Save)); | |
669 | ||
670 | // Turn off translations | |
04fee52e | 671 | msr = 0x00001000; |
71019aa0 | 672 | __asm__ volatile("sync"); |
04fee52e A |
673 | __asm__ volatile("mtmsr %0" : : "r" (msr)); |
674 | __asm__ volatile("isync"); | |
675 | ||
71019aa0 A |
676 | // Save the OF's Exceptions Vectors |
677 | bcopy(0x0, gOFVectorSave, kVectorSize); | |
678 | ||
679 | // Move the Exception Vectors | |
04fee52e A |
680 | bcopy(gVectorSaveAddr, 0x0, kVectorSize); |
681 | for (cnt = 0; cnt < kVectorSize; cnt += 0x20) { | |
682 | __asm__ volatile("dcbf 0, %0" : : "r" (cnt)); | |
683 | __asm__ volatile("icbi 0, %0" : : "r" (cnt)); | |
684 | } | |
685 | ||
686 | // Move the Image1 save area for OF 1.x / 2.x | |
687 | if (gOFVersion < kOFVersion3x) { | |
688 | bcopy((char *)kImageAddr1Phys, (char *)kImageAddr1, kImageSize1); | |
689 | for (cnt = kImageAddr1; cnt < kImageSize1; cnt += 0x20) { | |
690 | __asm__ volatile("dcbf 0, %0" : : "r" (cnt)); | |
691 | __asm__ volatile("icbi 0, %0" : : "r" (cnt)); | |
692 | } | |
693 | } | |
694 | ||
695 | // Make sure everything get sync'd up. | |
696 | __asm__ volatile("isync"); | |
697 | __asm__ volatile("sync"); | |
698 | __asm__ volatile("eieio"); | |
699 | ||
71019aa0 | 700 | // Call the Kernel's entry point |
04fee52e | 701 | (*(void (*)())gKernelEntryPoint)(gBootArgsAddr, kMacOSXSignature); |
8be739c0 | 702 | |
71019aa0 A |
703 | // Restore OF's Exception Vectors |
704 | bcopy(gOFVectorSave, 0x0, 0x3000); | |
705 | for (cnt = 0; cnt < kVectorSize; cnt += 0x20) { | |
706 | __asm__ volatile("dcbf 0, %0" : : "r" (cnt)); | |
707 | __asm__ volatile("icbi 0, %0" : : "r" (cnt)); | |
708 | } | |
709 | ||
710 | // Restore SPRs for OF | |
711 | __asm__ volatile("mtsprg 0, %0" : : "r" (gOFSPRG0Save)); | |
712 | __asm__ volatile("mtsprg 1, %0" : : "r" (gOFSPRG1Save)); | |
713 | __asm__ volatile("mtsprg 2, %0" : : "r" (gOFSPRG2Save)); | |
714 | __asm__ volatile("mtsprg 3, %0" : : "r" (gOFSPRG3Save)); | |
715 | ||
716 | // Restore translations | |
717 | __asm__ volatile("sync"); | |
718 | __asm__ volatile("mtmsr %0" : : "r" (gOFMSRSave)); | |
719 | __asm__ volatile("isync"); | |
720 | ||
04fee52e A |
721 | return -1; |
722 | } | |
723 | ||
724 | ||
725 | static void FailToBoot(long num) | |
726 | { | |
8be739c0 A |
727 | // useful for those holding down command-v ... |
728 | printf("FailToBoot: %d\n", num); | |
04fee52e | 729 | #if kFailToBoot |
366defd1 | 730 | DrawFailedBootPicture(); |
04fee52e A |
731 | while (1); |
732 | num = 0; | |
733 | #else | |
04fee52e A |
734 | Enter(); // For debugging |
735 | #endif | |
736 | } | |
737 | ||
738 | ||
739 | static long InitMemoryMap(void) | |
740 | { | |
741 | long result; | |
742 | ||
366defd1 A |
743 | result = Interpret(0, 1, |
744 | " dev /chosen" | |
745 | " new-device" | |
746 | " \" memory-map\" device-name" | |
747 | " active-package" | |
748 | " device-end" | |
749 | , &gMemoryMapPH); | |
04fee52e A |
750 | |
751 | return result; | |
752 | } | |
753 | ||
754 | ||
755 | static long GetOFVersion(void) | |
756 | { | |
757 | CICell ph; | |
758 | char versStr[256], *tmpStr; | |
759 | long vers, size; | |
760 | ||
761 | // Get the openprom package | |
762 | ph = FindDevice("/openprom"); | |
763 | if (ph == -1) return 0; | |
764 | ||
765 | // Get it's model property | |
766 | size = GetProp(ph, "model", versStr, 255); | |
767 | if (size == -1) return -1; | |
768 | versStr[size] = '\0'; | |
769 | ||
770 | // Find the start of the number. | |
771 | tmpStr = NULL; | |
772 | if (!strncmp(versStr, "Open Firmware, ", 15)) { | |
773 | tmpStr = versStr + 15; | |
774 | } else if (!strncmp(versStr, "OpenFirmware ", 13)) { | |
775 | tmpStr = versStr + 13; | |
8be739c0 | 776 | } else return -1; |
04fee52e A |
777 | |
778 | // Clasify by each instance as needed... | |
779 | switch (*tmpStr) { | |
780 | case '1' : | |
781 | vers = kOFVersion1x; | |
782 | break; | |
783 | ||
784 | case '2' : | |
785 | vers = kOFVersion2x; | |
786 | break; | |
787 | ||
788 | case '3' : | |
789 | vers = kOFVersion3x; | |
790 | break; | |
791 | ||
71019aa0 A |
792 | case '4' : |
793 | vers = kOFVersion4x; | |
794 | break; | |
795 | ||
04fee52e A |
796 | default : |
797 | vers = 0; | |
798 | break; | |
799 | } | |
800 | ||
801 | return vers; | |
802 | } | |
803 | ||
804 | ||
805 | static long TestForKey(long key) | |
806 | { | |
807 | long keyNum; | |
808 | long bp; | |
809 | char tc; | |
810 | ||
811 | if (gOFVersion < kOFVersion3x) { | |
812 | switch(key) { | |
813 | case 'a' : keyNum = 7; break; | |
814 | case 's' : keyNum = 6; break; | |
815 | case 'v' : keyNum = 14; break; | |
816 | case 'y' : keyNum = 23; break; | |
817 | case kCommandKey : keyNum = 48; break; | |
818 | case kOptKey : keyNum = 61; break; | |
819 | case kShiftKey : keyNum = 63; break; | |
820 | case kControlKey : keyNum = 49; break; | |
821 | default : keyNum = -1; break; | |
822 | } | |
823 | } else { | |
824 | switch(key) { | |
825 | case 'a' : keyNum = 3; break; | |
826 | case 's' : keyNum = 17; break; | |
827 | case 'v' : keyNum = 30; break; | |
828 | case 'y' : keyNum = 27; break; | |
829 | case kCommandKey : keyNum = 228; break; | |
830 | case kOptKey : keyNum = 229; break; | |
831 | case kShiftKey : keyNum = 230; break; | |
832 | case kControlKey : keyNum = 231; break; | |
8be739c0 | 833 | case kDeleteKey : keyNum = 45; break; |
04fee52e A |
834 | default : keyNum = -1; break; |
835 | } | |
836 | ||
837 | // Map the right modifier keys on to the left. | |
838 | gKeyMap[28] |= gKeyMap[28] << 4; | |
839 | } | |
840 | ||
841 | if (keyNum == -1) return 0; | |
842 | ||
843 | bp = keyNum & 7; | |
844 | tc = gKeyMap[keyNum >> 3]; | |
845 | ||
846 | return (tc & (1 << bp)) != 0; | |
847 | } | |
848 | ||
849 | ||
850 | #define kBootpBootFileOffset (108) | |
851 | ||
852 | static long GetBootPaths(void) | |
853 | { | |
854 | long ret, cnt, cnt2, cnt3, cnt4, size, partNum, bootplen, bsdplen; | |
b1faa321 | 855 | unsigned long adler32; |
8be739c0 | 856 | char *filePath, *buffer, uuidStr[64]; |
04fee52e A |
857 | |
858 | if (gBootSourceNumber == -1) { | |
8be739c0 A |
859 | // Get the boot device and derive its type |
860 | // (try chosen "bootpath", then boot-device in the options) | |
04fee52e A |
861 | size = GetProp(gChosenPH, "bootpath", gBootDevice, 255); |
862 | gBootDevice[size] = '\0'; | |
863 | if (gBootDevice[0] == '\0') { | |
864 | size = GetProp(gOptionsPH, "boot-device", gBootDevice, 255); | |
865 | gBootDevice[size] = '\0'; | |
866 | } | |
8be739c0 A |
867 | // hardcode to my Apple_Boot before my Apple_RAID |
868 | // debug: override boot device to boot from disk even if OF used TFTP | |
869 | //printf("old gBootDevice: %s\n", gBootDevice); | |
870 | //strcpy(gBootDevice, "fw/node@d0010100007a9d/sbp-2@c000/@0:12"); // SmartDisk | |
871 | //strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:9"); // mconcatI | |
872 | //strcpy(gBootDevice, "fw/node@d04b491d060252/sbp-2@c000/@0:11"); // mconcatI | |
873 | //strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:2"); // mconcatII | |
874 | //strcpy(gBootDevice, "fw/node@d04b491d075f57/sbp-2@c000/@0:4"); // mconcatII | |
875 | //strcpy(gBootDevice, "fw/node@50770e0000676f/sbp-2@4000/@0:3"); // m120 | |
876 | //strcpy(gBootDevice, "fw/node@50770e0000725b/sbp-2@4000/@0:3"); // m120 | |
877 | ||
878 | ||
879 | // Look for Boot.plist-based booter stuff (like RAID :) | |
880 | ret = ReadBootPlist(gBootDevice); | |
881 | if (ret == 0) { | |
882 | // success -> gBootDevice = "AppleRAID/#:0,\\\\:tbxi" | |
883 | (void)LookForRAID(gBootDict); // could take gBootDevice? | |
884 | } | |
04fee52e | 885 | |
8be739c0 A |
886 | |
887 | // note RAID itself is of "block" type like members | |
888 | gBootDeviceType = GetDeviceType(gBootDevice); | |
889 | if(gBootDeviceType == -1) { | |
890 | printf("Could not find boot device %s\n", gBootDevice); | |
891 | return -1; | |
892 | } | |
893 | ||
894 | ||
895 | // Get the boot file (e.g. mach_kernel) | |
04fee52e A |
896 | size = GetProp(gChosenPH, "bootargs", gBootFile, 256); |
897 | gBootFile[size] = '\0'; | |
898 | ||
899 | if (gBootFile[0] != '\0') { | |
900 | gBootFileType = GetDeviceType(gBootFile); | |
901 | gBootSourceNumberMax = 0; | |
902 | } else { | |
903 | gBootSourceNumber = 0; | |
904 | gBootFileType = gBootDeviceType; | |
905 | if (gBootFileType == kNetworkDeviceType) gBootSourceNumberMax = 1; | |
366defd1 A |
906 | else { |
907 | if (gOFVersion < kOFVersion3x) { | |
908 | gBootSourceNumberMax = 4; | |
909 | } else { | |
910 | gBootSourceNumberMax = 6; | |
911 | } | |
912 | } | |
04fee52e | 913 | } |
8be739c0 | 914 | // gBootSourceNumberMax = 2; // helpful to prevent lots of probing |
04fee52e A |
915 | |
916 | if (gBootFileType == kNetworkDeviceType) { | |
917 | SetProp(Peer(0), "net-boot", NULL, 0); | |
918 | } | |
919 | } | |
920 | ||
921 | if (gBootSourceNumber >= gBootSourceNumberMax) return -1; | |
922 | ||
923 | if (gBootSourceNumberMax != 0) { | |
924 | switch (gBootFileType) { | |
925 | case kNetworkDeviceType : | |
926 | // Find the end of the device spec. | |
927 | cnt = 0; | |
928 | while (gBootDevice[cnt] != ':') cnt++; | |
929 | ||
930 | // Copy the device spec with the ':'. | |
931 | strncpy(gBootFile, gBootDevice, cnt + 1); | |
932 | ||
933 | // Check for bootp-responce or bsdp-responce. | |
934 | bootplen = GetPropLen(gChosenPH, "bootp-response"); | |
935 | bsdplen = GetPropLen(gChosenPH, "bsdp-response"); | |
936 | if ((bootplen > 0) || (bsdplen > 0)) { | |
937 | if (bootplen > 0) { | |
938 | buffer = malloc(bootplen); | |
939 | GetProp(gChosenPH, "bootp-response", buffer, bootplen); | |
940 | } else { | |
941 | buffer = malloc(bsdplen); | |
942 | GetProp(gChosenPH, "bsdp-response", buffer, bsdplen); | |
943 | } | |
944 | ||
945 | // Flip the slash's to back slash's while looking for the last one. | |
946 | cnt = cnt2 = kBootpBootFileOffset; | |
947 | while (buffer[cnt] != '\0') { | |
948 | if (buffer[cnt] == '/') { | |
949 | buffer[cnt] = '\\'; | |
950 | cnt2 = cnt + 1; | |
951 | } | |
952 | cnt++; | |
953 | } | |
954 | ||
955 | // Add a comma at the front. | |
956 | buffer[kBootpBootFileOffset - 1] = ','; | |
957 | ||
958 | // Append the the root dir to the device spec. | |
959 | strncat(gBootFile, buffer + kBootpBootFileOffset - 1, | |
960 | cnt2 - kBootpBootFileOffset + 1); | |
961 | ||
962 | free(buffer); | |
963 | } else { | |
964 | // Look for the start of the root dir path. | |
965 | cnt3 = cnt; | |
966 | while (gBootDevice[cnt3] != ',') cnt3++; | |
967 | ||
968 | // Find the end of the path. Look for a comma or null. | |
969 | cnt2 = cnt3 + 1; | |
970 | while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt2] != ',')) cnt2++; | |
971 | ||
972 | // Find the last back slash or comma in the path | |
973 | cnt4 = cnt2 - 1; | |
974 | while ((gBootDevice[cnt4] != ',') && (gBootDevice[cnt4] != '\\')) cnt4--; | |
975 | ||
976 | // Copy the IP addresses if needed. | |
977 | if (gOFVersion < kOFVersion3x) { | |
978 | strncat(gBootFile, gBootDevice + cnt + 1, cnt3 - cnt - 1); | |
979 | } | |
980 | ||
981 | // Add on the directory path | |
982 | strncat(gBootFile, gBootDevice + cnt3, cnt4 - cnt3 + 1); | |
983 | } | |
984 | ||
985 | // Add on the kernel name | |
986 | strcat(gBootFile, "mach.macosx"); | |
987 | ||
988 | // Add on postfix | |
989 | strcat(gBootFile, gBootDevice + cnt2); | |
990 | break; | |
991 | ||
992 | case kBlockDeviceType : | |
993 | // Find the first ':'. | |
994 | cnt = 0; | |
995 | while ((gBootDevice[cnt] != '\0') && (gBootDevice[cnt] != ':')) cnt++; | |
996 | if (gBootDevice[cnt] == '\0') return -1; | |
997 | ||
998 | // Find the comma after the ':'. | |
999 | cnt2 = cnt + 1; | |
1000 | while ((gBootDevice[cnt2] != '\0') && (gBootDevice[cnt] != ',')) cnt2++; | |
1001 | ||
1002 | // Get just the partition number | |
1003 | strncpy(gBootFile, gBootDevice + cnt + 1, cnt2 - cnt - 1); | |
1b564a0a A |
1004 | partNum = strtol(gBootFile, 0, 10); |
1005 | if (partNum == 0) partNum = strtol(gBootFile, 0, 16); | |
04fee52e | 1006 | |
366defd1 A |
1007 | // Adjust the partition number. |
1008 | // Pass 0 & 1, no offset. Pass 2 & 3, offset 1, Pass 4 & 5, offset 2. | |
1009 | partNum += gBootSourceNumber / 2; | |
04fee52e A |
1010 | |
1011 | // Construct the boot-file | |
1012 | strncpy(gBootFile, gBootDevice, cnt + 1); | |
1013 | sprintf(gBootFile + cnt + 1, "%d,%s\\mach_kernel", | |
1014 | partNum, ((gBootSourceNumber & 1) ? "" : "\\")); | |
1b564a0a | 1015 | |
b1faa321 | 1016 | // and the cache file name |
1b564a0a | 1017 | |
b1faa321 A |
1018 | bzero(gCacheNameAdler + 64, sizeof(gBootFile)); |
1019 | strcpy(gCacheNameAdler + 64, gBootFile); | |
8be739c0 | 1020 | adler32 = Adler32(gCacheNameAdler, sizeof(gCacheNameAdler)); |
1b564a0a | 1021 | |
b1faa321 A |
1022 | strncpy(gBootKernelCacheFile, gBootDevice, cnt + 1); |
1023 | sprintf(gBootKernelCacheFile + cnt + 1, | |
1024 | "%d,\\System\\Library\\Caches\\com.apple.kernelcaches\\kernelcache.%08lX", partNum, adler32); | |
04fee52e | 1025 | break; |
1b564a0a | 1026 | |
04fee52e A |
1027 | default: |
1028 | printf("Failed to infer Boot Device Type.\n"); | |
1029 | return -1; | |
1030 | break; | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | // Figure out the root dir. | |
b1faa321 | 1035 | ret = ConvertFileSpec(gBootFile, gExtensionsSpec, &filePath); |
8be739c0 A |
1036 | if (ret == -1) { |
1037 | printf("Failed to determine root directory\n"); | |
1038 | return -1; | |
1039 | } | |
04fee52e | 1040 | |
b1faa321 | 1041 | strcat(gExtensionsSpec, ","); |
04fee52e A |
1042 | |
1043 | // Add in any extra path to gRootDir. | |
1044 | cnt = 0; | |
1045 | while (filePath[cnt] != '\0') cnt++; | |
1046 | ||
1047 | if (cnt != 0) { | |
1048 | for (cnt2 = cnt - 1; cnt2 >= 0; cnt2--) { | |
1049 | if (filePath[cnt2] == '\\') { | |
b1faa321 | 1050 | strncat(gExtensionsSpec, filePath, cnt2 + 1); |
04fee52e A |
1051 | break; |
1052 | } | |
1053 | } | |
1054 | } | |
b1faa321 A |
1055 | |
1056 | // Figure out the extensions dir. | |
1057 | if (gBootFileType == kBlockDeviceType) { | |
1058 | cnt = strlen(gExtensionsSpec); | |
1059 | if ((cnt > 2) && (gExtensionsSpec[cnt-1] == '\\') && (gExtensionsSpec[cnt-2] == '\\')) | |
1060 | cnt--; | |
1061 | strcpy(gExtensionsSpec + cnt, "System\\Library\\"); | |
1062 | } | |
1063 | ||
8be739c0 | 1064 | // technically could just do this once at the end |
04fee52e | 1065 | SetProp(gChosenPH, "rootpath", gBootFile, strlen(gBootFile) + 1); |
8be739c0 A |
1066 | |
1067 | if (GetFSUUID(gBootFile, uuidStr) == 0) { | |
1068 | printf("setting boot-uuid to: %s\n", uuidStr); | |
1069 | SetProp(gChosenPH, "boot-uuid", uuidStr, strlen(uuidStr) + 1); | |
1070 | } | |
04fee52e A |
1071 | |
1072 | gBootSourceNumber++; | |
1073 | ||
1074 | return 0; | |
1075 | } | |
1076 | ||
8be739c0 A |
1077 | #define BOOTPLIST_PATH "com.apple.Boot.plist" |
1078 | ||
1079 | // ReadBootPlist could live elsewhere | |
1080 | static long ReadBootPlist(char *devSpec) | |
1081 | { | |
1082 | char plistSpec[256]; | |
1083 | int len; | |
1084 | ||
1085 | do { | |
1086 | // construct the Boot.plist spec | |
1087 | if (ConvertFileSpec(devSpec, plistSpec, NULL)) break; | |
1088 | strncat(plistSpec, ",\\\\", 255-strlen(plistSpec)); | |
1089 | strncat(plistSpec, BOOTPLIST_PATH, 255-strlen(plistSpec)); | |
1090 | ||
1091 | // load the contents | |
1092 | if ((len = LoadFile(plistSpec)) < 0) break; | |
1093 | // we could try for the root as well as the blessed folder | |
1094 | *((char*)kLoadAddr + len) = '\0'; // terminate for parser safety | |
1095 | ||
1096 | if (ParseXML((char*)kLoadAddr, &gBootDict) < 0 || !gBootDict) { | |
1097 | printf("couldn't parse %s\n", BOOTPLIST_PATH); | |
1098 | break; | |
1099 | } | |
1100 | ||
1101 | return 0; | |
1102 | } while(0); | |
1103 | ||
1104 | return -1; | |
1105 | } | |
1106 | ||
04fee52e A |
1107 | // Public Functions |
1108 | ||
1109 | long GetDeviceType(char *devSpec) | |
1110 | { | |
1111 | CICell ph; | |
1112 | long size; | |
1113 | char deviceType[32]; | |
1114 | ||
8be739c0 A |
1115 | if (isRAIDPath(devSpec)) |
1116 | return kBlockDeviceType; | |
1117 | ||
04fee52e A |
1118 | ph = FindDevice(devSpec); |
1119 | if (ph == -1) return -1; | |
1120 | ||
1121 | size = GetProp(ph, "device_type", deviceType, 31); | |
1122 | if (size != -1) deviceType[size] = '\0'; | |
1123 | else deviceType[0] = '\0'; | |
1124 | ||
1125 | if (strcmp(deviceType, "network") == 0) return kNetworkDeviceType; | |
1126 | if (strcmp(deviceType, "block") == 0) return kBlockDeviceType; | |
1127 | ||
1128 | return kUnknownDeviceType; | |
1129 | } | |
1130 | ||
1131 | ||
1132 | long ConvertFileSpec(char *fileSpec, char *devSpec, char **filePath) | |
1133 | { | |
1134 | long cnt; | |
1135 | ||
1136 | // Find the first ':' in the fileSpec. | |
1137 | cnt = 0; | |
1138 | while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ':')) cnt++; | |
1139 | if (fileSpec[cnt] == '\0') return -1; | |
1140 | ||
1141 | // Find the next ',' in the fileSpec. | |
1142 | while ((fileSpec[cnt] != '\0') && (fileSpec[cnt] != ',')) cnt++; | |
1143 | ||
1144 | // Copy the string to devSpec. | |
1145 | strncpy(devSpec, fileSpec, cnt); | |
1146 | devSpec[cnt] = '\0'; | |
1147 | ||
1148 | // If there is a filePath start it after the ',', otherwise NULL. | |
1149 | if (filePath != NULL) { | |
1150 | if (fileSpec[cnt] != '\0') { | |
1151 | *filePath = fileSpec + cnt + 1; | |
1152 | } else { | |
1153 | *filePath = NULL; | |
1154 | } | |
1155 | } | |
1156 | ||
1157 | return 0; | |
1158 | } | |
1159 | ||
1160 | ||
1161 | long MatchThis(CICell phandle, char *string) | |
1162 | { | |
1163 | long ret, length; | |
1164 | char *name, *model, *compatible; | |
1165 | ||
1166 | ret = GetPackageProperty(phandle, "name", &name, &length); | |
1167 | if ((ret == -1) || (length == 0)) name = NULL; | |
1168 | ||
1169 | ret = GetPackageProperty(phandle, "model", &model, &length); | |
1170 | if ((ret == -1) || (length == 0)) model = NULL; | |
1171 | ||
1172 | ret = GetPackageProperty(phandle, "compatible", &compatible, &length); | |
1173 | if ((ret == -1) || (length == 0)) model = NULL; | |
1174 | ||
1175 | if ((name != NULL) && strcmp(name, string) == 0) return 0; | |
1176 | if ((model != NULL) && strcmp(model, string) == 0) return 0; | |
1177 | ||
1178 | if (compatible != NULL) { | |
1179 | while (*compatible != '\0') { | |
1180 | if (strcmp(compatible, string) == 0) return 0; | |
1181 | ||
1182 | compatible += strlen(compatible) + 1; | |
1183 | } | |
1184 | } | |
1185 | ||
1186 | return -1; | |
1187 | } | |
1188 | ||
1189 | ||
1190 | void *AllocateBootXMemory(long size) | |
1191 | { | |
1192 | long addr = gImageFirstBootXAddr - size; | |
1193 | ||
1194 | if (addr < gImageLastKernelAddr) return 0; | |
1195 | ||
1196 | gImageFirstBootXAddr = addr; | |
1197 | ||
1198 | return (void *)addr; | |
1199 | } | |
1200 | ||
1201 | ||
1202 | long AllocateKernelMemory(long size) | |
1203 | { | |
1204 | long addr = gImageLastKernelAddr; | |
1205 | ||
1206 | gImageLastKernelAddr += (size + 0xFFF) & ~0xFFF; | |
1207 | ||
1208 | if (gImageLastKernelAddr > gImageFirstBootXAddr) | |
1209 | FailToBoot(-1); | |
1210 | ||
1211 | return addr; | |
1212 | } | |
1213 | ||
1214 | ||
1215 | long AllocateMemoryRange(char *rangeName, long start, long length) | |
1216 | { | |
1217 | long result, *buffer; | |
1218 | ||
1219 | buffer = AllocateBootXMemory(2 * sizeof(long)); | |
1220 | if (buffer == 0) return -1; | |
1221 | ||
1222 | buffer[0] = start; | |
1223 | buffer[1] = length; | |
1224 | ||
1225 | result = SetProp(gMemoryMapPH, rangeName, (char *)buffer, 2 * sizeof(long)); | |
1226 | if (result == -1) return -1; | |
1227 | ||
1228 | return 0; | |
1229 | } | |
1230 | ||
8be739c0 A |
1231 | #define BASE 65521L /* largest prime smaller than 65536 */ |
1232 | #define NMAX 5000 | |
1233 | // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 | |
1234 | ||
1235 | #define DO1(buf,i) {s1 += buf[i]; s2 += s1;} | |
1236 | #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); | |
1237 | #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); | |
1238 | #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); | |
1239 | #define DO16(buf) DO8(buf,0); DO8(buf,8); | |
04fee52e | 1240 | |
8be739c0 | 1241 | unsigned long Adler32(unsigned char *buf, long len) |
04fee52e | 1242 | { |
8be739c0 A |
1243 | unsigned long s1 = 1; // adler & 0xffff; |
1244 | unsigned long s2 = 0; // (adler >> 16) & 0xffff; | |
1245 | int k; | |
04fee52e | 1246 | |
8be739c0 A |
1247 | while (len > 0) { |
1248 | k = len < NMAX ? len : NMAX; | |
1249 | len -= k; | |
1250 | while (k >= 16) { | |
1251 | DO16(buf); | |
1252 | buf += 16; | |
1253 | k -= 16; | |
1254 | } | |
1255 | if (k != 0) do { | |
1256 | s1 += *buf++; | |
1257 | s2 += s1; | |
1258 | } while (--k); | |
1259 | s1 %= BASE; | |
1260 | s2 %= BASE; | |
1261 | } | |
1262 | return (s2 << 16) | s1; | |
04fee52e | 1263 | } |