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

Archive Download this file

Revision: 53