Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/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 "platform.h"
28#include "graphics.h"
29#include "fdisk.h"
30#include "pci.h"
31#include "options.h"
32#include "modules.h"
33
34#ifndef EMBED_HELP
35#define EMBED_HELP 0
36#endif
37
38#if EMBED_HELP
39#include "embedded.h" //+ 1376 bytes
40#endif
41
42typedef struct {
43 char name[80];
44 void * param;
45} MenuItem;
46
47typedef struct {
48 int x;
49 int y;
50 int type;
51} CursorState;
52
53#if UNUSED
54extern int multiboot_timeout;
55extern int multiboot_timeout_set;
56#endif
57
58enum {
59 kMenuTopRow = 5,
60 kMenuMaxItems = 10,
61 kScreenLastRow = 24
62};
63
64static intselectIndex = 0;
65static MenuItem * menuItems = NULL;
66
67static int countdown( const char * msg, int row, int timeout, int *optionKey );
68static void showBootPrompt(int row, bool visible);
69static void updateBootArgs( int key );
70static void showMenu( const MenuItem * items, int count,
71 int selection, int row, int height );
72static int updateMenu( int key, void ** paramPtr );
73static void skipblanks( const char ** cpp );
74static const char * extractKernelName( char ** cpp );
75static bool flushKeyboardBuffer(void);
76static void moveCursor( int col, int row );
77static void changeCursor( int col, int row, int type, CursorState * cs );
78static void restoreCursor( const CursorState * cs );
79static void printMenuItem( const MenuItem * item, int highlight );
80
81//==========================================================================
82
83static void changeCursor( int col, int row, int type, CursorState * cs )
84{
85 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
86 setCursorType( type );
87 setCursorPosition( col, row, 0 );
88}
89
90static void moveCursor( int col, int row )
91{
92 setCursorPosition( col, row, 0 );
93}
94
95static void restoreCursor( const CursorState * cs )
96{
97 setCursorPosition( cs->x, cs->y, 0 );
98 setCursorType( cs->type );
99}
100
101//==========================================================================
102
103/* Flush keyboard buffer; returns TRUE if any of the flushed
104 * characters was F8.
105 */
106
107static bool flushKeyboardBuffer(void)
108{
109 bool status = false;
110
111 while ( readKeyboardStatus() ) {
112 if (bgetc() == 0x4200) status = true;
113 }
114 return status;
115}
116
117//==========================================================================
118
119static int countdown( const char * msg, register int row, register int timeout, int *optionKey )
120{
121 register unsigned long time;
122 int ch = 0;
123 register int col = strlen(msg) + 1;
124
125
126 flushKeyboardBuffer();
127
128moveCursor( 0, row );
129printf("%s",msg);
130
131 for ( time = time18(), timeout++; timeout > 0; )
132 {
133if ((ch = readKeyboardStatus())){
134*optionKey = ch;
135 break;
136}
137 // Count can be interrupted by holding down shift,
138 // control or alt key
139 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
140{
141 ch = 1;
142
143 break;
144 }
145
146 if ( time18() >= time )
147 {
148 time += 18;
149 timeout--;
150
151moveCursor( col, row );
152printf("(%d)", timeout);
153#ifdef ShowCurrentDate
154 printf("\n\n\n\nCurrent Date : %s", Date());
155#endif
156 }
157 }
158
159 flushKeyboardBuffer();
160
161 return ch;
162}
163
164//==========================================================================
165
166static char gBootArgs[BOOT_STRING_LEN];
167static char * gBootArgsPtr = gBootArgs;
168static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
169static char booterCommand[BOOT_STRING_LEN];
170static char booterParam[BOOT_STRING_LEN];
171
172void clearBootArgs(void)
173{
174gBootArgsPtr = gBootArgs;
175memset(gBootArgs, '\0', BOOT_STRING_LEN);
176
177}
178
179void addBootArg(const char * argStr)
180{
181if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
182{
183*gBootArgsPtr++ = ' ';
184strcat(gBootArgs, argStr);
185gBootArgsPtr += strlen(argStr);
186}
187}
188
189//==========================================================================
190
191static void showBootPrompt(int row, bool visible)
192{
193 char * bootPrompt = (char*)(uint32_t)get_env(envBootPrompt);
194 char * bootRescanPrompt = (char*)(uint32_t)get_env(envBootRescanPrompt);
195
196changeCursor( 0, row, kCursorTypeUnderline, 0 );
197clearScreenRows( row, kScreenLastRow );
198
199clearBootArgs();
200
201if (visible) {
202
203if (get_env(envgEnableCDROMRescan))
204{
205printf( "%s",bootRescanPrompt );
206}
207else
208{
209 printf( "%s",bootPrompt );
210}
211} else {
212printf("Press Enter to start up the foreign OS. ");
213}
214}
215
216//==========================================================================
217
218static void updateBootArgs( int key )
219{
220 key &= kASCIIKeyMask;
221
222 switch ( key )
223 {
224 case kBackspaceKey:
225 if ( gBootArgsPtr > gBootArgs )
226 {
227 int x, y, t;
228 getCursorPositionAndType( &x, &y, &t );
229 if ( x == 0 && y )
230 {
231 x = 80; y--;
232 }
233 if (x)
234{
235x--;
236}
237
238setCursorPosition( x, y, 0 );
239putca(' ', 0x07, 1);
240
241*gBootArgsPtr-- = '\0';
242}
243
244break;
245
246 default:
247 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
248 {
249putchar(key); // echo to screen
250*gBootArgsPtr++ = key;
251}
252
253break;
254 }
255}
256
257//==========================================================================
258
259static const MenuItem * gMenuItems = NULL;
260
261
262static void printMenuItem( const MenuItem * item, int highlight )
263{
264 printf(" ");
265
266 if ( highlight )
267 putca(' ', 0x70, strlen(item->name) + 4);
268 else
269 putca(' ', 0x07, 40);
270
271char Item[40];
272snprintf(Item, sizeof(Item), item->name);
273 printf(" %s\n", Item);
274}
275
276//==========================================================================
277
278static void showMenu( const MenuItem * items, int count,
279 int selection, int row, int height )
280{
281 int i;
282 CursorState cursorState;
283
284 if ( items == NULL || count == 0 )
285return;
286
287 // head and tail points to the start and the end of the list.
288 // top and bottom points to the first and last visible items
289 // in the menu window.
290
291 gMenuItems= items;
292 int MenuTop= 0;
293 int MenuBottom= min( count, height ) - 1;
294 int MenuSelection= selection;
295 int MenuStart= 0;
296 int MenuEnd = count; //min( count, gui.maxdevices ) - 1;
297
298// If the selected item is not visible, shift the list down.
299
300 if ( MenuSelection > MenuBottom )
301 {
302 MenuTop += ( MenuSelection - MenuBottom );
303 MenuBottom = MenuSelection;
304 }
305
306if ( MenuSelection > MenuEnd )
307 {
308MenuStart += ( MenuSelection - MenuEnd );
309 MenuEnd = MenuSelection;
310 }
311
312// Draw the visible items.
313
314changeCursor( 0, row, kCursorTypeHidden, &cursorState );
315
316for ( i = MenuTop; i <= MenuBottom; i++ )
317{
318printMenuItem( &items[i], (i == MenuSelection) );
319}
320
321 safe_set_env(envgMenuRow,row);
322 safe_set_env(envgMenuHeight,height);
323 safe_set_env(envgMenuItemCount,count);
324 safe_set_env(envgMenuTop,MenuTop);
325 safe_set_env(envgMenuBottom,MenuBottom);
326 safe_set_env(envgMenuSelection,MenuSelection);
327 safe_set_env(envgMenuStart,MenuStart);
328 safe_set_env(envgMenuEnd,MenuEnd);
329
330
331restoreCursor( &cursorState );
332}
333
334//==========================================================================
335
336static int updateMenu( int key, void ** paramPtr )
337{
338 int moved = 0;
339
340 int MenuTop = (int)get_env(envgMenuTop);
341 int MenuSelection = (int)get_env(envgMenuSelection);
342 int MenuRow = (int)get_env(envgMenuRow);
343 int MenuHeight = (int)get_env(envgMenuHeight);
344 int MenuBottom = (int)get_env(envgMenuBottom);
345 int MenuStart = (int)get_env(envgMenuStart);
346 int MenuEnd = (int)get_env(envgMenuEnd);
347
348 union {
349 struct {
350 unsigned int
351selectionUp : 1,
352selectionDown : 1,
353scrollUp : 1,
354scrollDown : 1;
355 } f;
356 unsigned int w;
357 } draw = {{0}};
358
359if ( gMenuItems == NULL )
360return 0;
361
362switch ( key )
363{
364case 0x4800: // Up Arrow
365 {
366if ( MenuSelection != MenuTop )
367draw.f.selectionUp = 1;
368else if ( MenuTop > 0 )
369draw.f.scrollDown = 1;
370break;
371 }
372case 0x5000: // Down Arrow
373 {
374if ( MenuSelection != MenuBottom )
375draw.f.selectionDown = 1;
376else if ( MenuBottom < (get_env(envgMenuItemCount) - 1) )
377draw.f.scrollUp = 1;
378break;
379 }
380default:
381break;
382}
383
384 if ( draw.w )
385 {
386 if ( draw.f.scrollUp )
387 {
388 scollPage(0, MenuRow, 40, MenuRow + MenuHeight - 1, 0x07, 1, 1);
389 MenuTop++; MenuBottom++;
390MenuStart++; MenuEnd++;
391 draw.f.selectionDown = 1;
392 }
393
394 if ( draw.f.scrollDown )
395 {
396 scollPage(0, MenuRow, 40, MenuRow + MenuHeight - 1, 0x07, 1, -1);
397 MenuTop--; MenuBottom--;
398 MenuStart--; MenuEnd--;
399 draw.f.selectionUp = 1;
400 }
401
402 if ( draw.f.selectionUp || draw.f.selectionDown )
403 {
404
405CursorState cursorState;
406
407// Set cursor at current position, and clear inverse video.
408changeCursor( 0, MenuRow + MenuSelection - MenuTop, kCursorTypeHidden, &cursorState );
409printMenuItem( &gMenuItems[MenuSelection], 0 );
410
411if ( draw.f.selectionUp )
412{
413MenuSelection--;
414if(( MenuSelection - MenuStart) == -1 )
415{
416MenuStart--;
417MenuEnd--;
418}
419
420} else {
421MenuSelection++;
422if(( MenuSelection - ( MenuEnd - 1) - MenuStart) > 0 )
423{
424MenuStart++;
425MenuEnd++;
426}
427}
428
429moveCursor( 0, MenuRow + MenuSelection - MenuTop );
430printMenuItem( &gMenuItems[MenuSelection], 1 );
431restoreCursor( &cursorState );
432
433}
434
435 *paramPtr = gMenuItems[MenuSelection].param;
436 moved = 1;
437 }
438
439 safe_set_env(envgMenuSelection,MenuSelection);
440 safe_set_env(envgMenuTop,MenuTop );
441 safe_set_env(envgMenuRow,MenuRow);
442 safe_set_env(envgMenuHeight,MenuHeight);
443 safe_set_env(envgMenuBottom,MenuBottom);
444 safe_set_env(envgMenuStart,MenuStart);
445 safe_set_env(envgMenuEnd,MenuEnd);
446
447return moved;
448}
449
450//==========================================================================
451
452static void skipblanks( const char ** cpp )
453{
454 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
455}
456
457//==========================================================================
458
459static const char * extractKernelName( char ** cpp )
460{
461 char * kn = *cpp;
462 char * cp = *cpp;
463 char c;
464
465 // Convert char to lower case.
466
467 c = *cp | 0x20;
468
469 // Must start with a letter or a '/'.
470
471 if ( (c < 'a' || c > 'z') && ( c != '/' ) ) return 0;
472
473 // Keep consuming characters until we hit a separator.
474
475 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
476{
477 cp++;
478}
479 // Only SPACE or TAB separator is accepted.
480 // Reject everything else.
481
482 if (*cp == '=') return 0;
483
484 // Overwrite the separator, and move the pointer past
485 // the kernel name.
486
487 if (*cp != '\0') *cp++ = '\0';
488 *cpp = cp;
489
490 return kn;
491}
492
493//==========================================================================
494
495void printMemoryInfo(void)
496{
497 int line;
498 unsigned long i;
499 MemoryRange *mp = (MemoryRange*)(uint32_t)get_env(envMemoryMap);
500
501 // Activate and clear page 1
502 setActiveDisplayPage(1);
503 clearScreenRows(0, 24);
504 setCursorPosition( 0, 0, 1 );
505
506 printf("BIOS reported memory ranges:\n");
507 line = 1;
508
509int memoryMapCount = (int)get_env(envMemoryMapCnt);
510 for (i=0; i<memoryMapCount; i++) {
511 printf("Base 0x%08x%08x, ",
512 (unsigned long)(mp->base >> 32),
513 (unsigned long)(mp->base));
514 printf("length 0x%08x%08x, type %d\n",
515 (unsigned long)(mp->length >> 32),
516 (unsigned long)(mp->length),
517 mp->type);
518 if (line++ > 20) {
519 pause();
520 line = 0;
521 }
522 mp++;
523 }
524 if (line > 0) {
525 pause();
526 }
527
528 setActiveDisplayPage(0);
529}
530
531char *getMemoryInfoString(void)
532{
533 unsigned long i;
534 MemoryRange *mp = (MemoryRange*)(uint32_t)get_env(envMemoryMap);
535char *buff = malloc(sizeof(char)*1024);
536if(!buff) return 0;
537
538char info[] = "BIOS reported memory ranges:\n";
539sprintf(buff, "%s", info);
540int memoryMapCount = (int)get_env(envMemoryMapCnt);
541
542 for (i=0; i<memoryMapCount; i++) {
543 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
544(unsigned long)(mp->base >> 32),
545(unsigned long)(mp->base));
546 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
547(unsigned long)(mp->length >> 32),
548(unsigned long)(mp->length),
549mp->type);
550 mp++;
551 }
552return buff;
553}
554//==========================================================================
555
556void lspci(void)
557{
558if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
559setActiveDisplayPage(1);
560clearScreenRows(0, 24);
561setCursorPosition(0, 0, 1);
562}
563
564dump_pci_dt(root_pci_dev->children);
565
566pause();
567
568if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
569setActiveDisplayPage(0);
570}
571}
572
573//==========================================================================
574
575int getBootOptions(bool firstRun)
576{
577int i;
578int key;
579int nextRow;
580int timeout;
581#if UNUSED
582int bvCount;
583#endif
584BVRef bvr;
585BVRef menuBVR;
586bool showPrompt, newShowPrompt, isCDROM;
587 int optionKey;
588
589// Initialize default menu selection entry.
590menuBVR = selectBootVolume(getBvChain());
591safe_set_env(envgBootVolume, (uint32_t)menuBVR);
592
593if (biosDevIsCDROM((int)get_env(envgBIOSDev))) {
594isCDROM = true;
595} else {
596isCDROM = false;
597}
598
599// Clear command line boot arguments
600clearBootArgs();
601
602// Allow user to override default timeout.
603#if UNUSED
604if (multiboot_timeout_set) {
605timeout = multiboot_timeout;
606} else
607#endif
608if (!getIntForKey(kTimeoutKey, &timeout, DEFAULT_BOOT_CONFIG)) {
609/* If there is no timeout key in the file use the default timeout
610 which is different for CDs vs. hard disks. However, if not booting
611 a CD and no config file could be loaded set the timeout
612 to zero which causes the menu to display immediately.
613 This way, if no partitions can be found, that is the disk is unpartitioned
614 or simply cannot be read) then an empty menu is displayed.
615 If some partitions are found, for example a Windows partition, then
616 these will be displayed in the menu as foreign partitions.
617 */
618if (isCDROM) {
619timeout = kCDBootTimeout;
620} else {
621timeout = get_env(envSysConfigValid) ? kBootTimeout : 0;
622}
623}
624
625 long gBootMode = (long)get_env(envgBootMode);
626
627if (timeout < 0) {
628gBootMode |= kBootModeQuiet;
629 safe_set_env(envgBootMode,gBootMode);
630
631}
632
633// If the user is holding down a modifier key, enter safe mode.
634if ((readKeyboardShiftFlags() & 0x0F) != 0) {
635
636gBootMode |= kBootModeSafe;
637 safe_set_env(envgBootMode,gBootMode);
638
639}
640
641// Checking user pressed keys
642bool f8press = false, spress = false, vpress = false;
643while (readKeyboardStatus()) {
644key = bgetc ();
645if (key == 0x4200) f8press = true;
646if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
647if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
648}
649// If user typed F8, abort quiet mode, and display the menu.
650if (f8press) {
651gBootMode &= ~kBootModeQuiet;
652 safe_set_env(envgBootMode,gBootMode);
653
654timeout = 0;
655}
656// If user typed 'v' or 'V', boot in verbose mode.
657if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
658addBootArg(kVerboseModeFlag);
659}
660// If user typed 's' or 'S', boot in single user mode.
661if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
662addBootArg(kSingleUserModeFlag);
663}
664
665setCursorPosition(0, 0, 0);
666clearScreenRows(0, kScreenLastRow);
667if (!(gBootMode & kBootModeQuiet)) {
668// Display banner and show hardware info.
669 char * bootBanner = (char*)(uint32_t)get_env(envBootBanner);
670
671printf(bootBanner, (int)(get_env(envConvMem) + get_env(envExtMem)) / 1024);
672}
673changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
674msglog("Scanning device %x...", (uint32_t)get_env(envgBIOSDev));
675
676// When booting from CD, default to hard drive boot when possible.
677if (isCDROM && firstRun) {
678const char *val;
679char *prompt = NULL;
680char *name = NULL;
681int cnt;
682
683if (getValueForKey(kCDROMPromptKey, &val, &cnt, DEFAULT_BOOT_CONFIG)) {
684prompt = malloc(cnt + 1);
685 if (!prompt) {
686 stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
687 return -1;
688 }
689strncat(prompt, val, cnt);
690} else {
691name = malloc(80);
692 if (!name) {
693 stop("Couldn't allocate memory for the device name\n"); //TODO: Find a better stategie
694 return -1;
695 }
696getBootVolumeDescription(((BVRef)(uint32_t)get_env(envgBootVolume)), name, 79, false);
697prompt = malloc(256);
698 if (!prompt) {
699 free(name);
700 stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
701 return -1;
702 }
703sprintf(prompt, "Press ENTER to start up from %s, or press any key to enter startup options.", name);
704free(name);
705}
706
707if (getIntForKey( kCDROMOptionKey, &optionKey, DEFAULT_BOOT_CONFIG )) {
708// The key specified is a special key.
709} else {
710// Default to F8.
711optionKey = 0x4200;
712}
713
714// If the timeout is zero then it must have been set above due to the
715// early catch of F8 which means the user wants to set boot options
716// which we ought to interpret as meaning he wants to boot the CD.
717if (timeout != 0) {
718key = countdown(prompt, kMenuTopRow, timeout, &optionKey);
719} else {
720key = optionKey;
721}
722
723if (prompt != NULL) {
724free(prompt);
725}
726
727clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
728
729 do {
730 // Hit the option key ?
731 if (key == optionKey) {
732
733 if (key != 0x1C0D) {
734 gBootMode &= ~kBootModeQuiet;
735 safe_set_env(envgBootMode,gBootMode);
736 timeout = 0;
737 break;
738 }
739
740 }
741
742 key = key & 0xFF;
743
744 // Try booting hard disk if user pressed 'h'
745 if (biosDevIsCDROM((int)get_env(envgBIOSDev)) && key == 'h') {
746 BVRef bvr;
747
748 // Look at partitions hosting OS X other than the CD-ROM
749 for (bvr = getBvChain(); bvr; bvr=bvr->next) {
750 if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != (int)get_env(envgBIOSDev)) {
751safe_set_env(envgBootVolume, (uint32_t)bvr);
752 }
753 }
754 }
755 goto done;
756
757 } while (0);
758
759}
760
761if (get_env(envgBootMode) & kBootModeQuiet) {
762// No input allowed from user.
763goto done;
764}
765
766if (firstRun && timeout > 0 ) {
767
768 key = countdown("Press ENTER to start up, or press any key to enter startup options.", kMenuTopRow, timeout, &optionKey);
769
770 if (key == 0x1C0D) {
771 goto done;
772
773 }
774 else if (key == 0)
775 {
776 // If the user is holding down a modifier key,
777 // enter safe mode.
778
779 if ((readKeyboardShiftFlags() & 0x0F) != 0) {
780 gBootMode |= kBootModeSafe;
781 safe_set_env(envgBootMode,gBootMode);
782 }
783 goto done;
784 }
785}
786int devcnt = (int)get_env(envgDeviceCount);
787
788if (devcnt) {
789// Allocate memory for an array of menu items.
790menuItems = malloc(sizeof(MenuItem) * devcnt);
791if (menuItems == NULL) {
792goto done;
793}
794
795// Associate a menu item for each BVRef.
796for (bvr=getBvChain(), i=devcnt-1, selectIndex=0; bvr; bvr=bvr->next) {
797if (bvr->visible) {
798getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
799menuItems[i].param = (void *) bvr;
800if (bvr == menuBVR) {
801selectIndex = i;
802}
803i--;
804}
805}
806}
807
808// Clear screen and hide the blinking cursor.
809clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
810changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
811
812nextRow = kMenuTopRow;
813/*showPrompt = true;*/
814
815if (devcnt) {
816printf("Use \30\31 keys to select the startup volume.");
817showMenu( menuItems, devcnt, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
818nextRow += min( devcnt, kMenuMaxItems ) + 3;
819}
820
821// Show the boot prompt.
822showPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
823showBootPrompt( nextRow, showPrompt );
824
825do {
826
827key = getc();
828updateMenu( key, (void **) &menuBVR );
829newShowPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
830
831if (newShowPrompt != showPrompt)
832{
833showPrompt = newShowPrompt;
834showBootPrompt( nextRow, showPrompt );
835}
836
837if (showPrompt)
838{
839updateBootArgs(key);
840}
841
842switch (key) {
843case kReturnKey:
844if (*gBootArgs == '?') {
845char * argPtr = gBootArgs;
846
847// Skip the leading "?" character.
848argPtr++;
849getNextArg(&argPtr, booterCommand);
850getNextArg(&argPtr, booterParam);
851
852/*
853 * TODO: this needs to be refactored.
854 */
855#if UNUSED
856if (strcmp( booterCommand, "video" ) == 0)
857{
858printVBEModeInfo();
859}
860else
861#endif
862if ( strcmp( booterCommand, "memory" ) == 0)
863{
864printMemoryInfo();
865}
866else if (strcmp(booterCommand, "lspci") == 0)
867{
868lspci();
869}
870else if (strcmp(booterCommand, "more") == 0)
871{
872showTextFile(booterParam);
873}
874else if (strcmp(booterCommand, "rd") == 0)
875{
876if (execute_hook("processRAMDiskCommand", (void*)argPtr, &booterParam, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
877showMessage("ramdisk module not found, please install RamdiskLoader.dylib in /Extra/modules/");
878}
879else if (strcmp(booterCommand, "norescan") == 0)
880{
881if (get_env(envgEnableCDROMRescan))
882{
883 safe_set_env(envgEnableCDROMRescan,false);
884break;
885}
886}
887else
888{
889showHelp();
890}
891key = 0;
892showBootPrompt(nextRow, showPrompt);
893break;
894}
895safe_set_env(envgBootVolume, (uint32_t)menuBVR);
896setRootVolume(menuBVR);
897 safe_set_env(envgBIOSDev,menuBVR->biosdev);
898break;
899
900case kEscapeKey:
901clearBootArgs();
902break;
903
904case kF5Key:
905// New behavior:
906// Clear gBootVolume to restart the loop
907// if the user enabled rescanning the optical drive.
908// Otherwise boot the default boot volume.
909if (get_env(envgEnableCDROMRescan)) {
910//gBootVolume = NULL;
911safe_set_env(envgBootVolume, (uint32_t)NULL);
912clearBootArgs();
913}
914break;
915
916case kF10Key:
917 safe_set_env(envgScanSingleDrive, false);
918
919 scanDisks();
920
921//gBootVolume = NULL;
922safe_set_env(envgBootVolume, (uint32_t)NULL);
923
924clearBootArgs();
925break;
926
927default:
928key = 0;
929break;
930}
931} while (0 == key);
932
933done:
934if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
935clearScreenRows(kMenuTopRow, kScreenLastRow);
936changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
937}
938 safe_set_env(envShouldboot, false);
939
940if (menuItems) {
941free(menuItems);
942menuItems = NULL;
943}
944return 0;
945}
946
947//==========================================================================
948
949bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
950{
951 int argLen = argName ? strlen(argName) : 0;
952 int len = argLen + cnt + 1; // +1 to account for space
953
954 if (len > *cntRemainingP) {
955 error("Warning: boot arguments too long, truncating\n");
956 return false;
957 }
958
959 if (argName) {
960 strncpy( *argP, argName, argLen );
961 *argP += argLen;
962 *argP[0] = '=';
963 (*argP)++;
964 len++; // +1 to account for '='
965 }
966 strncpy( *argP, val, cnt );
967 *argP += cnt;
968 *argP[0] = ' ';
969 (*argP)++;
970
971 *cntRemainingP -= len;
972 return true;
973}
974
975int
976processBootOptions(void)
977{
978char *cp_cache = (char*)(uint32_t)get_env(envgBootArgs);
979if (cp_cache)
980{
981bzero(gBootArgs,sizeof(gBootArgs));
982strlcpy(gBootArgs, cp_cache,sizeof(gBootArgs));
983}
984
985 const char * cp = gBootArgs;
986 const char * val = 0;
987 const char * kernel;
988 int cnt;
989 int userCnt;
990 char * argP;
991 char * configKernelFlags;
992int ArgCntRemaining;
993
994 skipblanks( &cp );
995
996 // Update the unit and partition number.
997
998 if ( ((BVRef)(uint32_t)get_env(envgBootVolume)) )
999 {
1000#ifndef NO_MULTIBOOT_SUPPORT
1001 if (!( ((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagNativeBoot ))
1002 {
1003 readBootSector( ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev, ((BVRef)(uint32_t)get_env(envgBootVolume))->part_boff,
1004 (void *) 0x7c00 );
1005
1006 //
1007 // Setup edx, and signal intention to chain load the
1008 // foreign booter.
1009 //
1010
1011extern unsigned char chainbootdev;
1012extern unsigned char chainbootflag;
1013
1014 chainbootdev = ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev;
1015 chainbootflag = 1;
1016
1017 return 1;
1018 }
1019#endif
1020 setRootVolume(((BVRef)(uint32_t)get_env(envgBootVolume)));
1021
1022 }
1023 // If no boot volume fail immediately because we're just going to fail
1024 // trying to load the config file anyway.
1025 else
1026return -1;
1027
1028 // Load config table specified by the user, or use the default.
1029
1030 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1031val = 0;
1032cnt = 0;
1033 }
1034
1035 // Load com.apple.Boot.plist from the selected volume
1036 // and use its contents to override default bootConfig.
1037 // This is not a mandatory opeartion anymore.
1038
1039 loadOverrideConfig();
1040
1041 // Load System com.apple.boot.plist config file
1042loadSystemConfig();
1043
1044#if virtualM || PCI_FIX // we can simply make an option for this fix
1045 addBootArg("npci=0x2000");
1046#endif
1047#if verbose
1048 addBootArg("-v");
1049#endif
1050
1051 // Use the kernel name specified by the user, or fetch the name
1052 // in the config table, or use the default if not specified.
1053 // Specifying a kernel name on the command line, or specifying
1054 // a non-default kernel name in the config file counts as
1055 // overriding the kernel, which causes the kernelcache not
1056 // to be used.
1057
1058 safe_set_env(envgOverrideKernel,false);
1059 if (( kernel = extractKernelName((char **)&cp) )) {
1060strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
1061 safe_set_env(envgOverrideKernel,true);
1062
1063 } else {
1064 if ( getValueForKey( kKernelNameKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1065 strlcpy( bootInfo->bootFile, val, sizeof(bootInfo->bootFile) );
1066 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1067 safe_set_env(envgOverrideKernel,true);
1068 }
1069 } else if (((BVRef)(uint32_t)get_env(envgBootVolume))->kernelfound == true) {
1070strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
1071 } else {
1072
1073 printf("No kernel found on this volume : hd(%d,%d)\n", BIOS_DEV_UNIT(((BVRef)(uint32_t)get_env(envgBootVolume))), ((BVRef)(uint32_t)get_env(envgBootVolume))->part_no);
1074 sleep(1);
1075 return -1;
1076 }
1077 }
1078
1079 ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1080 argP = bootArgs->CommandLine;
1081
1082 // Get config table kernel flags, if not ignored.
1083 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1084!getValueForKey( kKernelFlagsKey, &val, &cnt, DEFAULT_BOOT_CONFIG )) {
1085 val = "";
1086 cnt = 0;
1087 }
1088
1089 configKernelFlags = newString(val);
1090
1091{
1092bool isSafeMode = false;
1093if (configKernelFlags) {
1094isSafeMode = getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt);
1095}
1096
1097if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1098(isSafeMode == false)) {
1099if (get_env(envgBootMode) & kBootModeSafe) {
1100copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining);
1101}
1102}
1103}
1104
1105if (configKernelFlags) {
1106// Store the merged kernel flags and boot args.
1107
1108cnt = strlen(configKernelFlags);
1109if (cnt) {
1110if (cnt > ArgCntRemaining) {
1111printf("Warning: boot arguments too long, truncating\n");
1112cnt = ArgCntRemaining;
1113}
1114strncpy(argP, configKernelFlags, cnt);
1115argP[cnt++] = ' ';
1116ArgCntRemaining -= cnt;
1117}
1118}
1119
1120 userCnt = strlen(cp);
1121 if (userCnt > ArgCntRemaining) {
1122printf("Warning: boot arguments too long, truncating\n");
1123userCnt = ArgCntRemaining;
1124 }
1125 strncpy(&argP[cnt], cp, userCnt);
1126 argP[cnt+userCnt] = '\0';
1127
1128if(!get_env(envShouldboot))
1129{
1130bool gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ||
1131getValueForKey( kSingleUserModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG );
1132safe_set_env(envgVerboseMode, gVerboseMode);
1133
1134long gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) ?
1135kBootModeSafe : kBootModeNormal;
1136 safe_set_env(envgBootMode,gBootMode);
1137
1138
1139 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1140 gBootMode = kBootModeSafe;
1141 safe_set_env(envgBootMode,gBootMode);
1142
1143}
1144}
1145
1146if ( getValueForKey( kMKextCacheKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) )
1147{
1148 char * MKextName = (char*)(uint32_t)get_env(envMKextName);
1149 strlcpy(MKextName,val,Cache_len_name);
1150}
1151
1152if (configKernelFlags)
1153{
1154free(configKernelFlags);
1155}
1156safe_set_env(envArgCntRemaining,ArgCntRemaining);
1157 return 0;
1158}
1159
1160//==========================================================================
1161// Load the help file and display the file contents on the screen.
1162
1163void showTextBuffer(char *buf, int size)
1164{
1165char*bp;
1166intline;
1167intline_offset;
1168intc;
1169
1170
1171if(!(bp = buf)) return;
1172
1173while (size-- > 0) {
1174if (*bp == '\n') {
1175*bp = '\0';
1176}
1177bp++;
1178}
1179*bp = '\1';
1180line_offset = 0;
1181
1182setActiveDisplayPage(1);
1183
1184while (1) {
1185clearScreenRows(0, 24);
1186setCursorPosition(0, 0, 1);
1187bp = buf;
1188for (line = 0; *bp != '\1' && line < line_offset; line++) {
1189while (*bp != '\0') {
1190bp++;
1191}
1192bp++;
1193}
1194for (line = 0; *bp != '\1' && line < 23; line++) {
1195setCursorPosition(0, line, 1);
1196printf("%s\n", bp);
1197while (*bp != '\0') {
1198bp++;
1199}
1200bp++;
1201}
1202
1203setCursorPosition(0, 23, 1);
1204if (*bp == '\1') {
1205printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1206} else {
1207printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1208}
1209
1210c = getc();
1211if (c == 'q' || c == 'Q') {
1212break;
1213}
1214if ((c == 'p' || c == 'P') && line_offset > 0) {
1215line_offset -= 23;
1216}
1217if (c == ' ') {
1218if (*bp == '\1') {
1219break;
1220} else {
1221line_offset += 23;
1222}
1223}
1224}
1225setActiveDisplayPage(0);
1226}
1227
1228void showHelp(void)
1229{
1230#if EMBED_HELP==0
1231int fd = -1;
1232char dirspec[512];
1233char filename[512];
1234sprintf(filename, "BootHelp.txt");
1235
1236// Check Extra on booting partition
1237sprintf(dirspec,"/Extra/%s",filename);
1238fd=open (dirspec);
1239if (fd<0)
1240{// Fall back to booter partition
1241sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
1242fd=open (dirspec);
1243if (fd<0)
1244{
1245printf("BootHelp not found: %s\n", filename);
1246return;
1247}
1248}
1249int BootHelp_txt_len = file_size (fd);
1250void *BootHelp_txt=malloc(BootHelp_txt_len);
1251if (BootHelp_txt)
1252{
1253if (read (fd, BootHelp_txt, BootHelp_txt_len)!=BootHelp_txt_len)
1254{
1255printf("Couldn't read BootHelp %s\n",dirspec);
1256free (BootHelp_txt);
1257close (fd);
1258return;
1259}
1260
1261close (fd);
1262}
1263#endif
1264showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1265}
1266
1267void showMessage(char * message)
1268{
1269showTextBuffer(message, strlen(message));
1270}
1271
1272void showTextFile(const char * filename)
1273{
1274#define MAX_TEXT_FILE_SIZE 65536
1275char*buf;
1276intfd;
1277intsize;
1278
1279if ((fd = open_bvdev("bt(0,0)", filename)) < 0) {
1280printf("\nFile not found: %s\n", filename);
1281sleep(2);
1282return;
1283}
1284
1285size = file_size(fd);
1286if (size > MAX_TEXT_FILE_SIZE) {
1287size = MAX_TEXT_FILE_SIZE;
1288}
1289buf = malloc(size);
1290 if (!buf) {
1291 printf("Couldn't allocate memory for the buf in showTextFile\n");
1292 return ;
1293 }
1294read(fd, buf, size);
1295close(fd);
1296showTextBuffer(buf, size);
1297free(buf);
1298}
1299
1300bool promptForRescanOption(void)
1301{
1302printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1303if (getc() == kReturnKey) {
1304return true;
1305} else {
1306return false;
1307}
1308}
1309

Archive Download this file

Revision: 2006