]>
Commit | Line | Data |
---|---|---|
14c7c974 | 1 | /* |
57c72a9a | 2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. |
14c7c974 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
57c72a9a | 6 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights |
4f6e3300 A |
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 | |
57c72a9a | 9 | * Source License Version 2.0 (the "License"). You may not use this file |
4f6e3300 A |
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. | |
14c7c974 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
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. | |
14c7c974 A |
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 | */ | |
75b89a82 | 51 | |
57c72a9a | 52 | |
14c7c974 | 53 | #include "boot.h" |
f083c6c3 A |
54 | #include "bootstruct.h" |
55 | #include "sl.h" | |
57c72a9a | 56 | #include "libsa.h" |
14c7c974 | 57 | |
57c72a9a A |
58 | |
59 | long gBootMode; /* defaults to 0 == kBootModeNormal */ | |
60 | BOOL gOverrideKernel; | |
f083c6c3 | 61 | static char gBootKernelCacheFile[512]; |
57c72a9a A |
62 | static char gCacheNameAdler[64 + 256]; |
63 | char *gPlatformName = gCacheNameAdler; | |
bba600dd | 64 | char gRootDevice[512]; |
57c72a9a A |
65 | char gMKextName[512]; |
66 | BVRef gBootVolume; | |
67 | ||
68 | static | |
69 | unsigned long Adler32(unsigned char *buffer, long length); | |
70 | ||
14c7c974 | 71 | |
75b89a82 | 72 | static BOOL gUnloadPXEOnExit = 0; |
14c7c974 A |
73 | |
74 | /* | |
47b0a8bd A |
75 | * How long to wait (in seconds) to load the |
76 | * kernel after displaying the "boot:" prompt. | |
14c7c974 | 77 | */ |
75b89a82 | 78 | #define kBootErrorTimeout 5 |
14c7c974 | 79 | |
f083c6c3 A |
80 | /* |
81 | * Default path to kernel cache file | |
82 | */ | |
83 | #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache" | |
84 | ||
14c7c974 A |
85 | //========================================================================== |
86 | // Zero the BSS. | |
87 | ||
75b89a82 | 88 | static void zeroBSS() |
14c7c974 A |
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) ); | |
47b0a8bd | 95 | |
14c7c974 A |
96 | bzero( &_DATA__common__begin, |
97 | (&_DATA__common__end - &_DATA__common__begin) ); | |
98 | } | |
99 | ||
f083c6c3 A |
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); | |
bba600dd | 107 | asm volatile ("hlt"); |
f083c6c3 A |
108 | } |
109 | ||
14c7c974 | 110 | //========================================================================== |
47b0a8bd | 111 | // execKernel - Load the kernel image (mach-o) and jump to its entry point. |
14c7c974 | 112 | |
f083c6c3 | 113 | static int ExecKernel(void *binary) |
14c7c974 | 114 | { |
14c7c974 | 115 | entry_t kernelEntry; |
47b0a8bd | 116 | int ret; |
57c72a9a | 117 | BOOL bootGraphics; |
47b0a8bd | 118 | |
f083c6c3 | 119 | bootArgs->kaddr = bootArgs->ksize = 0; |
47b0a8bd | 120 | |
f083c6c3 A |
121 | ret = DecodeKernel(binary, |
122 | &kernelEntry, | |
123 | (char **) &bootArgs->kaddr, | |
bba600dd | 124 | (int *)&bootArgs->ksize ); |
14c7c974 A |
125 | |
126 | if ( ret != 0 ) | |
127 | return ret; | |
128 | ||
f083c6c3 A |
129 | // Reserve space for boot args |
130 | reserveKernBootStruct(); | |
131 | ||
75b89a82 | 132 | // Load boot drivers from the specifed root path. |
14c7c974 | 133 | |
f083c6c3 A |
134 | if (!gHaveKernelCache) { |
135 | LoadDrivers("/"); | |
136 | } | |
137 | ||
14c7c974 | 138 | clearActivityIndicator(); |
14c7c974 | 139 | |
75b89a82 | 140 | if (gErrors) { |
14c7c974 | 141 | printf("Errors encountered while starting up the computer.\n"); |
75b89a82 A |
142 | printf("Pausing %d seconds...\n", kBootErrorTimeout); |
143 | sleep(kBootErrorTimeout); | |
14c7c974 A |
144 | } |
145 | ||
75b89a82 | 146 | printf("Starting Darwin/x86"); |
14c7c974 | 147 | |
f083c6c3 | 148 | // Cleanup the PXE base code. |
14c7c974 | 149 | |
f083c6c3 | 150 | if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) { |
14c7c974 A |
151 | if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess ) |
152 | { | |
75b89a82 A |
153 | printf("nbpUnloadBaseCode error %d\n", (int) ret); |
154 | sleep(2); | |
14c7c974 A |
155 | } |
156 | } | |
157 | ||
57c72a9a A |
158 | // Unless Boot Graphics = No, Always switch to graphics mode |
159 | // just before starting the kernel. | |
14c7c974 | 160 | |
57c72a9a A |
161 | if (!getBoolForKey(kBootGraphicsKey, &bootGraphics)) { |
162 | bootGraphics = YES; | |
163 | } | |
164 | ||
165 | if (bootGraphics) { | |
bba600dd | 166 | if (bootArgs->Video.v_display == VGA_TEXT_MODE) { |
57c72a9a | 167 | // If we were in text mode, switch to graphics mode. |
bba600dd A |
168 | // This will draw the boot graphics unless we are in |
169 | // verbose mode. | |
57c72a9a A |
170 | setVideoMode( GRAPHICS_MODE ); |
171 | } else { | |
172 | // If we were already in graphics mode, clear the screen. | |
173 | drawBootGraphics(); | |
174 | } | |
175 | } else { | |
bba600dd A |
176 | // Always set text mode to initialize video fields |
177 | // in the boot args structure. | |
178 | setVideoMode( VGA_TEXT_MODE ); | |
179 | setCursorType( kCursorTypeHidden ); | |
57c72a9a | 180 | } |
14c7c974 | 181 | |
bba600dd A |
182 | finalizeBootStruct(); |
183 | ||
14c7c974 A |
184 | // Jump to kernel's entry point. There's no going back now. |
185 | ||
f083c6c3 | 186 | startprog( kernelEntry, bootArgs ); |
14c7c974 A |
187 | |
188 | // Not reached | |
189 | ||
190 | return 0; | |
191 | } | |
192 | ||
193 | //========================================================================== | |
75b89a82 | 194 | // Scan and record the system's hardware information. |
14c7c974 A |
195 | |
196 | static void scanHardware() | |
197 | { | |
75b89a82 A |
198 | extern int ReadPCIBusInfo(PCI_bus_info_t *); |
199 | extern void PCI_Bus_Init(PCI_bus_info_t *); | |
14c7c974 | 200 | |
bba600dd | 201 | ReadPCIBusInfo( &bootInfo->pciInfo ); |
75b89a82 A |
202 | |
203 | // | |
204 | // Initialize PCI matching support in the booter. | |
205 | // Not used, commented out to minimize code size. | |
206 | // | |
bba600dd | 207 | // PCI_Bus_Init( &bootInfo->pciInfo ); |
14c7c974 A |
208 | } |
209 | ||
210 | //========================================================================== | |
75b89a82 A |
211 | // The 'main' function for the booter. Called by boot0 when booting |
212 | // from a block device, or by the network booter. | |
14c7c974 A |
213 | // |
214 | // arguments: | |
75b89a82 A |
215 | // biosdev - Value passed from boot1/NBP to specify the device |
216 | // that the booter was loaded from. | |
14c7c974 | 217 | // |
75b89a82 | 218 | // If biosdev is kBIOSDevNetwork, then this function will return if |
14c7c974 | 219 | // booting was unsuccessful. This allows the PXE firmware to try the |
75b89a82 | 220 | // next boot device on its list. |
14c7c974 | 221 | |
57c72a9a A |
222 | #define DLOG(x) outb(0x80, (x)) |
223 | ||
75b89a82 | 224 | void boot(int biosdev) |
14c7c974 | 225 | { |
75b89a82 | 226 | int status; |
f083c6c3 | 227 | char *bootFile; |
57c72a9a A |
228 | unsigned long adler32; |
229 | BOOL quiet; | |
230 | BOOL firstRun = YES; | |
231 | BVRef bvChain; | |
14c7c974 A |
232 | |
233 | zeroBSS(); | |
234 | ||
f083c6c3 | 235 | // Initialize malloc |
f083c6c3 A |
236 | malloc_init(0, 0, 0, malloc_error); |
237 | ||
47b0a8bd | 238 | // Enable A20 gate before accessing memory above 1Mb. |
14c7c974 A |
239 | |
240 | enableA20(); | |
241 | ||
75b89a82 A |
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 | ||
75b89a82 | 245 | gUnloadPXEOnExit = 1; |
14c7c974 | 246 | |
75b89a82 A |
247 | // Record the device that the booter was loaded from. |
248 | ||
249 | gBIOSDev = biosdev & kBIOSDevMask; | |
14c7c974 A |
250 | |
251 | // Initialize boot info structure. | |
252 | ||
75b89a82 | 253 | initKernBootStruct( gBIOSDev ); |
14c7c974 A |
254 | |
255 | // Setup VGA text mode. | |
75b89a82 A |
256 | // Not sure if it is safe to call setVideoMode() before the |
257 | // config table has been loaded. Call video_mode() instead. | |
14c7c974 | 258 | |
bba600dd A |
259 | #if DEBUG |
260 | printf("before video_mode\n"); | |
261 | #endif | |
57c72a9a | 262 | video_mode( 2 ); // 80x25 mono text mode. |
bba600dd A |
263 | #if DEBUG |
264 | printf("after video_mode\n"); | |
265 | #endif | |
14c7c974 | 266 | |
bba600dd A |
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 | } | |
14c7c974 | 272 | |
bba600dd | 273 | // Scan hardware configuration. |
14c7c974 A |
274 | scanHardware(); |
275 | ||
57c72a9a A |
276 | // First get info for boot volume. |
277 | bvChain = scanBootVolumes(gBIOSDev, 0); | |
14c7c974 | 278 | |
57c72a9a A |
279 | // Record default boot device. |
280 | gBootVolume = selectBootVolume(bvChain); | |
bba600dd | 281 | bootInfo->kernDev = MAKEKERNDEV(gBIOSDev, |
57c72a9a A |
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 | } | |
14c7c974 A |
291 | |
292 | // Parse args, load and start kernel. | |
293 | ||
294 | while (1) | |
295 | { | |
f083c6c3 | 296 | const char *val; |
57c72a9a A |
297 | int len; |
298 | int trycache; | |
299 | long flags, cachetime, kerneltime, exttime; | |
f083c6c3 | 300 | int ret = -1; |
bba600dd | 301 | void *binary = (void *)kLoadAddr; |
f083c6c3 | 302 | |
14c7c974 A |
303 | // Initialize globals. |
304 | ||
47b0a8bd | 305 | sysConfigValid = 0; |
75b89a82 | 306 | gErrors = 0; |
14c7c974 | 307 | |
57c72a9a A |
308 | status = getBootOptions(firstRun); |
309 | firstRun = NO; | |
310 | if (status == -1) continue; | |
f083c6c3 | 311 | |
75b89a82 A |
312 | status = processBootOptions(); |
313 | if ( status == 1 ) break; | |
314 | if ( status == -1 ) continue; | |
14c7c974 A |
315 | |
316 | // Found and loaded a config file. Proceed with boot. | |
317 | ||
14c7c974 | 318 | |
57c72a9a | 319 | // Reset cache name. |
bba600dd | 320 | bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64); |
57c72a9a | 321 | |
bba600dd A |
322 | sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile); |
323 | ||
324 | adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler)); | |
57c72a9a A |
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 | ||
f083c6c3 | 334 | trycache = (((gBootMode & kBootModeSafe) == 0) && |
57c72a9a | 335 | (gOverrideKernel == NO) && |
f083c6c3 | 336 | (gBootFileType == kBlockDeviceType) && |
57c72a9a | 337 | (gMKextName[0] == '\0') && |
f083c6c3 A |
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 | |
bba600dd | 345 | ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime); |
f083c6c3 A |
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) | |
57c72a9a | 352 | || (cachetime < kerneltime)) { |
f083c6c3 A |
353 | trycache = 0; |
354 | break; | |
355 | } | |
57c72a9a | 356 | ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime); |
f083c6c3 | 357 | if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory) |
57c72a9a A |
358 | && (cachetime < exttime)) { |
359 | trycache = 0; | |
360 | break; | |
361 | } | |
362 | if (kerneltime > exttime) { | |
363 | exttime = kerneltime; | |
364 | } | |
365 | if (cachetime != (exttime + 1)) { | |
f083c6c3 A |
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); | |
bba600dd | 376 | binary = (void *)kLoadAddr; |
f083c6c3 A |
377 | if (ret >= 0) { |
378 | break; | |
379 | } | |
380 | } | |
bba600dd | 381 | bootFile = bootInfo->bootFile; |
f083c6c3 | 382 | verbose("Loading kernel %s\n", bootFile); |
bba600dd | 383 | ret = LoadThinFatFile(bootFile, &binary); |
f083c6c3 A |
384 | } while (0); |
385 | ||
386 | clearActivityIndicator(); | |
57c72a9a A |
387 | #if DEBUG |
388 | printf("Pausing..."); | |
389 | sleep(8); | |
390 | #endif | |
f083c6c3 A |
391 | |
392 | if (ret < 0) { | |
393 | error("Can't find %s\n", bootFile); | |
394 | ||
bba600dd | 395 | if ( gBootFileType == kNetworkDeviceType ) |
14c7c974 | 396 | { |
75b89a82 A |
397 | // Return control back to PXE. Don't unload PXE base code. |
398 | gUnloadPXEOnExit = 0; | |
399 | break; | |
14c7c974 | 400 | } |
f083c6c3 A |
401 | } else { |
402 | /* Won't return if successful. */ | |
bba600dd | 403 | ret = ExecKernel(binary); |
14c7c974 | 404 | } |
f083c6c3 | 405 | |
14c7c974 | 406 | } /* while(1) */ |
75b89a82 | 407 | |
f083c6c3 A |
408 | if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) { |
409 | nbpUnloadBaseCode(); | |
410 | } | |
14c7c974 | 411 | } |
57c72a9a A |
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 | ||
bba600dd | 449 |