]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/boot.c
boot-132.tar.gz
[apple/boot.git] / i386 / boot2 / boot.c
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