Chameleon

Chameleon Svn Source Tree

Root/tags/2.0/i386/boot2/options.c

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

Archive Download this file

Revision: 1689