]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights | |
7 | * Reserved. This file contains Original Code and/or Modifications of | |
8 | * Original Code as defined in and that are subject to the Apple Public | |
9 | * Source License Version 2.0 (the "License"). You may not use this file | |
10 | * except in compliance with the License. Please obtain a copy of the | |
11 | * License at http://www.apple.com/publicsource and read it before using | |
12 | * this file. | |
13 | * | |
14 | * The Original Code and all software distributed under the License are | |
15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
18 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the | |
19 | * License for the specific language governing rights and limitations | |
20 | * under the License. | |
21 | * | |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | /* | |
25 | * Mach Operating System | |
26 | * Copyright (c) 1990 Carnegie-Mellon University | |
27 | * Copyright (c) 1989 Carnegie-Mellon University | |
28 | * All rights reserved. The CMU software License Agreement specifies | |
29 | * the terms and conditions for use and redistribution. | |
30 | */ | |
31 | ||
32 | /* | |
33 | * INTEL CORPORATION PROPRIETARY INFORMATION | |
34 | * | |
35 | * This software is supplied under the terms of a license agreement or | |
36 | * nondisclosure agreement with Intel Corporation and may not be copied | |
37 | * nor disclosed except in accordance with the terms of that agreement. | |
38 | * | |
39 | * Copyright 1988, 1989 by Intel Corporation | |
40 | */ | |
41 | ||
42 | /* | |
43 | * Copyright 1993 NeXT Computer, Inc. | |
44 | * All rights reserved. | |
45 | */ | |
46 | ||
47 | /* | |
48 | * Completely reworked by Sam Streeper (sam_s@NeXT.com) | |
49 | * Reworked again by Curtis Galloway (galloway@NeXT.com) | |
50 | */ | |
51 | ||
52 | ||
53 | #include "boot.h" | |
54 | #include "bootstruct.h" | |
55 | #include "sl.h" | |
56 | #include "libsa.h" | |
57 | ||
58 | ||
59 | long gBootMode; /* defaults to 0 == kBootModeNormal */ | |
60 | BOOL gOverrideKernel; | |
61 | static char gBootKernelCacheFile[512]; | |
62 | static char gCacheNameAdler[64 + 256]; | |
63 | char *gPlatformName = gCacheNameAdler; | |
64 | char gRootDevice[512]; | |
65 | char gMKextName[512]; | |
66 | BVRef gBootVolume; | |
67 | ||
68 | static | |
69 | unsigned long Adler32(unsigned char *buffer, long length); | |
70 | ||
71 | ||
72 | static BOOL gUnloadPXEOnExit = 0; | |
73 | ||
74 | /* | |
75 | * How long to wait (in seconds) to load the | |
76 | * kernel after displaying the "boot:" prompt. | |
77 | */ | |
78 | #define kBootErrorTimeout 5 | |
79 | ||
80 | /* | |
81 | * Default path to kernel cache file | |
82 | */ | |
83 | #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache" | |
84 | ||
85 | //========================================================================== | |
86 | // Zero the BSS. | |
87 | ||
88 | static void zeroBSS() | |
89 | { | |
90 | extern char _DATA__bss__begin, _DATA__bss__end; | |
91 | extern char _DATA__common__begin, _DATA__common__end; | |
92 | ||
93 | bzero( &_DATA__bss__begin, | |
94 | (&_DATA__bss__end - &_DATA__bss__begin) ); | |
95 | ||
96 | bzero( &_DATA__common__begin, | |
97 | (&_DATA__common__end - &_DATA__common__begin) ); | |
98 | } | |
99 | ||
100 | //========================================================================== | |
101 | // Malloc error function | |
102 | ||
103 | static void malloc_error(char *addr, size_t size) | |
104 | { | |
105 | printf("\nMemory allocation error (0x%x, 0x%x)\n", | |
106 | (unsigned)addr, (unsigned)size); | |
107 | asm volatile ("hlt"); | |
108 | } | |
109 | ||
110 | //========================================================================== | |
111 | // execKernel - Load the kernel image (mach-o) and jump to its entry point. | |
112 | ||
113 | static int ExecKernel(void *binary) | |
114 | { | |
115 | entry_t kernelEntry; | |
116 | int ret; | |
117 | BOOL bootGraphics; | |
118 | ||
119 | bootArgs->kaddr = bootArgs->ksize = 0; | |
120 | ||
121 | ret = DecodeKernel(binary, | |
122 | &kernelEntry, | |
123 | (char **) &bootArgs->kaddr, | |
124 | (int *)&bootArgs->ksize ); | |
125 | ||
126 | if ( ret != 0 ) | |
127 | return ret; | |
128 | ||
129 | // Reserve space for boot args | |
130 | reserveKernBootStruct(); | |
131 | ||
132 | // Load boot drivers from the specifed root path. | |
133 | ||
134 | if (!gHaveKernelCache) { | |
135 | LoadDrivers("/"); | |
136 | } | |
137 | ||
138 | clearActivityIndicator(); | |
139 | ||
140 | if (gErrors) { | |
141 | printf("Errors encountered while starting up the computer.\n"); | |
142 | printf("Pausing %d seconds...\n", kBootErrorTimeout); | |
143 | sleep(kBootErrorTimeout); | |
144 | } | |
145 | ||
146 | printf("Starting Darwin/x86"); | |
147 | ||
148 | // Cleanup the PXE base code. | |
149 | ||
150 | if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) { | |
151 | if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess ) | |
152 | { | |
153 | printf("nbpUnloadBaseCode error %d\n", (int) ret); | |
154 | sleep(2); | |
155 | } | |
156 | } | |
157 | ||
158 | // Unless Boot Graphics = No, Always switch to graphics mode | |
159 | // just before starting the kernel. | |
160 | ||
161 | if (!getBoolForKey(kBootGraphicsKey, &bootGraphics)) { | |
162 | bootGraphics = YES; | |
163 | } | |
164 | ||
165 | if (bootGraphics) { | |
166 | if (bootArgs->Video.v_display == VGA_TEXT_MODE) { | |
167 | // If we were in text mode, switch to graphics mode. | |
168 | // This will draw the boot graphics unless we are in | |
169 | // verbose mode. | |
170 | setVideoMode( GRAPHICS_MODE ); | |
171 | } else { | |
172 | // If we were already in graphics mode, clear the screen. | |
173 | drawBootGraphics(); | |
174 | } | |
175 | } else { | |
176 | // Always set text mode to initialize video fields | |
177 | // in the boot args structure. | |
178 | setVideoMode( VGA_TEXT_MODE ); | |
179 | setCursorType( kCursorTypeHidden ); | |
180 | } | |
181 | ||
182 | finalizeBootStruct(); | |
183 | ||
184 | // Jump to kernel's entry point. There's no going back now. | |
185 | ||
186 | startprog( kernelEntry, bootArgs ); | |
187 | ||
188 | // Not reached | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
193 | //========================================================================== | |
194 | // Scan and record the system's hardware information. | |
195 | ||
196 | static void scanHardware() | |
197 | { | |
198 | extern int ReadPCIBusInfo(PCI_bus_info_t *); | |
199 | extern void PCI_Bus_Init(PCI_bus_info_t *); | |
200 | ||
201 | ReadPCIBusInfo( &bootInfo->pciInfo ); | |
202 | ||
203 | // | |
204 | // Initialize PCI matching support in the booter. | |
205 | // Not used, commented out to minimize code size. | |
206 | // | |
207 | // PCI_Bus_Init( &bootInfo->pciInfo ); | |
208 | } | |
209 | ||
210 | //========================================================================== | |
211 | // The 'main' function for the booter. Called by boot0 when booting | |
212 | // from a block device, or by the network booter. | |
213 | // | |
214 | // arguments: | |
215 | // biosdev - Value passed from boot1/NBP to specify the device | |
216 | // that the booter was loaded from. | |
217 | // | |
218 | // If biosdev is kBIOSDevNetwork, then this function will return if | |
219 | // booting was unsuccessful. This allows the PXE firmware to try the | |
220 | // next boot device on its list. | |
221 | ||
222 | #define DLOG(x) outb(0x80, (x)) | |
223 | ||
224 | void boot(int biosdev) | |
225 | { | |
226 | int status; | |
227 | char *bootFile; | |
228 | unsigned long adler32; | |
229 | BOOL quiet; | |
230 | BOOL firstRun = YES; | |
231 | BVRef bvChain; | |
232 | ||
233 | zeroBSS(); | |
234 | ||
235 | // Initialize malloc | |
236 | malloc_init(0, 0, 0, malloc_error); | |
237 | ||
238 | // Enable A20 gate before accessing memory above 1Mb. | |
239 | ||
240 | enableA20(); | |
241 | ||
242 | // Set reminder to unload the PXE base code. Neglect to unload | |
243 | // the base code will result in a hang or kernel panic. | |
244 | ||
245 | gUnloadPXEOnExit = 1; | |
246 | ||
247 | // Record the device that the booter was loaded from. | |
248 | ||
249 | gBIOSDev = biosdev & kBIOSDevMask; | |
250 | ||
251 | // Initialize boot info structure. | |
252 | ||
253 | initKernBootStruct( gBIOSDev ); | |
254 | ||
255 | // Setup VGA text mode. | |
256 | // Not sure if it is safe to call setVideoMode() before the | |
257 | // config table has been loaded. Call video_mode() instead. | |
258 | ||
259 | #if DEBUG | |
260 | printf("before video_mode\n"); | |
261 | #endif | |
262 | video_mode( 2 ); // 80x25 mono text mode. | |
263 | #if DEBUG | |
264 | printf("after video_mode\n"); | |
265 | #endif | |
266 | ||
267 | // Check to see that this hardware is supported. | |
268 | status = checkForSupportedHardware(); | |
269 | if (status != 0) { | |
270 | stop("This hardware configuration is not supported by Darwin/x86. (%d)", status); | |
271 | } | |
272 | ||
273 | // Scan hardware configuration. | |
274 | scanHardware(); | |
275 | ||
276 | // First get info for boot volume. | |
277 | bvChain = scanBootVolumes(gBIOSDev, 0); | |
278 | ||
279 | // Record default boot device. | |
280 | gBootVolume = selectBootVolume(bvChain); | |
281 | bootInfo->kernDev = MAKEKERNDEV(gBIOSDev, | |
282 | BIOS_DEV_UNIT(gBootVolume), | |
283 | gBootVolume->part_no ); | |
284 | ||
285 | // Load default config file from boot device. | |
286 | status = loadSystemConfig(0, 0); | |
287 | ||
288 | if ( getBoolForKey( kQuietBootKey, &quiet ) && quiet ) { | |
289 | gBootMode |= kBootModeQuiet; | |
290 | } | |
291 | ||
292 | // Parse args, load and start kernel. | |
293 | ||
294 | while (1) | |
295 | { | |
296 | const char *val; | |
297 | int len; | |
298 | int trycache; | |
299 | long flags, cachetime, kerneltime, exttime; | |
300 | int ret = -1; | |
301 | void *binary = (void *)kLoadAddr; | |
302 | ||
303 | // Initialize globals. | |
304 | ||
305 | sysConfigValid = 0; | |
306 | gErrors = 0; | |
307 | ||
308 | status = getBootOptions(firstRun); | |
309 | firstRun = NO; | |
310 | if (status == -1) continue; | |
311 | ||
312 | status = processBootOptions(); | |
313 | if ( status == 1 ) break; | |
314 | if ( status == -1 ) continue; | |
315 | ||
316 | // Found and loaded a config file. Proceed with boot. | |
317 | ||
318 | ||
319 | // Reset cache name. | |
320 | bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64); | |
321 | ||
322 | sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile); | |
323 | ||
324 | adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler)); | |
325 | ||
326 | if (getValueForKey(kKernelCacheKey, &val, &len) == YES) { | |
327 | strlcpy(gBootKernelCacheFile, val, len+1); | |
328 | } else { | |
329 | sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePath, adler32); | |
330 | } | |
331 | ||
332 | // Check for cache file. | |
333 | ||
334 | trycache = (((gBootMode & kBootModeSafe) == 0) && | |
335 | (gOverrideKernel == NO) && | |
336 | (gBootFileType == kBlockDeviceType) && | |
337 | (gMKextName[0] == '\0') && | |
338 | (gBootKernelCacheFile[0] != '\0')); | |
339 | ||
340 | printf("Loading Darwin/x86\n"); | |
341 | ||
342 | if (trycache) do { | |
343 | ||
344 | // if we haven't found the kernel yet, don't use the cache | |
345 | ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime); | |
346 | if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) { | |
347 | trycache = 0; | |
348 | break; | |
349 | } | |
350 | ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime); | |
351 | if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat) | |
352 | || (cachetime < kerneltime)) { | |
353 | trycache = 0; | |
354 | break; | |
355 | } | |
356 | ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime); | |
357 | if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory) | |
358 | && (cachetime < exttime)) { | |
359 | trycache = 0; | |
360 | break; | |
361 | } | |
362 | if (kerneltime > exttime) { | |
363 | exttime = kerneltime; | |
364 | } | |
365 | if (cachetime != (exttime + 1)) { | |
366 | trycache = 0; | |
367 | break; | |
368 | } | |
369 | } while (0); | |
370 | ||
371 | do { | |
372 | if (trycache) { | |
373 | bootFile = gBootKernelCacheFile; | |
374 | verbose("Loading kernel cache %s\n", bootFile); | |
375 | ret = LoadFile(bootFile); | |
376 | binary = (void *)kLoadAddr; | |
377 | if (ret >= 0) { | |
378 | break; | |
379 | } | |
380 | } | |
381 | bootFile = bootInfo->bootFile; | |
382 | verbose("Loading kernel %s\n", bootFile); | |
383 | ret = LoadThinFatFile(bootFile, &binary); | |
384 | } while (0); | |
385 | ||
386 | clearActivityIndicator(); | |
387 | #if DEBUG | |
388 | printf("Pausing..."); | |
389 | sleep(8); | |
390 | #endif | |
391 | ||
392 | if (ret < 0) { | |
393 | error("Can't find %s\n", bootFile); | |
394 | ||
395 | if ( gBootFileType == kNetworkDeviceType ) | |
396 | { | |
397 | // Return control back to PXE. Don't unload PXE base code. | |
398 | gUnloadPXEOnExit = 0; | |
399 | break; | |
400 | } | |
401 | } else { | |
402 | /* Won't return if successful. */ | |
403 | ret = ExecKernel(binary); | |
404 | } | |
405 | ||
406 | } /* while(1) */ | |
407 | ||
408 | if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) { | |
409 | nbpUnloadBaseCode(); | |
410 | } | |
411 | } | |
412 | ||
413 | #define BASE 65521L /* largest prime smaller than 65536 */ | |
414 | #define NMAX 5000 | |
415 | // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 | |
416 | ||
417 | #define DO1(buf,i) {s1 += buf[i]; s2 += s1;} | |
418 | #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); | |
419 | #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); | |
420 | #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); | |
421 | #define DO16(buf) DO8(buf,0); DO8(buf,8); | |
422 | ||
423 | unsigned long Adler32(unsigned char *buf, long len) | |
424 | { | |
425 | unsigned long s1 = 1; // adler & 0xffff; | |
426 | unsigned long s2 = 0; // (adler >> 16) & 0xffff; | |
427 | unsigned long result; | |
428 | int k; | |
429 | ||
430 | while (len > 0) { | |
431 | k = len < NMAX ? len : NMAX; | |
432 | len -= k; | |
433 | while (k >= 16) { | |
434 | DO16(buf); | |
435 | buf += 16; | |
436 | k -= 16; | |
437 | } | |
438 | if (k != 0) do { | |
439 | s1 += *buf++; | |
440 | s2 += s1; | |
441 | } while (--k); | |
442 | s1 %= BASE; | |
443 | s2 %= BASE; | |
444 | } | |
445 | result = (s2 << 16) | s1; | |
446 | return OSSwapHostToBigInt32(result); | |
447 | } | |
448 | ||
449 |