Chameleon

Chameleon Svn Source Tree

Root/branches/valv/i386/boot2/options.c

  • Property svn:executable set to
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 "bootstruct.h"
27#include "fdisk.h"
28#include "ramdisk.h"
29#include "gui.h"
30#include "embedded.h"
31#include "pci.h"
32#include "autoresolution.h"
33
34static bool shouldboot = false;
35
36extern int multiboot_timeout;
37extern int multiboot_timeout_set;
38
39extern BVRef bvChain;
40//extern intmenucount;
41
42extern intgDeviceCount;
43
44intselectIndex = 0;
45MenuItem * menuItems = NULL;
46
47enum {
48 kMenuTopRow = 5,
49 kMenuMaxItems = 10,
50 kScreenLastRow = 24
51};
52
53//==========================================================================
54
55typedef struct {
56 int x;
57 int y;
58 int type;
59} CursorState;
60
61static void changeCursor( int col, int row, int type, CursorState * cs )
62{
63 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
64 setCursorType( type );
65 setCursorPosition( col, row, 0 );
66}
67
68static void moveCursor( int col, int row )
69{
70 setCursorPosition( col, row, 0 );
71}
72
73static void restoreCursor( const CursorState * cs )
74{
75 setCursorPosition( cs->x, cs->y, 0 );
76 setCursorType( cs->type );
77}
78
79//==========================================================================
80
81/* Flush keyboard buffer; returns TRUE if any of the flushed
82 * characters was F8.
83 */
84
85static bool flushKeyboardBuffer(void)
86{
87 bool status = false;
88
89 while ( readKeyboardStatus() ) {
90 if (bgetc() == 0x4200) status = true;
91 }
92 return status;
93}
94
95//==========================================================================
96
97static int countdown( const char * msg, int row, int timeout )
98{
99 unsigned long time;
100 int ch = 0;
101 int col = strlen(msg) + 1;
102
103 flushKeyboardBuffer();
104
105if( bootArgs->Video.v_display == VGA_TEXT_MODE )
106{
107moveCursor( 0, row );
108printf(msg);
109
110} else {
111
112position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
113
114char dummy[80];
115getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
116drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
117drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
118
119// make this screen the new background
120memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
121
122}
123
124int multi_buff = 18 * (timeout);
125 int multi = ++multi_buff;
126
127 int lasttime=0;
128
129 for ( time = time18(), timeout++; timeout > 0; )
130 {
131if( time18() > lasttime)
132{
133multi--;
134lasttime=time18();
135}
136
137 if (ch = readKeyboardStatus())
138 break;
139
140 // Count can be interrupted by holding down shift,
141 // control or alt key
142 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
143{
144 ch = 1;
145 break;
146 }
147
148 if ( time18() >= time )
149 {
150 time += 18;
151 timeout--;
152
153if( bootArgs->Video.v_display == VGA_TEXT_MODE )
154{
155moveCursor( col, row );
156printf("(%d) ", timeout);
157}
158 }
159
160if( bootArgs->Video.v_display == GRAPHICS_MODE )
161{
162drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
163gui.redraw = true;
164updateVRAM();
165}
166
167 }
168
169 flushKeyboardBuffer();
170
171 return ch;
172}
173
174//==========================================================================
175
176static char gBootArgs[BOOT_STRING_LEN];
177static char * gBootArgsPtr = gBootArgs;
178static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
179static char booterCommand[BOOT_STRING_LEN];
180static char booterParam[BOOT_STRING_LEN];
181
182static void clearBootArgs(void)
183{
184gBootArgsPtr = gBootArgs;
185memset(gBootArgs, '\0', BOOT_STRING_LEN);
186
187if (bootArgs->Video.v_display == GRAPHICS_MODE) {
188clearGraphicBootPrompt();
189}
190}
191
192static void addBootArg(const char * argStr)
193{
194if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
195{
196*gBootArgsPtr++ = ' ';
197strcat(gBootArgs, argStr);
198gBootArgsPtr += strlen(argStr);
199}
200}
201
202//==========================================================================
203
204static void showBootPrompt(int row, bool visible)
205{
206extern char bootPrompt[];
207extern char bootRescanPrompt[];
208
209if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
210changeCursor( 0, row, kCursorTypeUnderline, 0 );
211clearScreenRows( row, kScreenLastRow );
212}
213
214clearBootArgs();
215
216if (visible) {
217if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
218if (gEnableCDROMRescan) {
219printf( bootRescanPrompt );
220} else {
221printf( bootPrompt );
222}
223}
224} else {
225if (bootArgs->Video.v_display == GRAPHICS_MODE) {
226clearGraphicBootPrompt();
227} else {
228printf("Press Enter to start up the foreign OS. ");
229}
230}
231}
232
233//==========================================================================
234
235static void updateBootArgs( int key )
236{
237 key &= kASCIIKeyMask;
238
239 switch ( key )
240 {
241 case kBackspaceKey:
242 if ( gBootArgsPtr > gBootArgs )
243 {
244 int x, y, t;
245 getCursorPositionAndType( &x, &y, &t );
246 if ( x == 0 && y )
247 {
248 x = 80; y--;
249 }
250 if (x)
251x--;
252if( bootArgs->Video.v_display == VGA_TEXT_MODE )
253{
254setCursorPosition( x, y, 0 );
255putca(' ', 0x07, 1);
256} else
257updateGraphicBootPrompt(kBackspaceKey);
258
259*gBootArgsPtr-- = '\0';
260}
261
262break;
263
264 default:
265 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
266 {
267if( bootArgs->Video.v_display == VGA_TEXT_MODE )
268putchar(key); // echo to screen
269else
270updateGraphicBootPrompt(key);
271*gBootArgsPtr++ = key;
272}
273
274break;
275 }
276}
277
278//==========================================================================
279
280static const MenuItem * gMenuItems = NULL;
281
282static int gMenuItemCount;
283static int gMenuRow;
284static int gMenuHeight;
285static int gMenuTop;
286static int gMenuBottom;
287static int gMenuSelection;
288
289static int gMenuStart;
290static int gMenuEnd;
291
292static void printMenuItem( const MenuItem * item, int highlight )
293{
294 printf(" ");
295
296 if ( highlight )
297 putca(' ', 0x70, strlen(item->name) + 4);
298 else
299 putca(' ', 0x07, 40);
300
301 printf(" %40s\n", item->name);
302}
303
304//==========================================================================
305
306static void showMenu( const MenuItem * items, int count,
307 int selection, int row, int height )
308{
309 int i;
310 CursorState cursorState;
311
312 if ( items == NULL || count == 0 )
313return;
314
315 // head and tail points to the start and the end of the list.
316 // top and bottom points to the first and last visible items
317 // in the menu window.
318
319 gMenuItems= items;
320 gMenuRow= row;
321 gMenuHeight= height;
322 gMenuItemCount= count;
323 gMenuTop= 0;
324 gMenuBottom= min( count, height ) - 1;
325 gMenuSelection= selection;
326
327 gMenuStart= 0;
328 gMenuEnd = min( count, gui.maxdevices ) - 1;
329
330// If the selected item is not visible, shift the list down.
331
332 if ( gMenuSelection > gMenuBottom )
333 {
334 gMenuTop += ( gMenuSelection - gMenuBottom );
335 gMenuBottom = gMenuSelection;
336 }
337
338if ( gMenuSelection > gMenuEnd )
339 {
340gMenuStart += ( gMenuSelection - gMenuEnd );
341 gMenuEnd = gMenuSelection;
342 }
343
344// Draw the visible items.
345
346if( bootArgs->Video.v_display == GRAPHICS_MODE )
347
348drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
349
350else {
351
352changeCursor( 0, row, kCursorTypeHidden, &cursorState );
353
354for ( i = gMenuTop; i <= gMenuBottom; i++ )
355{
356printMenuItem( &items[i], (i == gMenuSelection) );
357}
358
359restoreCursor( &cursorState );
360 }
361}
362
363//==========================================================================
364
365static int updateMenu( int key, void ** paramPtr )
366{
367 int moved = 0;
368
369 union {
370 struct {
371 unsigned int
372 selectionUp : 1,
373 selectionDown : 1,
374 scrollUp : 1,
375 scrollDown : 1;
376 } f;
377 unsigned int w;
378 } draw = {{0}};
379
380 if ( gMenuItems == NULL )
381return 0;
382
383if( bootArgs->Video.v_display == GRAPHICS_MODE )
384{
385int res;
386
387// set navigation keys for horizontal layout as defaults
388int previous= 0x4B00;// left arrow
389int subsequent= 0x4D00;// right arrow
390int menu= 0x5000;// down arrow
391
392if ( gui.layout == VerticalLayout )
393{
394// set navigation keys for vertical layout
395previous= 0x4800;// up arrow
396subsequent= 0x5000;// down arrow
397menu= 0x4B00;// right arrow
398}
399
400if ( key == previous )
401{
402if ( gMenuSelection > gMenuTop )
403draw.f.selectionUp = 1;
404else if ( gMenuTop > 0 )
405draw.f.scrollDown = 1;
406
407}
408
409else if ( key == subsequent )
410{
411if ( gMenuSelection != gMenuBottom)
412draw.f.selectionDown = 1;
413else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
414draw.f.scrollUp = 1;
415}
416
417else if ( key == menu )
418{
419if ( gui.menu.draw )
420updateInfoMenu(key);
421else
422drawInfoMenu();
423}
424
425else if ( gui.menu.draw )
426{
427res = updateInfoMenu(key);
428
429if ( res == CLOSE_INFO_MENU )
430gui.menu.draw = false;
431else
432{
433shouldboot = ( res != DO_NOT_BOOT );
434
435if ( shouldboot )
436gui.menu.draw = false;
437
438switch (res)
439{
440case BOOT_NORMAL:
441gVerboseMode = false;
442gBootMode = kBootModeNormal;
443break;
444
445case BOOT_VERBOSE:
446gVerboseMode = true;
447gBootMode = kBootModeNormal;
448addBootArg(kVerboseModeFlag);
449break;
450
451case BOOT_IGNORECACHE:
452gVerboseMode = false;
453gBootMode = kBootModeNormal;
454addBootArg(kIgnoreCachesFlag);
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
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 && bootArgs->Video.v_display == VGA_TEXT_MODE)
701{
702setVideoMode(GRAPHICS_MODE, 0);
703}
704
705// Clear command line boot arguments
706clearBootArgs();
707
708// Allow user to override default timeout.
709if (multiboot_timeout_set) {
710timeout = multiboot_timeout;
711} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
712/* If there is no timeout key in the file use the default timeout
713 which is different for CDs vs. hard disks. However, if not booting
714 a CD and no config file could be loaded set the timeout
715 to zero which causes the menu to display immediately.
716 This way, if no partitions can be found, that is the disk is unpartitioned
717 or simply cannot be read) then an empty menu is displayed.
718 If some partitions are found, for example a Windows partition, then
719 these will be displayed in the menu as foreign partitions.
720 */
721if (isCDROM) {
722timeout = kCDBootTimeout;
723} else {
724timeout = sysConfigValid ? kBootTimeout : 0;
725}
726}
727
728if (timeout < 0) {
729gBootMode |= kBootModeQuiet;
730}
731
732// If the user is holding down a modifier key, enter safe mode.
733if ((readKeyboardShiftFlags() & 0x0F) != 0) {
734gBootMode |= kBootModeSafe;
735}
736
737// 18seven's Quick-args macro
738bool f8 = false, altf = false, shiftf = false, alts = false,
739altv = false, altx = false; // x32 = false, x64 = false;
740while (readKeyboardStatus())
741{
742key = bgetc ();
743if (key == 0x4200) f8 = true;
744if (key == 0x2100) altf = true;
745if (key == 0x0046) shiftf = true;
746if (key == 0x1F00) alts = true;
747if (key == 0x2F00) altv = true;
748if (key == 0x2D00) altx = true;
749/*if (key == 0x0004) x32 = true;
750if (key == 0x0007) x64 = true;
751*/}
752
753// If user typed F8, abort quiet mode, and display the menu.
754if (f8) {
755gBootMode &= ~kBootModeQuiet;
756timeout = 0;
757}
758
759// If user typed 'alt-v', boot in verbose mode.
760if ((gBootMode & kBootModeQuiet) && firstRun && altv) {
761addBootArg(kVerboseModeFlag);
762}
763
764// If user typed 'alt-s', boot in single user mode.
765if ((gBootMode & kBootModeQuiet) && firstRun && alts) {
766addBootArg(kSingleUserModeFlag);
767}
768
769if ((gBootMode & kBootModeQuiet) && firstRun && altf) {
770addBootArg(kIgnoreCachesFlag);
771}
772
773if ((gBootMode & kBootModeQuiet) && firstRun && shiftf) {
774addBootArg(kIgnoreBootFileFlag);
775}
776
777if ((gBootMode & kBootModeQuiet) && firstRun && altx) {
778addBootArg(kSafeModeFlag);
779}
780/*
781if ((gBootMode & kBootModeQuiet) && firstRun && x32) {
782addBootArg(k32BitModeFlag);
783}
784
785if ((gBootMode & kBootModeQuiet) && firstRun && x64) {
786addBootArg(k64BitModeFlag);
787}
788*/
789if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
790setCursorPosition(0, 0, 0);
791clearScreenRows(0, kScreenLastRow);
792if (!(gBootMode & kBootModeQuiet)) {
793// Display banner and show hardware info.
794printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
795printf(getVBEInfoString());
796}
797changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
798verbose("Scanning device %x...", gBIOSDev);
799}
800
801// When booting from CD, default to hard drive boot when possible.
802if (isCDROM && firstRun) {
803const char *val;
804char *prompt = NULL;
805char *name = NULL;
806int cnt;
807int optionKey;
808
809if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig)) {
810prompt = malloc(cnt + 1);
811strncat(prompt, val, cnt);
812} else {
813name = malloc(80);
814getBootVolumeDescription(gBootVolume, name, 79, false);
815prompt = malloc(256);
816sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
817free(name);
818}
819
820if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig )) {
821// The key specified is a special key.
822} else {
823// Default to F8.
824optionKey = 0x4200;
825}
826
827// If the timeout is zero then it must have been set above due to the
828// early catch of F8 which means the user wants to set boot options
829// which we ought to interpret as meaning he wants to boot the CD.
830if (timeout != 0) {
831key = countdown(prompt, kMenuTopRow, timeout);
832} else {
833key = optionKey;
834}
835
836if (prompt != NULL) {
837free(prompt);
838}
839
840clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
841
842// Hit the option key ?
843if (key == optionKey) {
844gBootMode &= ~kBootModeQuiet;
845timeout = 0;
846} else {
847key = key & 0xFF;
848
849// Try booting hard disk if user pressed 'h'
850if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
851BVRef bvr;
852
853// Look at partitions hosting OS X other than the CD-ROM
854for (bvr = bvChain; bvr; bvr=bvr->next) {
855if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
856gBootVolume = bvr;
857}
858}
859}
860goto done;
861}
862}
863
864if (gBootMode & kBootModeQuiet) {
865// No input allowed from user.
866goto done;
867}
868
869if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
870// If the user is holding down a modifier key,
871// enter safe mode.
872if ((readKeyboardShiftFlags() & 0x0F) != 0) {
873gBootMode |= kBootModeSafe;
874}
875goto done;
876}
877
878if (gDeviceCount) {
879// Allocate memory for an array of menu items.
880menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
881if (menuItems == NULL) {
882goto done;
883}
884
885// Associate a menu item for each BVRef.
886for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
887if (bvr->visible) {
888getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
889menuItems[i].param = (void *) bvr;
890if (bvr == menuBVR) {
891selectIndex = i;
892}
893i--;
894}
895}
896}
897
898if (bootArgs->Video.v_display == GRAPHICS_MODE) {
899// redraw the background buffer
900gui.logo.draw = true;
901drawBackground();
902gui.devicelist.draw = true;
903gui.redraw = true;
904if (!(gBootMode & kBootModeQuiet)) {
905bool showBootBanner = true;
906
907// Check if "Boot Banner"=N switch is present in config file.
908getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
909if (showBootBanner) {
910// Display banner and show hardware info.
911gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
912}
913
914// redraw background
915memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
916}
917} else {
918// Clear screen and hide the blinking cursor.
919clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
920changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
921}
922
923nextRow = kMenuTopRow;
924showPrompt = true;
925
926if (gDeviceCount) {
927if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
928printf("Use \30\31 keys to select the startup volume.");
929}
930showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
931nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
932}
933
934// Show the boot prompt.
935showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
936showBootPrompt( nextRow, showPrompt );
937
938do {
939if (bootArgs->Video.v_display == GRAPHICS_MODE) {
940// redraw background
941memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
942// reset cursor co-ords
943gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
944}
945key = getc();
946updateMenu( key, (void **) &menuBVR );
947newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
948
949if (newShowPrompt != showPrompt) {
950showPrompt = newShowPrompt;
951showBootPrompt( nextRow, showPrompt );
952}
953
954if (showPrompt) {
955updateBootArgs(key);
956}
957
958switch (key) {
959case kReturnKey:
960if (gui.menu.draw) {
961key=0;
962break;
963}
964if (*gBootArgs == '?') {
965char * argPtr = gBootArgs;
966
967// Skip the leading "?" character.
968argPtr++;
969getNextArg(&argPtr, booterCommand);
970getNextArg(&argPtr, booterParam);
971
972/*
973* TODO: this needs to be refactored.
974*/
975if (strcmp( booterCommand, "video" ) == 0) {
976if (bootArgs->Video.v_display == GRAPHICS_MODE) {
977showInfoBox(getVBEInfoString(), getVBEModeInfoString());
978} else {
979printVBEModeInfo();
980}
981} else if ( strcmp( booterCommand, "memory" ) == 0) {
982if (bootArgs->Video.v_display == GRAPHICS_MODE ) {
983showInfoBox("Memory Map", getMemoryInfoString());
984} else {
985printMemoryInfo();
986}
987} else if (strcmp(booterCommand, "lspci") == 0) {
988lspci();
989} else if (strcmp(booterCommand, "more") == 0) {
990showTextFile(booterParam);
991} else if (strcmp(booterCommand, "rd") == 0) {
992processRAMDiskCommand(&argPtr, booterParam);
993} else if (strcmp(booterCommand, "norescan") == 0) {
994if (gEnableCDROMRescan) {
995gEnableCDROMRescan = false;
996break;
997}
998} else {
999showHelp();
1000}
1001key = 0;
1002showBootPrompt(nextRow, showPrompt);
1003break;
1004}
1005gBootVolume = menuBVR;
1006setRootVolume(menuBVR);
1007gBIOSDev = menuBVR->biosdev;
1008break;
1009
1010case kEscapeKey:
1011clearBootArgs();
1012break;
1013
1014case kF2Key:
1015
1016/*
1017 * AutoResolution - Reapply the patch if Graphics Mode was incorrect or EDID Info was insane
1018 */
1019
1020if ((gAutoResolution == TRUE) && map)
1021{
1022// get the new Graphics Mode key
1023processBootOptions();
1024
1025UInt32 params[4];
1026params[3] = 0;
1027//Has the target Resolution Changed ?
1028int count = getNumberArrayFromProperty(kGraphicsModeKey, params, 4);
1029if ( count < 3 )
1030getResolution(params);
1031
1032if ((params[0] != 0) && (params[1] != 0)
1033&& (params[0] != map->currentX) && (params[1] != map->currentY))
1034{
1035
1036//Go back to TEXT mode while we change the mode
1037if (bootArgs->Video.v_display == GRAPHICS_MODE)
1038{
1039CursorState cursorState;
1040
1041setVideoMode(VGA_TEXT_MODE, 0);
1042
1043setCursorPosition(0, 0, 0);
1044clearScreenRows(0, kScreenLastRow);
1045changeCursor( 0, 0, kCursorTypeHidden, &cursorState );
1046
1047//Reapply patch in case resolution have changed
1048
1049patchVbios(map, params[0], params[1], params[2], 0, 0);
1050
1051if (useGUI && (gui.initialised == true))
1052initGUI();
1053// Make sure all values are set
1054if (bootArgs->Video.v_display != GRAPHICS_MODE)
1055bootArgs->Video.v_display = GRAPHICS_MODE;
1056
1057if (!useGUI)
1058useGUI = true;
1059
1060// redraw the background buffer
1061drawBackground();
1062gui.devicelist.draw = true;
1063gui.redraw = true;
1064if (!(gBootMode & kBootModeQuiet))
1065{
1066bool showBootBanner = true;
1067
1068// Check config file.
1069getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
1070if (showBootBanner)
1071// Display banner and show hardware info.
1072gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
1073
1074// redraw background
1075memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
1076}
1077
1078nextRow = kMenuTopRow;
1079showPrompt = true;
1080
1081if (gDeviceCount)
1082{
1083showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1084nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
1085}
1086
1087// Show the boot prompt.
1088showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1089showBootPrompt( nextRow, showPrompt );
1090
1091//this is used to avoid resetting the incorrect mode while quiting the boot menu
1092map->hasSwitched = true;
1093}
1094}
1095clearBootArgs();
1096key = 0;
1097}
1098break;
1099
1100case kF5Key:
1101// New behavior:
1102// Clear gBootVolume to restart the loop
1103// if the user enabled rescanning the optical drive.
1104// Otherwise boot the default boot volume.
1105if (gEnableCDROMRescan) {
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;
1266 int cnt;
1267 int userCnt;
1268 int cntRemaining;
1269 char * argP;
1270 char uuidStr[64];
1271 bool uuidSet = false;
1272 char * configKernelFlags;
1273 char * valueBuffer;
1274
1275 valueBuffer = malloc(VALUE_SIZE);
1276
1277 skipblanks( &cp );
1278
1279 // Update the unit and partition number.
1280
1281 if ( gBootVolume )
1282 {
1283 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1284 {
1285 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1286 (void *) 0x7c00 );
1287
1288 //
1289 // Setup edx, and signal intention to chain load the
1290 // foreign booter.
1291 //
1292
1293 chainbootdev = gBootVolume->biosdev;
1294 chainbootflag = 1;
1295
1296 return 1;
1297 }
1298
1299 setRootVolume(gBootVolume);
1300
1301 }
1302 // If no boot volume fail immediately because we're just going to fail
1303 // trying to load the config file anyway.
1304 else
1305 return -1;
1306
1307 // Load config table specified by the user, or use the default.
1308
1309 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1310 val = 0;
1311 cnt = 0;
1312 }
1313
1314 // Load com.apple.Boot.plist from the selected volume
1315 // and use its contents to override default bootConfig.
1316 // This is not a mandatory operation anymore.
1317
1318 loadOverrideConfig(&bootInfo->overrideConfig);
1319
1320 // Use the kernel name specified by the user, or fetch the name
1321 // in the config table, or use the default if not specified.
1322 // Specifying a kernel name on the command line, or specifying
1323 // a non-default kernel name in the config file counts as
1324 // overriding the kernel, which causes the kernelcache not
1325 // to be used.
1326
1327 gOverrideKernel = false;
1328 if (( kernel = extractKernelName((char **)&cp) )) {
1329 strcpy( bootInfo->bootFile, kernel );
1330 gOverrideKernel = true;
1331 } else {
1332 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1333 strlcpy( bootInfo->bootFile, val, cnt+1 );
1334 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1335 gOverrideKernel = true;
1336 }
1337 } else {
1338 strcpy( bootInfo->bootFile, kDefaultKernel );
1339 }
1340 }
1341
1342 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1343 argP = bootArgs->CommandLine;
1344
1345 // Get config table kernel flags, if not ignored.
1346 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1347 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1348 val = "";
1349 cnt = 0;
1350 }
1351 configKernelFlags = malloc(cnt + 1);
1352 strlcpy(configKernelFlags, val, cnt + 1);
1353
1354 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1355 // boot-uuid was set either on the command-line
1356 // or in the config file.
1357 uuidSet = true;
1358 } else {
1359
1360 //
1361 // Try an alternate method for getting the root UUID on boot helper partitions.
1362 //
1363 if (gBootVolume->flags & kBVFlagBooter)
1364 {
1365 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1366 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1367 {
1368 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1369 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1370 uuidSet = true;
1371 }
1372 }
1373
1374 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1375 verbose("Setting boot-uuid to: %s\n", uuidStr);
1376 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1377 uuidSet = true;
1378 }
1379 }
1380
1381 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1382 cnt = 0;
1383 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1384 valueBuffer[0] = '*';
1385 cnt++;
1386 strlcpy(valueBuffer + 1, val, cnt);
1387 val = valueBuffer;
1388 } else {
1389 if (uuidSet) {
1390 val = "*uuid";
1391 cnt = 5;
1392 } else {
1393 // Don't set "rd=.." if there is no boot device key
1394 // and no UUID.
1395 val = "";
1396 cnt = 0;
1397 }
1398 }
1399 if (cnt > 0) {
1400 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1401 }
1402 strlcpy( gRootDevice, val, (cnt + 1));
1403 }
1404
1405 /*
1406 * Removed. We don't need this anymore.
1407 *
1408 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1409 getPlatformName(gPlatformName);
1410 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1411 }
1412 */
1413
1414 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1415 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1416 if (gBootMode & kBootModeSafe) {
1417 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1418 }
1419 }
1420
1421 // Store the merged kernel flags and boot args.
1422
1423 cnt = strlen(configKernelFlags);
1424 if (cnt) {
1425 if (cnt > cntRemaining) {
1426 error("Warning: boot arguments too long, truncating\n");
1427 cnt = cntRemaining;
1428 }
1429 strncpy(argP, configKernelFlags, cnt);
1430 argP[cnt++] = ' ';
1431 cntRemaining -= cnt;
1432 }
1433 userCnt = strlen(cp);
1434 if (userCnt > cntRemaining) {
1435 error("Warning: boot arguments too long, truncating\n");
1436 userCnt = cntRemaining;
1437 }
1438 strncpy(&argP[cnt], cp, userCnt);
1439 argP[cnt+userCnt] = '\0';
1440
1441if(!shouldboot)
1442{
1443gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1444getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1445
1446gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1447kBootModeSafe : kBootModeNormal;
1448
1449 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1450 gBootMode = kBootModeSafe;
1451 }
1452}
1453
1454if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1455{
1456strlcpy(gMKextName, val, cnt + 1);
1457}
1458
1459 free(configKernelFlags);
1460 free(valueBuffer);
1461
1462 return 0;
1463}
1464
1465
1466//==========================================================================
1467// Load the help file and display the file contents on the screen.
1468
1469static void showTextBuffer(char *buf, int size)
1470{
1471char*bp;
1472intline;
1473intline_offset;
1474intc;
1475
1476if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1477showInfoBox( "Press q to quit\n",buf );
1478return;
1479}
1480
1481 bp = buf;
1482 while (size-- > 0) {
1483if (*bp == '\n') {
1484*bp = '\0';
1485}
1486bp++;
1487 }
1488 *bp = '\1';
1489 line_offset = 0;
1490
1491 setActiveDisplayPage(1);
1492
1493 while (1) {
1494clearScreenRows(0, 24);
1495setCursorPosition(0, 0, 1);
1496bp = buf;
1497for (line = 0; *bp != '\1' && line < line_offset; line++) {
1498while (*bp != '\0') {
1499bp++;
1500}
1501bp++;
1502}
1503for (line = 0; *bp != '\1' && line < 23; line++) {
1504setCursorPosition(0, line, 1);
1505printf("%s\n", bp);
1506while (*bp != '\0') {
1507bp++;
1508}
1509bp++;
1510}
1511
1512setCursorPosition(0, 23, 1);
1513if (*bp == '\1') {
1514printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1515} else {
1516printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1517}
1518
1519c = getc();
1520if (c == 'q' || c == 'Q') {
1521break;
1522}
1523if ((c == 'p' || c == 'P') && line_offset > 0) {
1524line_offset -= 23;
1525}
1526if (c == ' ') {
1527if (*bp == '\1') {
1528break;
1529} else {
1530line_offset += 23;
1531}
1532}
1533 }
1534 setActiveDisplayPage(0);
1535}
1536
1537void showHelp(void)
1538{
1539if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1540showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1541} else {
1542showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1543}
1544}
1545
1546void showTextFile(const char * filename)
1547{
1548#define MAX_TEXT_FILE_SIZE 65536
1549char*buf;
1550intfd;
1551intsize;
1552
1553if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1554printf("\nFile not found: %s\n", filename);
1555sleep(2);
1556return;
1557}
1558
1559 size = file_size(fd);
1560 if (size > MAX_TEXT_FILE_SIZE) {
1561size = MAX_TEXT_FILE_SIZE;
1562}
1563 buf = malloc(size);
1564 read(fd, buf, size);
1565 close(fd);
1566showTextBuffer(buf, size);
1567free(buf);
1568}
1569
1570// This is a very simplistic prompting scheme that just grabs two hex characters
1571// Eventually we need to do something more user-friendly like display a menu
1572// based off of the Multiboot device list
1573
1574int selectAlternateBootDevice(int bootdevice)
1575{
1576int key;
1577int newbootdevice;
1578int digitsI = 0;
1579char *end;
1580char digits[3] = {0,0,0};
1581
1582// We've already printed the current boot device so user knows what it is
1583printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1584printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1585do {
1586key = getc();
1587switch (key & kASCIIKeyMask) {
1588case kBackspaceKey:
1589if (digitsI > 0) {
1590int x, y, t;
1591getCursorPositionAndType(&x, &y, &t);
1592// Assume x is not 0;
1593x--;
1594setCursorPosition(x,y,0); // back up one char
1595// Overwrite with space without moving cursor position
1596putca(' ', 0x07, 1);
1597digitsI--;
1598} else {
1599// TODO: Beep or something
1600}
1601break;
1602
1603case kReturnKey:
1604digits[digitsI] = '\0';
1605newbootdevice = strtol(digits, &end, 16);
1606if (end == digits && *end == '\0') {
1607// User entered empty string
1608printf("\nUsing default boot device %x\n", bootdevice);
1609key = 0;
1610} else if(end != digits && *end == '\0') {
1611bootdevice = newbootdevice;
1612printf("\n");
1613key = 0; // We gots da boot device
1614} else {
1615printf("\nCouldn't parse. try again: ");
1616digitsI = 0;
1617}
1618break;
1619
1620default:
1621if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1622putc(key & kASCIIKeyMask);
1623digits[digitsI++] = key & kASCIIKeyMask;
1624} else {
1625// TODO: Beep or something
1626}
1627break;
1628};
1629} while (key != 0);
1630
1631return bootdevice;
1632}
1633
1634bool promptForRescanOption(void)
1635{
1636printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1637if (getc() == kReturnKey) {
1638return true;
1639} else {
1640return false;
1641}
1642}
1643

Archive Download this file

Revision: 709