Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2531