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

Archive Download this file

Revision: 2592