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

Archive Download this file

Revision: 1887