Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2379