Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 403