]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/boot.c
48145f415d0635a303eee2fabc88e948bb854c07
[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 * Portions Copyright (c) 1999 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 1.1 (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 #include "boot.h"
53 #include "bootstruct.h"
54 #include "sl.h"
55
56 /*
57 * The user asked for boot graphics.
58 */
59 BOOL gBootGraphics = NO;
60 long gBootMode = kBootModeNormal;
61 static char gBootKernelCacheFile[512];
62
63 static BOOL gUnloadPXEOnExit = 0;
64
65 /*
66 * How long to wait (in seconds) to load the
67 * kernel after displaying the "boot:" prompt.
68 */
69 #define kBootErrorTimeout 5
70
71 /*
72 * Default path to kernel cache file
73 */
74 #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache"
75
76 //==========================================================================
77 // Zero the BSS.
78
79 static void zeroBSS()
80 {
81 extern char _DATA__bss__begin, _DATA__bss__end;
82 extern char _DATA__common__begin, _DATA__common__end;
83
84 bzero( &_DATA__bss__begin,
85 (&_DATA__bss__end - &_DATA__bss__begin) );
86
87 bzero( &_DATA__common__begin,
88 (&_DATA__common__end - &_DATA__common__begin) );
89 }
90
91 //==========================================================================
92 // Malloc error function
93
94 static void malloc_error(char *addr, size_t size)
95 {
96 printf("\nMemory allocation error (0x%x, 0x%x)\n",
97 (unsigned)addr, (unsigned)size);
98 asm("hlt");
99 }
100
101 //==========================================================================
102 // execKernel - Load the kernel image (mach-o) and jump to its entry point.
103
104 static int ExecKernel(void *binary)
105 {
106 entry_t kernelEntry;
107 int ret;
108
109 bootArgs->kaddr = bootArgs->ksize = 0;
110
111 ret = DecodeKernel(binary,
112 &kernelEntry,
113 (char **) &bootArgs->kaddr,
114 &bootArgs->ksize );
115
116 if ( ret != 0 )
117 return ret;
118
119 // Reserve space for boot args
120 reserveKernBootStruct();
121
122 // Load boot drivers from the specifed root path.
123
124 if (!gHaveKernelCache) {
125 LoadDrivers("/");
126 }
127
128 clearActivityIndicator();
129
130 if (gErrors) {
131 printf("Errors encountered while starting up the computer.\n");
132 printf("Pausing %d seconds...\n", kBootErrorTimeout);
133 sleep(kBootErrorTimeout);
134 }
135
136 printf("Starting Darwin/x86");
137
138 turnOffFloppy();
139
140 // Connect to APM BIOS.
141
142 if ( getBoolForKey("APM") )
143 {
144 if ( APMPresent() ) APMConnect32();
145 }
146
147 // Cleanup the PXE base code.
148
149 if ( (gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit ) {
150 if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
151 {
152 printf("nbpUnloadBaseCode error %d\n", (int) ret);
153 sleep(2);
154 }
155 }
156
157 // Switch to desired video mode just before starting the kernel.
158
159 setVideoMode( gBootGraphics ? GRAPHICS_MODE : TEXT_MODE );
160
161 // Jump to kernel's entry point. There's no going back now.
162
163 startprog( kernelEntry, bootArgs );
164
165 // Not reached
166
167 return 0;
168 }
169
170 //==========================================================================
171 // Scan and record the system's hardware information.
172
173 static void scanHardware()
174 {
175 extern int ReadPCIBusInfo(PCI_bus_info_t *);
176 extern void PCI_Bus_Init(PCI_bus_info_t *);
177
178 ReadPCIBusInfo( &bootArgs->pciInfo );
179
180 //
181 // Initialize PCI matching support in the booter.
182 // Not used, commented out to minimize code size.
183 //
184 // PCI_Bus_Init( &bootArgs->pciInfo );
185 }
186
187 //==========================================================================
188 // The 'main' function for the booter. Called by boot0 when booting
189 // from a block device, or by the network booter.
190 //
191 // arguments:
192 // biosdev - Value passed from boot1/NBP to specify the device
193 // that the booter was loaded from.
194 //
195 // If biosdev is kBIOSDevNetwork, then this function will return if
196 // booting was unsuccessful. This allows the PXE firmware to try the
197 // next boot device on its list.
198
199 void boot(int biosdev)
200 {
201 int status;
202 char *bootFile;
203
204 zeroBSS();
205
206 // Initialize malloc
207
208 malloc_init(0, 0, 0, malloc_error);
209
210 // Enable A20 gate before accessing memory above 1Mb.
211
212 enableA20();
213
214 // Set reminder to unload the PXE base code. Neglect to unload
215 // the base code will result in a hang or kernel panic.
216
217 gUnloadPXEOnExit = 1;
218
219 // Record the device that the booter was loaded from.
220
221 gBIOSDev = biosdev & kBIOSDevMask;
222
223 // Initialize boot info structure.
224
225 initKernBootStruct( gBIOSDev );
226
227 // Setup VGA text mode.
228 // Not sure if it is safe to call setVideoMode() before the
229 // config table has been loaded. Call video_mode() instead.
230
231 video_mode( 2 ); // 80x25 mono text mode.
232
233 // Scan hardware configuration.
234
235 scanHardware();
236
237 // Display banner and show hardware info.
238
239 setCursorPosition( 0, 0, 0 );
240 printf( bootBanner, bootArgs->convmem, bootArgs->extmem );
241 printVBEInfo();
242
243 // Parse args, load and start kernel.
244
245 while (1)
246 {
247 const char *val;
248 int len, trycache;
249 long flags, cachetime, time;
250 int ret = -1;
251
252 // Initialize globals.
253
254 sysConfigValid = 0;
255 gErrors = 0;
256
257 // Reset config space.
258 bootArgs->configEnd = bootArgs->config;
259
260 getBootOptions();
261 status = processBootOptions();
262 if ( status == 1 ) break;
263 if ( status == -1 ) continue;
264
265 // Found and loaded a config file. Proceed with boot.
266
267 // Check for cache file.
268
269 if (getValueForKey(kKernelCacheKey, &val, &len)) {
270 strncpy(gBootKernelCacheFile, val, len);
271 gBootKernelCacheFile[len] = '\0';
272 } else {
273 strcpy(gBootKernelCacheFile, kDefaultCachePath);
274 }
275
276 trycache = (((gBootMode & kBootModeSafe) == 0) &&
277 (gBootFileType == kBlockDeviceType) &&
278 (gBootKernelCacheFile[0] != '\0'));
279
280 printf("Loading Darwin/x86\n");
281
282 if (trycache) do {
283
284 // if we haven't found the kernel yet, don't use the cache
285 ret = GetFileInfo(NULL, bootArgs->bootFile, &flags, &time);
286 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
287 trycache = 0;
288 break;
289 }
290 ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
291 if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
292 || (cachetime < time)) {
293 trycache = 0;
294 break;
295 }
296 ret = GetFileInfo("/System/Library/", "Extensions", &flags, &time);
297 if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
298 && (cachetime < time)) {
299 trycache = 0;
300 break;
301 }
302 } while (0);
303
304 do {
305 if (trycache) {
306 bootFile = gBootKernelCacheFile;
307 verbose("Loading kernel cache %s\n", bootFile);
308 ret = LoadFile(bootFile);
309 if (ret >= 0) {
310 break;
311 }
312 }
313 bootFile = bootArgs->bootFile;
314 verbose("Loading kernel %s\n", bootFile);
315 ret = LoadFile(bootFile);
316 } while (0);
317
318 clearActivityIndicator();
319
320 if (ret < 0) {
321 error("Can't find %s\n", bootFile);
322
323 if ( gBootFileType == kBIOSDevTypeFloppy )
324 {
325 // floppy in drive, but failed to load kernel.
326 gBIOSDev = kBIOSDevTypeHardDrive;
327 initKernBootStruct( gBIOSDev );
328 printf("Attempt to load from hard drive.");
329 }
330 else if ( gBootFileType == kNetworkDeviceType )
331 {
332 // Return control back to PXE. Don't unload PXE base code.
333 gUnloadPXEOnExit = 0;
334 break;
335 }
336 } else {
337 /* Won't return if successful. */
338 ret = ExecKernel((void *)kLoadAddr);
339 }
340
341 } /* while(1) */
342
343 if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
344 nbpUnloadBaseCode();
345 }
346 }