Chameleon

Chameleon Svn Source Tree

Root/branches/ErmaC/Enoch_Modules/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
35bool showBootBanner = true; //Azi:showinfo
36static bool shouldboot = false;
37
38extern int multiboot_timeout;
39extern int multiboot_timeout_set;
40
41extern BVRef bvChain;
42//extern intmenucount;
43
44extern intgDeviceCount;
45
46intselectIndex = 0;
47MenuItem * menuItems = NULL;
48
49enum {
50 kMenuTopRow = 5,
51 kMenuMaxItems = 10,
52 kScreenLastRow = 24
53};
54
55//==========================================================================
56
57typedef struct {
58 int x;
59 int y;
60 int type;
61} CursorState;
62
63static void changeCursor( int col, int row, int type, CursorState * cs )
64{
65 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
66 setCursorType( type );
67 setCursorPosition( col, row, 0 );
68}
69
70static void moveCursor( int col, int row )
71{
72 setCursorPosition( col, row, 0 );
73}
74
75static void restoreCursor( const CursorState * cs )
76{
77 setCursorPosition( cs->x, cs->y, 0 );
78 setCursorType( cs->type );
79}
80
81//==========================================================================
82
83/* Flush keyboard buffer; returns TRUE if any of the flushed
84 * characters was F8.
85 */
86
87static bool flushKeyboardBuffer(void)
88{
89 bool status = false;
90
91 while ( readKeyboardStatus() ) {
92 if (bgetc() == 0x4200) status = true;
93 }
94 return status;
95}
96
97//==========================================================================
98
99static int countdown( const char * msg, int row, int timeout )
100{
101 unsigned long time;
102 int ch = 0;
103 int col = strlen(msg) + 1;
104
105 flushKeyboardBuffer();
106
107if( bootArgs->Video.v_display == VGA_TEXT_MODE )
108{
109moveCursor( 0, row );
110printf(msg);
111
112} else {
113
114position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
115
116char dummy[80];
117getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
118drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
119drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
120
121// make this screen the new background
122memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
123
124}
125
126int multi_buff = 18 * (timeout);
127 int multi = ++multi_buff;
128
129 int lasttime=0;
130
131 for ( time = time18(), timeout++; timeout > 0; )
132 {
133if( time18() > lasttime)
134{
135multi--;
136lasttime=time18();
137}
138
139 if ( (ch = readKeyboardStatus()) )
140 break;
141
142 // Count can be interrupted by holding down shift,
143 // control or alt key
144 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
145{
146 ch = 1;
147 break;
148 }
149
150 if ( time18() >= time )
151 {
152 time += 18;
153 timeout--;
154
155if( bootArgs->Video.v_display == VGA_TEXT_MODE )
156{
157moveCursor( col, row );
158printf("(%d) ", timeout);
159}
160 }
161
162if( bootArgs->Video.v_display != VGA_TEXT_MODE )
163{
164drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
165gui.redraw = true;
166updateVRAM();
167}
168
169 }
170
171 flushKeyboardBuffer();
172
173 return ch;
174}
175
176//==========================================================================
177
178char gBootArgs[BOOT_STRING_LEN];
179static char * gBootArgsPtr = gBootArgs;
180static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
181static char booterCommand[BOOT_STRING_LEN];
182static char booterParam[BOOT_STRING_LEN];
183
184static void clearBootArgs(void)
185{
186gBootArgsPtr = gBootArgs;
187memset(gBootArgs, '\0', BOOT_STRING_LEN);
188
189if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
190clearGraphicBootPrompt();
191}
192execute_hook("ClearArgs", NULL, NULL, NULL, NULL);
193}
194
195static void addBootArg(const char * argStr)
196{
197if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
198{
199if(gBootArgsPtr != gBootArgs) *gBootArgsPtr++ = ' ';
200strcat(gBootArgs, argStr);
201gBootArgsPtr += strlen(argStr);
202}
203}
204
205//==========================================================================
206
207static void showBootPrompt(int row, bool visible)
208{
209extern char bootPrompt[];
210extern char bootRescanPrompt[];
211
212if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
213changeCursor( 0, row, kCursorTypeUnderline, 0 );
214clearScreenRows( row, kScreenLastRow );
215}
216
217clearBootArgs();
218
219if (visible)
220{
221if (bootArgs->Video.v_display == VGA_TEXT_MODE)
222{
223if (gEnableCDROMRescan)
224{
225printf( bootRescanPrompt );
226}
227else
228{
229printf( bootPrompt );
230printf( gBootArgs );
231}
232}
233}
234else
235{
236if (bootArgs->Video.v_display != VGA_TEXT_MODE)
237{
238clearGraphicBootPrompt();
239}
240else
241{
242printf("Press Enter to start up the foreign OS. ");
243}
244}
245}
246
247//==========================================================================
248
249static void updateBootArgs( int key )
250{
251 key = ASCII_KEY(key);
252
253 switch ( key )
254 {
255 case KEY_BKSP:
256 if ( gBootArgsPtr > gBootArgs )
257 {
258 *--gBootArgsPtr = '\0';
259
260 int x, y, t;
261 getCursorPositionAndType( &x, &y, &t );
262 if ( x == 0 && y )
263 {
264 x = 80; y--;
265 }
266 if (x)
267{
268x--;
269}
270
271if( bootArgs->Video.v_display == VGA_TEXT_MODE )
272{
273setCursorPosition( x, y, 0 );
274putca(' ', 0x07, 1);
275}
276 else
277 {
278 updateGraphicBootPrompt();
279 }
280 }
281break;
282
283 default:
284 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
285 {
286 *gBootArgsPtr++ = key;
287
288 if( bootArgs->Video.v_display != VGA_TEXT_MODE ) updateGraphicBootPrompt();
289 else if ( key >= ' ' && key < 0x7f) putchar(key);
290}
291
292break;
293 }
294}
295
296//==========================================================================
297
298static const MenuItem * gMenuItems = NULL;
299
300static int gMenuItemCount;
301static int gMenuRow;
302static int gMenuHeight;
303static int gMenuTop;
304static int gMenuBottom;
305static int gMenuSelection;
306
307static int gMenuStart;
308static int gMenuEnd;
309
310static void printMenuItem( const MenuItem * item, int highlight )
311{
312 printf(" ");
313
314 if ( highlight )
315 putca(' ', 0x70, strlen(item->name) + 4);
316 else
317 putca(' ', 0x07, 40);
318
319 printf(" %40s\n", item->name);
320}
321
322//==========================================================================
323
324static void showMenu( const MenuItem * items, int count,
325 int selection, int row, int height )
326{
327 int i;
328 CursorState cursorState;
329
330 if ( items == NULL || count == 0 )
331return;
332
333 // head and tail points to the start and the end of the list.
334 // top and bottom points to the first and last visible items
335 // in the menu window.
336
337 gMenuItems= items;
338 gMenuRow= row;
339 gMenuHeight= height;
340 gMenuItemCount= count;
341 gMenuTop= 0;
342 gMenuBottom= MIN( count, height ) - 1;
343 gMenuSelection= selection;
344
345 gMenuStart= 0;
346 gMenuEnd = MIN( count, gui.maxdevices ) - 1;
347
348// If the selected item is not visible, shift the list down.
349
350 if ( gMenuSelection > gMenuBottom )
351 {
352 gMenuTop += ( gMenuSelection - gMenuBottom );
353 gMenuBottom = gMenuSelection;
354 }
355
356if ( gMenuSelection > gMenuEnd )
357 {
358gMenuStart += ( gMenuSelection - gMenuEnd );
359 gMenuEnd = gMenuSelection;
360 }
361
362// Draw the visible items.
363
364if( bootArgs->Video.v_display != VGA_TEXT_MODE )
365
366drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
367
368else {
369
370changeCursor( 0, row, kCursorTypeHidden, &cursorState );
371
372for ( i = gMenuTop; i <= gMenuBottom; i++ )
373{
374printMenuItem( &items[i], (i == gMenuSelection) );
375}
376
377restoreCursor( &cursorState );
378 }
379}
380
381//==========================================================================
382
383static int updateMenu( int key, void ** paramPtr )
384{
385 int moved = 0;
386
387 union {
388 struct {
389 unsigned int
390 selectionUp : 1,
391 selectionDown : 1,
392 scrollUp : 1,
393 scrollDown : 1;
394 } f;
395 unsigned int w;
396 } draw = {{0}};
397
398 if ( gMenuItems == NULL )
399return 0;
400
401if( bootArgs->Video.v_display != VGA_TEXT_MODE )
402{
403int res;
404
405// set navigation keys for horizontal layout as defaults
406int previous= 0x4B00;// left arrow
407int subsequent= 0x4D00;// right arrow
408int menu= 0x5000;// down arrow
409
410if ( gui.layout == VerticalLayout )
411{
412// set navigation keys for vertical layout
413previous= 0x4800;// up arrow
414subsequent= 0x5000;// down arrow
415menu= 0x4B00;// right arrow
416}
417
418if ( key == previous )
419{
420if ( gMenuSelection > gMenuTop )
421draw.f.selectionUp = 1;
422else if ( gMenuTop > 0 )
423draw.f.scrollDown = 1;
424
425}
426
427else if ( key == subsequent )
428{
429if ( gMenuSelection != gMenuBottom)
430draw.f.selectionDown = 1;
431else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
432draw.f.scrollUp = 1;
433}
434
435else if ( key == menu )
436{
437if ( gui.menu.draw )
438updateInfoMenu(key);
439else
440drawInfoMenu();
441}
442
443else if ( gui.menu.draw )
444{
445res = updateInfoMenu(key);
446
447if ( res == CLOSE_INFO_MENU )
448gui.menu.draw = false;
449else
450{
451shouldboot = ( res != DO_NOT_BOOT );
452
453if ( shouldboot )
454gui.menu.draw = false;
455
456switch (res)
457{
458case BOOT_NORMAL:
459gVerboseMode = false;
460gBootMode = kBootModeNormal;
461break;
462
463case BOOT_VERBOSE:
464gVerboseMode = true;
465gBootMode = kBootModeNormal;
466addBootArg(kVerboseModeFlag);
467break;
468
469case BOOT_IGNORECACHE:
470gVerboseMode = false;
471gBootMode = kBootModeNormal;
472addBootArg(kIgnoreCachesFlag);
473break;
474
475case BOOT_SINGLEUSER:
476gVerboseMode = true;
477gBootMode = kBootModeNormal;
478addBootArg(kSingleUserModeFlag);
479break;
480}
481
482}
483
484}
485
486} else {
487switch ( key )
488{
489 case 0x4800: // Up Arrow
490if ( gMenuSelection != gMenuTop )
491draw.f.selectionUp = 1;
492else if ( gMenuTop > 0 )
493draw.f.scrollDown = 1;
494break;
495
496case 0x5000: // Down Arrow
497if ( gMenuSelection != gMenuBottom )
498draw.f.selectionDown = 1;
499else if ( gMenuBottom < (gMenuItemCount - 1) )
500draw.f.scrollUp = 1;
501break;
502}
503}
504
505 if ( draw.w )
506 {
507 if ( draw.f.scrollUp )
508 {
509 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1);
510 gMenuTop++; gMenuBottom++;
511gMenuStart++; gMenuEnd++;
512 draw.f.selectionDown = 1;
513 }
514
515 if ( draw.f.scrollDown )
516 {
517 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1);
518 gMenuTop--; gMenuBottom--;
519 gMenuStart--; gMenuEnd--;
520 draw.f.selectionUp = 1;
521 }
522
523 if ( draw.f.selectionUp || draw.f.selectionDown )
524 {
525
526CursorState cursorState;
527
528// Set cursor at current position, and clear inverse video.
529
530if( bootArgs->Video.v_display == VGA_TEXT_MODE )
531{
532changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
533printMenuItem( &gMenuItems[gMenuSelection], 0 );
534}
535
536if ( draw.f.selectionUp )
537{
538gMenuSelection--;
539if(( gMenuSelection - gMenuStart) == -1 )
540{
541gMenuStart--;
542gMenuEnd--;
543}
544
545} else {
546gMenuSelection++;
547if(( gMenuSelection - ( gui.maxdevices - 1) - gMenuStart) > 0 )
548{
549gMenuStart++;
550gMenuEnd++;
551}
552 }
553
554if( bootArgs->Video.v_display == VGA_TEXT_MODE )
555 {
556moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
557printMenuItem( &gMenuItems[gMenuSelection], 1 );
558restoreCursor( &cursorState );
559
560 } else
561
562drawDeviceList (gMenuStart, gMenuEnd, gMenuSelection);
563
564}
565
566 *paramPtr = gMenuItems[gMenuSelection].param;
567 moved = 1;
568 }
569
570return moved;
571}
572
573//==========================================================================
574
575static void skipblanks( const char ** cpp )
576{
577 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
578}
579
580//==========================================================================
581
582static const char * extractKernelName( char ** cpp )
583{
584 char * kn = *cpp;
585 char * cp = *cpp;
586 char c;
587
588 // Convert char to lower case.
589
590 c = *cp | 0x20;
591
592 // Must start with a letter or a '/'.
593
594 if ( (c < 'a' || c > 'z') && ( c != '/' ) )
595 return 0;
596
597 // Keep consuming characters until we hit a separator.
598
599 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
600 cp++;
601
602 // Only SPACE or TAB separator is accepted.
603 // Reject everything else.
604
605 if (*cp == '=')
606 return 0;
607
608 // Overwrite the separator, and move the pointer past
609 // the kernel name.
610
611 if (*cp != '\0') *cp++ = '\0';
612 *cpp = cp;
613
614 return kn;
615}
616
617//==========================================================================
618
619static void
620printMemoryInfo(void)
621{
622 int line;
623 int i;
624 MemoryRange *mp = bootInfo->memoryMap;
625
626 // Activate and clear page 1
627 setActiveDisplayPage(1);
628 clearScreenRows(0, 24);
629 setCursorPosition( 0, 0, 1 );
630
631 printf("BIOS reported memory ranges:\n");
632 line = 1;
633 for (i=0; i<bootInfo->memoryMapCount; i++) {
634 printf("Base 0x%08x%08x, ",
635 (unsigned long)(mp->base >> 32),
636 (unsigned long)(mp->base));
637 printf("length 0x%08x%08x, type %d\n",
638 (unsigned long)(mp->length >> 32),
639 (unsigned long)(mp->length),
640 mp->type);
641 if (line++ > 20) {
642 pause();
643 line = 0;
644 }
645 mp++;
646 }
647 if (line > 0) {
648 pause();
649 }
650
651 setActiveDisplayPage(0);
652}
653
654char *getMemoryInfoString()
655{
656 int i;
657 MemoryRange *mp = bootInfo->memoryMap;
658char *buff = malloc(sizeof(char)*1024);
659if(!buff) return 0;
660
661char info[] = "BIOS reported memory ranges:\n";
662sprintf(buff, "%s", info);
663 for (i=0; i<bootInfo->memoryMapCount; i++) {
664 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
665 (unsigned long)(mp->base >> 32),
666 (unsigned long)(mp->base));
667 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
668 (unsigned long)(mp->length >> 32),
669 (unsigned long)(mp->length),
670 mp->type);
671 mp++;
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)
1033{
1034if (bootArgs->Video.v_display != VGA_TEXT_MODE)
1035{
1036setVideoMode(VGA_TEXT_MODE, 0);
1037
1038setCursorPosition(0, 0, 0);
1039clearScreenRows(0, kScreenLastRow);
1040
1041// Display banner and show hardware info.
1042printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
1043printf(getVBEInfoString());
1044
1045clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1046changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1047
1048nextRow = kMenuTopRow;
1049showPrompt = true;
1050
1051if (gDeviceCount)
1052{
1053printf("Use \30\31 keys to select the startup volume.");
1054showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
1055nextRow += MIN(gDeviceCount, kMenuMaxItems) + 3;
1056}
1057
1058showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1059showBootPrompt(nextRow, showPrompt);
1060//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1061} else {
1062gui.redraw = true;
1063setVideoMode(GRAPHICS_MODE, 0);
1064updateVRAM();
1065 updateGraphicBootPrompt();
1066}
1067}
1068key = 0;
1069break;
1070
1071default:
1072key = 0;
1073break;
1074}
1075} while (0 == key);
1076
1077done:
1078if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
1079clearScreenRows(kMenuTopRow, kScreenLastRow);
1080changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
1081}
1082shouldboot = false;
1083gui.menu.draw = false;
1084if (menuItems) {
1085free(menuItems);
1086menuItems = NULL;
1087}
1088execute_hook("BootOptions", gBootArgs, gBootArgsPtr, NULL, NULL);
1089return 0;
1090}
1091
1092//==========================================================================
1093
1094char gBootUUIDString[32+4+1] = ""; // UUID of the boot volume e.g. 5EB1869F-C4FA-3502-BDEB-3B8ED5D87292
1095extern unsigned char chainbootdev;
1096extern unsigned char chainbootflag;
1097
1098bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1099{
1100int argLen = argName ? strlen(argName) : 0;
1101int len = argLen + cnt + 1; // + 1 to account for space.
1102
1103if (len > *cntRemainingP)
1104{
1105error("Warning: boot arguments too long, truncating\n");
1106return false;
1107}
1108
1109if (argName)
1110{
1111strncpy(*argP, argName, argLen);
1112*argP += argLen;
1113*argP[0] = '=';
1114(*argP)++;
1115len++; // +1 to account for '='
1116}
1117
1118strncpy(*argP, val, cnt);
1119*argP += cnt;
1120*argP[0] = ' ';
1121(*argP)++;
1122*cntRemainingP -= len;
1123
1124return true;
1125}
1126
1127//
1128// Returns TRUE if an argument was copied, FALSE otherwise
1129bool
1130processBootArgument(
1131 const char *argName, // The argument to search for
1132 const char *userString, // Typed-in boot arguments
1133 const char *kernelFlags, // Kernel flags from config table
1134 const char *configTable,
1135 char **argP, // Output value
1136 int *cntRemainingP, // Output count
1137 char *foundVal, // found value
1138 int foundValSize // max found value size
1139 )
1140{
1141 const char *val;
1142 int cnt;
1143 bool found = false;
1144
1145if (getValueForBootKey(userString, argName, &val, &cnt))
1146{
1147// Don't copy; these values will be copied at the end of argument processing.
1148found = true;
1149}
1150else if (getValueForBootKey(kernelFlags, argName, &val, &cnt))
1151{
1152// Don't copy; these values will be copied at the end of argument processing.
1153found = true;
1154}
1155else if (getValueForKey(argName, &val, &cnt, &bootInfo->chameleonConfig))
1156{
1157copyArgument(argName, val, cnt, argP, cntRemainingP);
1158found = true;
1159}
1160if (found && foundVal)
1161{
1162strlcpy(foundVal, val, foundValSize);
1163}
1164return found;
1165}
1166
1167// Maximum config table value size
1168#define VALUE_SIZE 2048
1169
1170int processBootOptions()
1171{
1172const char *cp = gBootArgs;
1173const char *val = 0;
1174const char *kernel;
1175int cnt;
1176int userCnt;
1177int cntRemaining;
1178char *argP;
1179char *configKernelFlags;
1180char *valueBuffer;
1181
1182valueBuffer = malloc(VALUE_SIZE);
1183
1184skipblanks( &cp );
1185
1186// Update the unit and partition number.
1187
1188if ( gBootVolume )
1189{
1190if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1191{
1192readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, (void *) 0x7c00 );
1193//
1194// Setup edx, and signal intention to chain load the
1195// foreign booter.
1196//
1197
1198chainbootdev = gBootVolume->biosdev;
1199chainbootflag = 1;
1200
1201return 1;
1202}
1203
1204setRootVolume(gBootVolume);
1205
1206}
1207 // If no boot volume fail immediately because we're just going to fail
1208 // trying to load the config file anyway.
1209 else
1210 return -1;
1211
1212 // Load config table specified by the user, or use the default.
1213
1214 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1215 val = 0;
1216 cnt = 0;
1217 }
1218
1219 // Load com.apple.Boot.plist from the selected volume
1220 // and use its contents to override default bootConfig.
1221
1222 loadSystemConfig(&bootInfo->bootConfig);
1223 loadChameleonConfig(&bootInfo->chameleonConfig);
1224
1225 // Use the kernel name specified by the user, or fetch the name
1226 // in the config table, or use the default if not specified.
1227 // Specifying a kernel name on the command line, or specifying
1228 // a non-default kernel name in the config file counts as
1229 // overriding the kernel, which causes the kernelcache not
1230 // to be used.
1231
1232 gOverrideKernel = false;
1233 if (( kernel = extractKernelName((char **)&cp) )) {
1234 strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
1235 } else {
1236 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1237 strlcpy( bootInfo->bootFile, val, cnt+1 );
1238 } else {
1239 strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
1240 }
1241 }
1242if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1243gOverrideKernel = true;
1244}
1245
1246 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1247 argP = bootArgs->CommandLine;
1248
1249// Get config kernel flags, if not ignored.
1250 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1251 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1252 val = "";
1253 cnt = 0;
1254 }
1255 configKernelFlags = malloc(cnt + 1);
1256 strlcpy(configKernelFlags, val, cnt + 1);
1257
1258 // boot-uuid can be set either on the command-line or in the config file
1259if (!processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config,
1260 &argP, &cntRemaining, gBootUUIDString, sizeof(gBootUUIDString))) {
1261 //
1262 // Try an alternate method for getting the root UUID on boot helper partitions.
1263 //
1264 if (gBootVolume->flags & kBVFlagBooter)
1265{
1266// Load the configuration store in the boot helper partition
1267if (loadHelperConfig(&bootInfo->helperConfig) == 0)
1268 {
1269val = getStringForKey(kHelperRootUUIDKey, &bootInfo->helperConfig);
1270if (val != NULL)
1271strlcpy(gBootUUIDString, val, sizeof(gBootUUIDString));
1272}
1273 }
1274
1275 // Try to get the volume uuid string
1276if (!strlen(gBootUUIDString) && gBootVolume->fs_getuuid)
1277gBootVolume->fs_getuuid(gBootVolume, gBootUUIDString);
1278
1279// If we have the volume uuid add it to the commandline arguments
1280if (strlen(gBootUUIDString))
1281copyArgument(kBootUUIDKey, gBootUUIDString, strlen(gBootUUIDString), &argP, &cntRemaining);
1282}
1283
1284 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config,
1285 &argP, &cntRemaining, gRootDevice, ROOT_DEVICE_SIZE)) {
1286 cnt = 0;
1287 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->chameleonConfig)) {
1288 valueBuffer[0] = '*';
1289 cnt++;
1290 strlcpy(valueBuffer + 1, val, cnt);
1291 val = valueBuffer;
1292 } else {
1293 if (strlen(gBootUUIDString)) {
1294 val = "*uuid";
1295 cnt = 5;
1296 } else {
1297 // Don't set "rd=.." if there is no boot device key
1298 // and no UUID.
1299 val = "";
1300 cnt = 0;
1301 }
1302 }
1303 if (cnt > 0) {
1304 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1305 }
1306 strlcpy( gRootDevice, val, (cnt + 1));
1307 }
1308
1309 /*
1310 * Removed. We don't need this anymore.
1311 *
1312 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config,
1313 &argP, &cntRemaining, gPlatformName, sizeof(gCacheNameAdler))) {
1314 getPlatformName(gPlatformName);
1315 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1316 }
1317 */
1318
1319 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1320 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1321 if (gBootMode & kBootModeSafe) {
1322 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1323 }
1324 }
1325
1326 // Store the merged kernel flags and boot args.
1327
1328 cnt = strlen(configKernelFlags);
1329 if (cnt) {
1330 if (cnt > cntRemaining) {
1331 error("Warning: boot arguments too long, truncating\n");
1332 cnt = cntRemaining;
1333 }
1334 strncpy(argP, configKernelFlags, cnt);
1335 argP[cnt++] = ' ';
1336 cntRemaining -= cnt;
1337 }
1338 userCnt = strlen(cp);
1339 if (userCnt > cntRemaining) {
1340 error("Warning: boot arguments too long, truncating\n");
1341 userCnt = cntRemaining;
1342 }
1343 strncpy(&argP[cnt], cp, userCnt);
1344 argP[cnt+userCnt] = '\0';
1345
1346if(!shouldboot)
1347{
1348gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ||
1349getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->chameleonConfig );
1350
1351gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) ?
1352kBootModeSafe : kBootModeNormal;
1353
1354 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) {
1355 gBootMode = kBootModeSafe;
1356 }
1357}
1358
1359if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1360strlcpy(gMKextName, val, cnt + 1);
1361else
1362gMKextName[0]=0;
1363
1364 free(configKernelFlags);
1365 free(valueBuffer);
1366
1367 return 0;
1368}
1369
1370
1371//==========================================================================
1372// Load the help file and display the file contents on the screen.
1373
1374void showTextBuffer(char *buf_orig, int size)
1375{
1376char*bp;
1377char* buf;
1378intline;
1379intline_offset;
1380intc;
1381
1382if (bootArgs->Video.v_display != VGA_TEXT_MODE)
1383{
1384showInfoBox( "Press q to continue, space for next page.\n",buf_orig );
1385return;
1386}
1387
1388// Create a copy so that we don't mangle the original
1389buf = malloc(size + 1);
1390memcpy(buf, buf_orig, size);
1391
1392
1393 bp = buf;
1394 while (size-- > 0)
1395{
1396if (*bp == '\n')
1397{
1398*bp = '\0';
1399}
1400bp++;
1401 }
1402 *bp = '\1';
1403 line_offset = 0;
1404
1405 setActiveDisplayPage(1);
1406
1407 while (1)
1408{
1409clearScreenRows(0, 24);
1410setCursorPosition(0, 0, 1);
1411bp = buf;
1412for (line = 0; *bp != '\1' && line < line_offset; line++)
1413{
1414while (*bp != '\0')
1415{
1416bp++;
1417}
1418bp++;
1419}
1420for (line = 0; *bp != '\1' && line < 23; line++)
1421{
1422setCursorPosition(0, line, 1);
1423printf("%s\n", bp);
1424while (*bp != '\0')
1425{
1426bp++;
1427}
1428bp++;
1429}
1430
1431setCursorPosition(0, 23, 1);
1432if (*bp == '\1')
1433{
1434printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1435}
1436else
1437{
1438printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1439}
1440
1441c = getchar();
1442if (c == 'q' || c == 'Q')
1443{
1444break;
1445}
1446if ((c == 'p' || c == 'P') && line_offset > 0)
1447{
1448line_offset -= 23;
1449}
1450if (c == ' ')
1451{
1452if (*bp == '\1')
1453{
1454break;
1455}
1456else
1457{
1458line_offset += 23;
1459}
1460}
1461 }
1462 setActiveDisplayPage(0);
1463}
1464
1465void showHelp(void)
1466{
1467if (bootArgs->Video.v_display != VGA_TEXT_MODE)
1468{
1469showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1470}
1471else
1472{
1473showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1474}
1475}
1476
1477void showTextFile(const char * filename)
1478{
1479#define MAX_TEXT_FILE_SIZE 65536
1480char*buf;
1481intfd;
1482intsize;
1483
1484if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0)
1485{
1486printf("\nFile not found: %s\n", filename);
1487sleep(2);
1488return;
1489}
1490
1491 size = file_size(fd);
1492 if (size > MAX_TEXT_FILE_SIZE)
1493{
1494size = MAX_TEXT_FILE_SIZE;
1495}
1496 buf = malloc(size);
1497 read(fd, buf, size);
1498 close(fd);
1499showTextBuffer(buf, size);
1500free(buf);
1501}
1502
1503// This is a very simplistic prompting scheme that just grabs two hex characters
1504// Eventually we need to do something more user-friendly like display a menu
1505// based off of the Multiboot device list
1506
1507int selectAlternateBootDevice(int bootdevice)
1508{
1509int key;
1510int newbootdevice;
1511int digitsI = 0;
1512char *end;
1513char digits[3] = {0,0,0};
1514
1515// We've already printed the current boot device so user knows what it is
1516printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1517printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1518do {
1519key = getchar();
1520switch (ASCII_KEY(key))
1521{
1522case KEY_BKSP:
1523if (digitsI > 0)
1524{
1525int x, y, t;
1526getCursorPositionAndType(&x, &y, &t);
1527// Assume x is not 0;
1528x--;
1529setCursorPosition(x,y,0); // back up one char
1530// Overwrite with space without moving cursor position
1531putca(' ', 0x07, 1);
1532digitsI--;
1533}
1534else
1535{
1536// TODO: Beep or something
1537}
1538break;
1539
1540case KEY_ENTER:
1541digits[digitsI] = '\0';
1542newbootdevice = strtol(digits, &end, 16);
1543if (end == digits && *end == '\0')
1544{
1545// User entered empty string
1546printf("\nUsing default boot device %x\n", bootdevice);
1547key = 0;
1548}
1549else if(end != digits && *end == '\0')
1550{
1551bootdevice = newbootdevice;
1552printf("\n");
1553key = 0; // We gots da boot device
1554}
1555else
1556{
1557printf("\nCouldn't parse. try again: ");
1558digitsI = 0;
1559}
1560break;
1561
1562default:
1563if (isxdigit(ASCII_KEY(key)) && digitsI < 2)
1564{
1565putchar(ASCII_KEY(key));
1566digits[digitsI++] = ASCII_KEY(key);
1567}
1568else
1569{
1570// TODO: Beep or something
1571}
1572break;
1573};
1574} while (key != 0);
1575
1576return bootdevice;
1577}
1578
1579bool promptForRescanOption(void)
1580{
1581printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1582if (getchar() == KEY_ENTER)
1583{
1584return true;
1585}
1586else
1587{
1588return false;
1589}
1590}
1591

Archive Download this file

Revision: 2238