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

Archive Download this file

Revision: 2871