Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 1022