]>
Commit | Line | Data |
---|---|---|
75b89a82 | 1 | /* |
57c72a9a | 2 | * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved. |
75b89a82 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
57c72a9a | 6 | * Portions Copyright (c) 1999-2004 Apple Computer, Inc. All Rights |
4f6e3300 A |
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 | |
57c72a9a | 9 | * Source License Version 2.0 (the "License"). You may not use this file |
4f6e3300 A |
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. | |
75b89a82 A |
13 | * |
14 | * The Original Code and all software distributed under the License are | |
4f6e3300 | 15 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
75b89a82 A |
16 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
17 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
4f6e3300 A |
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. | |
75b89a82 A |
21 | * |
22 | * @APPLE_LICENSE_HEADER_END@ | |
23 | */ | |
24 | ||
25 | #include "boot.h" | |
f083c6c3 | 26 | #include "bootstruct.h" |
75b89a82 A |
27 | #include "fdisk.h" |
28 | ||
29 | enum { | |
30 | kReturnKey = 0x0d, | |
31 | kEscapeKey = 0x1b, | |
32 | kBackspaceKey = 0x08, | |
33 | kASCIIKeyMask = 0x7f | |
34 | }; | |
35 | ||
36 | enum { | |
37 | kMenuTopRow = 5, | |
38 | kMenuMaxItems = 6, | |
39 | kScreenLastRow = 24 | |
40 | }; | |
41 | ||
75b89a82 A |
42 | static void showHelp(); |
43 | ||
44 | //========================================================================== | |
45 | ||
46 | enum { | |
47 | kCursorTypeHidden = 0x0100, | |
48 | kCursorTypeUnderline = 0x0607 | |
49 | }; | |
50 | ||
51 | typedef struct { | |
52 | int x; | |
53 | int y; | |
54 | int type; | |
55 | } CursorState; | |
56 | ||
57 | static void changeCursor( int col, int row, int type, CursorState * cs ) | |
58 | { | |
59 | if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type ); | |
60 | setCursorType( type ); | |
61 | setCursorPosition( col, row, 0 ); | |
62 | } | |
63 | ||
64 | static void moveCursor( int col, int row ) | |
65 | { | |
66 | setCursorPosition( col, row, 0 ); | |
67 | } | |
68 | ||
69 | static void restoreCursor( const CursorState * cs ) | |
70 | { | |
71 | setCursorPosition( cs->x, cs->y, 0 ); | |
72 | setCursorType( cs->type ); | |
73 | } | |
74 | ||
75 | //========================================================================== | |
76 | ||
57c72a9a A |
77 | /* Flush keyboard buffer; returns TRUE if any of the flushed |
78 | * characters was F8. | |
79 | */ | |
80 | ||
81 | static BOOL flushKeyboardBuffer() | |
75b89a82 | 82 | { |
57c72a9a A |
83 | BOOL status = FALSE; |
84 | ||
85 | while ( readKeyboardStatus() ) { | |
86 | if (bgetc() == 0x4200) status = TRUE; | |
87 | } | |
88 | return status; | |
75b89a82 A |
89 | } |
90 | ||
91 | //========================================================================== | |
92 | ||
93 | static int countdown( const char * msg, int row, int timeout ) | |
94 | { | |
f083c6c3 | 95 | unsigned long time; |
75b89a82 A |
96 | int ch = 0; |
97 | int col = strlen(msg) + 1; | |
98 | ||
99 | flushKeyboardBuffer(); | |
100 | ||
101 | moveCursor( 0, row ); | |
102 | printf(msg); | |
103 | ||
104 | for ( time = time18(), timeout++; timeout; ) | |
105 | { | |
106 | if (ch = readKeyboardStatus()) | |
107 | break; | |
108 | ||
57c72a9a A |
109 | // Count can be interrupted by holding down shift, |
110 | // control or alt key | |
111 | if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) { | |
112 | ch = 1; | |
113 | break; | |
114 | } | |
115 | ||
75b89a82 A |
116 | if ( time18() >= time ) |
117 | { | |
118 | time += 18; | |
119 | timeout--; | |
120 | moveCursor( col, row ); | |
121 | printf("(%d) ", timeout); | |
122 | } | |
123 | } | |
124 | ||
125 | flushKeyboardBuffer(); | |
126 | ||
127 | return ch; | |
128 | } | |
129 | ||
130 | //========================================================================== | |
131 | ||
132 | static char gBootArgs[BOOT_STRING_LEN]; | |
133 | static char * gBootArgsPtr = gBootArgs; | |
134 | static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1; | |
135 | ||
136 | static void clearBootArgs() | |
137 | { | |
138 | gBootArgsPtr = gBootArgs; | |
139 | memset( gBootArgs, '\0', BOOT_STRING_LEN ); | |
140 | } | |
141 | ||
142 | //========================================================================== | |
143 | ||
144 | static void showBootPrompt( int row, BOOL visible ) | |
145 | { | |
146 | extern char bootPrompt[]; | |
147 | ||
148 | changeCursor( 0, row, kCursorTypeUnderline, 0 ); | |
149 | clearScreenRows( row, kScreenLastRow ); | |
150 | clearBootArgs(); | |
151 | ||
152 | if ( visible ) | |
153 | { | |
154 | printf( bootPrompt ); | |
155 | } | |
156 | else | |
157 | { | |
57c72a9a | 158 | printf("Press Enter to start up the foreign OS. "); |
75b89a82 A |
159 | } |
160 | } | |
161 | ||
162 | //========================================================================== | |
163 | ||
164 | static void updateBootArgs( int key ) | |
165 | { | |
166 | key &= kASCIIKeyMask; | |
167 | ||
168 | switch ( key ) | |
169 | { | |
170 | case kBackspaceKey: | |
171 | if ( gBootArgsPtr > gBootArgs ) | |
172 | { | |
173 | int x, y, t; | |
174 | getCursorPositionAndType( &x, &y, &t ); | |
175 | if ( x == 0 && y ) | |
176 | { | |
177 | x = 80; y--; | |
178 | } | |
179 | if (x) x--; | |
180 | setCursorPosition( x, y, 0 ); | |
181 | putca(' ', 0x07, 1); | |
182 | *gBootArgsPtr-- = '\0'; | |
183 | } | |
184 | break; | |
185 | ||
186 | default: | |
187 | if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd) | |
188 | { | |
189 | putchar(key); // echo to screen | |
190 | *gBootArgsPtr++ = key; | |
191 | } | |
192 | break; | |
193 | } | |
194 | } | |
195 | ||
196 | //========================================================================== | |
197 | ||
198 | typedef struct { | |
199 | char name[80]; | |
200 | void * param; | |
201 | } MenuItem; | |
202 | ||
203 | static const MenuItem * gMenuItems = NULL; | |
204 | static int gMenuItemCount; | |
205 | static int gMenuRow; | |
206 | static int gMenuHeight; | |
207 | static int gMenuTop; | |
208 | static int gMenuBottom; | |
209 | static int gMenuSelection; | |
210 | ||
211 | static void printMenuItem( const MenuItem * item, int highlight ) | |
212 | { | |
213 | printf(" "); | |
214 | ||
215 | if ( highlight ) | |
216 | putca(' ', 0x70, strlen(item->name) + 4); | |
217 | else | |
218 | putca(' ', 0x07, 40); | |
219 | ||
220 | printf(" %40s\n", item->name); | |
221 | } | |
222 | ||
223 | //========================================================================== | |
224 | ||
225 | static void showMenu( const MenuItem * items, int count, | |
226 | int selection, int row, int height ) | |
227 | { | |
228 | int i; | |
229 | CursorState cursorState; | |
230 | ||
231 | if ( items == NULL || count == 0 ) return; | |
232 | ||
233 | // head and tail points to the start and the end of the list. | |
234 | // top and bottom points to the first and last visible items | |
235 | // in the menu window. | |
236 | ||
237 | gMenuItems = items; | |
238 | gMenuRow = row; | |
239 | gMenuHeight = height; | |
240 | gMenuItemCount = count; | |
241 | gMenuTop = 0; | |
242 | gMenuBottom = min( count, height ) - 1; | |
243 | gMenuSelection = selection; | |
244 | ||
245 | // If the selected item is not visible, shift the list down. | |
246 | ||
247 | if ( gMenuSelection > gMenuBottom ) | |
248 | { | |
249 | gMenuTop += ( gMenuSelection - gMenuBottom ); | |
250 | gMenuBottom = gMenuSelection; | |
251 | } | |
252 | ||
253 | // Draw the visible items. | |
254 | ||
255 | changeCursor( 0, row, kCursorTypeHidden, &cursorState ); | |
256 | ||
257 | for ( i = gMenuTop; i <= gMenuBottom; i++ ) | |
258 | { | |
259 | printMenuItem( &items[i], (i == gMenuSelection) ); | |
260 | } | |
261 | ||
262 | restoreCursor( &cursorState ); | |
263 | } | |
264 | ||
265 | //========================================================================== | |
266 | ||
267 | static int updateMenu( int key, void ** paramPtr ) | |
268 | { | |
269 | int moved = 0; | |
270 | ||
271 | union { | |
272 | struct { | |
273 | unsigned int | |
274 | selectionUp : 1, | |
275 | selectionDown : 1, | |
276 | scrollUp : 1, | |
277 | scrollDown : 1; | |
278 | } f; | |
279 | unsigned int w; | |
280 | } draw = {{0}}; | |
281 | ||
282 | if ( NULL == gMenuItems ) return 0; | |
283 | ||
284 | // Look at the scan code. | |
285 | ||
286 | switch ( key ) | |
287 | { | |
288 | case 0x4800: // Up Arrow | |
289 | if ( gMenuSelection != gMenuTop ) | |
290 | draw.f.selectionUp = 1; | |
291 | else if ( gMenuTop > 0 ) | |
292 | draw.f.scrollDown = 1; | |
293 | break; | |
294 | ||
295 | case 0x5000: // Down Arrow | |
296 | if ( gMenuSelection != gMenuBottom ) | |
297 | draw.f.selectionDown = 1; | |
298 | else if ( gMenuBottom < (gMenuItemCount - 1) ) | |
299 | draw.f.scrollUp = 1; | |
300 | break; | |
301 | } | |
302 | ||
303 | if ( draw.w ) | |
304 | { | |
305 | if ( draw.f.scrollUp ) | |
306 | { | |
307 | scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1); | |
308 | gMenuTop++; gMenuBottom++; | |
309 | draw.f.selectionDown = 1; | |
310 | } | |
311 | ||
312 | if ( draw.f.scrollDown ) | |
313 | { | |
314 | scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1); | |
315 | gMenuTop--; gMenuBottom--; | |
316 | draw.f.selectionUp = 1; | |
317 | } | |
318 | ||
319 | if ( draw.f.selectionUp || draw.f.selectionDown ) | |
320 | { | |
321 | CursorState cursorState; | |
322 | ||
323 | // Set cursor at current position, and clear inverse video. | |
324 | ||
325 | changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, | |
326 | kCursorTypeHidden, &cursorState ); | |
327 | ||
328 | printMenuItem( &gMenuItems[gMenuSelection], 0 ); | |
329 | ||
330 | if ( draw.f.selectionUp ) gMenuSelection--; | |
331 | else gMenuSelection++; | |
332 | ||
333 | moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop ); | |
334 | ||
335 | printMenuItem( &gMenuItems[gMenuSelection], 1 ); | |
336 | ||
337 | restoreCursor( &cursorState ); | |
338 | } | |
339 | ||
340 | *paramPtr = gMenuItems[gMenuSelection].param; | |
341 | moved = 1; | |
342 | } | |
343 | ||
344 | return moved; | |
345 | } | |
346 | ||
347 | //========================================================================== | |
348 | ||
349 | static void skipblanks( const char ** cpp ) | |
350 | { | |
351 | while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp); | |
352 | } | |
353 | ||
354 | //========================================================================== | |
355 | ||
356 | static const char * extractKernelName( char ** cpp ) | |
357 | { | |
358 | char * kn = *cpp; | |
359 | char * cp = *cpp; | |
360 | char c; | |
361 | ||
362 | // Convert char to lower case. | |
363 | ||
364 | c = *cp | 0x20; | |
365 | ||
366 | // Must start with a letter or a '/'. | |
367 | ||
368 | if ( (c < 'a' || c > 'z') && ( c != '/' ) ) | |
369 | return 0; | |
370 | ||
371 | // Keep consuming characters until we hit a separator. | |
372 | ||
373 | while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') ) | |
374 | cp++; | |
375 | ||
376 | // Only SPACE or TAB separator is accepted. | |
377 | // Reject everything else. | |
378 | ||
379 | if (*cp == '=') | |
380 | return 0; | |
381 | ||
382 | // Overwrite the separator, and move the pointer past | |
383 | // the kernel name. | |
384 | ||
385 | if (*cp != '\0') *cp++ = '\0'; | |
386 | *cpp = cp; | |
387 | ||
388 | return kn; | |
389 | } | |
390 | ||
391 | //========================================================================== | |
392 | ||
57c72a9a A |
393 | static void |
394 | printMemoryInfo(void) | |
395 | { | |
396 | int line; | |
397 | int i; | |
398 | MemoryRange *mp = bootArgs->memoryMap; | |
399 | ||
400 | // Activate and clear page 1 | |
401 | setActiveDisplayPage(1); | |
402 | clearScreenRows(0, 24); | |
403 | setCursorPosition( 0, 0, 1 ); | |
404 | ||
405 | printf("BIOS reported memory ranges:\n"); | |
406 | line = 1; | |
407 | for (i=0; i<bootArgs->memoryMapCount; i++) { | |
408 | printf("Base 0x%08x%08x, ", | |
409 | (unsigned long)(mp->base >> 32), | |
410 | (unsigned long)(mp->base)); | |
411 | printf("length 0x%08x%08x, type %d\n", | |
412 | (unsigned long)(mp->length >> 32), | |
413 | (unsigned long)(mp->length), | |
414 | mp->type); | |
415 | if (line++ > 20) { | |
416 | printf("(Press a key to continue...)"); | |
417 | getc(); | |
418 | line = 0; | |
419 | } | |
420 | mp++; | |
421 | } | |
422 | if (line > 0) { | |
423 | printf("(Press a key to continue...)"); | |
424 | getc(); | |
425 | } | |
426 | ||
427 | setActiveDisplayPage(0); | |
428 | } | |
429 | ||
430 | //========================================================================== | |
431 | ||
432 | int | |
433 | getBootOptions(BOOL firstRun) | |
75b89a82 A |
434 | { |
435 | int i; | |
436 | int key; | |
437 | int selectIndex = 0; | |
438 | int bvCount; | |
439 | int nextRow; | |
57c72a9a | 440 | int timeout; |
75b89a82 A |
441 | BVRef bvr; |
442 | BVRef bvChain; | |
443 | BVRef menuBVR; | |
444 | BOOL showPrompt, newShowPrompt; | |
445 | MenuItem * menuItems = NULL; | |
57c72a9a A |
446 | |
447 | // Allow user to override default timeout. | |
448 | ||
449 | if ( getIntForKey(kTimeoutKey, &timeout) == NO ) | |
450 | { | |
451 | timeout = kBootTimeout; | |
452 | } | |
453 | ||
454 | // If the user is holding down a shift key, | |
455 | // abort quiet mode. | |
456 | if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) { | |
457 | gBootMode &= ~kBootModeQuiet; | |
458 | } | |
459 | ||
460 | // If user typed F8, abort quiet mode, | |
461 | // and display the menu. | |
462 | if (flushKeyboardBuffer()) { | |
463 | gBootMode &= ~kBootModeQuiet; | |
464 | timeout = 0; | |
465 | } | |
75b89a82 A |
466 | |
467 | clearBootArgs(); | |
57c72a9a A |
468 | |
469 | setCursorPosition( 0, 0, 0 ); | |
470 | clearScreenRows( 0, kScreenLastRow ); | |
471 | if ( ! ( gBootMode & kBootModeQuiet ) ) { | |
472 | // Display banner and show hardware info. | |
473 | printf( bootBanner, (bootArgs->convmem + bootArgs->extmem) / 1024 ); | |
474 | printVBEInfo(); | |
475 | } | |
476 | ||
75b89a82 | 477 | changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 ); |
57c72a9a | 478 | |
f083c6c3 | 479 | verbose("Scanning device %x...", gBIOSDev); |
75b89a82 A |
480 | |
481 | // Get a list of bootable volumes on the device. | |
482 | ||
483 | bvChain = scanBootVolumes( gBIOSDev, &bvCount ); | |
484 | gBootVolume = menuBVR = selectBootVolume( bvChain ); | |
485 | ||
486 | #if 0 | |
487 | // When booting from CD (via HD emulation), default to hard | |
488 | // drive boot when possible. | |
489 | ||
490 | if ( gBootVolume->part_type == FDISK_BOOTER && | |
491 | gBootVolume->biosdev == 0x80 ) | |
492 | { | |
493 | // Scan the original device 0x80 that has been displaced | |
494 | // by the CD-ROM. | |
495 | ||
496 | BVRef hd_bvr = selectBootVolume(scanBootVolumes(0x81, 0)); | |
497 | if ( hd_bvr->flags & kBVFlagNativeBoot ) | |
498 | { | |
499 | int key = countdown("Press C to start up from CD-ROM.", | |
500 | kMenuTopRow, 5); | |
501 | ||
502 | if ( (key & 0x5f) != 'c' ) | |
503 | { | |
504 | gBootVolume = hd_bvr; | |
505 | gBIOSDev = hd_bvr->biosdev; | |
506 | initKernBootStruct( gBIOSDev ); | |
507 | goto done; | |
508 | } | |
509 | } | |
510 | } | |
511 | #endif | |
512 | ||
57c72a9a A |
513 | if ( gBootMode & kBootModeQuiet ) |
514 | { | |
515 | // No input allowed from user. | |
516 | goto done; | |
517 | } | |
75b89a82 | 518 | |
57c72a9a A |
519 | if ( firstRun && ( timeout > 0 ) && |
520 | ( countdown("Press any key to enter startup options.", | |
521 | kMenuTopRow, timeout) == 0 ) ) | |
75b89a82 A |
522 | { |
523 | goto done; | |
524 | } | |
525 | ||
526 | if ( bvCount ) | |
527 | { | |
528 | // Allocate memory for an array of menu items. | |
529 | ||
530 | menuItems = (MenuItem *) malloc( sizeof(MenuItem) * bvCount ); | |
531 | if ( menuItems == NULL ) goto done; | |
532 | ||
533 | // Associate a menu item for each BVRef. | |
534 | ||
535 | for ( bvr = bvChain, i = bvCount - 1, selectIndex = 0; | |
536 | bvr; bvr = bvr->next, i-- ) | |
537 | { | |
57c72a9a | 538 | getBootVolumeDescription( bvr, menuItems[i].name, 80, YES ); |
75b89a82 A |
539 | menuItems[i].param = (void *) bvr; |
540 | if ( bvr == menuBVR ) selectIndex = i; | |
541 | } | |
542 | } | |
543 | ||
544 | // Clear screen and hide the blinking cursor. | |
545 | ||
546 | clearScreenRows( kMenuTopRow, kMenuTopRow + 2 ); | |
547 | changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 ); | |
548 | nextRow = kMenuTopRow; | |
549 | showPrompt = YES; | |
550 | ||
551 | // Show the menu. | |
552 | ||
553 | if ( bvCount ) | |
554 | { | |
555 | printf("Use \30\31 keys to select the startup volume."); | |
556 | showMenu( menuItems, bvCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems ); | |
557 | nextRow += min( bvCount, kMenuMaxItems ) + 3; | |
558 | } | |
559 | ||
560 | // Show the boot prompt. | |
561 | ||
562 | showPrompt = (bvCount == 0) || (menuBVR->flags & kBVFlagNativeBoot); | |
563 | showBootPrompt( nextRow, showPrompt ); | |
564 | ||
565 | do { | |
566 | key = getc(); | |
567 | ||
568 | updateMenu( key, (void **) &menuBVR ); | |
569 | ||
570 | newShowPrompt = (bvCount == 0) || | |
571 | (menuBVR->flags & kBVFlagNativeBoot); | |
572 | ||
573 | if ( newShowPrompt != showPrompt ) | |
574 | { | |
575 | showPrompt = newShowPrompt; | |
576 | showBootPrompt( nextRow, showPrompt ); | |
577 | } | |
578 | if ( showPrompt ) updateBootArgs( key ); | |
579 | ||
580 | switch ( key & kASCIIKeyMask ) | |
581 | { | |
582 | case kReturnKey: | |
583 | if ( *gBootArgs == '?' ) | |
584 | { | |
57c72a9a A |
585 | if ( strcmp( gBootArgs, "?video" ) == 0 ) { |
586 | printVBEModeInfo(); | |
587 | } else if ( strcmp( gBootArgs, "?memory" ) == 0 ) { | |
588 | printMemoryInfo(); | |
589 | } else { | |
590 | showHelp(); | |
591 | } | |
592 | key = 0; | |
75b89a82 A |
593 | showBootPrompt( nextRow, showPrompt ); |
594 | break; | |
595 | } | |
596 | gBootVolume = menuBVR; | |
597 | break; | |
598 | ||
599 | case kEscapeKey: | |
600 | clearBootArgs(); | |
601 | break; | |
602 | ||
603 | default: | |
604 | key = 0; | |
605 | } | |
606 | } | |
607 | while ( 0 == key ); | |
608 | ||
609 | done: | |
610 | firstRun = NO; | |
611 | ||
612 | clearScreenRows( kMenuTopRow, kScreenLastRow ); | |
613 | changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 ); | |
614 | ||
615 | if ( menuItems ) free(menuItems); | |
57c72a9a A |
616 | |
617 | return 0; | |
75b89a82 A |
618 | } |
619 | ||
620 | //========================================================================== | |
621 | ||
622 | extern unsigned char chainbootdev; | |
623 | extern unsigned char chainbootflag; | |
624 | ||
625 | int processBootOptions() | |
626 | { | |
75b89a82 A |
627 | const char * cp = gBootArgs; |
628 | const char * val = 0; | |
629 | const char * kernel; | |
630 | int cnt; | |
f083c6c3 A |
631 | int userCnt; |
632 | int cntRemaining; | |
57c72a9a | 633 | char * argP; |
75b89a82 A |
634 | |
635 | skipblanks( &cp ); | |
636 | ||
637 | // Update the unit and partition number. | |
638 | ||
639 | if ( gBootVolume ) | |
640 | { | |
641 | if ( gBootVolume->flags & kBVFlagForeignBoot ) | |
642 | { | |
643 | readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, | |
644 | (void *) 0x7c00 ); | |
645 | ||
646 | // | |
647 | // Setup edx, and signal intention to chain load the | |
648 | // foreign booter. | |
649 | // | |
650 | ||
651 | chainbootdev = gBootVolume->biosdev; | |
652 | chainbootflag = 1; | |
653 | ||
654 | return 1; | |
655 | } | |
656 | ||
f083c6c3 | 657 | bootArgs->kernDev &= ~((B_UNITMASK << B_UNITSHIFT ) | |
75b89a82 A |
658 | (B_PARTITIONMASK << B_PARTITIONSHIFT)); |
659 | ||
f083c6c3 A |
660 | bootArgs->kernDev |= MAKEKERNDEV( 0, |
661 | /* unit */ BIOS_DEV_UNIT(gBootVolume), | |
75b89a82 A |
662 | /* partition */ gBootVolume->part_no ); |
663 | } | |
664 | ||
665 | // Load config table specified by the user, or use the default. | |
666 | ||
f083c6c3 A |
667 | if (getValueForBootKey( cp, "config", &val, &cnt ) == FALSE) { |
668 | val = 0; | |
669 | cnt = 0; | |
670 | } | |
75b89a82 A |
671 | loadSystemConfig(val, cnt); |
672 | if ( !sysConfigValid ) return -1; | |
673 | ||
674 | // Use the kernel name specified by the user, or fetch the name | |
57c72a9a A |
675 | // in the config table, or use the default if not specified. |
676 | // Specifying a kernel name on the command line, or specifying | |
677 | // a non-default kernel name in the config file counts as | |
678 | // overriding the kernel, which causes the kernelcache not | |
679 | // to be used. | |
680 | ||
681 | gOverrideKernel = NO; | |
682 | if (( kernel = extractKernelName((char **)&cp) )) { | |
f083c6c3 | 683 | strcpy( bootArgs->bootFile, kernel ); |
57c72a9a A |
684 | gOverrideKernel = YES; |
685 | } else { | |
686 | if ( getValueForKey( kKernelNameKey, &val, &cnt ) ) { | |
f083c6c3 | 687 | strlcpy( bootArgs->bootFile, val, cnt+1 ); |
57c72a9a A |
688 | if (strcmp( bootArgs->bootFile, kDefaultKernel ) != 0) { |
689 | gOverrideKernel = YES; | |
690 | } | |
691 | } else { | |
692 | strcpy( bootArgs->bootFile, kDefaultKernel ); | |
693 | } | |
694 | } | |
695 | ||
696 | cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space | |
697 | ||
698 | // Check to see if we need to specify root device. | |
699 | // If user types "rd=.." on the boot line, it overrides | |
700 | // the boot device key in the boot arguments file. | |
701 | // | |
702 | argP = bootArgs->bootString; | |
703 | if ( getValueForBootKey( cp, kRootDeviceKey, &val, &cnt ) == FALSE && | |
704 | getValueForKey( kRootDeviceKey, &val, &cnt ) == FALSE ) { | |
705 | if ( getValueForKey( kBootDeviceKey, &val, &cnt ) ) { | |
706 | strcpy( argP, "rd=*" ); | |
707 | argP += 4; | |
708 | strlcpy( argP, val, cnt+1); | |
709 | cntRemaining -= cnt; | |
710 | argP += cnt; | |
711 | *argP++ = ' '; | |
712 | } | |
f083c6c3 A |
713 | } |
714 | ||
715 | // Check to see if we should ignore saved kernel flags. | |
57c72a9a | 716 | if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) == FALSE) { |
f083c6c3 A |
717 | if (getValueForKey( kKernelFlagsKey, &val, &cnt ) == FALSE) { |
718 | val = 0; | |
719 | cnt = 0; | |
720 | } | |
75b89a82 A |
721 | } |
722 | ||
723 | // Store the merged kernel flags and boot args. | |
724 | ||
f083c6c3 A |
725 | if (cnt > cntRemaining) { |
726 | error("Warning: boot arguments too long, truncated\n"); | |
727 | cnt = cntRemaining; | |
728 | } | |
729 | if (cnt) { | |
57c72a9a A |
730 | strncpy(argP, val, cnt); |
731 | argP[cnt++] = ' '; | |
75b89a82 | 732 | } |
f083c6c3 A |
733 | cntRemaining = cntRemaining - cnt; |
734 | userCnt = strlen(cp); | |
735 | if (userCnt > cntRemaining) { | |
736 | error("Warning: boot arguments too long, truncated\n"); | |
737 | userCnt = cntRemaining; | |
738 | } | |
57c72a9a A |
739 | strncpy(&argP[cnt], cp, userCnt); |
740 | argP[cnt+userCnt] = '\0'; | |
75b89a82 | 741 | |
57c72a9a A |
742 | gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt ) || |
743 | getValueForKey( kSingleUserModeFlag, &val, &cnt ); | |
75b89a82 | 744 | |
57c72a9a A |
745 | gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt ) ) ? |
746 | kBootModeSafe : kBootModeNormal; | |
75b89a82 | 747 | |
57c72a9a A |
748 | if ( getValueForKey( kPlatformKey, &val, &cnt ) ) { |
749 | strlcpy(gPlatformName, val, cnt + 1); | |
750 | } else { | |
751 | strcpy(gPlatformName, "ACPI"); | |
752 | } | |
f083c6c3 | 753 | |
57c72a9a A |
754 | if ( getValueForKey( kMKextCacheKey, &val, &cnt ) ) { |
755 | strlcpy(gMKextName, val, cnt + 1); | |
756 | } | |
75b89a82 A |
757 | |
758 | return 0; | |
759 | } | |
760 | ||
761 | //========================================================================== | |
762 | // Load the help file and display the file contents on the screen. | |
763 | ||
764 | static void showHelp() | |
765 | { | |
766 | #define BOOT_HELP_PATH "/usr/standalone/i386/BootHelp.txt" | |
767 | ||
768 | int fd; | |
57c72a9a A |
769 | int size; |
770 | int line; | |
771 | int line_offset; | |
772 | int c; | |
75b89a82 A |
773 | |
774 | if ( (fd = open(BOOT_HELP_PATH, 0)) >= 0 ) | |
775 | { | |
776 | char * buffer; | |
57c72a9a A |
777 | char * bp; |
778 | ||
779 | size = file_size(fd); | |
780 | buffer = malloc( size + 1 ); | |
781 | read(fd, buffer, size); | |
782 | close(fd); | |
75b89a82 | 783 | |
57c72a9a A |
784 | bp = buffer; |
785 | while (size > 0) { | |
786 | while (*bp != '\n') { | |
787 | bp++; | |
788 | size--; | |
789 | } | |
790 | *bp++ = '\0'; | |
791 | size--; | |
792 | } | |
793 | *bp = '\1'; | |
794 | line_offset = 0; | |
75b89a82 A |
795 | |
796 | setActiveDisplayPage(1); | |
75b89a82 | 797 | |
57c72a9a A |
798 | while (1) { |
799 | clearScreenRows(0, 24); | |
800 | setCursorPosition(0, 0, 1); | |
801 | bp = buffer; | |
802 | for (line = 0; *bp != '\1' && line < line_offset; line++) { | |
803 | while (*bp != '\0') bp++; | |
804 | bp++; | |
805 | } | |
806 | for (line = 0; *bp != '\1' && line < 23; line++) { | |
807 | setCursorPosition(0, line, 1); | |
808 | printf("%s\n", bp); | |
809 | while (*bp != '\0') bp++; | |
810 | bp++; | |
811 | } | |
812 | ||
813 | setCursorPosition(0, 23, 1); | |
814 | if (*bp == '\1') { | |
815 | printf("[Type %sq or space to quit help]", | |
816 | (line_offset > 0) ? "p for previous page, " : ""); | |
817 | } else { | |
818 | printf("[Type %s%sq to quit help]", | |
819 | (line_offset > 0) ? "p for previous page, " : "", | |
820 | (*bp != '\1') ? "space for next page, " : ""); | |
821 | } | |
822 | ||
823 | c = getc(); | |
824 | if (c == 'q' || c == 'Q') { | |
825 | break; | |
826 | } | |
827 | if ((c == 'p' || c == 'P') && line_offset > 0) { | |
828 | line_offset -= 23; | |
829 | } | |
830 | if (c == ' ') { | |
831 | if (*bp == '\1') { | |
832 | break; | |
833 | } else { | |
834 | line_offset += 23; | |
835 | } | |
836 | } | |
837 | } | |
838 | ||
839 | free(buffer); | |
75b89a82 A |
840 | setActiveDisplayPage(0); |
841 | } | |
842 | } |