Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 603