Chameleon

Chameleon Svn Source Tree

Root/branches/prasys/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#include "ramdisk.h"
29#include "gui.h"
30#ifdef EMBED_THEME
31#include "embedded.h"
32#endif
33
34int shouldboot=0;
35
36extern int multiboot_timeout;
37extern int multiboot_timeout_set;
38
39extern BVRef bvChain;
40//extern intmenucount;
41
42extern intgDeviceCount;
43
44intselectIndex = 0;
45MenuItem * menuItems = NULL;
46
47enum {
48 kMenuTopRow = 5,
49 kMenuMaxItems = 10,
50 kScreenLastRow = 24
51};
52
53//==========================================================================
54
55typedef struct {
56 int x;
57 int y;
58 int type;
59} CursorState;
60
61static void changeCursor( int col, int row, int type, CursorState * cs )
62{
63 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
64 setCursorType( type );
65 setCursorPosition( col, row, 0 );
66}
67
68static void moveCursor( int col, int row )
69{
70 setCursorPosition( col, row, 0 );
71}
72
73static void restoreCursor( const CursorState * cs )
74{
75 setCursorPosition( cs->x, cs->y, 0 );
76 setCursorType( cs->type );
77}
78
79//==========================================================================
80
81/* Flush keyboard buffer; returns TRUE if any of the flushed
82 * characters was F8.
83 */
84
85static BOOL flushKeyboardBuffer()
86{
87 BOOL status = FALSE;
88
89 while ( readKeyboardStatus() ) {
90 if (bgetc() == 0x4200) status = TRUE;
91 }
92 return status;
93}
94
95//==========================================================================
96
97static int countdown( const char * msg, int row, int timeout )
98{
99 unsigned long time;
100 int ch = 0;
101 int col = strlen(msg) + 1;
102
103 flushKeyboardBuffer();
104
105if( bootArgs->Video.v_display == VGA_TEXT_MODE )
106{
107moveCursor( 0, row );
108printf(msg);
109
110} else {
111
112position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
113
114char dummy[80];
115getBootVolumeDescription( gBootVolume, dummy, 80, YES );
116drawDeviceIcon( gBootVolume, gui.screen.pixmap, p );
117drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
118
119// make this screen the new background
120memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
121
122}
123
124int multi_buff = 18 * (timeout);
125 int multi = ++multi_buff;
126
127 int lasttime=0;
128
129 for ( time = time18(), timeout++; timeout > 0; )
130 {
131if( time18() > lasttime)
132{
133multi--;
134lasttime=time18();
135}
136
137 if (ch = readKeyboardStatus())
138 break;
139
140 // Count can be interrupted by holding down shift,
141 // control or alt key
142 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
143{
144 ch = 1;
145 break;
146 }
147
148 if ( time18() >= time )
149 {
150 time += 18;
151 timeout--;
152
153if( bootArgs->Video.v_display == VGA_TEXT_MODE )
154{
155moveCursor( col, row );
156printf("(%d) ", timeout);
157}
158 }
159
160if( bootArgs->Video.v_display == GRAPHICS_MODE )
161{
162drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
163gui.redraw = YES;
164updateVRAM();
165}
166
167 }
168
169 flushKeyboardBuffer();
170
171 return ch;
172}
173
174//==========================================================================
175
176static char gBootArgs[BOOT_STRING_LEN];
177static char * gBootArgsPtr = gBootArgs;
178static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
179static char booterCommand[BOOT_STRING_LEN];
180static char booterParam[BOOT_STRING_LEN];
181
182static void clearBootArgs()
183{
184 gBootArgsPtr = gBootArgs;
185 memset( gBootArgs, '\0', BOOT_STRING_LEN );
186
187if( bootArgs->Video.v_display == GRAPHICS_MODE )
188clearGraphicBootPrompt();
189
190}
191
192//==========================================================================
193
194static void showBootPrompt( int row, BOOL visible )
195{
196 extern char bootPrompt[];
197 extern char bootRescanPrompt[];
198
199if( bootArgs->Video.v_display == VGA_TEXT_MODE )
200 {
201changeCursor( 0, row, kCursorTypeUnderline, 0 );
202clearScreenRows( row, kScreenLastRow );
203 }
204
205 clearBootArgs();
206
207 if ( visible )
208 {
209if( bootArgs->Video.v_display == VGA_TEXT_MODE )
210if (gEnableCDROMRescan)
211printf( bootRescanPrompt );
212else
213printf( bootPrompt );
214 }
215 else
216 {
217if( bootArgs->Video.v_display == GRAPHICS_MODE )
218clearGraphicBootPrompt();
219else
220printf("Press Enter to start up the foreign OS. ");
221
222 }
223}
224
225//==========================================================================
226
227static void updateBootArgs( int key )
228{
229 key &= kASCIIKeyMask;
230
231 switch ( key )
232 {
233 case kBackspaceKey:
234 if ( gBootArgsPtr > gBootArgs )
235 {
236 int x, y, t;
237 getCursorPositionAndType( &x, &y, &t );
238 if ( x == 0 && y )
239 {
240 x = 80; y--;
241 }
242 if (x)
243x--;
244if( bootArgs->Video.v_display == VGA_TEXT_MODE )
245{
246setCursorPosition( x, y, 0 );
247putca(' ', 0x07, 1);
248} else
249updateGraphicBootPrompt(kBackspaceKey);
250
251*gBootArgsPtr-- = '\0';
252}
253
254break;
255
256 default:
257 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
258 {
259if( bootArgs->Video.v_display == VGA_TEXT_MODE )
260putchar(key); // echo to screen
261else
262updateGraphicBootPrompt(key);
263*gBootArgsPtr++ = key;
264}
265
266break;
267 }
268}
269
270//==========================================================================
271
272static const MenuItem * gMenuItems = NULL;
273
274static int gMenuItemCount;
275static int gMenuRow;
276static int gMenuHeight;
277static int gMenuTop;
278static int gMenuBottom;
279static int gMenuSelection;
280
281static int gMenuStart;
282static int gMenuEnd;
283
284static void printMenuItem( const MenuItem * item, int highlight )
285{
286 printf(" ");
287
288 if ( highlight )
289 putca(' ', 0x70, strlen(item->name) + 4);
290 else
291 putca(' ', 0x07, 40);
292
293 printf(" %40s\n", item->name);
294}
295
296//==========================================================================
297
298static void showMenu( const MenuItem * items, int count,
299 int selection, int row, int height )
300{
301 int i;
302 CursorState cursorState;
303
304 if ( items == NULL || count == 0 )
305return;
306
307 // head and tail points to the start and the end of the list.
308 // top and bottom points to the first and last visible items
309 // in the menu window.
310
311 gMenuItems= items;
312 gMenuRow= row;
313 gMenuHeight= height;
314 gMenuItemCount= count;
315 gMenuTop= 0;
316 gMenuBottom= min( count, height ) - 1;
317 gMenuSelection= selection;
318
319 gMenuStart= 0;
320 gMenuEnd = min( count, gui.maxdevices ) - 1;
321
322// If the selected item is not visible, shift the list down.
323
324 if ( gMenuSelection > gMenuBottom )
325 {
326 gMenuTop += ( gMenuSelection - gMenuBottom );
327 gMenuBottom = gMenuSelection;
328 }
329
330if ( gMenuSelection > gMenuEnd )
331 {
332gMenuStart += ( gMenuSelection - gMenuEnd );
333 gMenuEnd = gMenuSelection;
334 }
335
336// Draw the visible items.
337
338if( bootArgs->Video.v_display == GRAPHICS_MODE )
339
340drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
341
342else {
343
344changeCursor( 0, row, kCursorTypeHidden, &cursorState );
345
346for ( i = gMenuTop; i <= gMenuBottom; i++ )
347{
348printMenuItem( &items[i], (i == gMenuSelection) );
349}
350
351restoreCursor( &cursorState );
352 }
353}
354
355//==========================================================================
356
357static int updateMenu( int key, void ** paramPtr )
358{
359 int moved = 0;
360
361 union {
362 struct {
363 unsigned int
364 selectionUp : 1,
365 selectionDown : 1,
366 scrollUp : 1,
367 scrollDown : 1;
368 } f;
369 unsigned int w;
370 } draw = {{0}};
371
372 if ( gMenuItems == NULL )
373return 0;
374
375if( bootArgs->Video.v_display == GRAPHICS_MODE )
376{
377int res;
378
379// set navigation keys for horizontal layout as defaults
380int previous= 0x4B00;// left arrow
381int subsequent= 0x4D00;// right arrow
382int menu= 0x5000;// down arrow
383
384if ( gui.layout == VerticalLayout )
385{
386// set navigation keys for vertical layout
387previous= 0x4800;// up arrow
388subsequent= 0x5000;// down arrow
389menu= 0x4B00;// right arrow
390}
391
392if ( key == previous )
393{
394if ( gMenuSelection > gMenuTop )
395draw.f.selectionUp = 1;
396else if ( gMenuTop > 0 )
397draw.f.scrollDown = 1;
398
399}
400
401else if ( key == subsequent )
402{
403if ( gMenuSelection != gMenuBottom)
404draw.f.selectionDown = 1;
405else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
406draw.f.scrollUp = 1;
407}
408
409else if ( key == menu )
410{
411if ( gui.menu.draw )
412updateInfoMenu(key);
413else
414drawInfoMenu();
415}
416
417else if ( gui.menu.draw )
418{
419res = updateInfoMenu(key);
420
421if ( res == CLOSE_INFO_MENU )
422gui.menu.draw = NO;
423else
424{
425shouldboot = ( res != DO_NOT_BOOT );
426
427if ( shouldboot )
428gui.menu.draw = NO;
429
430switch (res)
431{
432case BOOT_NORMAL:
433gVerboseMode = NO;
434gBootMode = kBootModeNormal;
435break;
436
437case BOOT_VERBOSE:
438gVerboseMode = YES;
439gBootMode = kBootModeNormal;
440*gBootArgsPtr++ = '-';
441*gBootArgsPtr++ = 'v';
442break;
443
444case BOOT_IGNORECACHE:
445gVerboseMode = NO;
446gBootMode = kBootModeNormal;
447*gBootArgsPtr++ = '-';
448*gBootArgsPtr++ = 'f';
449break;
450
451case BOOT_SINGLEUSER:
452gVerboseMode = YES;
453gBootMode = kBootModeNormal;
454*gBootArgsPtr++ = '-';
455*gBootArgsPtr++ = 's';
456break;
457}
458
459}
460
461}
462
463} else {
464switch ( key )
465{
466 case 0x4800: // Up Arrow
467if ( gMenuSelection != gMenuTop )
468draw.f.selectionUp = 1;
469else if ( gMenuTop > 0 )
470draw.f.scrollDown = 1;
471break;
472
473case 0x5000: // Down Arrow
474if ( gMenuSelection != gMenuBottom )
475draw.f.selectionDown = 1;
476else if ( gMenuBottom < (gMenuItemCount - 1) )
477draw.f.scrollUp = 1;
478break;
479}
480}
481
482 if ( draw.w )
483 {
484 if ( draw.f.scrollUp )
485 {
486 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1);
487 gMenuTop++; gMenuBottom++;
488gMenuStart++; gMenuEnd++;
489 draw.f.selectionDown = 1;
490 }
491
492 if ( draw.f.scrollDown )
493 {
494 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1);
495 gMenuTop--; gMenuBottom--;
496 gMenuStart--; gMenuEnd--;
497 draw.f.selectionUp = 1;
498 }
499
500 if ( draw.f.selectionUp || draw.f.selectionDown )
501 {
502
503CursorState cursorState;
504
505// Set cursor at current position, and clear inverse video.
506
507if( bootArgs->Video.v_display == VGA_TEXT_MODE )
508{
509changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
510printMenuItem( &gMenuItems[gMenuSelection], 0 );
511}
512
513if ( draw.f.selectionUp )
514{
515gMenuSelection--;
516if(( gMenuSelection - gMenuStart) == -1 )
517{
518gMenuStart--;
519gMenuEnd--;
520}
521
522} else {
523gMenuSelection++;
524if(( gMenuSelection - ( gui.maxdevices - 1) - gMenuStart) > 0 )
525{
526gMenuStart++;
527gMenuEnd++;
528}
529 }
530
531if( bootArgs->Video.v_display == VGA_TEXT_MODE )
532 {
533moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
534printMenuItem( &gMenuItems[gMenuSelection], 1 );
535restoreCursor( &cursorState );
536
537 } else
538
539drawDeviceList (gMenuStart, gMenuEnd, gMenuSelection);
540
541}
542
543 *paramPtr = gMenuItems[gMenuSelection].param;
544 moved = 1;
545 }
546
547return moved;
548}
549
550//==========================================================================
551
552static void skipblanks( const char ** cpp )
553{
554 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
555}
556
557//==========================================================================
558
559static const char * extractKernelName( char ** cpp )
560{
561 char * kn = *cpp;
562 char * cp = *cpp;
563 char c;
564
565 // Convert char to lower case.
566
567 c = *cp | 0x20;
568
569 // Must start with a letter or a '/'.
570
571 if ( (c < 'a' || c > 'z') && ( c != '/' ) )
572 return 0;
573
574 // Keep consuming characters until we hit a separator.
575
576 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
577 cp++;
578
579 // Only SPACE or TAB separator is accepted.
580 // Reject everything else.
581
582 if (*cp == '=')
583 return 0;
584
585 // Overwrite the separator, and move the pointer past
586 // the kernel name.
587
588 if (*cp != '\0') *cp++ = '\0';
589 *cpp = cp;
590
591 return kn;
592}
593
594//==========================================================================
595
596static void
597printMemoryInfo(void)
598{
599 int line;
600 int i;
601 MemoryRange *mp = bootInfo->memoryMap;
602
603 // Activate and clear page 1
604 setActiveDisplayPage(1);
605 clearScreenRows(0, 24);
606 setCursorPosition( 0, 0, 1 );
607
608 printf("BIOS reported memory ranges:\n");
609 line = 1;
610 for (i=0; i<bootInfo->memoryMapCount; i++) {
611 printf("Base 0x%08x%08x, ",
612 (unsigned long)(mp->base >> 32),
613 (unsigned long)(mp->base));
614 printf("length 0x%08x%08x, type %d\n",
615 (unsigned long)(mp->length >> 32),
616 (unsigned long)(mp->length),
617 mp->type);
618 if (line++ > 20) {
619 printf("(Press a key to continue...)");
620 getc();
621 line = 0;
622 }
623 mp++;
624 }
625 if (line > 0) {
626 printf("(Press a key to continue...)");
627 getc();
628 }
629
630 setActiveDisplayPage(0);
631}
632
633char *getMemoryInfoString()
634{
635 int i;
636 MemoryRange *mp = bootInfo->memoryMap;
637char *buff = malloc(sizeof(char)*1024);
638if(!buff) return 0;
639
640char info[] = "BIOS reported memory ranges:\n";
641sprintf(buff, "%s", info);
642 for (i=0; i<bootInfo->memoryMapCount; i++) {
643 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
644 (unsigned long)(mp->base >> 32),
645 (unsigned long)(mp->base));
646 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
647 (unsigned long)(mp->length >> 32),
648 (unsigned long)(mp->length),
649 mp->type);
650 mp++;
651 }
652return buff;
653}
654
655//==========================================================================
656extern void lspci(const char *booterParam);
657
658int
659getBootOptions(BOOL firstRun)
660{
661 int i;
662 int key;
663 int nextRow;
664 int timeout;
665 int bvCount;
666 BVRef bvr;
667 BVRef menuBVR;
668 BOOL showPrompt, newShowPrompt, isCDROM;
669
670 // Initialize default menu selection entry.
671gBootVolume = menuBVR = selectBootVolume(bvChain);
672
673if ( biosDevIsCDROM(gBIOSDev) )
674 isCDROM = TRUE;
675 else
676 isCDROM = FALSE;
677
678// ensure we're in graphics mode if gui is setup
679if(gui.initialised == YES)
680if( bootArgs->Video.v_display == VGA_TEXT_MODE )
681setVideoMode( GRAPHICS_MODE, 0 );
682
683 // Allow user to override default timeout.
684if (multiboot_timeout_set)
685timeout=multiboot_timeout;
686else if ( getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig) == NO )
687 {
688 /* If there is no timeout key in the file use the default timeout
689 which is different for CDs vs. hard disks. However, if not booting
690 a CD and no config file could be loaded set the timeout
691 to zero which causes the menu to display immediately.
692 This way, if no partitions can be found, that is the disk is unpartitioned
693 or simply cannot be read) then an empty menu is displayed.
694 If some partitions are found, for example a Windows partition, then
695 these will be displayed in the menu as foreign partitions.
696 */
697 if ( isCDROM )
698 timeout = kCDBootTimeout;
699 else
700 timeout = sysConfigValid?kBootTimeout:0;
701 }
702
703 if (timeout < 0 || gDeviceCount <= 1)
704gBootMode |= kBootModeQuiet;
705
706 // If the user is holding down a modifier key,
707 // abort quiet mode.
708 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) {
709 //gBootMode |= kBootModeSafe;
710gBootMode &= ~kBootModeQuiet;
711firstRun = NO;
712 }
713
714
715/*
716Patch from 18seven & modified by me to make it even more mac like and to include couple of commands
717
718 * Bootargs keyboard shortcut
719 * Keys were obtaiend from ApplePS2ToADBMap.h
720* F8 abort quiet mode, and display the menu.
721* alt+f old safe mode
722* shift+f ignore boot configuration file
723* alt+s single user mode
724* alt+v verbose (in mac its command +v)
725* alt+x safe mode (aka boot args with -x , in macs its command +x)
726* alt+l legacy mode (not sure why you need this)
727*/
728{
729bool f8 = false, altf = false, shiftf = false, alts = false, altv = false, altl = false, altx = false;
730int key;
731while (readKeyboardStatus()) {
732key = bgetc ();
733if (key == 0x4200) f8 = true;
734if (key == 0x2100) altf = true;
735if (key == 0x2146) shiftf = true;
736if (key == 0x1F00) alts = true;
737if (key == 0x2F00) altv = true;
738if (key == 0x2D00) altx = true;
739if (key == 0x2600) altl = true;
740}
741if (f8) {
742gBootMode &= ~kBootModeQuiet;
743timeout = 0;
744}
745if ((altf) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
746*(gBootArgsPtr++) = ' ';
747*(gBootArgsPtr++) = '-';
748*(gBootArgsPtr++) = 'f';
749}
750if ((shiftf) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
751*(gBootArgsPtr++) = ' ';
752*(gBootArgsPtr++) = '-';
753*(gBootArgsPtr++) = 'F';
754}
755if ((alts) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
756*(gBootArgsPtr++) = ' ';
757*(gBootArgsPtr++) = '-';
758*(gBootArgsPtr++) = 's';
759}
760if ((altv) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
761*(gBootArgsPtr++) = ' ';
762*(gBootArgsPtr++) = '-';
763*(gBootArgsPtr++) = 'v';
764}
765if ((altx) && (gBootArgsPtr + 5 < gBootArgsEnd)) {
766*(gBootArgsPtr++) = ' ';
767*(gBootArgsPtr++) = '-';
768*(gBootArgsPtr++) = 'x';
769//*(gBootArgsPtr++) = '';
770//*(gBootArgsPtr++) = '';
771}
772if ((altl) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
773*(gBootArgsPtr++) = ' ';
774*(gBootArgsPtr++) = '-';
775*(gBootArgsPtr++) = 'legacy';
776
777}
778}
779
780if( bootArgs->Video.v_display == VGA_TEXT_MODE )
781{
782 setCursorPosition( 0, 0, 0 );
783 clearScreenRows( 0, kScreenLastRow );
784
785if ( ! ( gBootMode & kBootModeQuiet ) )
786{
787// Display banner and show hardware info.
788printf( bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024 );
789printf( getVBEInfoString() );
790}
791
792changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
793verbose("Scanning device %x...", gBIOSDev);
794
795}
796
797 // When booting from CD, default to hard
798 // drive boot when possible.
799
800 if ( isCDROM && firstRun )
801 {
802 const char *val;
803 char *prompt;
804char *name;
805 int cnt;
806 int optionKey;
807
808 if (getValueForKey( kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig )) {
809 cnt += 1;
810 prompt = malloc(cnt);
811 strlcpy(prompt, val, cnt);
812 } else {
813name = malloc(80);
814getBootVolumeDescription( gBootVolume, name, 80, NO );
815prompt = malloc(256);
816sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
817free(name);
818cnt = 0;
819}
820
821 if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig ))
822{
823 // The key specified is a special key.
824 } else if (getValueForKey( kCDROMOptionKey, &val, &cnt, &bootInfo->bootConfig ) && cnt >= 1) {
825 optionKey = val[0];
826 } else {
827 // Default to F8.
828 optionKey = 0x4200;
829 }
830
831 // If the timeout is zero then it must have been set above due to the
832 // early catch of F8 which means the user wants to set boot options
833 // which we ought to interpret as meaning he wants to boot the CD.
834 if(timeout != 0)
835 key = countdown(prompt, kMenuTopRow, timeout);
836 else
837 key = optionKey;
838
839 if (cnt)
840 free(prompt);
841
842clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
843
844// Hit the option key ?
845if ( key == optionKey )
846{
847gBootMode &= ~kBootModeQuiet;
848timeout = 0;
849
850} else {
851
852key = key & 0xFF;
853
854// Try booting hard disk if user pressed 'h'
855if ( biosDevIsCDROM(gBIOSDev) && key == 'h' )
856{
857BVRef bvr;
858
859// Look at partitions hosting OS X other than the CD-ROM
860for ( bvr = bvChain; bvr; bvr = bvr->next )
861if ( (bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev )
862gBootVolume = bvr;
863}
864
865goto done;
866}
867}
868
869 if ( gBootMode & kBootModeQuiet )
870 {
871 // No input allowed from user.
872 goto done;
873 }
874
875 if ( firstRun && ( timeout > 0 ) &&
876 ( countdown(""/*"Press any key to enter startup options."*/,
877 kMenuTopRow, timeout) == 0 ) )
878 {
879 // If the user is holding down a modifier key,
880 // enter safe mode.
881 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) {
882 gBootMode |= kBootModeSafe;
883 }
884 goto done;
885 }
886
887 if ( gDeviceCount )
888 {
889 // Allocate memory for an array of menu items.
890 menuItems = (MenuItem *) malloc( sizeof(MenuItem) * gDeviceCount );
891 if ( menuItems == NULL ) goto done;
892
893// Associate a menu item for each BVRef.
894 for ( bvr = bvChain, i = gDeviceCount - 1, selectIndex = 0;
895 bvr; bvr = bvr->next)
896if (bvr->visible)
897{
898getBootVolumeDescription( bvr, menuItems[i].name, 80, YES );
899menuItems[i].param = (void *) bvr;
900if ( bvr == menuBVR ) selectIndex = i;
901i--;
902}
903
904}
905
906if( bootArgs->Video.v_display == GRAPHICS_MODE )
907{
908// redraw the background buffer
909drawBackground();
910gui.devicelist.draw = YES;
911gui.redraw = YES;
912if ( ! ( gBootMode & kBootModeQuiet ) )
913
914{
915 BOOL showBootBanner = YES;
916
917 // Check if "Boot Banner"=N switch is present in config file.
918 getBoolForKey( kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
919
920 if ( showBootBanner )
921 {
922 // Display banner and show hardware info.
923 gprintf( &gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024 );
924 }
925
926// redraw background
927memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
928}
929} else {
930 // Clear screen and hide the blinking cursor.
931 clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
932 changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 );
933 }
934
935 nextRow = kMenuTopRow;
936 showPrompt = YES;
937
938 if ( gDeviceCount )
939 {
940 if( bootArgs->Video.v_display == VGA_TEXT_MODE )
941 printf("Use \30\31 keys to select the startup volume.");
942
943 showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
944 nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
945 }
946
947// Show the boot prompt.
948showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
949showBootPrompt( nextRow, showPrompt );
950
951 do {
952
953 if( bootArgs->Video.v_display == GRAPHICS_MODE )
954 {
955 // redraw background
956 memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
957
958 // reset cursor co-ords
959 gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
960
961 }
962
963 key = getc();
964
965 updateMenu( key, (void **) &menuBVR );
966
967 newShowPrompt = (gDeviceCount == 0) ||
968 (menuBVR->flags & kBVFlagNativeBoot);
969
970 if ( newShowPrompt != showPrompt )
971 {
972 showPrompt = newShowPrompt;
973 showBootPrompt( nextRow, showPrompt );
974 }
975
976 if ( showPrompt )
977 updateBootArgs( key );
978
979 switch ( key )
980 {
981 case kReturnKey:
982
983 if ( gui.menu.draw )
984 {
985 key=0;
986 break;
987 }
988
989 if ( *gBootArgs == '?' )
990 {
991 char * argPtr = gBootArgs;
992
993 // Skip the leading "?" character.
994 argPtr++;
995 getNextArg(&argPtr, booterCommand);
996 getNextArg(&argPtr, booterParam);
997
998 /*
999 * TODO: this needs to be refactored.
1000 */
1001
1002 if ( strcmp( booterCommand, "video" ) == 0 )
1003 {
1004 if( bootArgs->Video.v_display == GRAPHICS_MODE )
1005 showInfoBox( getVBEInfoString(), getVBEModeInfoString() );
1006 else
1007 printVBEModeInfo();
1008 }
1009
1010 else if ( strcmp( booterCommand, "memory" ) == 0 )
1011 if( bootArgs->Video.v_display == GRAPHICS_MODE )
1012 showInfoBox( "Memory Map", getMemoryInfoString() );
1013 else
1014 printMemoryInfo();
1015
1016 else if ( strcmp( booterCommand, "lspci" ) == 0 )
1017 lspci(booterParam);
1018
1019 else if ( strcmp( booterCommand, "more" ) == 0 )
1020 showTextFile(booterParam);
1021
1022 else if ( strcmp( booterCommand, "rd" ) == 0 )
1023 processRAMDiskCommand(&argPtr, booterParam);
1024
1025 else if ( strcmp( booterCommand, "norescan" ) == 0 )
1026 {
1027 if (gEnableCDROMRescan)
1028 {
1029 gEnableCDROMRescan = FALSE;
1030 break;
1031 }
1032 }
1033
1034 else
1035 {
1036 showHelp();
1037 }
1038
1039 key = 0;
1040 showBootPrompt( nextRow, showPrompt );
1041 break;
1042 }
1043
1044 gBootVolume = menuBVR;
1045 setRootVolume(menuBVR);
1046 gBIOSDev = menuBVR->biosdev;
1047 break;
1048
1049 case kEscapeKey:
1050 clearBootArgs();
1051 break;
1052
1053 case kF5Key:
1054 // New behavior:
1055 // Clear gBootVolume to restart the loop
1056 // if the user enabled rescanning the optical drive.
1057 // Otherwise boot the default boot volume.
1058 if (gEnableCDROMRescan)
1059 {
1060 gBootVolume = NULL;
1061 clearBootArgs();
1062 }
1063 break;
1064
1065 case kF10Key:
1066 gScanSingleDrive = FALSE;
1067 scanDisks(gBIOSDev, &bvCount);
1068 gBootVolume = NULL;
1069 clearBootArgs();
1070 break;
1071
1072 case kTabKey:
1073 // New behavior:
1074 // Switch between text & graphic interfaces
1075 // Only Permitted if started in graphics interface
1076 if (useGUI)
1077 {
1078 if (bootArgs->Video.v_display == GRAPHICS_MODE)
1079 {
1080 setVideoMode( VGA_TEXT_MODE, 0 );
1081
1082 setCursorPosition( 0, 0, 0 );
1083 clearScreenRows( 0, kScreenLastRow );
1084
1085 // Display banner and show hardware info.
1086 printf( bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024 );
1087 printf( getVBEInfoString() );
1088
1089 clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
1090 changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 );
1091
1092 nextRow = kMenuTopRow;
1093 showPrompt = YES;
1094
1095 if ( gDeviceCount )
1096 {
1097 printf("Use \30\31 keys to select the startup volume.");
1098 showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1099 nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
1100 }
1101
1102 showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1103 showBootPrompt( nextRow, showPrompt );
1104
1105 //changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1106
1107 }
1108 else
1109 {
1110 gui.redraw = YES;
1111 setVideoMode( GRAPHICS_MODE, 0 );
1112 updateVRAM();
1113 }
1114 }
1115 key = 0;
1116 break;
1117
1118 default:
1119 key = 0;
1120 }
1121 }
1122 while ( 0 == key );
1123
1124done:
1125 firstRun = NO;
1126
1127if( bootArgs->Video.v_display == VGA_TEXT_MODE )
1128 {
1129clearScreenRows( kMenuTopRow, kScreenLastRow );
1130changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1131 }
1132
1133 shouldboot = NO;
1134gui.menu.draw = NO;
1135
1136 if ( menuItems )
1137free(menuItems);
1138
1139 return 0;
1140}
1141
1142//==========================================================================
1143
1144extern unsigned char chainbootdev;
1145extern unsigned char chainbootflag;
1146
1147BOOL
1148copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1149{
1150 int argLen = argName ? strlen(argName) : 0;
1151 int len = argLen + cnt + 1; // +1 to account for space
1152
1153 if (len > *cntRemainingP) {
1154 error("Warning: boot arguments too long, truncating\n");
1155 return NO;
1156 }
1157
1158 if (argName) {
1159 strncpy( *argP, argName, argLen );
1160 *argP += argLen;
1161 *argP[0] = '=';
1162 (*argP)++;
1163 len++; // +1 to account for '='
1164 }
1165 strncpy( *argP, val, cnt );
1166 *argP += cnt;
1167 *argP[0] = ' ';
1168 (*argP)++;
1169
1170 *cntRemainingP -= len;
1171 return YES;
1172}
1173
1174//
1175// Returns TRUE if an argument was copied, FALSE otherwise
1176
1177BOOL
1178processBootArgument(
1179 const char *argName, // The argument to search for
1180 const char *userString, // Typed-in boot arguments
1181 const char *kernelFlags, // Kernel flags from config table
1182 const char *configTable,
1183 char **argP, // Output value
1184 int *cntRemainingP, // Output count
1185 char *foundVal // found value
1186 )
1187{
1188 const char *val;
1189 int cnt;
1190 BOOL found = NO;
1191
1192 if (getValueForBootKey(userString, argName, &val, &cnt)) {
1193 // Don't copy; these values will be copied at the end of argument processing.
1194 found = YES;
1195 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
1196 // Don't copy; these values will be copied at the end of argument processing.
1197 found = YES;
1198 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
1199 copyArgument(argName, val, cnt, argP, cntRemainingP);
1200 found = YES;
1201 }
1202 if (found && foundVal) {
1203 strlcpy(foundVal, val, cnt+1);
1204 }
1205 return found;
1206}
1207
1208// Maximum config table value size
1209#define VALUE_SIZE 2048
1210
1211int
1212processBootOptions()
1213{
1214 const char * cp = gBootArgs;
1215 const char * val = 0;
1216 const char * kernel;
1217 int cnt;
1218 int userCnt;
1219 int cntRemaining;
1220 char * argP;
1221 char uuidStr[64];
1222 BOOL uuidSet = NO;
1223 char * configKernelFlags;
1224 char * valueBuffer;
1225
1226 valueBuffer = (char *)malloc(VALUE_SIZE);
1227
1228 skipblanks( &cp );
1229
1230 // Update the unit and partition number.
1231
1232 if ( gBootVolume )
1233 {
1234 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1235 {
1236 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1237 (void *) 0x7c00 );
1238
1239 //
1240 // Setup edx, and signal intention to chain load the
1241 // foreign booter.
1242 //
1243
1244 chainbootdev = gBootVolume->biosdev;
1245 chainbootflag = 1;
1246
1247 return 1;
1248 }
1249
1250 setRootVolume(gBootVolume);
1251
1252 }
1253 // If no boot volume fail immediately because we're just going to fail
1254 // trying to load the config file anyway.
1255 else
1256 return -1;
1257
1258 // Load config table specified by the user, or use the default.
1259
1260 if (getValueForBootKey( cp, "config", &val, &cnt ) == FALSE) {
1261 val = 0;
1262 cnt = 0;
1263 }
1264
1265 // Load com.apple.Boot.plist from the selected volume
1266 // and use its contents to override default bootConfig.
1267 // This is not a mandatory opeartion anymore.
1268
1269 loadOverrideConfig(&bootInfo->overrideConfig);
1270
1271 // Use the kernel name specified by the user, or fetch the name
1272 // in the config table, or use the default if not specified.
1273 // Specifying a kernel name on the command line, or specifying
1274 // a non-default kernel name in the config file counts as
1275 // overriding the kernel, which causes the kernelcache not
1276 // to be used.
1277
1278 gOverrideKernel = NO;
1279 if (( kernel = extractKernelName((char **)&cp) )) {
1280 strcpy( bootInfo->bootFile, kernel );
1281 gOverrideKernel = YES;
1282 } else {
1283 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1284 strlcpy( bootInfo->bootFile, val, cnt+1 );
1285 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1286 gOverrideKernel = YES;
1287 }
1288 } else {
1289 strcpy( bootInfo->bootFile, kDefaultKernel );
1290 }
1291 }
1292
1293 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1294 argP = bootArgs->CommandLine;
1295
1296 // Get config table kernel flags, if not ignored.
1297 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) == TRUE ||
1298 getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig ) == FALSE) {
1299 val = "";
1300 cnt = 0;
1301 }
1302 configKernelFlags = (char *)malloc(cnt + 1);
1303 strlcpy(configKernelFlags, val, cnt + 1);
1304
1305 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1306 // boot-uuid was set either on the command-line
1307 // or in the config file.
1308 uuidSet = YES;
1309 } else {
1310
1311 //
1312 // Try an alternate method for getting the root UUID on boot helper partitions.
1313 //
1314 if (gBootVolume->flags & kBVFlagBooter)
1315 {
1316 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1317 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1318 {
1319 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1320 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1321 uuidSet = YES;
1322 }
1323 }
1324
1325 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1326 verbose("Setting boot-uuid to: %s\n", uuidStr);
1327 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1328 uuidSet = YES;
1329 }
1330 }
1331
1332 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1333 cnt = 0;
1334 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1335 valueBuffer[0] = '*';
1336 cnt++;
1337 strlcpy(valueBuffer + 1, val, cnt);
1338 val = valueBuffer;
1339 } else {
1340 if (uuidSet) {
1341 val = "*uuid";
1342 cnt = 5;
1343 } else {
1344 // Don't set "rd=.." if there is no boot device key
1345 // and no UUID.
1346 val = "";
1347 cnt = 0;
1348 }
1349 }
1350 if (cnt > 0) {
1351 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1352 }
1353 strlcpy( gRootDevice, val, (cnt + 1));
1354 }
1355
1356 /*
1357 * Removed. We don't need this anymore.
1358 *
1359 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1360 getPlatformName(gPlatformName);
1361 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1362 }
1363 */
1364
1365 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1366 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1367 if (gBootMode & kBootModeSafe) {
1368 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1369 }
1370 }
1371
1372 // Store the merged kernel flags and boot args.
1373
1374 cnt = strlen(configKernelFlags);
1375 if (cnt) {
1376 if (cnt > cntRemaining) {
1377 error("Warning: boot arguments too long, truncating\n");
1378 cnt = cntRemaining;
1379 }
1380 strncpy(argP, configKernelFlags, cnt);
1381 argP[cnt++] = ' ';
1382 cntRemaining -= cnt;
1383 }
1384 userCnt = strlen(cp);
1385 if (userCnt > cntRemaining) {
1386 error("Warning: boot arguments too long, truncating\n");
1387 userCnt = cntRemaining;
1388 }
1389 strncpy(&argP[cnt], cp, userCnt);
1390 argP[cnt+userCnt] = '\0';
1391
1392 if(!shouldboot)
1393 {
1394 gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1395 getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1396
1397 gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1398 kBootModeSafe : kBootModeNormal;
1399
1400 if ( getValueForKey( kOldSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1401 gBootMode = kBootModeSafe;
1402 }
1403
1404 if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1405 strlcpy(gMKextName, val, cnt + 1);
1406 }
1407
1408 }
1409
1410 free(configKernelFlags);
1411 free(valueBuffer);
1412
1413 return 0;
1414}
1415
1416
1417//==========================================================================
1418// Load the help file and display the file contents on the screen.
1419
1420void showHelp()
1421{
1422#define BOOT_HELP_PATH "bt(0,0)/Extra/BootHelp.txt"
1423
1424#ifdef EMBED_THEME
1425if( bootArgs->Video.v_display == GRAPHICS_MODE )
1426{
1427showInfoBox( "Help. Press q to quit.\n" , (char *)BootHelp_txt );
1428return;
1429}
1430#endif
1431 showTextFile(BOOT_HELP_PATH);
1432}
1433
1434void showTextFile(const char * filename)
1435{
1436#define MAX_TEXT_FILE_SIZE 65536
1437
1438 int fd;
1439 int size;
1440 int line;
1441 int line_offset;
1442 int c;
1443 char fn[1024];
1444
1445 *fn = '\0';
1446 strcat(fn, filename);
1447
1448 if ( (fd = open(fn, 0)) >= 0 )
1449 {
1450 char * buffer;
1451 char * bp;
1452
1453 size = file_size(fd);
1454 if (size > MAX_TEXT_FILE_SIZE)
1455size = MAX_TEXT_FILE_SIZE;
1456 buffer = malloc( size + 1 );
1457 read(fd, buffer, size);
1458 close(fd);
1459
1460if( bootArgs->Video.v_display == GRAPHICS_MODE )
1461{
1462showInfoBox( "Help. Press q to quit.\n" , buffer );
1463return;
1464}
1465
1466 bp = buffer;
1467 while (size > 0) {
1468 while (*bp != '\n') {
1469 bp++;
1470 size--;
1471 }
1472 *bp++ = '\0';
1473 size--;
1474 }
1475 *bp = '\1';
1476 line_offset = 0;
1477
1478 setActiveDisplayPage(1);
1479
1480 while (1) {
1481 clearScreenRows(0, 24);
1482 setCursorPosition(0, 0, 1);
1483 bp = buffer;
1484 for (line = 0; *bp != '\1' && line < line_offset; line++) {
1485 while (*bp != '\0') bp++;
1486 bp++;
1487 }
1488 for (line = 0; *bp != '\1' && line < 23; line++) {
1489 setCursorPosition(0, line, 1);
1490 printf("%s\n", bp);
1491 while (*bp != '\0') bp++;
1492 bp++;
1493 }
1494
1495 setCursorPosition(0, 23, 1);
1496 if (*bp == '\1') {
1497 printf("[Type %sq or space to quit viewer]",
1498 (line_offset > 0) ? "p for previous page, " : "");
1499 } else {
1500 printf("[Type %s%sq to quit viewer]",
1501 (line_offset > 0) ? "p for previous page, " : "",
1502 (*bp != '\1') ? "space for next page, " : "");
1503 }
1504
1505 c = getc();
1506 if (c == 'q' || c == 'Q') {
1507 break;
1508 }
1509 if ((c == 'p' || c == 'P') && line_offset > 0) {
1510 line_offset -= 23;
1511 }
1512 if (c == ' ') {
1513 if (*bp == '\1') {
1514 break;
1515 } else {
1516 line_offset += 23;
1517 }
1518 }
1519 }
1520
1521 free(buffer);
1522 setActiveDisplayPage(0);
1523 }
1524 else
1525 {
1526 printf("\nFile not found: %s\n", fn);
1527 sleep(2);
1528 }
1529}
1530
1531static inline int isHexDigit(char ch)
1532{
1533 return ('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') || ('a' <= ch && ch <= 'f');
1534}
1535
1536// This is a very simplistic prompting scheme that just grabs two hex characters
1537// Eventually we need to do something more user-friendly like display a menu
1538// based off of the Multiboot device list
1539
1540int selectAlternateBootDevice(int bootdevice)
1541{
1542 int digitsI = 0;
1543 char digits[3] = {0,0,0};
1544
1545 // We've already printed the current boot device so user knows what it is
1546 printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1547 printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1548 int key = 0;
1549 do {
1550 key = getc();
1551 switch(key & kASCIIKeyMask)
1552 {
1553 case kBackspaceKey:
1554 if(digitsI > 0)
1555 {
1556 int x, y, t;
1557 getCursorPositionAndType(&x, &y, &t);
1558 // Assume x is not 0;
1559 x--;
1560 setCursorPosition(x,y,0); // back up one char
1561 // Overwrite with space without moving cursor position
1562 putca(' ', 0x07, 1);
1563 digitsI--;
1564 }
1565 else
1566 {
1567 // TODO: Beep or something
1568 }
1569 break;
1570 case kReturnKey:
1571 if(1)
1572 {
1573 digits[digitsI] = '\0';
1574 char *end;
1575 int newbootdevice = strtol(digits, &end, 16);
1576 if(end == digits && *end == '\0') // User entered empty string
1577 {
1578 printf("\nUsing default boot device %x\n", bootdevice);
1579 key = 0;
1580 }
1581 else if(end != digits && *end == '\0')
1582 {
1583 bootdevice = newbootdevice;
1584 printf("\n");
1585 key = 0; // We gots da boot device
1586 }
1587 else
1588 {
1589 printf("\nCouldn't parse. try again: ");
1590 digitsI = 0;
1591 }
1592 }
1593 break;
1594 default:
1595 if( isHexDigit(key & kASCIIKeyMask) && digitsI < 2 )
1596 {
1597 putc(key & kASCIIKeyMask);
1598 digits[digitsI++] = key & kASCIIKeyMask;
1599 }
1600 else
1601 {
1602 // TODO: Beep or something
1603 }
1604 };
1605 } while(key != 0);
1606 return bootdevice;
1607}
1608
1609
1610BOOL promptForRescanOption(void)
1611{
1612 int key;
1613 BOOL result = FALSE;
1614
1615 printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1616 key = getc();
1617
1618 switch ( key )
1619 {
1620 case kReturnKey:
1621 result = TRUE;
1622 break;
1623 }
1624
1625 return result;
1626}

Archive Download this file

Revision: 52