]> git.saurik.com Git - apple/boot.git/blame - i386/boot2/boot.c
boot-132.tar.gz
[apple/boot.git] / i386 / boot2 / boot.c
CommitLineData
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
59long gBootMode; /* defaults to 0 == kBootModeNormal */
60BOOL gOverrideKernel;
f083c6c3 61static char gBootKernelCacheFile[512];
57c72a9a
A
62static char gCacheNameAdler[64 + 256];
63char *gPlatformName = gCacheNameAdler;
bba600dd 64char gRootDevice[512];
57c72a9a
A
65char gMKextName[512];
66BVRef gBootVolume;
67
68static
69unsigned long Adler32(unsigned char *buffer, long length);
70
14c7c974 71
75b89a82 72static 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 88static 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
103static 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 113static 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
196static 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 224void 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
423unsigned 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