]>
Commit | Line | Data |
---|---|---|
14c7c974 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
f083c6c3 A |
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. | |
14c7c974 A |
14 | * |
15 | * The Original Code and all software distributed under the License are | |
f083c6c3 | 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
14c7c974 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
f083c6c3 A |
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. | |
14c7c974 A |
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 | */ | |
75b89a82 | 52 | |
14c7c974 | 53 | #include "boot.h" |
f083c6c3 A |
54 | #include "bootstruct.h" |
55 | #include "sl.h" | |
14c7c974 | 56 | |
14c7c974 A |
57 | /* |
58 | * The user asked for boot graphics. | |
59 | */ | |
75b89a82 | 60 | BOOL gBootGraphics = NO; |
75b89a82 | 61 | long gBootMode = kBootModeNormal; |
f083c6c3 | 62 | static char gBootKernelCacheFile[512]; |
14c7c974 | 63 | |
75b89a82 | 64 | static BOOL gUnloadPXEOnExit = 0; |
14c7c974 A |
65 | |
66 | /* | |
47b0a8bd A |
67 | * How long to wait (in seconds) to load the |
68 | * kernel after displaying the "boot:" prompt. | |
14c7c974 | 69 | */ |
75b89a82 | 70 | #define kBootErrorTimeout 5 |
14c7c974 | 71 | |
f083c6c3 A |
72 | /* |
73 | * Default path to kernel cache file | |
74 | */ | |
75 | #define kDefaultCachePath "/System/Library/Caches/com.apple.kernelcaches/kernelcache" | |
76 | ||
14c7c974 A |
77 | //========================================================================== |
78 | // Zero the BSS. | |
79 | ||
75b89a82 | 80 | static void zeroBSS() |
14c7c974 A |
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) ); | |
47b0a8bd | 87 | |
14c7c974 A |
88 | bzero( &_DATA__common__begin, |
89 | (&_DATA__common__end - &_DATA__common__begin) ); | |
90 | } | |
91 | ||
f083c6c3 A |
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 | ||
14c7c974 | 102 | //========================================================================== |
47b0a8bd | 103 | // execKernel - Load the kernel image (mach-o) and jump to its entry point. |
14c7c974 | 104 | |
f083c6c3 | 105 | static int ExecKernel(void *binary) |
14c7c974 | 106 | { |
14c7c974 | 107 | entry_t kernelEntry; |
47b0a8bd A |
108 | int ret; |
109 | ||
f083c6c3 | 110 | bootArgs->kaddr = bootArgs->ksize = 0; |
47b0a8bd | 111 | |
f083c6c3 A |
112 | ret = DecodeKernel(binary, |
113 | &kernelEntry, | |
114 | (char **) &bootArgs->kaddr, | |
115 | &bootArgs->ksize ); | |
14c7c974 A |
116 | |
117 | if ( ret != 0 ) | |
118 | return ret; | |
119 | ||
f083c6c3 A |
120 | // Reserve space for boot args |
121 | reserveKernBootStruct(); | |
122 | ||
75b89a82 | 123 | // Load boot drivers from the specifed root path. |
14c7c974 | 124 | |
f083c6c3 A |
125 | if (!gHaveKernelCache) { |
126 | LoadDrivers("/"); | |
127 | } | |
128 | ||
14c7c974 | 129 | clearActivityIndicator(); |
14c7c974 | 130 | |
75b89a82 | 131 | if (gErrors) { |
14c7c974 | 132 | printf("Errors encountered while starting up the computer.\n"); |
75b89a82 A |
133 | printf("Pausing %d seconds...\n", kBootErrorTimeout); |
134 | sleep(kBootErrorTimeout); | |
14c7c974 A |
135 | } |
136 | ||
75b89a82 | 137 | printf("Starting Darwin/x86"); |
14c7c974 A |
138 | |
139 | turnOffFloppy(); | |
140 | ||
47b0a8bd A |
141 | // Connect to APM BIOS. |
142 | ||
14c7c974 A |
143 | if ( getBoolForKey("APM") ) |
144 | { | |
145 | if ( APMPresent() ) APMConnect32(); | |
146 | } | |
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 | ||
75b89a82 | 158 | // Switch to desired video mode just before starting the kernel. |
14c7c974 | 159 | |
75b89a82 | 160 | setVideoMode( gBootGraphics ? GRAPHICS_MODE : TEXT_MODE ); |
14c7c974 A |
161 | |
162 | // Jump to kernel's entry point. There's no going back now. | |
163 | ||
f083c6c3 | 164 | startprog( kernelEntry, bootArgs ); |
14c7c974 A |
165 | |
166 | // Not reached | |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
171 | //========================================================================== | |
75b89a82 | 172 | // Scan and record the system's hardware information. |
14c7c974 A |
173 | |
174 | static void scanHardware() | |
175 | { | |
75b89a82 A |
176 | extern int ReadPCIBusInfo(PCI_bus_info_t *); |
177 | extern void PCI_Bus_Init(PCI_bus_info_t *); | |
14c7c974 | 178 | |
f083c6c3 | 179 | ReadPCIBusInfo( &bootArgs->pciInfo ); |
75b89a82 A |
180 | |
181 | // | |
182 | // Initialize PCI matching support in the booter. | |
183 | // Not used, commented out to minimize code size. | |
184 | // | |
f083c6c3 | 185 | // PCI_Bus_Init( &bootArgs->pciInfo ); |
14c7c974 A |
186 | } |
187 | ||
188 | //========================================================================== | |
75b89a82 A |
189 | // The 'main' function for the booter. Called by boot0 when booting |
190 | // from a block device, or by the network booter. | |
14c7c974 A |
191 | // |
192 | // arguments: | |
75b89a82 A |
193 | // biosdev - Value passed from boot1/NBP to specify the device |
194 | // that the booter was loaded from. | |
14c7c974 | 195 | // |
75b89a82 | 196 | // If biosdev is kBIOSDevNetwork, then this function will return if |
14c7c974 | 197 | // booting was unsuccessful. This allows the PXE firmware to try the |
75b89a82 | 198 | // next boot device on its list. |
14c7c974 | 199 | |
75b89a82 | 200 | void boot(int biosdev) |
14c7c974 | 201 | { |
75b89a82 | 202 | int status; |
f083c6c3 | 203 | char *bootFile; |
14c7c974 A |
204 | |
205 | zeroBSS(); | |
206 | ||
f083c6c3 A |
207 | // Initialize malloc |
208 | ||
209 | malloc_init(0, 0, 0, malloc_error); | |
210 | ||
47b0a8bd | 211 | // Enable A20 gate before accessing memory above 1Mb. |
14c7c974 A |
212 | |
213 | enableA20(); | |
214 | ||
75b89a82 A |
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 | ||
75b89a82 | 218 | gUnloadPXEOnExit = 1; |
14c7c974 | 219 | |
75b89a82 A |
220 | // Record the device that the booter was loaded from. |
221 | ||
222 | gBIOSDev = biosdev & kBIOSDevMask; | |
14c7c974 A |
223 | |
224 | // Initialize boot info structure. | |
225 | ||
75b89a82 | 226 | initKernBootStruct( gBIOSDev ); |
14c7c974 A |
227 | |
228 | // Setup VGA text mode. | |
75b89a82 A |
229 | // Not sure if it is safe to call setVideoMode() before the |
230 | // config table has been loaded. Call video_mode() instead. | |
14c7c974 | 231 | |
75b89a82 | 232 | video_mode( 2 ); // 80x25 mono text mode. |
14c7c974 | 233 | |
14c7c974 A |
234 | // Scan hardware configuration. |
235 | ||
236 | scanHardware(); | |
237 | ||
75b89a82 | 238 | // Display banner and show hardware info. |
14c7c974 | 239 | |
75b89a82 | 240 | setCursorPosition( 0, 0, 0 ); |
f083c6c3 | 241 | printf( bootBanner, bootArgs->convmem, bootArgs->extmem ); |
75b89a82 | 242 | printVBEInfo(); |
14c7c974 A |
243 | |
244 | // Parse args, load and start kernel. | |
245 | ||
246 | while (1) | |
247 | { | |
f083c6c3 A |
248 | const char *val; |
249 | int len, trycache; | |
250 | long flags, cachetime, time; | |
251 | int ret = -1; | |
252 | ||
14c7c974 A |
253 | // Initialize globals. |
254 | ||
47b0a8bd | 255 | sysConfigValid = 0; |
75b89a82 | 256 | gErrors = 0; |
14c7c974 | 257 | |
f083c6c3 A |
258 | // Reset config space. |
259 | bootArgs->configEnd = bootArgs->config; | |
260 | ||
75b89a82 A |
261 | getBootOptions(); |
262 | status = processBootOptions(); | |
263 | if ( status == 1 ) break; | |
264 | if ( status == -1 ) continue; | |
14c7c974 A |
265 | |
266 | // Found and loaded a config file. Proceed with boot. | |
267 | ||
f083c6c3 | 268 | // Check for cache file. |
14c7c974 | 269 | |
f083c6c3 A |
270 | if (getValueForKey(kKernelCacheKey, &val, &len)) { |
271 | strncpy(gBootKernelCacheFile, val, len); | |
272 | gBootKernelCacheFile[len] = '\0'; | |
273 | } else { | |
274 | strcpy(gBootKernelCacheFile, kDefaultCachePath); | |
14c7c974 | 275 | } |
14c7c974 | 276 | |
f083c6c3 A |
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 ) | |
14c7c974 A |
325 | { |
326 | // floppy in drive, but failed to load kernel. | |
75b89a82 A |
327 | gBIOSDev = kBIOSDevTypeHardDrive; |
328 | initKernBootStruct( gBIOSDev ); | |
329 | printf("Attempt to load from hard drive."); | |
14c7c974 | 330 | } |
f083c6c3 | 331 | else if ( gBootFileType == kNetworkDeviceType ) |
14c7c974 | 332 | { |
75b89a82 A |
333 | // Return control back to PXE. Don't unload PXE base code. |
334 | gUnloadPXEOnExit = 0; | |
335 | break; | |
14c7c974 | 336 | } |
f083c6c3 A |
337 | } else { |
338 | /* Won't return if successful. */ | |
339 | ret = ExecKernel((void *)kLoadAddr); | |
14c7c974 | 340 | } |
f083c6c3 | 341 | |
14c7c974 | 342 | } /* while(1) */ |
75b89a82 | 343 | |
f083c6c3 A |
344 | if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) { |
345 | nbpUnloadBaseCode(); | |
346 | } | |
14c7c974 | 347 | } |