Chameleon

Chameleon Svn Source Tree

Root/branches/valv/i386/boot2/options.c

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

Archive Download this file

Revision: 701