Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 387