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#define QUICK_KEYS_ENABLED 1
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#if QUICK_KEYS_ENABLED
729{
730bool f8 = false, altf = false, shiftf = false, alts = false, altv = false, altl = false, altx = false;
731int key;
732while (readKeyboardStatus()) {
733key = bgetc ();
734if (key == 0x4200) f8 = true;
735if (key == 0x2100) altf = true;
736if (key == 0x2146) shiftf = true;
737if (key == 0x1F00) alts = true;
738if (key == 0x2F00) altv = true;
739if (key == 0x2D00) altx = true;
740if (key == 0x0403) altl = true;
741}
742if (f8) {
743gBootMode &= ~kBootModeQuiet;
744timeout = 0;
745}
746if ((altf) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
747*(gBootArgsPtr++) = ' ';
748*(gBootArgsPtr++) = '-';
749*(gBootArgsPtr++) = 'f';
750}
751if ((shiftf) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
752*(gBootArgsPtr++) = ' ';
753*(gBootArgsPtr++) = '-';
754*(gBootArgsPtr++) = 'F';
755}
756if ((alts) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
757*(gBootArgsPtr++) = ' ';
758*(gBootArgsPtr++) = '-';
759*(gBootArgsPtr++) = 's';
760}
761if ((altv) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
762*(gBootArgsPtr++) = ' ';
763*(gBootArgsPtr++) = '-';
764*(gBootArgsPtr++) = 'v';
765}
766if ((altx) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
767*(gBootArgsPtr++) = ' ';
768*(gBootArgsPtr++) = '-';
769*(gBootArgsPtr++) = 'x';
770//*(gBootArgsPtr++) = '';
771//*(gBootArgsPtr++) = '';
772}
773if ((altl) && (gBootArgsPtr + 3 < gBootArgsEnd)) {
774*(gBootArgsPtr++) = ' ';
775*(gBootArgsPtr++) = '-';
776*(gBootArgsPtr++) = 'x';
777*(gBootArgsPtr++) = '3';
778*(gBootArgsPtr++) = '2';
779
780}
781}
782#else
783{
784bool f8 = false;
785int key;
786while (readKeyboardStatus()) {
787key = bgetc ();
788if (key == 0x4200) f8 = true;
789}
790if (f8) {
791gBootMode &= ~kBootModeQuiet;
792timeout = 0;
793}
794}
795#endif
796
797if( bootArgs->Video.v_display == VGA_TEXT_MODE )
798{
799 setCursorPosition( 0, 0, 0 );
800 clearScreenRows( 0, kScreenLastRow );
801
802if ( ! ( gBootMode & kBootModeQuiet ) )
803{
804// Display banner and show hardware info.
805printf( bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024 );
806printf( getVBEInfoString() );
807}
808
809changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
810verbose("Scanning device %x...", gBIOSDev);
811
812}
813
814 // When booting from CD, default to hard
815 // drive boot when possible.
816
817 if ( isCDROM && firstRun )
818 {
819 const char *val;
820 char *prompt;
821char *name;
822 int cnt;
823 int optionKey;
824
825 if (getValueForKey( kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig )) {
826 cnt += 1;
827 prompt = malloc(cnt);
828 strlcpy(prompt, val, cnt);
829 } else {
830name = malloc(80);
831getBootVolumeDescription( gBootVolume, name, 80, NO );
832prompt = malloc(256);
833sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
834free(name);
835cnt = 0;
836}
837
838 if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig ))
839{
840 // The key specified is a special key.
841 } else if (getValueForKey( kCDROMOptionKey, &val, &cnt, &bootInfo->bootConfig ) && cnt >= 1) {
842 optionKey = val[0];
843 } else {
844 // Default to F8.
845 optionKey = 0x4200;
846 }
847
848 // If the timeout is zero then it must have been set above due to the
849 // early catch of F8 which means the user wants to set boot options
850 // which we ought to interpret as meaning he wants to boot the CD.
851 if(timeout != 0)
852 key = countdown(prompt, kMenuTopRow, timeout);
853 else
854 key = optionKey;
855
856 if (cnt)
857 free(prompt);
858
859clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
860
861// Hit the option key ?
862if ( key == optionKey )
863{
864gBootMode &= ~kBootModeQuiet;
865timeout = 0;
866
867} else {
868
869key = key & 0xFF;
870
871// Try booting hard disk if user pressed 'h'
872if ( biosDevIsCDROM(gBIOSDev) && key == 'h' )
873{
874BVRef bvr;
875
876// Look at partitions hosting OS X other than the CD-ROM
877for ( bvr = bvChain; bvr; bvr = bvr->next )
878if ( (bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev )
879gBootVolume = bvr;
880}
881
882goto done;
883}
884}
885
886 if ( gBootMode & kBootModeQuiet )
887 {
888 // No input allowed from user.
889 goto done;
890 }
891
892 if ( firstRun && ( timeout > 0 ) &&
893 ( countdown(""/*"Press any key to enter startup options."*/,
894 kMenuTopRow, timeout) == 0 ) )
895 {
896 // If the user is holding down a modifier key,
897 // enter safe mode.
898 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) {
899 gBootMode |= kBootModeSafe;
900 }
901 goto done;
902 }
903
904 if ( gDeviceCount )
905 {
906 // Allocate memory for an array of menu items.
907 menuItems = (MenuItem *) malloc( sizeof(MenuItem) * gDeviceCount );
908 if ( menuItems == NULL ) goto done;
909
910// Associate a menu item for each BVRef.
911 for ( bvr = bvChain, i = gDeviceCount - 1, selectIndex = 0;
912 bvr; bvr = bvr->next)
913if (bvr->visible)
914{
915getBootVolumeDescription( bvr, menuItems[i].name, 80, YES );
916menuItems[i].param = (void *) bvr;
917if ( bvr == menuBVR ) selectIndex = i;
918i--;
919}
920
921}
922
923if( bootArgs->Video.v_display == GRAPHICS_MODE )
924{
925// redraw the background buffer
926drawBackground();
927gui.devicelist.draw = YES;
928gui.redraw = YES;
929if ( ! ( gBootMode & kBootModeQuiet ) )
930
931{
932 BOOL showBootBanner = YES;
933
934 // Check if "Boot Banner"=N switch is present in config file.
935 getBoolForKey( kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
936
937 if ( showBootBanner )
938 {
939 // Display banner and show hardware info.
940 gprintf( &gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024 );
941 }
942
943// redraw background
944memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
945}
946} else {
947 // Clear screen and hide the blinking cursor.
948 clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
949 changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 );
950 }
951
952 nextRow = kMenuTopRow;
953 showPrompt = YES;
954
955 if ( gDeviceCount )
956 {
957 if( bootArgs->Video.v_display == VGA_TEXT_MODE )
958 printf("Use \30\31 keys to select the startup volume.");
959
960 showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
961 nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
962 }
963
964// Show the boot prompt.
965showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
966showBootPrompt( nextRow, showPrompt );
967
968 do {
969
970 if( bootArgs->Video.v_display == GRAPHICS_MODE )
971 {
972 // redraw background
973 memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
974
975 // reset cursor co-ords
976 gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
977
978 }
979
980 key = getc();
981
982 updateMenu( key, (void **) &menuBVR );
983
984 newShowPrompt = (gDeviceCount == 0) ||
985 (menuBVR->flags & kBVFlagNativeBoot);
986
987 if ( newShowPrompt != showPrompt )
988 {
989 showPrompt = newShowPrompt;
990 showBootPrompt( nextRow, showPrompt );
991 }
992
993 if ( showPrompt )
994 updateBootArgs( key );
995
996 switch ( key )
997 {
998 case kReturnKey:
999
1000 if ( gui.menu.draw )
1001 {
1002 key=0;
1003 break;
1004 }
1005
1006 if ( *gBootArgs == '?' )
1007 {
1008 char * argPtr = gBootArgs;
1009
1010 // Skip the leading "?" character.
1011 argPtr++;
1012 getNextArg(&argPtr, booterCommand);
1013 getNextArg(&argPtr, booterParam);
1014
1015 /*
1016 * TODO: this needs to be refactored.
1017 */
1018
1019 if ( strcmp( booterCommand, "video" ) == 0 )
1020 {
1021 if( bootArgs->Video.v_display == GRAPHICS_MODE )
1022 showInfoBox( getVBEInfoString(), getVBEModeInfoString() );
1023 else
1024 printVBEModeInfo();
1025 }
1026
1027 else if ( strcmp( booterCommand, "memory" ) == 0 )
1028 if( bootArgs->Video.v_display == GRAPHICS_MODE )
1029 showInfoBox( "Memory Map", getMemoryInfoString() );
1030 else
1031 printMemoryInfo();
1032
1033 else if ( strcmp( booterCommand, "lspci" ) == 0 )
1034 lspci(booterParam);
1035
1036 else if ( strcmp( booterCommand, "more" ) == 0 )
1037 showTextFile(booterParam);
1038
1039 else if ( strcmp( booterCommand, "rd" ) == 0 )
1040 processRAMDiskCommand(&argPtr, booterParam);
1041
1042 else if ( strcmp( booterCommand, "norescan" ) == 0 )
1043 {
1044 if (gEnableCDROMRescan)
1045 {
1046 gEnableCDROMRescan = FALSE;
1047 break;
1048 }
1049 }
1050
1051 else
1052 {
1053 showHelp();
1054 }
1055
1056 key = 0;
1057 showBootPrompt( nextRow, showPrompt );
1058 break;
1059 }
1060
1061 gBootVolume = menuBVR;
1062 setRootVolume(menuBVR);
1063 gBIOSDev = menuBVR->biosdev;
1064 break;
1065
1066 case kEscapeKey:
1067 clearBootArgs();
1068 break;
1069
1070 case kF5Key:
1071 // New behavior:
1072 // Clear gBootVolume to restart the loop
1073 // if the user enabled rescanning the optical drive.
1074 // Otherwise boot the default boot volume.
1075 if (gEnableCDROMRescan)
1076 {
1077 gBootVolume = NULL;
1078 clearBootArgs();
1079 }
1080 break;
1081
1082 case kF10Key:
1083 gScanSingleDrive = FALSE;
1084 scanDisks(gBIOSDev, &bvCount);
1085 gBootVolume = NULL;
1086 clearBootArgs();
1087 break;
1088
1089 case kTabKey:
1090 // New behavior:
1091 // Switch between text & graphic interfaces
1092 // Only Permitted if started in graphics interface
1093 if (useGUI)
1094 {
1095 if (bootArgs->Video.v_display == GRAPHICS_MODE)
1096 {
1097 setVideoMode( VGA_TEXT_MODE, 0 );
1098
1099 setCursorPosition( 0, 0, 0 );
1100 clearScreenRows( 0, kScreenLastRow );
1101
1102 // Display banner and show hardware info.
1103 printf( bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024 );
1104 printf( getVBEInfoString() );
1105
1106 clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
1107 changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 );
1108
1109 nextRow = kMenuTopRow;
1110 showPrompt = YES;
1111
1112 if ( gDeviceCount )
1113 {
1114 printf("Use \30\31 keys to select the startup volume.");
1115 showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1116 nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
1117 }
1118
1119 showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1120 showBootPrompt( nextRow, showPrompt );
1121
1122 //changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1123
1124 }
1125 else
1126 {
1127 gui.redraw = YES;
1128 setVideoMode( GRAPHICS_MODE, 0 );
1129 updateVRAM();
1130 }
1131 }
1132 key = 0;
1133 break;
1134
1135 default:
1136 key = 0;
1137 }
1138 }
1139 while ( 0 == key );
1140
1141done:
1142 firstRun = NO;
1143
1144if( bootArgs->Video.v_display == VGA_TEXT_MODE )
1145 {
1146clearScreenRows( kMenuTopRow, kScreenLastRow );
1147changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1148 }
1149
1150 shouldboot = NO;
1151gui.menu.draw = NO;
1152
1153 if ( menuItems )
1154free(menuItems);
1155
1156 return 0;
1157}
1158
1159//==========================================================================
1160
1161extern unsigned char chainbootdev;
1162extern unsigned char chainbootflag;
1163
1164BOOL
1165copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1166{
1167 int argLen = argName ? strlen(argName) : 0;
1168 int len = argLen + cnt + 1; // +1 to account for space
1169
1170 if (len > *cntRemainingP) {
1171 error("Warning: boot arguments too long, truncating\n");
1172 return NO;
1173 }
1174
1175 if (argName) {
1176 strncpy( *argP, argName, argLen );
1177 *argP += argLen;
1178 *argP[0] = '=';
1179 (*argP)++;
1180 len++; // +1 to account for '='
1181 }
1182 strncpy( *argP, val, cnt );
1183 *argP += cnt;
1184 *argP[0] = ' ';
1185 (*argP)++;
1186
1187 *cntRemainingP -= len;
1188 return YES;
1189}
1190
1191//
1192// Returns TRUE if an argument was copied, FALSE otherwise
1193
1194BOOL
1195processBootArgument(
1196 const char *argName, // The argument to search for
1197 const char *userString, // Typed-in boot arguments
1198 const char *kernelFlags, // Kernel flags from config table
1199 const char *configTable,
1200 char **argP, // Output value
1201 int *cntRemainingP, // Output count
1202 char *foundVal // found value
1203 )
1204{
1205 const char *val;
1206 int cnt;
1207 BOOL found = NO;
1208
1209 if (getValueForBootKey(userString, argName, &val, &cnt)) {
1210 // Don't copy; these values will be copied at the end of argument processing.
1211 found = YES;
1212 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
1213 // Don't copy; these values will be copied at the end of argument processing.
1214 found = YES;
1215 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
1216 copyArgument(argName, val, cnt, argP, cntRemainingP);
1217 found = YES;
1218 }
1219 if (found && foundVal) {
1220 strlcpy(foundVal, val, cnt+1);
1221 }
1222 return found;
1223}
1224
1225// Maximum config table value size
1226#define VALUE_SIZE 2048
1227
1228int
1229processBootOptions()
1230{
1231 const char * cp = gBootArgs;
1232 const char * val = 0;
1233 const char * kernel;
1234 int cnt;
1235 int userCnt;
1236 int cntRemaining;
1237 char * argP;
1238 char uuidStr[64];
1239 BOOL uuidSet = NO;
1240 char * configKernelFlags;
1241 char * valueBuffer;
1242
1243 valueBuffer = (char *)malloc(VALUE_SIZE);
1244
1245 skipblanks( &cp );
1246
1247 // Update the unit and partition number.
1248
1249 if ( gBootVolume )
1250 {
1251 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1252 {
1253 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1254 (void *) 0x7c00 );
1255
1256 //
1257 // Setup edx, and signal intention to chain load the
1258 // foreign booter.
1259 //
1260
1261 chainbootdev = gBootVolume->biosdev;
1262 chainbootflag = 1;
1263
1264 return 1;
1265 }
1266
1267 setRootVolume(gBootVolume);
1268
1269 }
1270 // If no boot volume fail immediately because we're just going to fail
1271 // trying to load the config file anyway.
1272 else
1273 return -1;
1274
1275 // Load config table specified by the user, or use the default.
1276
1277 if (getValueForBootKey( cp, "config", &val, &cnt ) == FALSE) {
1278 val = 0;
1279 cnt = 0;
1280 }
1281
1282 // Load com.apple.Boot.plist from the selected volume
1283 // and use its contents to override default bootConfig.
1284 // This is not a mandatory opeartion anymore.
1285
1286 loadOverrideConfig(&bootInfo->overrideConfig);
1287
1288 // Use the kernel name specified by the user, or fetch the name
1289 // in the config table, or use the default if not specified.
1290 // Specifying a kernel name on the command line, or specifying
1291 // a non-default kernel name in the config file counts as
1292 // overriding the kernel, which causes the kernelcache not
1293 // to be used.
1294
1295 gOverrideKernel = NO;
1296 if (( kernel = extractKernelName((char **)&cp) )) {
1297 strcpy( bootInfo->bootFile, kernel );
1298 gOverrideKernel = YES;
1299 } else {
1300 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1301 strlcpy( bootInfo->bootFile, val, cnt+1 );
1302 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1303 gOverrideKernel = YES;
1304 }
1305 } else {
1306 strcpy( bootInfo->bootFile, kDefaultKernel );
1307 }
1308 }
1309
1310 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1311 argP = bootArgs->CommandLine;
1312
1313 // Get config table kernel flags, if not ignored.
1314 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) == TRUE ||
1315 getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig ) == FALSE) {
1316 val = "";
1317 cnt = 0;
1318 }
1319 configKernelFlags = (char *)malloc(cnt + 1);
1320 strlcpy(configKernelFlags, val, cnt + 1);
1321
1322 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1323 // boot-uuid was set either on the command-line
1324 // or in the config file.
1325 uuidSet = YES;
1326 } else {
1327
1328 //
1329 // Try an alternate method for getting the root UUID on boot helper partitions.
1330 //
1331 if (gBootVolume->flags & kBVFlagBooter)
1332 {
1333 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1334 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1335 {
1336 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1337 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1338 uuidSet = YES;
1339 }
1340 }
1341
1342 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1343 verbose("Setting boot-uuid to: %s\n", uuidStr);
1344 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1345 uuidSet = YES;
1346 }
1347 }
1348
1349 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1350 cnt = 0;
1351 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1352 valueBuffer[0] = '*';
1353 cnt++;
1354 strlcpy(valueBuffer + 1, val, cnt);
1355 val = valueBuffer;
1356 } else {
1357 if (uuidSet) {
1358 val = "*uuid";
1359 cnt = 5;
1360 } else {
1361 // Don't set "rd=.." if there is no boot device key
1362 // and no UUID.
1363 val = "";
1364 cnt = 0;
1365 }
1366 }
1367 if (cnt > 0) {
1368 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1369 }
1370 strlcpy( gRootDevice, val, (cnt + 1));
1371 }
1372
1373 /*
1374 * Removed. We don't need this anymore.
1375 *
1376 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1377 getPlatformName(gPlatformName);
1378 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1379 }
1380 */
1381
1382 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1383 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1384 if (gBootMode & kBootModeSafe) {
1385 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1386 }
1387 }
1388
1389 // Store the merged kernel flags and boot args.
1390
1391 cnt = strlen(configKernelFlags);
1392 if (cnt) {
1393 if (cnt > cntRemaining) {
1394 error("Warning: boot arguments too long, truncating\n");
1395 cnt = cntRemaining;
1396 }
1397 strncpy(argP, configKernelFlags, cnt);
1398 argP[cnt++] = ' ';
1399 cntRemaining -= cnt;
1400 }
1401 userCnt = strlen(cp);
1402 if (userCnt > cntRemaining) {
1403 error("Warning: boot arguments too long, truncating\n");
1404 userCnt = cntRemaining;
1405 }
1406 strncpy(&argP[cnt], cp, userCnt);
1407 argP[cnt+userCnt] = '\0';
1408
1409 if(!shouldboot)
1410 {
1411 gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1412 getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1413
1414 gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1415 kBootModeSafe : kBootModeNormal;
1416
1417 if ( getValueForKey( kOldSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1418 gBootMode = kBootModeSafe;
1419 }
1420
1421 if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1422 strlcpy(gMKextName, val, cnt + 1);
1423 }
1424
1425 }
1426
1427 free(configKernelFlags);
1428 free(valueBuffer);
1429
1430 return 0;
1431}
1432
1433
1434//==========================================================================
1435// Load the help file and display the file contents on the screen.
1436
1437void showHelp()
1438{
1439#define BOOT_HELP_PATH "bt(0,0)/Extra/BootHelp.txt"
1440
1441#ifdef EMBED_THEME
1442if( bootArgs->Video.v_display == GRAPHICS_MODE )
1443{
1444showInfoBox( "Help. Press q to quit.\n" , (char *)BootHelp_txt );
1445return;
1446}
1447#endif
1448 showTextFile(BOOT_HELP_PATH);
1449}
1450
1451void showTextFile(const char * filename)
1452{
1453#define MAX_TEXT_FILE_SIZE 65536
1454
1455 int fd;
1456 int size;
1457 int line;
1458 int line_offset;
1459 int c;
1460 char fn[1024];
1461
1462 *fn = '\0';
1463 strcat(fn, filename);
1464
1465 if ( (fd = open(fn, 0)) >= 0 )
1466 {
1467 char * buffer;
1468 char * bp;
1469
1470 size = file_size(fd);
1471 if (size > MAX_TEXT_FILE_SIZE)
1472size = MAX_TEXT_FILE_SIZE;
1473 buffer = malloc( size + 1 );
1474 read(fd, buffer, size);
1475 close(fd);
1476
1477if( bootArgs->Video.v_display == GRAPHICS_MODE )
1478{
1479showInfoBox( "Help. Press q to quit.\n" , buffer );
1480return;
1481}
1482
1483 bp = buffer;
1484 while (size > 0) {
1485 while (*bp != '\n') {
1486 bp++;
1487 size--;
1488 }
1489 *bp++ = '\0';
1490 size--;
1491 }
1492 *bp = '\1';
1493 line_offset = 0;
1494
1495 setActiveDisplayPage(1);
1496
1497 while (1) {
1498 clearScreenRows(0, 24);
1499 setCursorPosition(0, 0, 1);
1500 bp = buffer;
1501 for (line = 0; *bp != '\1' && line < line_offset; line++) {
1502 while (*bp != '\0') bp++;
1503 bp++;
1504 }
1505 for (line = 0; *bp != '\1' && line < 23; line++) {
1506 setCursorPosition(0, line, 1);
1507 printf("%s\n", bp);
1508 while (*bp != '\0') bp++;
1509 bp++;
1510 }
1511
1512 setCursorPosition(0, 23, 1);
1513 if (*bp == '\1') {
1514 printf("[Type %sq or space to quit viewer]",
1515 (line_offset > 0) ? "p for previous page, " : "");
1516 } else {
1517 printf("[Type %s%sq to quit viewer]",
1518 (line_offset > 0) ? "p for previous page, " : "",
1519 (*bp != '\1') ? "space for next page, " : "");
1520 }
1521
1522 c = getc();
1523 if (c == 'q' || c == 'Q') {
1524 break;
1525 }
1526 if ((c == 'p' || c == 'P') && line_offset > 0) {
1527 line_offset -= 23;
1528 }
1529 if (c == ' ') {
1530 if (*bp == '\1') {
1531 break;
1532 } else {
1533 line_offset += 23;
1534 }
1535 }
1536 }
1537
1538 free(buffer);
1539 setActiveDisplayPage(0);
1540 }
1541 else
1542 {
1543 printf("\nFile not found: %s\n", fn);
1544 sleep(2);
1545 }
1546}
1547
1548static inline int isHexDigit(char ch)
1549{
1550 return ('0' <= ch && ch <= '9') || ('A' <= ch && ch <= 'F') || ('a' <= ch && ch <= 'f');
1551}
1552
1553// This is a very simplistic prompting scheme that just grabs two hex characters
1554// Eventually we need to do something more user-friendly like display a menu
1555// based off of the Multiboot device list
1556
1557int selectAlternateBootDevice(int bootdevice)
1558{
1559 int digitsI = 0;
1560 char digits[3] = {0,0,0};
1561
1562 // We've already printed the current boot device so user knows what it is
1563 printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1564 printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1565 int key = 0;
1566 do {
1567 key = getc();
1568 switch(key & kASCIIKeyMask)
1569 {
1570 case kBackspaceKey:
1571 if(digitsI > 0)
1572 {
1573 int x, y, t;
1574 getCursorPositionAndType(&x, &y, &t);
1575 // Assume x is not 0;
1576 x--;
1577 setCursorPosition(x,y,0); // back up one char
1578 // Overwrite with space without moving cursor position
1579 putca(' ', 0x07, 1);
1580 digitsI--;
1581 }
1582 else
1583 {
1584 // TODO: Beep or something
1585 }
1586 break;
1587 case kReturnKey:
1588 if(1)
1589 {
1590 digits[digitsI] = '\0';
1591 char *end;
1592 int newbootdevice = strtol(digits, &end, 16);
1593 if(end == digits && *end == '\0') // User entered empty string
1594 {
1595 printf("\nUsing default boot device %x\n", bootdevice);
1596 key = 0;
1597 }
1598 else if(end != digits && *end == '\0')
1599 {
1600 bootdevice = newbootdevice;
1601 printf("\n");
1602 key = 0; // We gots da boot device
1603 }
1604 else
1605 {
1606 printf("\nCouldn't parse. try again: ");
1607 digitsI = 0;
1608 }
1609 }
1610 break;
1611 default:
1612 if( isHexDigit(key & kASCIIKeyMask) && digitsI < 2 )
1613 {
1614 putc(key & kASCIIKeyMask);
1615 digits[digitsI++] = key & kASCIIKeyMask;
1616 }
1617 else
1618 {
1619 // TODO: Beep or something
1620 }
1621 };
1622 } while(key != 0);
1623 return bootdevice;
1624}
1625
1626
1627BOOL promptForRescanOption(void)
1628{
1629 int key;
1630 BOOL result = FALSE;
1631
1632 printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1633 key = getc();
1634
1635 switch ( key )
1636 {
1637 case kReturnKey:
1638 result = TRUE;
1639 break;
1640 }
1641
1642 return result;
1643}

Archive Download this file

Revision: 64