Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2629