]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/boot.c
fbd37ca11135fa8ef8e02584a9a70f0b43a0fc7b
[apple/boot.git] / i386 / boot2 / boot.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Mach Operating System
27 * Copyright (c) 1990 Carnegie-Mellon University
28 * Copyright (c) 1989 Carnegie-Mellon University
29 * All rights reserved. The CMU software License Agreement specifies
30 * the terms and conditions for use and redistribution.
31 */
32
33 /*
34 * INTEL CORPORATION PROPRIETARY INFORMATION
35 *
36 * This software is supplied under the terms of a license agreement or
37 * nondisclosure agreement with Intel Corporation and may not be copied
38 * nor disclosed except in accordance with the terms of that agreement.
39 *
40 * Copyright 1988, 1989 by Intel Corporation
41 */
42
43 /*
44 * Copyright 1993 NeXT Computer, Inc.
45 * All rights reserved.
46 */
47
48 /*
49 * Completely reworked by Sam Streeper (sam_s@NeXT.com)
50 * Reworked again by Curtis Galloway (galloway@NeXT.com)
51 */
52
53 #include "boot.h"
54 #include "bootstruct.h"
55 #include "sl.h"
56
57 /*
58 * The user asked for boot graphics.
59 */
60 BOOL gBootGraphics = NO;
61 long gBootMode = kBootModeNormal;
62 static char gBootKernelCacheFile[512];
63
64 static BOOL gUnloadPXEOnExit = 0;
65
66 /*
67 * How long to wait (in seconds) to load the
68 * kernel after displaying the "boot:" prompt.
69 */
70 #define kBootErrorTimeout 5
71
72 /*
73 * Default path to kernel cache file
74 */
75 #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache"
76
77 //==========================================================================
78 // Zero the BSS.
79
80 static void zeroBSS()
81 {
82 extern char _DATA__bss__begin, _DATA__bss__end;
83 extern char _DATA__common__begin, _DATA__common__end;
84
85 bzero( &_DATA__bss__begin,
86 (&_DATA__bss__end - &_DATA__bss__begin) );
87
88 bzero( &_DATA__common__begin,
89 (&_DATA__common__end - &_DATA__common__begin) );
90 }
91
92 //==========================================================================
93 // Malloc error function
94
95 static void malloc_error(char *addr, size_t size)
96 {
97 printf("\nMemory allocation error (0x%x, 0x%x)\n",
98 (unsigned)addr, (unsigned)size);
99 asm("hlt");
100 }
101
102 //==========================================================================
103 // execKernel - Load the kernel image (mach-o) and jump to its entry point.
104
105 static int ExecKernel(void *binary)
106 {
107 entry_t kernelEntry;
108 int ret;
109
110 bootArgs->kaddr = bootArgs->ksize = 0;
111
112 ret = DecodeKernel(binary,
113 &kernelEntry,
114 (char **) &bootArgs->kaddr,
115 &bootArgs->ksize );
116
117 if ( ret != 0 )
118 return ret;
119
120 // Reserve space for boot args
121 reserveKernBootStruct();
122
123 // Load boot drivers from the specifed root path.
124
125 if (!gHaveKernelCache) {
126 LoadDrivers("/");
127 }
128
129 clearActivityIndicator();
130
131 if (gErrors) {
132 printf("Errors encountered while starting up the computer.\n");
133 printf("Pausing %d seconds...\n", kBootErrorTimeout);
134 sleep(kBootErrorTimeout);
135 }
136
137 printf("Starting Darwin/x86");
138
139 turnOffFloppy();
140
141 // Connect to APM BIOS.
142
143 if ( getBoolForKey("APM") )
144 {
145 if ( APMPresent() ) APMConnect32();
146 }
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 // Switch to desired video mode just before starting the kernel.
159
160 setVideoMode( gBootGraphics ? GRAPHICS_MODE : TEXT_MODE );
161
162 // Jump to kernel's entry point. There's no going back now.
163
164 startprog( kernelEntry, bootArgs );
165
166 // Not reached
167
168 return 0;
169 }
170
171 //==========================================================================
172 // Scan and record the system's hardware information.
173
174 static void scanHardware()
175 {
176 extern int ReadPCIBusInfo(PCI_bus_info_t *);
177 extern void PCI_Bus_Init(PCI_bus_info_t *);
178
179 ReadPCIBusInfo( &bootArgs->pciInfo );
180
181 //
182 // Initialize PCI matching support in the booter.
183 // Not used, commented out to minimize code size.
184 //
185 // PCI_Bus_Init( &bootArgs->pciInfo );
186 }
187
188 //==========================================================================
189 // The 'main' function for the booter. Called by boot0 when booting
190 // from a block device, or by the network booter.
191 //
192 // arguments:
193 // biosdev - Value passed from boot1/NBP to specify the device
194 // that the booter was loaded from.
195 //
196 // If biosdev is kBIOSDevNetwork, then this function will return if
197 // booting was unsuccessful. This allows the PXE firmware to try the
198 // next boot device on its list.
199
200 void boot(int biosdev)
201 {
202 int status;
203 char *bootFile;
204
205 zeroBSS();
206
207 // Initialize malloc
208
209 malloc_init(0, 0, 0, malloc_error);
210
211 // Enable A20 gate before accessing memory above 1Mb.
212
213 enableA20();
214
215 // Set reminder to unload the PXE base code. Neglect to unload
216 // the base code will result in a hang or kernel panic.
217
218 gUnloadPXEOnExit = 1;
219
220 // Record the device that the booter was loaded from.
221
222 gBIOSDev = biosdev & kBIOSDevMask;
223
224 // Initialize boot info structure.
225
226 initKernBootStruct( gBIOSDev );
227
228 // Setup VGA text mode.
229 // Not sure if it is safe to call setVideoMode() before the
230 // config table has been loaded. Call video_mode() instead.
231
232 video_mode( 2 ); // 80x25 mono text mode.
233
234 // Scan hardware configuration.
235
236 scanHardware();
237
238 // Display banner and show hardware info.
239
240 setCursorPosition( 0, 0, 0 );
241 printf( bootBanner, bootArgs->convmem, bootArgs->extmem );
242 printVBEInfo();
243
244 // Parse args, load and start kernel.
245
246 while (1)
247 {
248 const char *val;
249 int len, trycache;
250 long flags, cachetime, time;
251 int ret = -1;
252
253 // Initialize globals.
254
255 sysConfigValid = 0;
256 gErrors = 0;
257
258 // Reset config space.
259 bootArgs->configEnd = bootArgs->config;
260
261 getBootOptions();
262 status = processBootOptions();
263 if ( status == 1 ) break;
264 if ( status == -1 ) continue;
265
266 // Found and loaded a config file. Proceed with boot.
267
268 // Check for cache file.
269
270 if (getValueForKey(kKernelCacheKey, &val, &len)) {
271 strncpy(gBootKernelCacheFile, val, len);
272 gBootKernelCacheFile[len] = '\0';
273 } else {
274 strcpy(gBootKernelCacheFile, kDefaultCachePath);
275 }
276
277 trycache = (((gBootMode & kBootModeSafe) == 0) &&
278 (gBootFileType == kBlockDeviceType) &&
279 (gBootKernelCacheFile[0] != '\0'));
280
281 printf("Loading Darwin/x86\n");
282
283 if (trycache) do {
284
285 // if we haven't found the kernel yet, don't use the cache
286 ret = GetFileInfo(NULL, bootArgs->bootFile, &flags, &time);
287 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
288 trycache = 0;
289 break;
290 }
291 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
292 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
293 || (cachetime < time)) {
294 trycache = 0;
295 break;
296 }
297 ret = GetFileInfo("/System/Library/", "Extensions", &flags, &time);
298 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
299 && (cachetime < time)) {
300 trycache = 0;
301 break;
302 }
303 } while (0);
304
305 do {
306 if (trycache) {
307 bootFile = gBootKernelCacheFile;
308 verbose("Loading kernel cache %s\n", bootFile);
309 ret = LoadFile(bootFile);
310 if (ret >= 0) {
311 break;
312 }
313 }
314 bootFile = bootArgs->bootFile;
315 verbose("Loading kernel %s\n", bootFile);
316 ret = LoadFile(bootFile);
317 } while (0);
318
319 clearActivityIndicator();
320
321 if (ret < 0) {
322 error("Can't find %s\n", bootFile);
323
324 if ( gBootFileType == kBIOSDevTypeFloppy )
325 {
326 // floppy in drive, but failed to load kernel.
327 gBIOSDev = kBIOSDevTypeHardDrive;
328 initKernBootStruct( gBIOSDev );
329 printf("Attempt to load from hard drive.");
330 }
331 else if ( gBootFileType == kNetworkDeviceType )
332 {
333 // Return control back to PXE. Don't unload PXE base code.
334 gUnloadPXEOnExit = 0;
335 break;
336 }
337 } else {
338 /* Won't return if successful. */
339 ret = ExecKernel((void *)kLoadAddr);
340 }
341
342 } /* while(1) */
343
344 if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
345 nbpUnloadBaseCode();
346 }
347 }