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

Archive Download this file

Revision: HEAD