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++ = 'f';
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
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;
1134const char*value;
1135int len;
1136 int cnt;
1137 int userCnt;
1138 int cntRemaining;
1139 char * argP;
1140 char uuidStr[64];
1141 bool uuidSet = false;
1142 char * configKernelFlags;
1143 char * valueBuffer;
1144config_file_t systemVersion;
1145
1146 valueBuffer = malloc(VALUE_SIZE);
1147
1148 skipblanks( &cp );
1149
1150 // Update the unit and partition number.
1151
1152 if ( gBootVolume )
1153 {
1154 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1155 {
1156 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1157 (void *) 0x7c00 );
1158
1159 //
1160 // Setup edx, and signal intention to chain load the
1161 // foreign booter.
1162 //
1163
1164 chainbootdev = gBootVolume->biosdev;
1165 chainbootflag = 1;
1166
1167 return 1;
1168 }
1169
1170 setRootVolume(gBootVolume);
1171
1172 }
1173 // If no boot volume fail immediately because we're just going to fail
1174 // trying to load the config file anyway.
1175 else
1176 return -1;
1177
1178// Needed to enable search for override Boot.plist on OS specific folders
1179// from loadOverrideConfig(). Find out which version mac os we're booting.
1180if (!loadConfigFile("/System/Library/CoreServices/SystemVersion.plist", &systemVersion))
1181{
1182if (getValueForKey(kProductVersion, &value, &len, &systemVersion))
1183{
1184// getValueForKey uses const char for val
1185// so copy it and trim
1186strncpy(gMacOSVersion, value, MIN(len, 4));
1187gMacOSVersion[MIN(len, 4)] = '\0';
1188}
1189} // doesn't print to screen here!
1190
1191//Azi: implemented at loadOverrideConfig.
1192 // Load config table specified by the user, or use the default.
1193 //if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1194 // val = 0;
1195 // cnt = 0;
1196 //}
1197
1198 // Load com.apple.Boot.plist from the selected volume
1199 // and use its contents to override default bootConfig.
1200 // This is not a mandatory operation anymore.
1201
1202 loadOverrideConfig(&bootInfo->overrideConfig);
1203
1204 // Use the kernel name specified by the user, or fetch the name
1205 // in the config table, or use the default if not specified.
1206 // Specifying a kernel name on the command line, or specifying
1207 // a non-default kernel name in the config file counts as
1208 // overriding the kernel, which causes the kernelcache not
1209 // to be used.
1210
1211 gOverrideKernel = false;
1212 if (( kernel = extractKernelName((char **)&cp) )) {
1213 strcpy( bootInfo->bootFile, kernel );
1214 gOverrideKernel = true;
1215 } else {
1216 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1217 strlcpy( bootInfo->bootFile, val, cnt+1 );
1218 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1219 gOverrideKernel = true;
1220 }
1221 } else {
1222 strcpy( bootInfo->bootFile, kDefaultKernel );
1223 }
1224 }
1225
1226 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1227 argP = bootArgs->CommandLine;
1228
1229 // Get config table kernel flags, if not ignored.
1230 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1231 !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1232 val = "";
1233 cnt = 0;
1234 }
1235 configKernelFlags = malloc(cnt + 1);
1236 strlcpy(configKernelFlags, val, cnt + 1);
1237
1238 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1239 // boot-uuid was set either on the command-line
1240 // or in the config file.
1241 uuidSet = true;
1242 } else {
1243
1244 //
1245 // Try an alternate method for getting the root UUID on boot helper partitions.
1246 //
1247 if (gBootVolume->flags & kBVFlagBooter)
1248 {
1249 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1250 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1251 {
1252 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1253 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1254 uuidSet = true;
1255 }
1256 }
1257
1258 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1259 verbose("Setting boot-uuid to: %s\n", uuidStr);
1260 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1261 uuidSet = true;
1262 }
1263 }
1264
1265 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1266 cnt = 0;
1267 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1268 valueBuffer[0] = '*';
1269 cnt++;
1270 strlcpy(valueBuffer + 1, val, cnt);
1271 val = valueBuffer;
1272 } else {
1273 if (uuidSet) {
1274 val = "*uuid";
1275 cnt = 5;
1276 } else {
1277 // Don't set "rd=.." if there is no boot device key
1278 // and no UUID.
1279 val = "";
1280 cnt = 0;
1281 }
1282 }
1283 if (cnt > 0) {
1284 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1285 }
1286 strlcpy( gRootDevice, val, (cnt + 1));
1287 }
1288
1289 /*
1290 * Removed. We don't need this anymore.
1291 *
1292 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1293 getPlatformName(gPlatformName);
1294 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1295 }
1296 */
1297
1298 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1299 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1300 if (gBootMode & kBootModeSafe) {
1301 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1302 }
1303 }
1304
1305 // Store the merged kernel flags and boot args.
1306
1307 cnt = strlen(configKernelFlags);
1308 if (cnt) {
1309 if (cnt > cntRemaining) {
1310 error("Warning: boot arguments too long, truncating\n");
1311 cnt = cntRemaining;
1312 }
1313 strncpy(argP, configKernelFlags, cnt);
1314 argP[cnt++] = ' ';
1315 cntRemaining -= cnt;
1316 }
1317 userCnt = strlen(cp);
1318 if (userCnt > cntRemaining) {
1319 error("Warning: boot arguments too long, truncating\n");
1320 userCnt = cntRemaining;
1321 }
1322 strncpy(&argP[cnt], cp, userCnt);
1323 argP[cnt+userCnt] = '\0';
1324
1325 if(!shouldboot)
1326 {
1327 gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1328 getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1329
1330 gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1331 kBootModeSafe : kBootModeNormal;
1332
1333 if ( getValueForKey( kOldSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1334 gBootMode = kBootModeSafe;
1335 }
1336
1337 if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1338 strlcpy(gMKextName, val, cnt + 1);
1339 }
1340
1341 }
1342
1343 free(configKernelFlags);
1344 free(valueBuffer);
1345
1346 return 0;
1347}
1348
1349
1350//==========================================================================
1351// Load the help file and display the file contents on the screen.
1352
1353static void showTextBuffer(char *buf, int size)
1354{
1355char*bp;
1356intline;
1357intline_offset;
1358intc;
1359
1360if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1361showInfoBox( "Press q to quit\n",buf );
1362return;
1363}
1364
1365 bp = buf;
1366 while (size-- > 0) {
1367if (*bp == '\n') {
1368*bp = '\0';
1369}
1370bp++;
1371 }
1372 *bp = '\1';
1373 line_offset = 0;
1374
1375 setActiveDisplayPage(1);
1376
1377 while (1) {
1378clearScreenRows(0, 24);
1379setCursorPosition(0, 0, 1);
1380bp = buf;
1381for (line = 0; *bp != '\1' && line < line_offset; line++) {
1382while (*bp != '\0') {
1383bp++;
1384}
1385bp++;
1386}
1387for (line = 0; *bp != '\1' && line < 23; line++) {
1388setCursorPosition(0, line, 1);
1389printf("%s\n", bp);
1390while (*bp != '\0') {
1391bp++;
1392}
1393bp++;
1394}
1395
1396setCursorPosition(0, 23, 1);
1397if (*bp == '\1') {
1398printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1399} else {
1400printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1401}
1402
1403c = getc();
1404if (c == 'q' || c == 'Q') {
1405break;
1406}
1407if ((c == 'p' || c == 'P') && line_offset > 0) {
1408line_offset -= 23;
1409}
1410if (c == ' ') {
1411if (*bp == '\1') {
1412break;
1413} else {
1414line_offset += 23;
1415}
1416}
1417 }
1418 setActiveDisplayPage(0);
1419}
1420
1421void showHelp(void)
1422{
1423if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1424showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1425} else {
1426showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1427}
1428}
1429
1430void showTextFile(const char * filename)
1431{
1432#define MAX_TEXT_FILE_SIZE 65536
1433char*buf;
1434intfd;
1435intsize;
1436
1437if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1438printf("\nFile not found: %s\n", filename);
1439sleep(2);
1440return;
1441}
1442
1443 size = file_size(fd);
1444 if (size > MAX_TEXT_FILE_SIZE) {
1445size = MAX_TEXT_FILE_SIZE;
1446}
1447 buf = malloc(size);
1448 read(fd, buf, size);
1449 close(fd);
1450showTextBuffer(buf, size);
1451free(buf);
1452}
1453
1454// This is a very simplistic prompting scheme that just grabs two hex characters
1455// Eventually we need to do something more user-friendly like display a menu
1456// based off of the Multiboot device list
1457
1458int selectAlternateBootDevice(int bootdevice)
1459{
1460int key;
1461int newbootdevice;
1462int digitsI = 0;
1463char *end;
1464char digits[3] = {0,0,0};
1465
1466// We've already printed the current boot device so user knows what it is
1467printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1468printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1469do {
1470key = getc();
1471switch (key & kASCIIKeyMask) {
1472case kBackspaceKey:
1473if (digitsI > 0) {
1474int x, y, t;
1475getCursorPositionAndType(&x, &y, &t);
1476// Assume x is not 0;
1477x--;
1478setCursorPosition(x,y,0); // back up one char
1479// Overwrite with space without moving cursor position
1480putca(' ', 0x07, 1);
1481digitsI--;
1482} else {
1483// TODO: Beep or something
1484}
1485break;
1486
1487case kReturnKey:
1488digits[digitsI] = '\0';
1489newbootdevice = strtol(digits, &end, 16);
1490if (end == digits && *end == '\0') {
1491// User entered empty string
1492printf("\nUsing default boot device %x\n", bootdevice);
1493key = 0;
1494} else if(end != digits && *end == '\0') {
1495bootdevice = newbootdevice;
1496printf("\n");
1497key = 0; // We gots da boot device
1498} else {
1499printf("\nCouldn't parse. try again: ");
1500digitsI = 0;
1501}
1502break;
1503
1504default:
1505if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1506putc(key & kASCIIKeyMask);
1507digits[digitsI++] = key & kASCIIKeyMask;
1508} else {
1509// TODO: Beep or something
1510}
1511break;
1512};
1513} while (key != 0);
1514
1515return bootdevice;
1516}
1517
1518bool promptForRescanOption(void)
1519{
1520printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1521if (getc() == kReturnKey) {
1522return true;
1523} else {
1524return false;
1525}
1526}
1527

Archive Download this file

Revision: 360