]>
git.saurik.com Git - apple/boot.git/blob - i386/boot2/options.c
2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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
22 * @APPLE_LICENSE_HEADER_END@
26 #include "bootstruct.h"
42 static void showHelp();
44 //==========================================================================
47 kCursorTypeHidden
= 0x0100,
48 kCursorTypeUnderline
= 0x0607
57 static void changeCursor( int col
, int row
, int type
, CursorState
* cs
)
59 if (cs
) getCursorPositionAndType( &cs
->x
, &cs
->y
, &cs
->type
);
60 setCursorType( type
);
61 setCursorPosition( col
, row
, 0 );
64 static void moveCursor( int col
, int row
)
66 setCursorPosition( col
, row
, 0 );
69 static void restoreCursor( const CursorState
* cs
)
71 setCursorPosition( cs
->x
, cs
->y
, 0 );
72 setCursorType( cs
->type
);
75 //==========================================================================
77 /* Flush keyboard buffer; returns TRUE if any of the flushed
81 static BOOL
flushKeyboardBuffer()
85 while ( readKeyboardStatus() ) {
86 if (bgetc() == 0x4200) status
= TRUE
;
91 //==========================================================================
93 static int countdown( const char * msg
, int row
, int timeout
)
97 int col
= strlen(msg
) + 1;
99 flushKeyboardBuffer();
101 moveCursor( 0, row
);
104 for ( time
= time18(), timeout
++; timeout
; )
106 if (ch
= readKeyboardStatus())
109 // Count can be interrupted by holding down shift,
110 // control or alt key
111 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) {
116 if ( time18() >= time
)
120 moveCursor( col
, row
);
121 printf("(%d) ", timeout
);
125 flushKeyboardBuffer();
130 //==========================================================================
132 static char gBootArgs
[BOOT_STRING_LEN
];
133 static char * gBootArgsPtr
= gBootArgs
;
134 static char * gBootArgsEnd
= gBootArgs
+ BOOT_STRING_LEN
- 1;
136 static void clearBootArgs()
138 gBootArgsPtr
= gBootArgs
;
139 memset( gBootArgs
, '\0', BOOT_STRING_LEN
);
142 //==========================================================================
144 static void showBootPrompt( int row
, BOOL visible
)
146 extern char bootPrompt
[];
148 changeCursor( 0, row
, kCursorTypeUnderline
, 0 );
149 clearScreenRows( row
, kScreenLastRow
);
154 printf( bootPrompt
);
158 printf("Press Enter to start up the foreign OS. ");
162 //==========================================================================
164 static void updateBootArgs( int key
)
166 key
&= kASCIIKeyMask
;
171 if ( gBootArgsPtr
> gBootArgs
)
174 getCursorPositionAndType( &x
, &y
, &t
);
180 setCursorPosition( x
, y
, 0 );
182 *gBootArgsPtr
-- = '\0';
187 if ( key
>= ' ' && gBootArgsPtr
< gBootArgsEnd
)
189 putchar(key
); // echo to screen
190 *gBootArgsPtr
++ = key
;
196 //==========================================================================
203 static const MenuItem
* gMenuItems
= NULL
;
204 static int gMenuItemCount
;
206 static int gMenuHeight
;
208 static int gMenuBottom
;
209 static int gMenuSelection
;
211 static void printMenuItem( const MenuItem
* item
, int highlight
)
216 putca(' ', 0x70, strlen(item
->name
) + 4);
218 putca(' ', 0x07, 40);
220 printf(" %40s\n", item
->name
);
223 //==========================================================================
225 static void showMenu( const MenuItem
* items
, int count
,
226 int selection
, int row
, int height
)
229 CursorState cursorState
;
231 if ( items
== NULL
|| count
== 0 ) return;
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.
239 gMenuHeight
= height
;
240 gMenuItemCount
= count
;
242 gMenuBottom
= min( count
, height
) - 1;
243 gMenuSelection
= selection
;
245 // If the selected item is not visible, shift the list down.
247 if ( gMenuSelection
> gMenuBottom
)
249 gMenuTop
+= ( gMenuSelection
- gMenuBottom
);
250 gMenuBottom
= gMenuSelection
;
253 // Draw the visible items.
255 changeCursor( 0, row
, kCursorTypeHidden
, &cursorState
);
257 for ( i
= gMenuTop
; i
<= gMenuBottom
; i
++ )
259 printMenuItem( &items
[i
], (i
== gMenuSelection
) );
262 restoreCursor( &cursorState
);
265 //==========================================================================
267 static int updateMenu( int key
, void ** paramPtr
)
282 if ( NULL
== gMenuItems
) return 0;
284 // Look at the scan code.
288 case 0x4800: // Up Arrow
289 if ( gMenuSelection
!= gMenuTop
)
290 draw
.f
.selectionUp
= 1;
291 else if ( gMenuTop
> 0 )
292 draw
.f
.scrollDown
= 1;
295 case 0x5000: // Down Arrow
296 if ( gMenuSelection
!= gMenuBottom
)
297 draw
.f
.selectionDown
= 1;
298 else if ( gMenuBottom
< (gMenuItemCount
- 1) )
305 if ( draw
.f
.scrollUp
)
307 scollPage(0, gMenuRow
, 40, gMenuRow
+ gMenuHeight
- 1, 0x07, 1, 1);
308 gMenuTop
++; gMenuBottom
++;
309 draw
.f
.selectionDown
= 1;
312 if ( draw
.f
.scrollDown
)
314 scollPage(0, gMenuRow
, 40, gMenuRow
+ gMenuHeight
- 1, 0x07, 1, -1);
315 gMenuTop
--; gMenuBottom
--;
316 draw
.f
.selectionUp
= 1;
319 if ( draw
.f
.selectionUp
|| draw
.f
.selectionDown
)
321 CursorState cursorState
;
323 // Set cursor at current position, and clear inverse video.
325 changeCursor( 0, gMenuRow
+ gMenuSelection
- gMenuTop
,
326 kCursorTypeHidden
, &cursorState
);
328 printMenuItem( &gMenuItems
[gMenuSelection
], 0 );
330 if ( draw
.f
.selectionUp
) gMenuSelection
--;
331 else gMenuSelection
++;
333 moveCursor( 0, gMenuRow
+ gMenuSelection
- gMenuTop
);
335 printMenuItem( &gMenuItems
[gMenuSelection
], 1 );
337 restoreCursor( &cursorState
);
340 *paramPtr
= gMenuItems
[gMenuSelection
].param
;
347 //==========================================================================
349 static void skipblanks( const char ** cpp
)
351 while ( **(cpp
) == ' ' || **(cpp
) == '\t' ) ++(*cpp
);
354 //==========================================================================
356 static const char * extractKernelName( char ** cpp
)
362 // Convert char to lower case.
366 // Must start with a letter or a '/'.
368 if ( (c
< 'a' || c
> 'z') && ( c
!= '/' ) )
371 // Keep consuming characters until we hit a separator.
373 while ( *cp
&& (*cp
!= '=') && (*cp
!= ' ') && (*cp
!= '\t') )
376 // Only SPACE or TAB separator is accepted.
377 // Reject everything else.
382 // Overwrite the separator, and move the pointer past
385 if (*cp
!= '\0') *cp
++ = '\0';
391 //==========================================================================
394 printMemoryInfo(void)
398 MemoryRange
*mp
= bootArgs
->memoryMap
;
400 // Activate and clear page 1
401 setActiveDisplayPage(1);
402 clearScreenRows(0, 24);
403 setCursorPosition( 0, 0, 1 );
405 printf("BIOS reported memory ranges:\n");
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
),
416 printf("(Press a key to continue...)");
423 printf("(Press a key to continue...)");
427 setActiveDisplayPage(0);
430 //==========================================================================
433 getBootOptions(BOOL firstRun
)
444 BOOL showPrompt
, newShowPrompt
;
445 MenuItem
* menuItems
= NULL
;
447 // Allow user to override default timeout.
449 if ( getIntForKey(kTimeoutKey
, &timeout
) == NO
)
451 timeout
= kBootTimeout
;
454 // If the user is holding down a shift key,
456 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) {
457 gBootMode
&= ~kBootModeQuiet
;
460 // If user typed F8, abort quiet mode,
461 // and display the menu.
462 if (flushKeyboardBuffer()) {
463 gBootMode
&= ~kBootModeQuiet
;
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 );
477 changeCursor( 0, kMenuTopRow
, kCursorTypeUnderline
, 0 );
479 verbose("Scanning device %x...", gBIOSDev
);
481 // Get a list of bootable volumes on the device.
483 bvChain
= scanBootVolumes( gBIOSDev
, &bvCount
);
484 gBootVolume
= menuBVR
= selectBootVolume( bvChain
);
487 // When booting from CD (via HD emulation), default to hard
488 // drive boot when possible.
490 if ( gBootVolume
->part_type
== FDISK_BOOTER
&&
491 gBootVolume
->biosdev
== 0x80 )
493 // Scan the original device 0x80 that has been displaced
496 BVRef hd_bvr
= selectBootVolume(scanBootVolumes(0x81, 0));
497 if ( hd_bvr
->flags
& kBVFlagNativeBoot
)
499 int key
= countdown("Press C to start up from CD-ROM.",
502 if ( (key
& 0x5f) != 'c' )
504 gBootVolume
= hd_bvr
;
505 gBIOSDev
= hd_bvr
->biosdev
;
506 initKernBootStruct( gBIOSDev
);
513 if ( gBootMode
& kBootModeQuiet
)
515 // No input allowed from user.
519 if ( firstRun
&& ( timeout
> 0 ) &&
520 ( countdown("Press any key to enter startup options.",
521 kMenuTopRow
, timeout
) == 0 ) )
528 // Allocate memory for an array of menu items.
530 menuItems
= (MenuItem
*) malloc( sizeof(MenuItem
) * bvCount
);
531 if ( menuItems
== NULL
) goto done
;
533 // Associate a menu item for each BVRef.
535 for ( bvr
= bvChain
, i
= bvCount
- 1, selectIndex
= 0;
536 bvr
; bvr
= bvr
->next
, i
-- )
538 getBootVolumeDescription( bvr
, menuItems
[i
].name
, 80, YES
);
539 menuItems
[i
].param
= (void *) bvr
;
540 if ( bvr
== menuBVR
) selectIndex
= i
;
544 // Clear screen and hide the blinking cursor.
546 clearScreenRows( kMenuTopRow
, kMenuTopRow
+ 2 );
547 changeCursor( 0, kMenuTopRow
, kCursorTypeHidden
, 0 );
548 nextRow
= kMenuTopRow
;
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;
560 // Show the boot prompt.
562 showPrompt
= (bvCount
== 0) || (menuBVR
->flags
& kBVFlagNativeBoot
);
563 showBootPrompt( nextRow
, showPrompt
);
568 updateMenu( key
, (void **) &menuBVR
);
570 newShowPrompt
= (bvCount
== 0) ||
571 (menuBVR
->flags
& kBVFlagNativeBoot
);
573 if ( newShowPrompt
!= showPrompt
)
575 showPrompt
= newShowPrompt
;
576 showBootPrompt( nextRow
, showPrompt
);
578 if ( showPrompt
) updateBootArgs( key
);
580 switch ( key
& kASCIIKeyMask
)
583 if ( *gBootArgs
== '?' )
585 if ( strcmp( gBootArgs
, "?video" ) == 0 ) {
587 } else if ( strcmp( gBootArgs
, "?memory" ) == 0 ) {
593 showBootPrompt( nextRow
, showPrompt
);
596 gBootVolume
= menuBVR
;
612 clearScreenRows( kMenuTopRow
, kScreenLastRow
);
613 changeCursor( 0, kMenuTopRow
, kCursorTypeUnderline
, 0 );
615 if ( menuItems
) free(menuItems
);
620 //==========================================================================
622 extern unsigned char chainbootdev
;
623 extern unsigned char chainbootflag
;
625 int processBootOptions()
627 const char * cp
= gBootArgs
;
628 const char * val
= 0;
637 // Update the unit and partition number.
641 if ( gBootVolume
->flags
& kBVFlagForeignBoot
)
643 readBootSector( gBootVolume
->biosdev
, gBootVolume
->part_boff
,
647 // Setup edx, and signal intention to chain load the
651 chainbootdev
= gBootVolume
->biosdev
;
657 bootArgs
->kernDev
&= ~((B_UNITMASK
<< B_UNITSHIFT
) |
658 (B_PARTITIONMASK
<< B_PARTITIONSHIFT
));
660 bootArgs
->kernDev
|= MAKEKERNDEV( 0,
661 /* unit */ BIOS_DEV_UNIT(gBootVolume
),
662 /* partition */ gBootVolume
->part_no
);
665 // Load config table specified by the user, or use the default.
667 if (getValueForBootKey( cp
, "config", &val
, &cnt
) == FALSE
) {
671 loadSystemConfig(val
, cnt
);
672 if ( !sysConfigValid
) return -1;
674 // Use the kernel name specified by the user, or fetch the name
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
681 gOverrideKernel
= NO
;
682 if (( kernel
= extractKernelName((char **)&cp
) )) {
683 strcpy( bootArgs
->bootFile
, kernel
);
684 gOverrideKernel
= YES
;
686 if ( getValueForKey( kKernelNameKey
, &val
, &cnt
) ) {
687 strlcpy( bootArgs
->bootFile
, val
, cnt
+1 );
688 if (strcmp( bootArgs
->bootFile
, kDefaultKernel
) != 0) {
689 gOverrideKernel
= YES
;
692 strcpy( bootArgs
->bootFile
, kDefaultKernel
);
696 cntRemaining
= BOOT_STRING_LEN
- 2; // save 1 for NULL, 1 for space
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.
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=*" );
708 strlcpy( argP
, val
, cnt
+1);
715 // Check to see if we should ignore saved kernel flags.
716 if (getValueForBootKey(cp
, kIgnoreBootFileFlag
, &val
, &cnt
) == FALSE
) {
717 if (getValueForKey( kKernelFlagsKey
, &val
, &cnt
) == FALSE
) {
723 // Store the merged kernel flags and boot args.
725 if (cnt
> cntRemaining
) {
726 error("Warning: boot arguments too long, truncated\n");
730 strncpy(argP
, val
, cnt
);
733 cntRemaining
= cntRemaining
- cnt
;
734 userCnt
= strlen(cp
);
735 if (userCnt
> cntRemaining
) {
736 error("Warning: boot arguments too long, truncated\n");
737 userCnt
= cntRemaining
;
739 strncpy(&argP
[cnt
], cp
, userCnt
);
740 argP
[cnt
+userCnt
] = '\0';
742 gVerboseMode
= getValueForKey( kVerboseModeFlag
, &val
, &cnt
) ||
743 getValueForKey( kSingleUserModeFlag
, &val
, &cnt
);
745 gBootMode
= ( getValueForKey( kSafeModeFlag
, &val
, &cnt
) ) ?
746 kBootModeSafe
: kBootModeNormal
;
748 if ( getValueForKey( kPlatformKey
, &val
, &cnt
) ) {
749 strlcpy(gPlatformName
, val
, cnt
+ 1);
751 strcpy(gPlatformName
, "ACPI");
754 if ( getValueForKey( kMKextCacheKey
, &val
, &cnt
) ) {
755 strlcpy(gMKextName
, val
, cnt
+ 1);
761 //==========================================================================
762 // Load the help file and display the file contents on the screen.
764 static void showHelp()
766 #define BOOT_HELP_PATH "/usr/standalone/i386/BootHelp.txt"
774 if ( (fd
= open(BOOT_HELP_PATH
, 0)) >= 0 )
779 size
= file_size(fd
);
780 buffer
= malloc( size
+ 1 );
781 read(fd
, buffer
, size
);
786 while (*bp
!= '\n') {
796 setActiveDisplayPage(1);
799 clearScreenRows(0, 24);
800 setCursorPosition(0, 0, 1);
802 for (line
= 0; *bp
!= '\1' && line
< line_offset
; line
++) {
803 while (*bp
!= '\0') bp
++;
806 for (line
= 0; *bp
!= '\1' && line
< 23; line
++) {
807 setCursorPosition(0, line
, 1);
809 while (*bp
!= '\0') bp
++;
813 setCursorPosition(0, 23, 1);
815 printf("[Type %sq or space to quit help]",
816 (line_offset
> 0) ? "p for previous page, " : "");
818 printf("[Type %s%sq to quit help]",
819 (line_offset
> 0) ? "p for previous page, " : "",
820 (*bp
!= '\1') ? "space for next page, " : "");
824 if (c
== 'q' || c
== 'Q') {
827 if ((c
== 'p' || c
== 'P') && line_offset
> 0) {
840 setActiveDisplayPage(0);