]> git.saurik.com Git - apple/boot.git/blob - i386/boot2/boot.c
boot-83.2.tar.gz
[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 #include "libsa.h"
52 #include "memory.h"
53 #include "saio.h"
54 #include "libsaio.h"
55 #include "kernBootStruct.h"
56 #include "boot.h"
57 #include "nbp.h"
58
59 /*
60 * The user asked for boot graphics.
61 */
62 static BOOL gWantBootGraphics = NO;
63
64 /*
65 * The device that the booter was loaded from.
66 */
67 int gBootDev;
68
69 extern char * gFilename;
70 extern BOOL sysConfigValid;
71 extern char bootPrompt[];
72 extern BOOL errors;
73 extern BOOL gVerboseMode;
74 extern BOOL gSilentBoot;
75
76 /*
77 * Prototypes.
78 */
79 static void getBootString();
80
81 /*
82 * How long to wait (in seconds) to load the
83 * kernel after displaying the "boot:" prompt.
84 */
85 #define kBootTimeout 10
86
87 //==========================================================================
88 // Zero the BSS.
89
90 static void
91 zeroBSS()
92 {
93 extern char _DATA__bss__begin, _DATA__bss__end;
94 extern char _DATA__common__begin, _DATA__common__end;
95
96 bzero( &_DATA__bss__begin,
97 (&_DATA__bss__end - &_DATA__bss__begin) );
98
99 bzero( &_DATA__common__begin,
100 (&_DATA__common__end - &_DATA__common__begin) );
101 }
102
103 //==========================================================================
104 // execKernel - Load the kernel image (mach-o) and jump to its entry point.
105
106 static int
107 execKernel(int fd)
108 {
109 register KERNBOOTSTRUCT * kbp = kernBootStruct;
110 static struct mach_header head;
111 entry_t kernelEntry;
112 int ret;
113
114 verbose("Loading kernel %s\n", kbp->bootFile);
115
116 // Perform the actual load.
117
118 kbp->kaddr = kbp->ksize = 0;
119
120 ret = loadprog( kbp->kernDev,
121 fd,
122 &head,
123 &kernelEntry,
124 (char **) &kbp->kaddr,
125 &kbp->ksize );
126 close(fd);
127 clearActivityIndicator();
128
129 if ( ret != 0 )
130 return ret;
131
132 // Load boot drivers from the specifed root.
133
134 LoadDrivers("/");
135 clearActivityIndicator();
136
137 if (errors) {
138 printf("Errors encountered while starting up the computer.\n");
139 printf("Pausing %d seconds...\n", kBootTimeout);
140 sleep(kBootTimeout);
141 }
142
143 message("Starting Darwin/x86", 0);
144
145 turnOffFloppy();
146
147 // Connect to APM BIOS.
148
149 if ( getBoolForKey("APM") )
150 {
151 if ( APMPresent() ) APMConnect32();
152 }
153
154 // Cleanup the PXE base code.
155
156 if ( gBootDev == kBootDevNetwork )
157 {
158 if ( (ret = nbpUnloadBaseCode()) != nbpStatusSuccess )
159 {
160 printf("nbpUnloadBaseCode error %d\n", (int) ret); sleep(2);
161 }
162 }
163
164 // Switch to graphics mode just before starting the kernel.
165
166 if ( gWantBootGraphics )
167 {
168 setMode(GRAPHICS_MODE);
169 }
170
171 // Jump to kernel's entry point. There's no going back now.
172
173 startprog(kernelEntry);
174
175 // Not reached
176
177 return 0;
178 }
179
180 //==========================================================================
181 // Scan and record the system's PCI bus information.
182
183 static void scanHardware()
184 {
185 extern int ReadPCIBusInfo(PCI_bus_info_t *);
186 extern void PCI_Bus_Init(PCI_bus_info_t *);
187
188 ReadPCIBusInfo( &kernBootStruct->pciInfo );
189 PCI_Bus_Init( &kernBootStruct->pciInfo );
190 }
191
192 //==========================================================================
193 // The 'main' function for the booter. This function is called by the
194 // assembly routine init(), which is in turn called by boot1 or by
195 // NBP.
196 //
197 // arguments:
198 // bootdev - Value passed from boot1/NBP to specify the device
199 // that the booter was loaded from. See boot.h for the list
200 // of allowable values.
201 //
202 // If bootdev is kBootDevNetwork, then this function will return if
203 // booting was unsuccessful. This allows the PXE firmware to try the
204 // next bootable device on its list. If bootdev is not kBootDevNetwork,
205 // this function will not return control back to the caller.
206
207 void
208 boot(int bootdev)
209 {
210 register KERNBOOTSTRUCT * kbp = kernBootStruct;
211 int fd;
212
213 zeroBSS();
214
215 // Enable A20 gate before accessing memory above 1Mb.
216
217 enableA20();
218
219 // Remember the device that the booter was loaded from.
220
221 gBootDev = bootdev;
222
223 // Initialize boot info structure.
224
225 initKernBootStruct();
226
227 // Setup VGA text mode.
228
229 setMode(TEXT_MODE);
230
231 // Scan hardware configuration.
232
233 scanHardware();
234
235 // Display boot prompt.
236
237 printf( bootPrompt, kbp->convmem, kbp->extmem, kBootTimeout );
238
239 // Parse args, load and start kernel.
240
241 while (1)
242 {
243 // Initialize globals.
244
245 sysConfigValid = 0;
246 errors = 0;
247
248 // Make sure we are in VGA text mode.
249
250 setMode(TEXT_MODE);
251
252 // Set up kbp->kernDev to reflect the boot device.
253
254 if ( bootdev == kBootDevHardDisk )
255 {
256 if (kbp->numIDEs > 0)
257 {
258 kbp->kernDev = DEV_HD;
259 }
260 else
261 {
262 kbp->kernDev = DEV_SD;
263 }
264 }
265 else if ( bootdev == kBootDevFloppyDisk )
266 {
267 kbp->kernDev = DEV_FLOPPY;
268 }
269 else
270 {
271 kbp->kernDev = DEV_EN;
272 }
273 flushdev();
274
275 // Display boot prompt and get user supplied boot string.
276
277 getBootString();
278
279 if ( bootdev != kBootDevNetwork )
280 {
281 // To force loading config file off same device as kernel,
282 // open kernel file to force device change if necessary.
283
284 fd = open(kbp->bootFile, 0);
285 if (fd >= 0) close(fd);
286 }
287
288 if ( sysConfigValid == 0 )
289 {
290 if (kbp->kernDev == DEV_EN)
291 break; // return control back to PXE
292 else
293 continue; // keep looping
294 }
295
296 // Found and loaded a config file. Proceed with boot.
297
298 gWantBootGraphics = getBoolForKey( kBootGraphicsKey );
299 gSilentBoot = getBoolForKey( kQuietBootKey );
300
301 message("Loading Darwin/x86", 0);
302
303 if ( (fd = openfile(kbp->bootFile, 0)) >= 0 )
304 {
305 execKernel(fd); // will not return on success
306 }
307 else
308 {
309 error("Can't find %s\n", kbp->bootFile);
310
311 if ( bootdev == kBootDevFloppyDisk )
312 {
313 // floppy in drive, but failed to load kernel.
314 bootdev = kBootDevHardDisk;
315 message("Couldn't start up the computer using this "
316 "floppy disk.", 0);
317 }
318 else if ( bootdev == kBootDevNetwork )
319 {
320 break; // Return control back to PXE.
321 }
322 }
323 } /* while(1) */
324 }
325
326 //==========================================================================
327 // Skip spaces/tabs characters.
328
329 static inline void
330 skipblanks(char ** cp)
331 {
332 while ( **(cp) == ' ' || **(cp) == '\t' )
333 ++(*cp);
334 }
335
336 //==========================================================================
337 // Load the help file and display the file contents on the screen.
338
339 static void showHelp()
340 {
341 #define BOOT_DIR_DISK "/usr/standalone/i386/"
342 #define BOOT_DIR_NET ""
343 #define makeFilePath(x) \
344 (gBootDev == kBootDevNetwork) ? BOOT_DIR_NET x : BOOT_DIR_DISK x
345
346 int fd;
347 char * help = makeFilePath("BootHelp.txt");
348
349 if ( (fd = open(help, 0)) >= 0 )
350 {
351 char * buffer = malloc( file_size(fd) );
352 read(fd, buffer, file_size(fd) - 1);
353 close(fd);
354 printf("%s", buffer);
355 free(buffer);
356 }
357 }
358
359 //==========================================================================
360 // Returns 1 if the string pointed by 'cp' contains an user-specified
361 // kernel image file name. Used by getBootString() function.
362
363 static int
364 containsKernelName(const char * cp)
365 {
366 register char c;
367
368 skipblanks(&cp);
369
370 // Convert char to lower case.
371
372 c = *cp | 0x20;
373
374 // Must start with a letter or a '/'.
375
376 if ( (c < 'a' || c > 'z') && ( c != '/' ) )
377 return 0;
378
379 // Keep consuming characters until we hit a separator.
380
381 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
382 cp++;
383
384 // Only SPACE or TAB separator is accepted.
385 // Reject everything else.
386
387 if (*cp == '=')
388 return 0;
389
390 return 1;
391 }
392
393 //==========================================================================
394 // Display the "boot:" prompt and copies the user supplied string to
395 // kernBootStruct->bootString. The kernel image file name is written
396 // to kernBootStruct->bootFile.
397
398 static void
399 getBootString()
400 {
401 char line[BOOT_STRING_LEN];
402 char * cp;
403 char * val;
404 int count;
405 static int timeout = kBootTimeout;
406
407 do {
408 line[0] = '\0';
409 cp = &line[0];
410
411 // If there were errors, don't timeout on boot prompt since
412 // the same error is likely to occur again.
413
414 if ( errors ) timeout = 0;
415 errors = 0;
416
417 // Print the boot prompt and wait a few seconds for user input.
418
419 printf("\n");
420 count = Gets(line, sizeof(line), timeout, "boot: ", "");
421 flushdev();
422
423 // If something was typed, don't use automatic boot again.
424 // The boot: prompt will not timeout and go away until
425 // the user hits the return key.
426
427 if ( count ) timeout = 0;
428
429 skipblanks(&cp);
430
431 // If user typed '?', then display the usage message.
432
433 if ( *cp == '?' )
434 {
435 showHelp();
436 continue;
437 }
438
439 // Load config table file specified by the user, or fallback
440 // to the default one.
441
442 val = 0;
443 getValueForBootKey(cp, "config", &val, &count);
444 loadSystemConfig(val, count);
445 if ( !sysConfigValid )
446 continue;
447 }
448 while ( 0 );
449
450 // Did the user specify a kernel file name at the boot prompt?
451
452 if ( containsKernelName(cp) == 0 )
453 {
454 // User did not type a kernel image file name on the boot prompt.
455 // This is fine, read the default kernel file name from the
456 // config table.
457
458 if ( getValueForKey(kKernelNameKey, &val, &count) )
459 {
460 strncpy(kernBootStruct->bootFile, val, count);
461 }
462 }
463 else
464 {
465 // Get the kernel name from the user-supplied boot string,
466 // and copy the name to the buffer provided.
467
468 char * namep = kernBootStruct->bootFile;
469
470 while ( *cp && !(*cp == ' ' || *cp == '\t') )
471 *namep++ = *cp++;
472
473 *namep = '\0';
474 }
475
476 // Verbose flag specified.
477
478 gVerboseMode = getValueForBootKey(cp, "-v", &val, &count);
479
480 // Save the boot string in kernBootStruct->bootString.
481
482 if ( getValueForKey(kKernelFlagsKey, &val, &count) && count )
483 {
484 strncpy( kernBootStruct->bootString, val, count );
485 }
486 if ( strlen(cp) )
487 {
488 strcat(kernBootStruct->bootString, " ");
489 strcat(kernBootStruct->bootString, cp);
490 }
491 }