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

Archive Download this file

Revision: 469