Chameleon

Chameleon Svn Source Tree

Root/branches/JrCs/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 "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 strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
1200 } else {
1201 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1202 strlcpy( bootInfo->bootFile, val, cnt+1 );
1203 } else {
1204 strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
1205 }
1206 }
1207if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1208gOverrideKernel = true;
1209}
1210
1211 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1212 argP = bootArgs->CommandLine;
1213
1214 // Get config table kernel flags, if not ignored.
1215 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1216 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1217 val = "";
1218 cnt = 0;
1219 }
1220 configKernelFlags = malloc(cnt + 1);
1221 strlcpy(configKernelFlags, val, cnt + 1);
1222
1223 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1224 // boot-uuid was set either on the command-line
1225 // or in the config file.
1226 uuidSet = true;
1227 } else {
1228
1229 //
1230 // Try an alternate method for getting the root UUID on boot helper partitions.
1231 //
1232 if (gBootVolume->flags & kBVFlagBooter)
1233 {
1234 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1235 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1236 {
1237 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1238 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1239 uuidSet = true;
1240 }
1241 }
1242
1243 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1244 verbose("Setting boot-uuid to: %s\n", uuidStr);
1245 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1246 uuidSet = true;
1247 }
1248
1249 }
1250
1251 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1252 cnt = 0;
1253 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->chameleonConfig)) {
1254 valueBuffer[0] = '*';
1255 cnt++;
1256 strlcpy(valueBuffer + 1, val, cnt);
1257 val = valueBuffer;
1258 } else {
1259 if (uuidSet) {
1260 val = "*uuid";
1261 cnt = 5;
1262 } else {
1263 // Don't set "rd=.." if there is no boot device key
1264 // and no UUID.
1265 val = "";
1266 cnt = 0;
1267 }
1268 }
1269 if (cnt > 0) {
1270 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1271 }
1272 strlcpy( gRootDevice, val, (cnt + 1));
1273 }
1274
1275 /*
1276 * Removed. We don't need this anymore.
1277 *
1278 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1279 getPlatformName(gPlatformName);
1280 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1281 }
1282 */
1283
1284 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1285 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1286 if (gBootMode & kBootModeSafe) {
1287 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1288 }
1289 }
1290
1291 // Store the merged kernel flags and boot args.
1292
1293 cnt = strlen(configKernelFlags);
1294 if (cnt) {
1295 if (cnt > cntRemaining) {
1296 error("Warning: boot arguments too long, truncating\n");
1297 cnt = cntRemaining;
1298 }
1299 strncpy(argP, configKernelFlags, cnt);
1300 argP[cnt++] = ' ';
1301 cntRemaining -= cnt;
1302 }
1303 userCnt = strlen(cp);
1304 if (userCnt > cntRemaining) {
1305 error("Warning: boot arguments too long, truncating\n");
1306 userCnt = cntRemaining;
1307 }
1308 strncpy(&argP[cnt], cp, userCnt);
1309 argP[cnt+userCnt] = '\0';
1310
1311if(!shouldboot)
1312{
1313gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ||
1314getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->chameleonConfig );
1315
1316gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) ?
1317kBootModeSafe : kBootModeNormal;
1318
1319 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) {
1320 gBootMode = kBootModeSafe;
1321 }
1322}
1323
1324if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1325strlcpy(gMKextName, val, cnt + 1);
1326else
1327gMKextName[0]=0;
1328
1329 free(configKernelFlags);
1330 free(valueBuffer);
1331
1332 return 0;
1333}
1334
1335
1336//==========================================================================
1337// Load the help file and display the file contents on the screen.
1338
1339void showTextBuffer(char *buf_orig, int size)
1340{
1341char*bp;
1342char* buf;
1343intline;
1344intline_offset;
1345intc;
1346
1347if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1348showInfoBox( "Press q to continue, space for next page.\n",buf_orig );
1349return;
1350}
1351
1352// Create a copy so that we don't mangle the original
1353buf = malloc(size + 1);
1354memcpy(buf, buf_orig, size);
1355
1356
1357 bp = buf;
1358 while (size-- > 0) {
1359if (*bp == '\n') {
1360*bp = '\0';
1361}
1362bp++;
1363 }
1364 *bp = '\1';
1365 line_offset = 0;
1366
1367 setActiveDisplayPage(1);
1368
1369 while (1) {
1370clearScreenRows(0, 24);
1371setCursorPosition(0, 0, 1);
1372bp = buf;
1373for (line = 0; *bp != '\1' && line < line_offset; line++) {
1374while (*bp != '\0') {
1375bp++;
1376}
1377bp++;
1378}
1379for (line = 0; *bp != '\1' && line < 23; line++) {
1380setCursorPosition(0, line, 1);
1381printf("%s\n", bp);
1382while (*bp != '\0') {
1383bp++;
1384}
1385bp++;
1386}
1387
1388setCursorPosition(0, 23, 1);
1389if (*bp == '\1') {
1390printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1391} else {
1392printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1393}
1394
1395c = getchar();
1396if (c == 'q' || c == 'Q') {
1397break;
1398}
1399if ((c == 'p' || c == 'P') && line_offset > 0) {
1400line_offset -= 23;
1401}
1402if (c == ' ') {
1403if (*bp == '\1') {
1404break;
1405} else {
1406line_offset += 23;
1407}
1408}
1409 }
1410 setActiveDisplayPage(0);
1411}
1412
1413void showHelp(void)
1414{
1415if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
1416showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1417} else {
1418showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1419}
1420}
1421
1422void showTextFile(const char * filename)
1423{
1424#define MAX_TEXT_FILE_SIZE 65536
1425char*buf;
1426intfd;
1427intsize;
1428
1429if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1430printf("\nFile not found: %s\n", filename);
1431sleep(2);
1432return;
1433}
1434
1435 size = file_size(fd);
1436 if (size > MAX_TEXT_FILE_SIZE) {
1437size = MAX_TEXT_FILE_SIZE;
1438}
1439 buf = malloc(size);
1440 read(fd, buf, size);
1441 close(fd);
1442showTextBuffer(buf, size);
1443free(buf);
1444}
1445
1446// This is a very simplistic prompting scheme that just grabs two hex characters
1447// Eventually we need to do something more user-friendly like display a menu
1448// based off of the Multiboot device list
1449
1450int selectAlternateBootDevice(int bootdevice)
1451{
1452int key;
1453int newbootdevice;
1454int digitsI = 0;
1455char *end;
1456char digits[3] = {0,0,0};
1457
1458// We've already printed the current boot device so user knows what it is
1459printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1460printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1461do {
1462key = getchar();
1463switch (key & kASCIIKeyMask) {
1464case kBackspaceKey:
1465if (digitsI > 0) {
1466int x, y, t;
1467getCursorPositionAndType(&x, &y, &t);
1468// Assume x is not 0;
1469x--;
1470setCursorPosition(x,y,0); // back up one char
1471// Overwrite with space without moving cursor position
1472putca(' ', 0x07, 1);
1473digitsI--;
1474} else {
1475// TODO: Beep or something
1476}
1477break;
1478
1479case kReturnKey:
1480digits[digitsI] = '\0';
1481newbootdevice = strtol(digits, &end, 16);
1482if (end == digits && *end == '\0') {
1483// User entered empty string
1484printf("\nUsing default boot device %x\n", bootdevice);
1485key = 0;
1486} else if(end != digits && *end == '\0') {
1487bootdevice = newbootdevice;
1488printf("\n");
1489key = 0; // We gots da boot device
1490} else {
1491printf("\nCouldn't parse. try again: ");
1492digitsI = 0;
1493}
1494break;
1495
1496default:
1497if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1498putchar(key & kASCIIKeyMask);
1499digits[digitsI++] = key & kASCIIKeyMask;
1500} else {
1501// TODO: Beep or something
1502}
1503break;
1504};
1505} while (key != 0);
1506
1507return bootdevice;
1508}
1509
1510bool promptForRescanOption(void)
1511{
1512printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1513if (getchar() == kReturnKey) {
1514return true;
1515} else {
1516return false;
1517}
1518}
1519

Archive Download this file

Revision: 1466