Chameleon

Chameleon Svn Source Tree

Root/branches/meklort/i386/boot2/options.c

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

Archive Download this file

Revision: 519