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#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 = (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#endif
573
574//==========================================================================
575
576int getBootOptions(bool firstRun)
577{
578int i;
579int key;
580int nextRow;
581int timeout;
582#if UNUSED
583int bvCount;
584#endif
585BVRef bvr;
586BVRef menuBVR;
587bool showPrompt, newShowPrompt, isCDROM;
588 int optionKey;
589
590// Initialize default menu selection entry.
591gBootVolume = menuBVR = selectBootVolume(getBvChain());
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(gBootVolume, 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)) {
751 gBootVolume = 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#ifndef OPTION_ROM
856#if UNUSED
857if (strcmp( booterCommand, "video" ) == 0)
858{
859printVBEModeInfo();
860}
861else
862#endif
863if ( strcmp( booterCommand, "memory" ) == 0)
864{
865printMemoryInfo();
866}
867else if (strcmp(booterCommand, "lspci") == 0)
868{
869lspci();
870}
871else if (strcmp(booterCommand, "more") == 0)
872{
873showTextFile(booterParam);
874}
875else if (strcmp(booterCommand, "rd") == 0)
876{
877if (execute_hook("processRAMDiskCommand", (void*)argPtr, &booterParam, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
878showMessage("ramdisk module not found, please install RamdiskLoader.dylib in /Extra/modules/");
879}
880else if (strcmp(booterCommand, "norescan") == 0)
881{
882if (get_env(envgEnableCDROMRescan))
883{
884 safe_set_env(envgEnableCDROMRescan,false);
885break;
886}
887}
888else
889{
890showHelp();
891}
892#endif
893key = 0;
894showBootPrompt(nextRow, showPrompt);
895break;
896}
897gBootVolume = menuBVR;
898setRootVolume(menuBVR);
899 safe_set_env(envgBIOSDev,menuBVR->biosdev);
900break;
901
902case kEscapeKey:
903clearBootArgs();
904break;
905#ifndef OPTION_ROM
906case kF5Key:
907// New behavior:
908// Clear gBootVolume to restart the loop
909// if the user enabled rescanning the optical drive.
910// Otherwise boot the default boot volume.
911if (get_env(envgEnableCDROMRescan)) {
912gBootVolume = NULL;
913clearBootArgs();
914}
915break;
916
917case kF10Key:
918 safe_set_env(envgScanSingleDrive, false);
919#if UNUSED
920 scanDisks((int)get_env(envgBIOSDev), &bvCount);
921#else
922 scanDisks();
923#endif
924gBootVolume = NULL;
925clearBootArgs();
926break;
927#endif
928default:
929key = 0;
930break;
931}
932} while (0 == key);
933
934done:
935if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
936clearScreenRows(kMenuTopRow, kScreenLastRow);
937changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
938}
939 safe_set_env(envShouldboot, false);
940
941if (menuItems) {
942free(menuItems);
943menuItems = NULL;
944}
945return 0;
946}
947
948//==========================================================================
949
950extern unsigned char chainbootdev;
951extern unsigned char chainbootflag;
952
953bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
954{
955 int argLen = argName ? strlen(argName) : 0;
956 int len = argLen + cnt + 1; // +1 to account for space
957
958 if (len > *cntRemainingP) {
959 error("Warning: boot arguments too long, truncating\n");
960 return false;
961 }
962
963 if (argName) {
964 strncpy( *argP, argName, argLen );
965 *argP += argLen;
966 *argP[0] = '=';
967 (*argP)++;
968 len++; // +1 to account for '='
969 }
970 strncpy( *argP, val, cnt );
971 *argP += cnt;
972 *argP[0] = ' ';
973 (*argP)++;
974
975 *cntRemainingP -= len;
976 return true;
977}
978
979int
980processBootOptions(void)
981{
982char *cp_cache = (char*)(uint32_t)get_env(envgBootArgs);
983if (cp_cache)
984{
985bzero(gBootArgs,sizeof(gBootArgs));
986strlcpy(gBootArgs, cp_cache,sizeof(gBootArgs));
987}
988
989 const char * cp = gBootArgs;
990 const char * val = 0;
991 const char * kernel;
992 int cnt;
993 int userCnt;
994 char * argP;
995 char * configKernelFlags;
996int ArgCntRemaining;
997
998 skipblanks( &cp );
999
1000 // Update the unit and partition number.
1001
1002 if ( gBootVolume )
1003 {
1004 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1005 {
1006 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1007 (void *) 0x7c00 );
1008
1009 //
1010 // Setup edx, and signal intention to chain load the
1011 // foreign booter.
1012 //
1013
1014 chainbootdev = gBootVolume->biosdev;
1015 chainbootflag = 1;
1016
1017 return 1;
1018 }
1019
1020 setRootVolume(gBootVolume);
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
1047#endif
1048#if verbose
1049 addBootArg("-v");
1050#endif
1051
1052 // Use the kernel name specified by the user, or fetch the name
1053 // in the config table, or use the default if not specified.
1054 // Specifying a kernel name on the command line, or specifying
1055 // a non-default kernel name in the config file counts as
1056 // overriding the kernel, which causes the kernelcache not
1057 // to be used.
1058
1059 safe_set_env(envgOverrideKernel,false);
1060 if (( kernel = extractKernelName((char **)&cp) )) {
1061strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
1062 safe_set_env(envgOverrideKernel,true);
1063
1064 } else {
1065 if ( getValueForKey( kKernelNameKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1066 strlcpy( bootInfo->bootFile, val, sizeof(bootInfo->bootFile) );
1067 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1068 safe_set_env(envgOverrideKernel,true);
1069 }
1070 } else if (gBootVolume->kernelfound == true) {
1071strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
1072 } else {
1073
1074 printf("No kernel found on this volume : hd(%d,%d)\n", BIOS_DEV_UNIT(gBootVolume), gBootVolume->part_no);
1075 sleep(1);
1076 return -1;
1077 }
1078 }
1079
1080 ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1081 argP = bootArgs->CommandLine;
1082
1083 // Get config table kernel flags, if not ignored.
1084 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1085!getValueForKey( kKernelFlagsKey, &val, &cnt, DEFAULT_BOOT_CONFIG )) {
1086 val = "";
1087 cnt = 0;
1088 }
1089
1090 configKernelFlags = newString(val);
1091
1092{
1093bool isSafeMode = false;
1094if (configKernelFlags) {
1095isSafeMode = getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt);
1096}
1097
1098if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1099(isSafeMode == false)) {
1100if (get_env(envgBootMode) & kBootModeSafe) {
1101copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining);
1102}
1103}
1104}
1105
1106if (configKernelFlags) {
1107// Store the merged kernel flags and boot args.
1108
1109cnt = strlen(configKernelFlags);
1110if (cnt) {
1111if (cnt > ArgCntRemaining) {
1112printf("Warning: boot arguments too long, truncating\n");
1113cnt = ArgCntRemaining;
1114}
1115strncpy(argP, configKernelFlags, cnt);
1116argP[cnt++] = ' ';
1117ArgCntRemaining -= cnt;
1118}
1119}
1120
1121 userCnt = strlen(cp);
1122 if (userCnt > ArgCntRemaining) {
1123printf("Warning: boot arguments too long, truncating\n");
1124userCnt = ArgCntRemaining;
1125 }
1126 strncpy(&argP[cnt], cp, userCnt);
1127 argP[cnt+userCnt] = '\0';
1128
1129if(!get_env(envShouldboot))
1130{
1131gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ||
1132getValueForKey( kSingleUserModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG );
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#ifndef OPTION_ROM
1161
1162//==========================================================================
1163// Load the help file and display the file contents on the screen.
1164
1165void showTextBuffer(char *buf, int size)
1166{
1167char*bp;
1168intline;
1169intline_offset;
1170intc;
1171
1172
1173if(!(bp = buf)) return;
1174
1175while (size-- > 0) {
1176if (*bp == '\n') {
1177*bp = '\0';
1178}
1179bp++;
1180}
1181*bp = '\1';
1182line_offset = 0;
1183
1184setActiveDisplayPage(1);
1185
1186while (1) {
1187clearScreenRows(0, 24);
1188setCursorPosition(0, 0, 1);
1189bp = buf;
1190for (line = 0; *bp != '\1' && line < line_offset; line++) {
1191while (*bp != '\0') {
1192bp++;
1193}
1194bp++;
1195}
1196for (line = 0; *bp != '\1' && line < 23; line++) {
1197setCursorPosition(0, line, 1);
1198printf("%s\n", bp);
1199while (*bp != '\0') {
1200bp++;
1201}
1202bp++;
1203}
1204
1205setCursorPosition(0, 23, 1);
1206if (*bp == '\1') {
1207printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1208} else {
1209printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1210}
1211
1212c = getc();
1213if (c == 'q' || c == 'Q') {
1214break;
1215}
1216if ((c == 'p' || c == 'P') && line_offset > 0) {
1217line_offset -= 23;
1218}
1219if (c == ' ') {
1220if (*bp == '\1') {
1221break;
1222} else {
1223line_offset += 23;
1224}
1225}
1226}
1227setActiveDisplayPage(0);
1228}
1229
1230void showHelp(void)
1231{
1232#if EMBED_HELP==0
1233int fd = -1;
1234char dirspec[512];
1235char filename[512];
1236sprintf(filename, "BootHelp.txt");
1237
1238// Check Extra on booting partition
1239sprintf(dirspec,"/Extra/%s",filename);
1240fd=open (dirspec);
1241if (fd<0)
1242{// Fall back to booter partition
1243sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
1244fd=open (dirspec);
1245if (fd<0)
1246{
1247printf("BootHelp not found: %s\n", filename);
1248return;
1249}
1250}
1251int BootHelp_txt_len = file_size (fd);
1252void *BootHelp_txt=malloc(BootHelp_txt_len);
1253if (BootHelp_txt)
1254{
1255if (read (fd, BootHelp_txt, BootHelp_txt_len)!=BootHelp_txt_len)
1256{
1257printf("Couldn't read BootHelp %s\n",dirspec);
1258free (BootHelp_txt);
1259close (fd);
1260return;
1261}
1262
1263close (fd);
1264}
1265#endif
1266showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1267}
1268
1269void showMessage(char * message)
1270{
1271showTextBuffer(message, strlen(message));
1272}
1273
1274void showTextFile(const char * filename)
1275{
1276#define MAX_TEXT_FILE_SIZE 65536
1277char*buf;
1278intfd;
1279intsize;
1280
1281if ((fd = open_bvdev("bt(0,0)", filename)) < 0) {
1282printf("\nFile not found: %s\n", filename);
1283sleep(2);
1284return;
1285}
1286
1287size = file_size(fd);
1288if (size > MAX_TEXT_FILE_SIZE) {
1289size = MAX_TEXT_FILE_SIZE;
1290}
1291buf = malloc(size);
1292 if (!buf) {
1293 printf("Couldn't allocate memory for the buf in showTextFile\n");
1294 return ;
1295 }
1296read(fd, buf, size);
1297close(fd);
1298showTextBuffer(buf, size);
1299free(buf);
1300}
1301#endif
1302
1303#ifndef OPTION_ROM
1304bool promptForRescanOption(void)
1305{
1306printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1307if (getc() == kReturnKey) {
1308return true;
1309} else {
1310return false;
1311}
1312}
1313#endif
1314

Archive Download this file

Revision: 1919