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

Archive Download this file

Revision: 399