]>
git.saurik.com Git - apple/boot.git/blob - i386/boot2/options.c
72d4014c261b7e12a636b7e3745fe33295730470
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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 BVRef gBootVolume
= 0;
44 static void showHelp();
46 //==========================================================================
49 kCursorTypeHidden
= 0x0100,
50 kCursorTypeUnderline
= 0x0607
59 static void changeCursor( int col
, int row
, int type
, CursorState
* cs
)
61 if (cs
) getCursorPositionAndType( &cs
->x
, &cs
->y
, &cs
->type
);
62 setCursorType( type
);
63 setCursorPosition( col
, row
, 0 );
66 static void moveCursor( int col
, int row
)
68 setCursorPosition( col
, row
, 0 );
71 static void restoreCursor( const CursorState
* cs
)
73 setCursorPosition( cs
->x
, cs
->y
, 0 );
74 setCursorType( cs
->type
);
77 //==========================================================================
79 static void flushKeyboardBuffer()
81 while ( readKeyboardStatus() ) getc();
84 //==========================================================================
86 static int countdown( const char * msg
, int row
, int timeout
)
90 int col
= strlen(msg
) + 1;
92 flushKeyboardBuffer();
97 for ( time
= time18(), timeout
++; timeout
; )
99 if (ch
= readKeyboardStatus())
102 if ( time18() >= time
)
106 moveCursor( col
, row
);
107 printf("(%d) ", timeout
);
111 flushKeyboardBuffer();
116 //==========================================================================
118 static char gBootArgs
[BOOT_STRING_LEN
];
119 static char * gBootArgsPtr
= gBootArgs
;
120 static char * gBootArgsEnd
= gBootArgs
+ BOOT_STRING_LEN
- 1;
122 static void clearBootArgs()
124 gBootArgsPtr
= gBootArgs
;
125 memset( gBootArgs
, '\0', BOOT_STRING_LEN
);
128 //==========================================================================
130 static void showBootPrompt( int row
, BOOL visible
)
132 extern char bootPrompt
[];
134 changeCursor( 0, row
, kCursorTypeUnderline
, 0 );
135 clearScreenRows( row
, kScreenLastRow
);
140 printf( bootPrompt
);
144 printf("Press Return to start up the foreign OS. ");
148 //==========================================================================
150 static void updateBootArgs( int key
)
152 key
&= kASCIIKeyMask
;
157 if ( gBootArgsPtr
> gBootArgs
)
160 getCursorPositionAndType( &x
, &y
, &t
);
166 setCursorPosition( x
, y
, 0 );
168 *gBootArgsPtr
-- = '\0';
173 if ( key
>= ' ' && gBootArgsPtr
< gBootArgsEnd
)
175 putchar(key
); // echo to screen
176 *gBootArgsPtr
++ = key
;
182 //==========================================================================
189 static const MenuItem
* gMenuItems
= NULL
;
190 static int gMenuItemCount
;
192 static int gMenuHeight
;
194 static int gMenuBottom
;
195 static int gMenuSelection
;
197 static void printMenuItem( const MenuItem
* item
, int highlight
)
202 putca(' ', 0x70, strlen(item
->name
) + 4);
204 putca(' ', 0x07, 40);
206 printf(" %40s\n", item
->name
);
209 //==========================================================================
211 static void showMenu( const MenuItem
* items
, int count
,
212 int selection
, int row
, int height
)
215 CursorState cursorState
;
217 if ( items
== NULL
|| count
== 0 ) return;
219 // head and tail points to the start and the end of the list.
220 // top and bottom points to the first and last visible items
221 // in the menu window.
225 gMenuHeight
= height
;
226 gMenuItemCount
= count
;
228 gMenuBottom
= min( count
, height
) - 1;
229 gMenuSelection
= selection
;
231 // If the selected item is not visible, shift the list down.
233 if ( gMenuSelection
> gMenuBottom
)
235 gMenuTop
+= ( gMenuSelection
- gMenuBottom
);
236 gMenuBottom
= gMenuSelection
;
239 // Draw the visible items.
241 changeCursor( 0, row
, kCursorTypeHidden
, &cursorState
);
243 for ( i
= gMenuTop
; i
<= gMenuBottom
; i
++ )
245 printMenuItem( &items
[i
], (i
== gMenuSelection
) );
248 restoreCursor( &cursorState
);
251 //==========================================================================
253 static int updateMenu( int key
, void ** paramPtr
)
268 if ( NULL
== gMenuItems
) return 0;
270 // Look at the scan code.
274 case 0x4800: // Up Arrow
275 if ( gMenuSelection
!= gMenuTop
)
276 draw
.f
.selectionUp
= 1;
277 else if ( gMenuTop
> 0 )
278 draw
.f
.scrollDown
= 1;
281 case 0x5000: // Down Arrow
282 if ( gMenuSelection
!= gMenuBottom
)
283 draw
.f
.selectionDown
= 1;
284 else if ( gMenuBottom
< (gMenuItemCount
- 1) )
291 if ( draw
.f
.scrollUp
)
293 scollPage(0, gMenuRow
, 40, gMenuRow
+ gMenuHeight
- 1, 0x07, 1, 1);
294 gMenuTop
++; gMenuBottom
++;
295 draw
.f
.selectionDown
= 1;
298 if ( draw
.f
.scrollDown
)
300 scollPage(0, gMenuRow
, 40, gMenuRow
+ gMenuHeight
- 1, 0x07, 1, -1);
301 gMenuTop
--; gMenuBottom
--;
302 draw
.f
.selectionUp
= 1;
305 if ( draw
.f
.selectionUp
|| draw
.f
.selectionDown
)
307 CursorState cursorState
;
309 // Set cursor at current position, and clear inverse video.
311 changeCursor( 0, gMenuRow
+ gMenuSelection
- gMenuTop
,
312 kCursorTypeHidden
, &cursorState
);
314 printMenuItem( &gMenuItems
[gMenuSelection
], 0 );
316 if ( draw
.f
.selectionUp
) gMenuSelection
--;
317 else gMenuSelection
++;
319 moveCursor( 0, gMenuRow
+ gMenuSelection
- gMenuTop
);
321 printMenuItem( &gMenuItems
[gMenuSelection
], 1 );
323 restoreCursor( &cursorState
);
326 *paramPtr
= gMenuItems
[gMenuSelection
].param
;
333 //==========================================================================
335 static void skipblanks( const char ** cpp
)
337 while ( **(cpp
) == ' ' || **(cpp
) == '\t' ) ++(*cpp
);
340 //==========================================================================
342 static const char * extractKernelName( char ** cpp
)
348 // Convert char to lower case.
352 // Must start with a letter or a '/'.
354 if ( (c
< 'a' || c
> 'z') && ( c
!= '/' ) )
357 // Keep consuming characters until we hit a separator.
359 while ( *cp
&& (*cp
!= '=') && (*cp
!= ' ') && (*cp
!= '\t') )
362 // Only SPACE or TAB separator is accepted.
363 // Reject everything else.
368 // Overwrite the separator, and move the pointer past
371 if (*cp
!= '\0') *cp
++ = '\0';
377 //==========================================================================
379 void getBootOptions()
389 BOOL showPrompt
, newShowPrompt
;
390 MenuItem
* menuItems
= NULL
;
391 static BOOL firstRun
= YES
;
394 clearScreenRows( kMenuTopRow
, kScreenLastRow
);
395 changeCursor( 0, kMenuTopRow
, kCursorTypeUnderline
, 0 );
396 verbose("Scanning device %x...", gBIOSDev
);
398 // Get a list of bootable volumes on the device.
400 bvChain
= scanBootVolumes( gBIOSDev
, &bvCount
);
401 gBootVolume
= menuBVR
= selectBootVolume( bvChain
);
404 // When booting from CD (via HD emulation), default to hard
405 // drive boot when possible.
407 if ( gBootVolume
->part_type
== FDISK_BOOTER
&&
408 gBootVolume
->biosdev
== 0x80 )
410 // Scan the original device 0x80 that has been displaced
413 BVRef hd_bvr
= selectBootVolume(scanBootVolumes(0x81, 0));
414 if ( hd_bvr
->flags
& kBVFlagNativeBoot
)
416 int key
= countdown("Press C to start up from CD-ROM.",
419 if ( (key
& 0x5f) != 'c' )
421 gBootVolume
= hd_bvr
;
422 gBIOSDev
= hd_bvr
->biosdev
;
423 initKernBootStruct( gBIOSDev
);
430 // Allow user to override default setting.
433 countdown("Press any key to enter startup options.",
434 kMenuTopRow
, 3) == 0 )
441 // Allocate memory for an array of menu items.
443 menuItems
= (MenuItem
*) malloc( sizeof(MenuItem
) * bvCount
);
444 if ( menuItems
== NULL
) goto done
;
446 // Associate a menu item for each BVRef.
448 for ( bvr
= bvChain
, i
= bvCount
- 1, selectIndex
= 0;
449 bvr
; bvr
= bvr
->next
, i
-- )
451 getBootVolumeDescription( bvr
, menuItems
[i
].name
, 80 );
452 menuItems
[i
].param
= (void *) bvr
;
453 if ( bvr
== menuBVR
) selectIndex
= i
;
457 // Clear screen and hide the blinking cursor.
459 clearScreenRows( kMenuTopRow
, kMenuTopRow
+ 2 );
460 changeCursor( 0, kMenuTopRow
, kCursorTypeHidden
, 0 );
461 nextRow
= kMenuTopRow
;
468 printf("Use \30\31 keys to select the startup volume.");
469 showMenu( menuItems
, bvCount
, selectIndex
, kMenuTopRow
+ 2, kMenuMaxItems
);
470 nextRow
+= min( bvCount
, kMenuMaxItems
) + 3;
473 // Show the boot prompt.
475 showPrompt
= (bvCount
== 0) || (menuBVR
->flags
& kBVFlagNativeBoot
);
476 showBootPrompt( nextRow
, showPrompt
);
481 updateMenu( key
, (void **) &menuBVR
);
483 newShowPrompt
= (bvCount
== 0) ||
484 (menuBVR
->flags
& kBVFlagNativeBoot
);
486 if ( newShowPrompt
!= showPrompt
)
488 showPrompt
= newShowPrompt
;
489 showBootPrompt( nextRow
, showPrompt
);
491 if ( showPrompt
) updateBootArgs( key
);
493 switch ( key
& kASCIIKeyMask
)
496 if ( *gBootArgs
== '?' )
499 showBootPrompt( nextRow
, showPrompt
);
502 gBootVolume
= menuBVR
;
518 clearScreenRows( kMenuTopRow
, kScreenLastRow
);
519 changeCursor( 0, kMenuTopRow
, kCursorTypeUnderline
, 0 );
521 if ( menuItems
) free(menuItems
);
524 //==========================================================================
526 extern unsigned char chainbootdev
;
527 extern unsigned char chainbootflag
;
529 int processBootOptions()
531 const char * cp
= gBootArgs
;
532 const char * val
= 0;
540 // Update the unit and partition number.
544 if ( gBootVolume
->flags
& kBVFlagForeignBoot
)
546 readBootSector( gBootVolume
->biosdev
, gBootVolume
->part_boff
,
550 // Setup edx, and signal intention to chain load the
554 chainbootdev
= gBootVolume
->biosdev
;
560 bootArgs
->kernDev
&= ~((B_UNITMASK
<< B_UNITSHIFT
) |
561 (B_PARTITIONMASK
<< B_PARTITIONSHIFT
));
563 bootArgs
->kernDev
|= MAKEKERNDEV( 0,
564 /* unit */ BIOS_DEV_UNIT(gBootVolume
),
565 /* partition */ gBootVolume
->part_no
);
568 // Load config table specified by the user, or use the default.
570 if (getValueForBootKey( cp
, "config", &val
, &cnt
) == FALSE
) {
574 loadSystemConfig(val
, cnt
);
575 if ( !sysConfigValid
) return -1;
577 // Use the kernel name specified by the user, or fetch the name
578 // in the config table.
580 if (( kernel
= extractKernelName((char **)&cp
) ))
582 strcpy( bootArgs
->bootFile
, kernel
);
586 if ( getValueForKey( kKernelNameKey
, &val
, &cnt
) )
587 strlcpy( bootArgs
->bootFile
, val
, cnt
+1 );
590 // Check to see if we should ignore saved kernel flags.
591 if (getValueForBootKey(cp
, "-F", &val
, &cnt
) == FALSE
) {
592 if (getValueForKey( kKernelFlagsKey
, &val
, &cnt
) == FALSE
) {
598 // Store the merged kernel flags and boot args.
600 cntRemaining
= BOOT_STRING_LEN
- 2; // save 1 for NULL, 1 for space
601 if (cnt
> cntRemaining
) {
602 error("Warning: boot arguments too long, truncated\n");
606 strncpy(bootArgs
->bootString
, val
, cnt
);
607 bootArgs
->bootString
[cnt
++] = ' ';
609 cntRemaining
= cntRemaining
- cnt
;
610 userCnt
= strlen(cp
);
611 if (userCnt
> cntRemaining
) {
612 error("Warning: boot arguments too long, truncated\n");
613 userCnt
= cntRemaining
;
615 strncpy(&bootArgs
->bootString
[cnt
], cp
, userCnt
);
616 bootArgs
->bootString
[cnt
+userCnt
] = '\0';
618 gVerboseMode
= getValueForKey( "-v", &val
, &cnt
) ||
619 getValueForKey( "-s", &val
, &cnt
);
621 gBootGraphics
= getBoolForKey( kBootGraphicsKey
);
624 if ( getValueForKey(kBootGraphicsKey
, &val
, &cnt
) && cnt
&&
625 (val
[0] == 'N' || val
[0] == 'n') )
628 gBootMode
= ( getValueForKey( "-f", &val
, &cnt
) ) ?
629 kBootModeSafe
: kBootModeNormal
;
634 //==========================================================================
635 // Load the help file and display the file contents on the screen.
637 static void showHelp()
639 #define BOOT_HELP_PATH "/usr/standalone/i386/BootHelp.txt"
643 if ( (fd
= open(BOOT_HELP_PATH
, 0)) >= 0 )
647 // Activate and clear page 1
648 // Perhaps this should be loaded only once?
650 setActiveDisplayPage(1);
651 clearScreenRows(0, 24);
652 setCursorPosition( 0, 0, 1 );
654 buffer
= malloc( file_size(fd
) );
655 read(fd
, buffer
, file_size(fd
) - 1);
657 printf("%s", buffer
);
660 // Wait for a keystroke and return to page 0.
663 setActiveDisplayPage(0);