]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/boot.c
boot-122.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 gMKextName[512];
65 BVRef gBootVolume;
66
67 static
68 unsigned long Adler32(unsigned char *buffer, long length);
69
70
71 static BOOL gUnloadPXEOnExit = 0;
72
73 /*
74 * How long to wait (in seconds) to load the
75 * kernel after displaying the "boot:" prompt.
76 */
77 #define kBootErrorTimeout 5
78
79 /*
80 * Default path to kernel cache file
81 */
82 #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache"
83
84 //==========================================================================
85 // Zero the BSS.
86
87 static void zeroBSS()
88 {
89 extern char _DATA__bss__begin, _DATA__bss__end;
90 extern char _DATA__common__begin, _DATA__common__end;
91
92 bzero( &_DATA__bss__begin,
93 (&_DATA__bss__end - &_DATA__bss__begin) );
94
95 bzero( &_DATA__common__begin,
96 (&_DATA__common__end - &_DATA__common__begin) );
97 }
98
99 //==========================================================================
100 // Malloc error function
101
102 static void malloc_error(char *addr, size_t size)
103 {
104 printf("\nMemory allocation error (0x%x, 0x%x)\n",
105 (unsigned)addr, (unsigned)size);
106 asm("hlt");
107 }
108
109 //==========================================================================
110 // execKernel - Load the kernel image (mach-o) and jump to its entry point.
111
112 static int ExecKernel(void *binary)
113 {
114 entry_t kernelEntry;
115 int ret;
116 #ifdef APM_SUPPORT
117 BOOL apm;
118 #endif /* APM_SUPPORT */
119 BOOL bootGraphics;
120
121 bootArgs->kaddr = bootArgs->ksize = 0;
122
123 ret = DecodeKernel(binary,
124 &kernelEntry,
125 (char **) &bootArgs->kaddr,
126 &bootArgs->ksize );
127
128 if ( ret != 0 )
129 return ret;
130
131 // Reserve space for boot args
132 reserveKernBootStruct();
133
134 // Load boot drivers from the specifed root path.
135
136 if (!gHaveKernelCache) {
137 LoadDrivers("/");
138 }
139
140 clearActivityIndicator();
141
142 if (gErrors) {
143 printf("Errors encountered while starting up the computer.\n");
144 printf("Pausing %d seconds...\n", kBootErrorTimeout);
145 sleep(kBootErrorTimeout);
146 }
147
148 printf("Starting Darwin/x86");
149
150 turnOffFloppy();
151
152 #ifdef APM_SUPPORT
153 // Connect to APM BIOS.
154
155 if ( getBoolForKey("APM", &apm) && apm == YES )
156 {
157 if ( APMPresent() ) APMConnect32();
158 }
159 #endif /* APM_SUPPORT */
160
161 // Cleanup the PXE base code.
162
163 if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) {
164 if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
165 {
166 printf("nbpUnloadBaseCode error %d\n", (int) ret);
167 sleep(2);
168 }
169 }
170
171 // Unless Boot Graphics = No, Always switch to graphics mode
172 // just before starting the kernel.
173
174 if (!getBoolForKey(kBootGraphicsKey, &bootGraphics)) {
175 bootGraphics = YES;
176 }
177
178 if (bootGraphics) {
179 if (bootArgs->graphicsMode == TEXT_MODE) {
180 // If we were in text mode, switch to graphics mode.
181 // This will draw the boot graphics.
182 setVideoMode( GRAPHICS_MODE );
183 } else {
184 // If we were already in graphics mode, clear the screen.
185 drawBootGraphics();
186 }
187 } else {
188 if (bootArgs->graphicsMode == GRAPHICS_MODE) {
189 setVideoMode( TEXT_MODE );
190 }
191 }
192
193 // Jump to kernel's entry point. There's no going back now.
194
195 startprog( kernelEntry, bootArgs );
196
197 // Not reached
198
199 return 0;
200 }
201
202 //==========================================================================
203 // Scan and record the system's hardware information.
204
205 static void scanHardware()
206 {
207 extern int ReadPCIBusInfo(PCI_bus_info_t *);
208 extern void PCI_Bus_Init(PCI_bus_info_t *);
209
210 ReadPCIBusInfo( &bootArgs->pciInfo );
211
212 //
213 // Initialize PCI matching support in the booter.
214 // Not used, commented out to minimize code size.
215 //
216 // PCI_Bus_Init( &bootArgs->pciInfo );
217 }
218
219 //==========================================================================
220 // The 'main' function for the booter. Called by boot0 when booting
221 // from a block device, or by the network booter.
222 //
223 // arguments:
224 // biosdev - Value passed from boot1/NBP to specify the device
225 // that the booter was loaded from.
226 //
227 // If biosdev is kBIOSDevNetwork, then this function will return if
228 // booting was unsuccessful. This allows the PXE firmware to try the
229 // next boot device on its list.
230
231 #define DLOG(x) outb(0x80, (x))
232
233 void boot(int biosdev)
234 {
235 int status;
236 char *bootFile;
237 unsigned long adler32;
238 BOOL quiet;
239 BOOL firstRun = YES;
240 BVRef bvChain;
241
242 zeroBSS();
243
244 // Initialize malloc
245
246 malloc_init(0, 0, 0, malloc_error);
247
248 // Enable A20 gate before accessing memory above 1Mb.
249
250 enableA20();
251
252 // Set reminder to unload the PXE base code. Neglect to unload
253 // the base code will result in a hang or kernel panic.
254
255 gUnloadPXEOnExit = 1;
256
257 // Record the device that the booter was loaded from.
258
259 gBIOSDev = biosdev & kBIOSDevMask;
260
261 // Initialize boot info structure.
262
263 initKernBootStruct( gBIOSDev );
264
265 // Setup VGA text mode.
266 // Not sure if it is safe to call setVideoMode() before the
267 // config table has been loaded. Call video_mode() instead.
268
269 video_mode( 2 ); // 80x25 mono text mode.
270
271 // Scan hardware configuration.
272
273 scanHardware();
274
275 // First get info for boot volume.
276 bvChain = scanBootVolumes(gBIOSDev, 0);
277
278 // Record default boot device.
279 gBootVolume = selectBootVolume(bvChain);
280 bootArgs->kernDev = MAKEKERNDEV(gBIOSDev,
281 BIOS_DEV_UNIT(gBootVolume),
282 gBootVolume->part_no );
283
284 // Load default config file from boot device.
285 status = loadSystemConfig(0, 0);
286
287 if ( getBoolForKey( kQuietBootKey, &quiet ) && quiet ) {
288 gBootMode |= kBootModeQuiet;
289 }
290
291 // Parse args, load and start kernel.
292
293 while (1)
294 {
295 const char *val;
296 int len;
297 int trycache;
298 long flags, cachetime, kerneltime, exttime;
299 int ret = -1;
300
301 // Initialize globals.
302
303 sysConfigValid = 0;
304 gErrors = 0;
305
306 status = getBootOptions(firstRun);
307 firstRun = NO;
308 if (status == -1) continue;
309
310 status = processBootOptions();
311 if ( status == 1 ) break;
312 if ( status == -1 ) continue;
313
314 // Found and loaded a config file. Proceed with boot.
315
316
317 // Reset cache name.
318 bzero(gCacheNameAdler, sizeof(gCacheNameAdler));
319
320 if ( getValueForKey( kRootDeviceKey, &val, &len ) == YES ) {
321 if (*val == '*') {
322 val++;
323 len--;
324 }
325 strncpy( gCacheNameAdler + 64, val, len );
326 sprintf(gCacheNameAdler + 64 + len, ",%s", bootArgs->bootFile);
327 } else {
328 strcpy(gCacheNameAdler + 64, bootArgs->bootFile);
329 }
330 adler32 = Adler32(gCacheNameAdler, sizeof(gCacheNameAdler));
331
332 if (getValueForKey(kKernelCacheKey, &val, &len) == YES) {
333 strlcpy(gBootKernelCacheFile, val, len+1);
334 } else {
335 sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePath, adler32);
336 }
337
338 // Check for cache file.
339
340
341 trycache = (((gBootMode & kBootModeSafe) == 0) &&
342 (gOverrideKernel == NO) &&
343 (gBootFileType == kBlockDeviceType) &&
344 (gMKextName[0] == '\0') &&
345 (gBootKernelCacheFile[0] != '\0'));
346
347 printf("Loading Darwin/x86\n");
348
349 if (trycache) do {
350
351 // if we haven't found the kernel yet, don't use the cache
352 ret = GetFileInfo(NULL, bootArgs->bootFile, &flags, &kerneltime);
353 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
354 trycache = 0;
355 break;
356 }
357 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
358 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
359 || (cachetime < kerneltime)) {
360 trycache = 0;
361 break;
362 }
363 ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
364 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
365 && (cachetime < exttime)) {
366 trycache = 0;
367 break;
368 }
369 if (kerneltime > exttime) {
370 exttime = kerneltime;
371 }
372 if (cachetime != (exttime + 1)) {
373 trycache = 0;
374 break;
375 }
376 } while (0);
377
378 do {
379 if (trycache) {
380 bootFile = gBootKernelCacheFile;
381 verbose("Loading kernel cache %s\n", bootFile);
382 ret = LoadFile(bootFile);
383 if (ret >= 0) {
384 break;
385 }
386 }
387 bootFile = bootArgs->bootFile;
388 verbose("Loading kernel %s\n", bootFile);
389 ret = LoadFile(bootFile);
390 } while (0);
391
392 clearActivityIndicator();
393 #if DEBUG
394 printf("Pausing...");
395 sleep(8);
396 #endif
397
398 if (ret < 0) {
399 error("Can't find %s\n", bootFile);
400
401 if ( gBootFileType == kBIOSDevTypeFloppy )
402 {
403 // floppy in drive, but failed to load kernel.
404 gBIOSDev = kBIOSDevTypeHardDrive;
405 initKernBootStruct( gBIOSDev );
406 printf("Attempting to load from hard drive...");
407 }
408 else if ( gBootFileType == kNetworkDeviceType )
409 {
410 // Return control back to PXE. Don't unload PXE base code.
411 gUnloadPXEOnExit = 0;
412 break;
413 }
414 } else {
415 /* Won't return if successful. */
416 ret = ExecKernel((void *)kLoadAddr);
417 }
418
419 } /* while(1) */
420
421 if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
422 nbpUnloadBaseCode();
423 }
424 }
425
426 #define BASE 65521L /* largest prime smaller than 65536 */
427 #define NMAX 5000
428 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
429
430 #define DO1(buf,i) {s1 += buf[i]; s2 += s1;}
431 #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
432 #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
433 #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
434 #define DO16(buf) DO8(buf,0); DO8(buf,8);
435
436 unsigned long Adler32(unsigned char *buf, long len)
437 {
438 unsigned long s1 = 1; // adler & 0xffff;
439 unsigned long s2 = 0; // (adler >> 16) & 0xffff;
440 unsigned long result;
441 int k;
442
443 while (len > 0) {
444 k = len < NMAX ? len : NMAX;
445 len -= k;
446 while (k >= 16) {
447 DO16(buf);
448 buf += 16;
449 k -= 16;
450 }
451 if (k != 0) do {
452 s1 += *buf++;
453 s2 += s1;
454 } while (--k);
455 s1 %= BASE;
456 s2 %= BASE;
457 }
458 result = (s2 << 16) | s1;
459 return OSSwapHostToBigInt32(result);
460 }
461