Chameleon

Chameleon Svn Source Tree

Root/branches/azimutz/Chazi/i386/boot2/options.c

1/*
2 * Copyright (c) 1999-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999-2004 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 2.0 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include "boot.h"
26#include "fdisk.h"
27#include "ramdisk.h"
28#include "gui.h"
29#include "embedded.h"
30#include "pci.h"
31#include "options.h"
32#include "efi.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
43//extern intgDeviceCount; //Azi: header
44chargMacOSVersion[8]; //Azi: moved from boot.c - extern on boot.h/bootargs.h
45static bool getOSVersion(char *str); //||
46
47intselectIndex = 0;
48MenuItem * menuItems = NULL;
49
50//==========================================================================
51
52//static //Azi:autoresolution
53void changeCursor( int col, int row, int type, CursorState * cs )
54{
55 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
56 setCursorType( type );
57 setCursorPosition( col, row, 0 );
58}
59
60static void moveCursor( int col, int row )
61{
62 setCursorPosition( col, row, 0 );
63}
64
65static void restoreCursor( const CursorState * cs )
66{
67 setCursorPosition( cs->x, cs->y, 0 );
68 setCursorType( cs->type );
69}
70
71//==========================================================================
72
73/* Flush keyboard buffer; returns TRUE if any of the flushed
74 * characters was F8.
75 */
76
77static bool flushKeyboardBuffer(void)
78{
79 bool status = false;
80
81 while ( readKeyboardStatus() ) {
82 if (bgetc() == 0x4200) status = true;
83 }
84 return status;
85}
86
87//==========================================================================
88
89static int countdown( const char * msg, int row, int timeout )
90{
91 unsigned long time;
92 int ch = 0;
93 int col = strlen(msg) + 1;
94
95 flushKeyboardBuffer();
96
97if( bootArgs->Video.v_display == VGA_TEXT_MODE )
98{
99moveCursor( 0, row );
100printf(msg);
101
102} else {
103
104position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
105
106char dummy[80];
107getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
108drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
109drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
110
111// make this screen the new background
112memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
113
114}
115
116int multi_buff = 18 * (timeout);
117 int multi = ++multi_buff;
118
119 int lasttime=0;
120
121 for ( time = time18(), timeout++; timeout > 0; )
122 {
123if( time18() > lasttime)
124{
125multi--;
126lasttime=time18();
127}
128
129 if (ch = readKeyboardStatus())
130 break;
131
132 // Count can be interrupted by holding down shift,
133 // control or alt key
134 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
135{
136 ch = 1;
137 break;
138 }
139
140 if ( time18() >= time )
141 {
142 time += 18;
143 timeout--;
144
145if( bootArgs->Video.v_display == VGA_TEXT_MODE )
146{
147moveCursor( col, row );
148printf("(%d) ", timeout);
149}
150 }
151
152if( bootArgs->Video.v_display != VGA_TEXT_MODE )
153{
154drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
155gui.redraw = true;
156updateVRAM();
157}
158
159 }
160
161 flushKeyboardBuffer();
162
163 return ch;
164}
165
166//==========================================================================
167//Azi: bootargs reminder
168//static - getc --> getchar
169char gBootArgs[BOOT_STRING_LEN];
170static char * gBootArgsPtr = gBootArgs;
171static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
172static char booterCommand[BOOT_STRING_LEN];
173static char booterParam[BOOT_STRING_LEN];
174
175//static //Azi:autoresolution
176void clearBootArgs(void)
177{
178gBootArgsPtr = gBootArgs;
179memset(gBootArgs, '\0', BOOT_STRING_LEN);
180
181if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
182clearGraphicBootPrompt();
183}
184}
185
186static void addBootArg(const char * argStr)
187{
188if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
189{
190*gBootArgsPtr++ = ' ';
191strcat(gBootArgs, argStr);
192gBootArgsPtr += strlen(argStr);
193}
194}
195
196//==========================================================================
197
198//static //Azi:autoresolution
199void 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
209//clearBootArgs();
210
211if (visible) {
212if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
213if (gEnableCDROMRescan) {
214printf( bootRescanPrompt );
215} else {
216printf( bootPrompt );
217printf( gBootArgs );
218}
219}
220} else {
221if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
222//clearGraphicBootPrompt();
223} else {
224printf("Press Enter to start up the foreign OS. ");
225}
226}
227}
228
229//==========================================================================
230
231static void updateBootArgs( int key )
232{
233 key &= kASCIIKeyMask;
234
235 switch ( key )
236 {
237 case kBackspaceKey:
238 if ( gBootArgsPtr > gBootArgs )
239 {
240 *--gBootArgsPtr = '\0';
241
242 int x, y, t;
243 getCursorPositionAndType( &x, &y, &t );
244 if ( x == 0 && y )
245 {
246 x = 80; y--;
247 }
248 if (x) x--;
249
250if( bootArgs->Video.v_display == VGA_TEXT_MODE )
251{
252setCursorPosition( x, y, 0 );
253putca(' ', 0x07, 1);
254}
255 else
256 {
257 updateGraphicBootPrompt();
258 }
259 }
260break;
261
262 default:
263 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
264 {
265 *gBootArgsPtr++ = key;
266
267 if( bootArgs->Video.v_display != VGA_TEXT_MODE ) updateGraphicBootPrompt();
268 else if ( key >= ' ' && key < 0x7f) putchar(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
303//static //Azi:autoresolution
304void showMenu( const MenuItem * items, int count,
305 int selection, int row, int height )
306{
307 int i;
308 CursorState cursorState;
309
310 if ( items == NULL || count == 0 )
311return;
312
313 // head and tail points to the start and the end of the list.
314 // top and bottom points to the first and last visible items
315 // in the menu window.
316
317 gMenuItems= items;
318 gMenuRow= row;
319 gMenuHeight= height;
320 gMenuItemCount= count;
321 gMenuTop= 0;
322 gMenuBottom= MIN( count, height ) - 1;
323 gMenuSelection= selection;
324
325 gMenuStart= 0;
326 gMenuEnd = MIN( count, gui.maxdevices ) - 1;
327
328// If the selected item is not visible, shift the list down.
329
330 if ( gMenuSelection > gMenuBottom )
331 {
332 gMenuTop += ( gMenuSelection - gMenuBottom );
333 gMenuBottom = gMenuSelection;
334 }
335
336if ( gMenuSelection > gMenuEnd )
337 {
338gMenuStart += ( gMenuSelection - gMenuEnd );
339 gMenuEnd = gMenuSelection;
340 }
341
342// Draw the visible items.
343
344if( bootArgs->Video.v_display != VGA_TEXT_MODE )
345
346drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
347
348else {
349
350changeCursor( 0, row, kCursorTypeHidden, &cursorState );
351
352for ( i = gMenuTop; i <= gMenuBottom; i++ )
353{
354printMenuItem( &items[i], (i == gMenuSelection) );
355}
356
357restoreCursor( &cursorState );
358 }
359}
360
361//==========================================================================
362
363static int updateMenu( int key, void ** paramPtr )
364{
365 int moved = 0;
366
367 union {
368 struct {
369 unsigned int
370 selectionUp : 1,
371 selectionDown : 1,
372 scrollUp : 1,
373 scrollDown : 1;
374 } f;
375 unsigned int w;
376 } draw = {{0}};
377
378 if ( gMenuItems == NULL )
379return 0;
380
381if( bootArgs->Video.v_display != VGA_TEXT_MODE )
382{
383int res;
384
385// set navigation keys for horizontal layout as defaults
386int previous= 0x4B00;// left arrow
387int subsequent= 0x4D00;// right arrow
388int menu= 0x5000;// down arrow
389
390if ( gui.layout == VerticalLayout )
391{
392// set navigation keys for vertical layout
393previous= 0x4800;// up arrow
394subsequent= 0x5000;// down arrow
395menu= 0x4B00;// right arrow
396}
397
398if ( key == previous )
399{
400if ( gMenuSelection > gMenuTop )
401draw.f.selectionUp = 1;
402else if ( gMenuTop > 0 )
403draw.f.scrollDown = 1;
404
405}
406
407else if ( key == subsequent )
408{
409if ( gMenuSelection != gMenuBottom)
410draw.f.selectionDown = 1;
411else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
412draw.f.scrollUp = 1;
413}
414
415else if ( key == menu )
416{
417if ( gui.menu.draw )
418updateInfoMenu(key);
419else
420drawInfoMenu();
421}
422
423else if ( gui.menu.draw )
424{
425res = updateInfoMenu(key);
426
427if ( res == CLOSE_INFO_MENU )
428gui.menu.draw = false;
429else
430{
431shouldboot = ( res != DO_NOT_BOOT );
432
433if ( shouldboot )
434gui.menu.draw = false;
435
436switch (res)
437{
438case BOOT_NORMAL:
439gVerboseMode = false;
440gBootMode = kBootModeNormal;
441break;
442
443case BOOT_VERBOSE:
444gVerboseMode = true;
445gBootMode = kBootModeNormal;
446addBootArg(kVerboseModeFlag);
447break;
448
449case BOOT_IGNORECACHE:
450gVerboseMode = false;
451gBootMode = kBootModeNormal;
452addBootArg(kIgnoreCachesFlag);
453//Azi: this one crossed my mind a lot of times.. nice going :)
454addBootArg(kVerboseModeFlag); //Slice - if ignore cache then verbose
455break;
456
457case BOOT_SINGLEUSER:
458gVerboseMode = true;
459gBootMode = kBootModeNormal;
460addBootArg(kSingleUserModeFlag);
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//Azi: autoresolution
679int key;
680int nextRow;
681BVRef menuBVR;
682bool showPrompt;
683extern void reloadAutoRes();
684
685int getBootOptions(bool firstRun)
686{
687int i;
688//int key;
689//int nextRow;
690int timeout;
691int bvCount;
692BVRef bvr;
693//BVRef menuBVR;
694//bool showPrompt;
695bool newShowPrompt, isCDROM;
696
697// Initialize default menu selection entry.
698gBootVolume = menuBVR = selectBootVolume(bvChain);
699
700if (biosDevIsCDROM(gBIOSDev)) {
701isCDROM = true;
702} else {
703isCDROM = false;
704}
705
706// ensure we're in graphics mode if gui is setup
707if (firstRun && gui.initialised && bootArgs->Video.v_display == VGA_TEXT_MODE)
708{
709setVideoMode(GRAPHICS_MODE, 0);
710}
711
712// Clear command line boot arguments
713clearBootArgs();
714
715// Allow user to override default timeout.
716if (multiboot_timeout_set) {
717timeout = multiboot_timeout;
718} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
719/* If there is no timeout key in the file use the default timeout
720 which is different for CDs vs. hard disks. However, if not booting
721 a CD and no config file could be loaded set the timeout
722 to zero which causes the menu to display immediately.
723 This way, if no partitions can be found, that is the disk is unpartitioned
724 or simply cannot be read) then an empty menu is displayed.
725 If some partitions are found, for example a Windows partition, then
726 these will be displayed in the menu as foreign partitions.
727 */
728if (isCDROM) {
729timeout = kCDBootTimeout;
730} else {
731timeout = sysConfigValid ? kBootTimeout : 0;
732}
733}
734
735if (timeout < 0) {
736gBootMode |= kBootModeQuiet;
737}
738
739// If the user is holding down a modifier key, enter safe mode.
740if ((readKeyboardShiftFlags() & 0x0F) != 0) {
741gBootMode |= kBootModeSafe;
742}
743
744// Checking user pressed keys
745bool f8press = false, spress = false, vpress = false;
746while (readKeyboardStatus()) {
747key = bgetc ();
748if (key == 0x4200) f8press = true;
749if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
750if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
751}
752// If user typed F8, abort quiet mode, and display the menu.
753if (f8press) {
754gBootMode &= ~kBootModeQuiet;
755timeout = 0;
756}
757// If user typed 'v' or 'V', boot in verbose mode.
758if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
759addBootArg(kVerboseModeFlag);
760}
761// If user typed 's' or 'S', boot in single user mode.
762if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
763addBootArg(kSingleUserModeFlag);
764}
765
766if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
767setCursorPosition(0, 0, 0);
768clearScreenRows(0, kScreenLastRow);
769if (!(gBootMode & kBootModeQuiet)) {
770// Display banner and show hardware info.
771printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
772printf(getVBEInfoString());
773}
774changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
775verbose("Scanning device %x...", gBIOSDev);
776}
777
778// When booting from CD, default to hard drive boot when possible.
779if (isCDROM && firstRun) {
780const char *val;
781char *prompt = NULL;
782char *name = NULL;
783int cnt;
784int optionKey;
785
786//Azi:---
787if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig))
788{
789prompt = malloc(cnt + 1);
790strncat(prompt, val, cnt);
791}
792else
793{
794name = malloc(80);
795getBootVolumeDescription(gBootVolume, name, 79, false);
796prompt = malloc(256);
797//Azi: too long for 80X25, GUI=n, vmware, depending on the device name (more than 5 char).
798sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
799free(name);
800}
801
802if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig ))
803{
804// The key specified is a special key.
805}
806else
807{
808// Default to F8.
809optionKey = 0x4200;
810}
811
812// If the timeout is zero then it must have been set above due to the
813// early catch of F8 which means the user wants to set boot options
814// which we ought to interpret as meaning he wants to boot the CD.
815if (timeout != 0) {
816key = countdown(prompt, kMenuTopRow, timeout);
817} else {
818key = optionKey;
819}
820
821if (prompt != NULL) {
822free(prompt);
823}
824
825clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
826
827// Hit the option key ?
828if (key == optionKey) {
829gBootMode &= ~kBootModeQuiet;
830timeout = 0;
831} else {
832key = key & 0xFF;
833
834// Try booting hard disk if user pressed 'h'
835if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
836BVRef bvr;
837
838// Look at partitions hosting OS X other than the CD-ROM
839for (bvr = bvChain; bvr; bvr=bvr->next) {
840if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
841gBootVolume = bvr;
842}
843}
844}
845goto done;
846}
847}
848
849if (gBootMode & kBootModeQuiet) {
850// No input allowed from user.
851goto done;
852}
853
854if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
855// If the user is holding down a modifier key,
856// enter safe mode.
857if ((readKeyboardShiftFlags() & 0x0F) != 0) {
858gBootMode |= kBootModeSafe;
859}
860goto done;
861}
862
863if (gDeviceCount) {
864// Allocate memory for an array of menu items.
865menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
866if (menuItems == NULL) {
867goto done;
868}
869
870// Associate a menu item for each BVRef.
871for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
872if (bvr->visible) {
873getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
874menuItems[i].param = (void *) bvr;
875if (bvr == menuBVR) {
876selectIndex = i;
877}
878i--;
879}
880}
881}
882
883if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
884// redraw the background buffer
885gui.logo.draw = true;
886drawBackground();
887gui.devicelist.draw = true;
888gui.redraw = true;
889if (!(gBootMode & kBootModeQuiet)) {
890
891// Check if "Boot Banner"=N switch is present in config file.
892getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
893if (showBootBanner) {
894// Display banner and show hardware info.
895gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
896}
897
898// redraw background
899memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
900}
901} else {
902// Clear screen and hide the blinking cursor.
903clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
904changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
905}
906
907nextRow = kMenuTopRow;
908showPrompt = true;
909
910if (gDeviceCount) {
911if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
912printf("Use \30\31 keys to select the startup volume.");
913}
914showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
915nextRow += MIN( gDeviceCount, kMenuMaxItems ) + 3;
916}
917
918// Show the boot prompt.
919showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
920showBootPrompt( nextRow, showPrompt );
921
922do {
923if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
924// redraw background
925memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
926// reset cursor co-ords
927gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
928}
929key = getchar();
930updateMenu( key, (void **) &menuBVR );
931newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
932
933if (newShowPrompt != showPrompt) {
934showPrompt = newShowPrompt;
935showBootPrompt( nextRow, showPrompt );
936}
937
938if (showPrompt) {
939updateBootArgs(key);
940}
941
942switch (key) {
943case kReturnKey:
944if (gui.menu.draw) {
945key=0;
946break;
947}
948if (*gBootArgs == '?') {
949char * argPtr = gBootArgs;
950
951// Skip the leading "?" character.
952argPtr++;
953getNextArg(&argPtr, booterCommand);
954getNextArg(&argPtr, booterParam);
955
956/*
957* TODO: this needs to be refactored.
958*/
959if (strcmp( booterCommand, "video" ) == 0)
960{
961if (bootArgs->Video.v_display != VGA_TEXT_MODE)
962{
963showInfoBox(getVBEInfoString(), getVBEModeInfoString());
964}
965else
966{
967printVBEModeInfo();
968}
969}
970else if ( strcmp( booterCommand, "memory" ) == 0)
971{
972if (bootArgs->Video.v_display != VGA_TEXT_MODE )
973{
974showInfoBox("Memory Map", getMemoryInfoString());
975}
976else
977{
978printMemoryInfo();
979}
980}
981else if (strcmp(booterCommand, "lspci") == 0)
982{
983lspci();
984}
985else if (strcmp(booterCommand, "more") == 0)
986{
987showTextFile(booterParam);
988}
989else if (strcmp(booterCommand, "rd") == 0)
990{
991processRAMDiskCommand(&argPtr, booterParam);
992}
993else if (strcmp(booterCommand, "norescan") == 0)
994{
995if (gEnableCDROMRescan)
996{
997gEnableCDROMRescan = false;
998break;
999}
1000}
1001else
1002{
1003showHelp();
1004}
1005key = 0;
1006showBootPrompt(nextRow, showPrompt);
1007break;
1008}
1009gBootVolume = menuBVR;
1010setRootVolume(menuBVR);
1011gBIOSDev = menuBVR->biosdev;
1012break;
1013
1014case kEscapeKey:
1015clearBootArgs();
1016break;
1017
1018// AutoResolution - Reapply the patch if Graphics Mode was incorrect
1019// or EDID Info was insane.
1020case kF2Key:
1021reloadAutoRes(); // clearBootArgs is on the function
1022break;
1023
1024case kF5Key:
1025// New behavior:
1026// Clear gBootVolume to restart the loop
1027// if the user enabled rescanning the optical drive.
1028// Otherwise boot the default boot volume.
1029if (gEnableCDROMRescan) {
1030gBootVolume = NULL;
1031clearBootArgs();
1032}
1033break;
1034
1035case kF10Key: //Azi: disable "Scan Single Drive"=y (if set) and rescan disks.
1036gScanSingleDrive = false;
1037scanDisks(gBIOSDev, &bvCount);
1038gBootVolume = NULL;
1039clearBootArgs();
1040break;
1041
1042case kTabKey:
1043// New behavior:
1044// Switch between text & graphic interfaces
1045// Only Permitted if started in graphics interface
1046if (useGUI) {
1047if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1048setVideoMode(VGA_TEXT_MODE, 0);
1049
1050setCursorPosition(0, 0, 0);
1051clearScreenRows(0, kScreenLastRow);
1052
1053// Display banner and show hardware info.
1054printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
1055printf(getVBEInfoString());
1056
1057clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1058changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1059
1060nextRow = kMenuTopRow;
1061showPrompt = true;
1062
1063if (gDeviceCount) {
1064printf("Use \30\31 keys to select the startup volume.");
1065showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
1066nextRow += MIN(gDeviceCount, kMenuMaxItems) + 3;
1067}
1068
1069showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1070showBootPrompt(nextRow, showPrompt);
1071//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1072} else {
1073gui.redraw = true;
1074setVideoMode(GRAPHICS_MODE, 0);
1075updateVRAM();
1076updateGraphicBootPrompt();
1077}
1078}
1079key = 0;
1080break;
1081
1082default:
1083key = 0;
1084break;
1085}
1086} while (0 == key);
1087
1088done:
1089if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
1090clearScreenRows(kMenuTopRow, kScreenLastRow);
1091changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
1092}
1093shouldboot = false;
1094gui.menu.draw = false;
1095if (menuItems) {
1096free(menuItems);
1097menuItems = NULL;
1098}
1099return 0;
1100}
1101
1102//==========================================================================
1103
1104extern unsigned char chainbootdev;
1105extern unsigned char chainbootflag;
1106
1107bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1108{
1109 int argLen = argName ? strlen(argName) : 0;
1110 int len = argLen + cnt + 1; // +1 to account for space
1111
1112 if (len > *cntRemainingP) {
1113 error("Warning: boot arguments too long, truncating\n");
1114 return false;
1115 }
1116
1117 if (argName) {
1118 strncpy( *argP, argName, argLen );
1119 *argP += argLen;
1120 *argP[0] = '=';
1121 (*argP)++;
1122 len++; // +1 to account for '='
1123 }
1124 strncpy( *argP, val, cnt );
1125 *argP += cnt;
1126 *argP[0] = ' ';
1127 (*argP)++;
1128
1129 *cntRemainingP -= len;
1130 return true;
1131}
1132
1133//
1134// Returns TRUE if an argument was copied, FALSE otherwise
1135bool
1136processBootArgument(
1137 const char *argName, // The argument to search for
1138 const char *userString, // Typed-in boot arguments
1139 const char *kernelFlags, // Kernel flags from config table
1140 const char *configTable,
1141 char **argP, // Output value
1142 int *cntRemainingP, // Output count
1143 char *foundVal // found value
1144 )
1145{
1146 const char *val;
1147 int cnt;
1148 bool found = false;
1149
1150 if (getValueForBootKey(userString, argName, &val, &cnt)) {
1151 // Don't copy; these values will be copied at the end of argument processing.
1152 found = true;
1153 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
1154 // Don't copy; these values will be copied at the end of argument processing.
1155 found = true;
1156 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
1157 copyArgument(argName, val, cnt, argP, cntRemainingP);
1158 found = true;
1159 }
1160 if (found && foundVal) {
1161 strlcpy(foundVal, val, cnt+1);
1162 }
1163 return found;
1164}
1165
1166// Maximum config table value size
1167#define VALUE_SIZE 2048
1168
1169int
1170processBootOptions()
1171{
1172 const char * cp = gBootArgs;
1173 const char * val = 0;
1174 const char * kernel;
1175 int cnt;
1176 int userCnt;
1177 int cntRemaining;
1178 char * argP;
1179 char uuidStr[64];
1180 bool uuidSet = false;
1181 char * configKernelFlags;
1182 char * valueBuffer;
1183extern void setupSmbiosConfigFile(); // test :P
1184
1185 valueBuffer = malloc(VALUE_SIZE); // 2048
1186
1187 skipblanks( &cp );
1188
1189 // Update the unit and partition number.
1190
1191 if ( gBootVolume )
1192 {
1193 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1194 {
1195 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1196 (void *) 0x7c00 );
1197
1198 //
1199 // Setup edx, and signal intention to chain load the
1200 // foreign booter.
1201 //
1202
1203 chainbootdev = gBootVolume->biosdev;
1204 chainbootflag = 1;
1205
1206 return 1;
1207 }
1208
1209 setRootVolume(gBootVolume);
1210
1211 }
1212 // If no boot volume fail immediately because we're just going to fail
1213 // trying to load the config file anyway.
1214 else
1215 return -1;
1216
1217// Moved here to enable search for override Boot.plist on OS specific folders.
1218// Find out which Mac OS version we're booting.
1219// make sure the damn thing get's zeroed, just in case... :)*
1220bzero(gMacOSVersion, sizeof(gMacOSVersion)); // do this to argP ??... check it*****
1221getOSVersion(gMacOSVersion);
1222
1223//Azi: implemented at loadOverrideConfig. ???
1224 // Load config table specified by the user, or use the default.
1225 //if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1226 // val = 0;
1227 // cnt = 0;
1228 //}
1229//loadSystemConfig(val, cnt); Azi:reminder
1230// if ( !sysConfigValid ) return -1;
1231
1232 // Load com.apple.Boot.plist from the selected volume
1233 // and use its contents to override default bootConfig.
1234 // This is not a mandatory operation anymore.
1235
1236 loadOverrideConfig(&bootInfo->overrideConfig);
1237// testing ugly hack :P
1238setupSmbiosConfigFile("SMBIOS.plist");
1239
1240 // Use the kernel name specified by the user, or fetch the name
1241 // in the config table, or use the default if not specified.
1242 // Specifying a kernel name on the command line, or specifying
1243 // a non-default kernel name in the config file counts as
1244 // overriding the kernel, which causes the kernelcache not
1245 // to be used.
1246
1247gOverrideKernel = false;
1248//Azi: setting bootFile - kernel name (path) used in common_boot()
1249if (( kernel = extractKernelName((char **)&cp) )) // boot prompt
1250{
1251strcpy( bootInfo->bootFile, kernel );
1252gOverrideKernel = true;
1253}
1254else
1255{
1256if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) // Boot.plist
1257{
1258strlcpy( bootInfo->bootFile, val, cnt+1 );
1259if (strcmp( bootInfo->bootFile, kDefaultKernelName ) != 0)
1260{
1261gOverrideKernel = true;
1262}
1263}
1264else
1265{
1266strcpy( bootInfo->bootFile, kDefaultKernelName ); // mach_kernel
1267}
1268}
1269
1270 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1271 argP = bootArgs->CommandLine;
1272
1273 // Get config table kernel flags, if not ignored.
1274 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) || // if -F arg was used...
1275// don't get the value/s passed by "Kernel Flags" key on "override" Boot.plist.
1276//Azi: test this*****
1277 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig ))
1278{
1279 val = "";
1280 cnt = 0;
1281 }
1282 configKernelFlags = malloc(cnt + 1);
1283 strlcpy(configKernelFlags, val, cnt + 1);
1284
1285// user provided a uuid... at boot prompt or override Boot.plist ??
1286 if (processBootArgument(kBootUUIDKey/*boot-uuid*/, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0))
1287{
1288 // "boot-uuid" was set either on the command-line or in the config file.
1289 uuidSet = true;
1290 }
1291else
1292{
1293 // Try an alternate method for getting the root UUID on boot helper partitions.
1294 if (gBootVolume->flags & kBVFlagBooter)
1295 {
1296 if ((loadHelperConfig(&bootInfo->helperConfig) == 0) &&
1297getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1298 {
1299 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1300 copyArgument(kBootUUIDKey/*boot-uuid*/, val, cnt, &argP, &cntRemaining);
1301 uuidSet = true;
1302 }
1303 }
1304
1305 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid(gBootVolume, uuidStr) == 0)
1306{
1307 verbose("Setting boot-uuid to: %s\n", uuidStr);
1308 copyArgument(kBootUUIDKey/*boot-uuid*/, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1309 uuidSet = true;
1310 }
1311 }
1312
1313// if no rd=diskXsY key issued by user... at boot prompt or override Boot.plist ??
1314 if (!processBootArgument(kRootDeviceKey,
1315cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice))
1316{
1317 cnt = 0;
1318// try "Boot Device" key ???
1319 if (getValueForKey(kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig))
1320{
1321 valueBuffer[0] = '*'; // check for rd=*uuid ???
1322 cnt++;
1323 strlcpy(valueBuffer + 1, val, cnt);
1324 val = valueBuffer;
1325 }
1326else
1327{
1328 if (uuidSet)
1329{
1330 val = "*uuid";
1331 cnt = 5; // nr of characters on *uuid
1332 }
1333else
1334{
1335 // Don't set "rd=.." if there is no boot device key
1336 // and no UUID.
1337 val = "";
1338 cnt = 0;
1339 }
1340 }
1341
1342 if (cnt > 0)
1343{
1344 copyArgument(kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1345 }
1346 strlcpy(gRootDevice, val, (cnt + 1));
1347 }
1348
1349 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1350 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt))
1351{
1352 if (gBootMode & kBootModeSafe)
1353{
1354 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1355 }
1356 }
1357
1358 // Store the merged kernel flags and boot args.
1359cnt = strlen(configKernelFlags);
1360if (cnt)
1361{
1362if (cnt > cntRemaining) {
1363error("Warning: boot arguments too long, truncating\n");
1364cnt = cntRemaining;
1365}
1366strncpy(argP, configKernelFlags, cnt);
1367argP[cnt++] = ' ';
1368cntRemaining -= cnt;
1369}
1370
1371userCnt = strlen(cp);
1372if (userCnt > cntRemaining)
1373{
1374 error("Warning: boot arguments too long, truncating\n");
1375 userCnt = cntRemaining;
1376}
1377strncpy(&argP[cnt], cp, userCnt);
1378verbose("BootArgs = %s\n", argP); //Azi: checking...
1379argP[cnt+userCnt] = '\0'; // shouldn't this null argP ?? see getOSVersion***
1380verbose("BootArgs check = %s\n", argP); // ||
1381
1382if (!shouldboot)
1383{
1384gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1385getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1386
1387gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1388kBootModeSafe : kBootModeNormal;
1389
1390 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1391 gBootMode = kBootModeSafe; //Azi: ??
1392 }
1393}
1394
1395if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1396{
1397strlcpy(gMKextName, val, cnt + 1);
1398}
1399
1400 free(configKernelFlags);
1401 free(valueBuffer);
1402
1403 return 0;
1404}
1405
1406static bool getOSVersion(char *str) //Azi: moved from boot.c
1407{
1408bool valid = false;
1409config_file_t systemVersion;
1410const char *val;
1411int len;
1412
1413if (!loadConfigFile("/System/Library/CoreServices/SystemVersion.plist", &systemVersion))
1414{ //Azi: so, is this path on selected or current volume?? ... clean!
1415valid = true;
1416}
1417else if (!loadConfigFile("/System/Library/CoreServices/ServerVersion.plist", &systemVersion))
1418{
1419valid = true;
1420}
1421
1422if (valid)
1423{
1424if (getValueForKey("ProductVersion", &val, &len, &systemVersion))
1425{
1426// getValueForKey uses const char for val
1427strncat(str, val, len); //Azi: nothing better to do :P
1428//msglog("System Version: %s\n", str);
1429verbose("Loading Darwin %s\n", str);
1430
1431// so copy it and trim
1432*str = '\0';
1433strncat(str, val, MIN(len, 4));
1434}
1435else
1436valid = false;
1437}
1438
1439return valid;
1440}
1441
1442//==========================================================================
1443// Load the help file and display the file contents on the screen.
1444
1445static void showTextBuffer(char *buf, int size)
1446{
1447char*bp;
1448intline;
1449intline_offset;
1450intc;
1451
1452if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1453showInfoBox( "Press q to quit\n",buf );
1454return;
1455}
1456
1457 bp = buf;
1458 while (size-- > 0) {
1459if (*bp == '\n') {
1460*bp = '\0';
1461}
1462bp++;
1463 }
1464 *bp = '\1';
1465 line_offset = 0;
1466
1467 setActiveDisplayPage(1);
1468
1469 while (1) {
1470clearScreenRows(0, 24);
1471setCursorPosition(0, 0, 1);
1472bp = buf;
1473for (line = 0; *bp != '\1' && line < line_offset; line++) {
1474while (*bp != '\0') {
1475bp++;
1476}
1477bp++;
1478}
1479for (line = 0; *bp != '\1' && line < 23; line++) {
1480setCursorPosition(0, line, 1);
1481printf("%s\n", bp);
1482while (*bp != '\0') {
1483bp++;
1484}
1485bp++;
1486}
1487
1488setCursorPosition(0, 23, 1);
1489if (*bp == '\1') {
1490printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1491} else {
1492printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1493}
1494
1495c = getchar();
1496if (c == 'q' || c == 'Q') {
1497break;
1498}
1499if ((c == 'p' || c == 'P') && line_offset > 0) {
1500line_offset -= 23;
1501}
1502if (c == ' ') {
1503if (*bp == '\1') {
1504break;
1505} else {
1506line_offset += 23;
1507}
1508}
1509 }
1510 setActiveDisplayPage(0);
1511}
1512
1513void showHelp(void)
1514{
1515if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1516showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1517} else {
1518showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1519}
1520}
1521
1522void showTextFile(const char * filename) //Azi:?more
1523{
1524#define MAX_TEXT_FILE_SIZE 65536
1525char *buf;
1526int fd;
1527int size;
1528
1529if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0)
1530{
1531printf("\nFile not found: %s\n", filename);
1532sleep(2);
1533return;
1534}
1535
1536 size = file_size(fd);
1537
1538 if (size > MAX_TEXT_FILE_SIZE)
1539 {
1540size = MAX_TEXT_FILE_SIZE;
1541}
1542
1543 buf = malloc(size);
1544 read(fd, buf, size);
1545 close(fd);
1546
1547showTextBuffer(buf, size);
1548free(buf);
1549}
1550
1551// This is a very simplistic prompting scheme that just grabs two hex characters
1552// Eventually we need to do something more user-friendly like display a menu
1553// based off of the Multiboot device list
1554
1555//Azi: is this stuff still used for anything?? check multiboot()...
1556int selectAlternateBootDevice(int bootdevice)
1557{
1558int key;
1559int newbootdevice;
1560int digitsI = 0;
1561char *end;
1562char digits[3] = {0,0,0};
1563
1564// We've already printed the current boot device so user knows what it is
1565printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1566printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1567do {
1568key = getchar();
1569switch (key & kASCIIKeyMask) {
1570case kBackspaceKey:
1571if (digitsI > 0) {
1572int x, y, t;
1573getCursorPositionAndType(&x, &y, &t);
1574// Assume x is not 0;
1575x--;
1576setCursorPosition(x,y,0); // back up one char
1577// Overwrite with space without moving cursor position
1578putca(' ', 0x07, 1);
1579digitsI--;
1580} else {
1581// TODO: Beep or something
1582}
1583break;
1584
1585case kReturnKey:
1586digits[digitsI] = '\0';
1587newbootdevice = strtol(digits, &end, 16);
1588if (end == digits && *end == '\0') {
1589// User entered empty string
1590printf("\nUsing default boot device %x\n", bootdevice);
1591key = 0;
1592} else if(end != digits && *end == '\0') {
1593bootdevice = newbootdevice;
1594printf("\n");
1595key = 0; // We gots da boot device
1596} else {
1597printf("\nCouldn't parse. try again: ");
1598digitsI = 0;
1599}
1600break;
1601
1602default:
1603if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1604putchar(key & kASCIIKeyMask);
1605digits[digitsI++] = key & kASCIIKeyMask;
1606} else {
1607// TODO: Beep or something
1608}
1609break;
1610};
1611} while (key != 0);
1612
1613return bootdevice;
1614}
1615
1616bool promptForRescanOption(void)
1617{
1618printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1619if (getchar() == kReturnKey) {
1620return true;
1621} else {
1622return false;
1623}
1624}
1625

Archive Download this file

Revision: 1047