Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2560