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