]>
git.saurik.com Git - apple/boot.git/blob - i386/boot2/boot.c
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
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.
33 * INTEL CORPORATION PROPRIETARY INFORMATION
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.
39 * Copyright 1988, 1989 by Intel Corporation
43 * Copyright 1993 NeXT Computer, Inc.
44 * All rights reserved.
48 * Completely reworked by Sam Streeper (sam_s@NeXT.com)
49 * Reworked again by Curtis Galloway (galloway@NeXT.com)
54 #include "bootstruct.h"
59 long gBootMode
; /* defaults to 0 == kBootModeNormal */
61 static char gBootKernelCacheFile
[512];
62 static char gCacheNameAdler
[64 + 256];
63 char *gPlatformName
= gCacheNameAdler
;
68 unsigned long Adler32(unsigned char *buffer
, long length
);
71 static BOOL gUnloadPXEOnExit
= 0;
74 * How long to wait (in seconds) to load the
75 * kernel after displaying the "boot:" prompt.
77 #define kBootErrorTimeout 5
80 * Default path to kernel cache file
82 #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache"
84 //==========================================================================
89 extern char _DATA__bss__begin
, _DATA__bss__end
;
90 extern char _DATA__common__begin
, _DATA__common__end
;
92 bzero( &_DATA__bss__begin
,
93 (&_DATA__bss__end
- &_DATA__bss__begin
) );
95 bzero( &_DATA__common__begin
,
96 (&_DATA__common__end
- &_DATA__common__begin
) );
99 //==========================================================================
100 // Malloc error function
102 static void malloc_error(char *addr
, size_t size
)
104 printf("\nMemory allocation error (0x%x, 0x%x)\n",
105 (unsigned)addr
, (unsigned)size
);
109 //==========================================================================
110 // execKernel - Load the kernel image (mach-o) and jump to its entry point.
112 static int ExecKernel(void *binary
)
118 #endif /* APM_SUPPORT */
121 bootArgs
->kaddr
= bootArgs
->ksize
= 0;
123 ret
= DecodeKernel(binary
,
125 (char **) &bootArgs
->kaddr
,
131 // Reserve space for boot args
132 reserveKernBootStruct();
134 // Load boot drivers from the specifed root path.
136 if (!gHaveKernelCache
) {
140 clearActivityIndicator();
143 printf("Errors encountered while starting up the computer.\n");
144 printf("Pausing %d seconds...\n", kBootErrorTimeout
);
145 sleep(kBootErrorTimeout
);
148 printf("Starting Darwin/x86");
153 // Connect to APM BIOS.
155 if ( getBoolForKey("APM", &apm
) && apm
== YES
)
157 if ( APMPresent() ) APMConnect32();
159 #endif /* APM_SUPPORT */
161 // Cleanup the PXE base code.
163 if ( (gBootFileType
== kNetworkDeviceType
) && gUnloadPXEOnExit
) {
164 if ( (ret
= nbpUnloadBaseCode()) != nbpStatusSuccess
)
166 printf("nbpUnloadBaseCode error %d\n", (int) ret
);
171 // Unless Boot Graphics = No, Always switch to graphics mode
172 // just before starting the kernel.
174 if (!getBoolForKey(kBootGraphicsKey
, &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
);
184 // If we were already in graphics mode, clear the screen.
188 if (bootArgs
->graphicsMode
== GRAPHICS_MODE
) {
189 setVideoMode( TEXT_MODE
);
193 // Jump to kernel's entry point. There's no going back now.
195 startprog( kernelEntry
, bootArgs
);
202 //==========================================================================
203 // Scan and record the system's hardware information.
205 static void scanHardware()
207 extern int ReadPCIBusInfo(PCI_bus_info_t
*);
208 extern void PCI_Bus_Init(PCI_bus_info_t
*);
210 ReadPCIBusInfo( &bootArgs
->pciInfo
);
213 // Initialize PCI matching support in the booter.
214 // Not used, commented out to minimize code size.
216 // PCI_Bus_Init( &bootArgs->pciInfo );
219 //==========================================================================
220 // The 'main' function for the booter. Called by boot0 when booting
221 // from a block device, or by the network booter.
224 // biosdev - Value passed from boot1/NBP to specify the device
225 // that the booter was loaded from.
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.
231 #define DLOG(x) outb(0x80, (x))
233 void boot(int biosdev
)
237 unsigned long adler32
;
246 malloc_init(0, 0, 0, malloc_error
);
248 // Enable A20 gate before accessing memory above 1Mb.
252 // Set reminder to unload the PXE base code. Neglect to unload
253 // the base code will result in a hang or kernel panic.
255 gUnloadPXEOnExit
= 1;
257 // Record the device that the booter was loaded from.
259 gBIOSDev
= biosdev
& kBIOSDevMask
;
261 // Initialize boot info structure.
263 initKernBootStruct( gBIOSDev
);
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.
269 video_mode( 2 ); // 80x25 mono text mode.
271 // Scan hardware configuration.
275 // First get info for boot volume.
276 bvChain
= scanBootVolumes(gBIOSDev
, 0);
278 // Record default boot device.
279 gBootVolume
= selectBootVolume(bvChain
);
280 bootArgs
->kernDev
= MAKEKERNDEV(gBIOSDev
,
281 BIOS_DEV_UNIT(gBootVolume
),
282 gBootVolume
->part_no
);
284 // Load default config file from boot device.
285 status
= loadSystemConfig(0, 0);
287 if ( getBoolForKey( kQuietBootKey
, &quiet
) && quiet
) {
288 gBootMode
|= kBootModeQuiet
;
291 // Parse args, load and start kernel.
298 long flags
, cachetime
, kerneltime
, exttime
;
301 // Initialize globals.
306 status
= getBootOptions(firstRun
);
308 if (status
== -1) continue;
310 status
= processBootOptions();
311 if ( status
== 1 ) break;
312 if ( status
== -1 ) continue;
314 // Found and loaded a config file. Proceed with boot.
318 bzero(gCacheNameAdler
, sizeof(gCacheNameAdler
));
320 if ( getValueForKey( kRootDeviceKey
, &val
, &len
) == YES
) {
325 strncpy( gCacheNameAdler
+ 64, val
, len
);
326 sprintf(gCacheNameAdler
+ 64 + len
, ",%s", bootArgs
->bootFile
);
328 strcpy(gCacheNameAdler
+ 64, bootArgs
->bootFile
);
330 adler32
= Adler32(gCacheNameAdler
, sizeof(gCacheNameAdler
));
332 if (getValueForKey(kKernelCacheKey
, &val
, &len
) == YES
) {
333 strlcpy(gBootKernelCacheFile
, val
, len
+1);
335 sprintf(gBootKernelCacheFile
, "%s.%08lX", kDefaultCachePath
, adler32
);
338 // Check for cache file.
341 trycache
= (((gBootMode
& kBootModeSafe
) == 0) &&
342 (gOverrideKernel
== NO
) &&
343 (gBootFileType
== kBlockDeviceType
) &&
344 (gMKextName
[0] == '\0') &&
345 (gBootKernelCacheFile
[0] != '\0'));
347 printf("Loading Darwin/x86\n");
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
)) {
357 ret
= GetFileInfo(NULL
, gBootKernelCacheFile
, &flags
, &cachetime
);
358 if ((ret
!= 0) || ((flags
& kFileTypeMask
) != kFileTypeFlat
)
359 || (cachetime
< kerneltime
)) {
363 ret
= GetFileInfo("/System/Library/", "Extensions", &flags
, &exttime
);
364 if ((ret
== 0) && ((flags
& kFileTypeMask
) == kFileTypeDirectory
)
365 && (cachetime
< exttime
)) {
369 if (kerneltime
> exttime
) {
370 exttime
= kerneltime
;
372 if (cachetime
!= (exttime
+ 1)) {
380 bootFile
= gBootKernelCacheFile
;
381 verbose("Loading kernel cache %s\n", bootFile
);
382 ret
= LoadFile(bootFile
);
387 bootFile
= bootArgs
->bootFile
;
388 verbose("Loading kernel %s\n", bootFile
);
389 ret
= LoadFile(bootFile
);
392 clearActivityIndicator();
394 printf("Pausing...");
399 error("Can't find %s\n", bootFile
);
401 if ( gBootFileType
== kBIOSDevTypeFloppy
)
403 // floppy in drive, but failed to load kernel.
404 gBIOSDev
= kBIOSDevTypeHardDrive
;
405 initKernBootStruct( gBIOSDev
);
406 printf("Attempting to load from hard drive...");
408 else if ( gBootFileType
== kNetworkDeviceType
)
410 // Return control back to PXE. Don't unload PXE base code.
411 gUnloadPXEOnExit
= 0;
415 /* Won't return if successful. */
416 ret
= ExecKernel((void *)kLoadAddr
);
421 if ((gBootFileType
== kNetworkDeviceType
) && gUnloadPXEOnExit
) {
426 #define BASE 65521L /* largest prime smaller than 65536 */
428 // NMAX (was 5521) the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
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);
436 unsigned long Adler32(unsigned char *buf
, long len
)
438 unsigned long s1
= 1; // adler & 0xffff;
439 unsigned long s2
= 0; // (adler >> 16) & 0xffff;
440 unsigned long result
;
444 k
= len
< NMAX
? len
: NMAX
;
458 result
= (s2
<< 16) | s1
;
459 return OSSwapHostToBigInt32(result
);