Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 567