Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2899