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

Archive Download this file

Revision: 381