Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2769