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++ = ' ';
184strlcat(gBootArgs, argStr, BOOT_STRING_LEN);
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 = calloc(1024, sizeof(char));
536if(!buff) return 0;
537
538char info[] = "BIOS reported memory ranges:\n";
539snprintf(buff, sizeof(char)*1024 ,"%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(((pci_dt_t *)(uint32_t)get_env(envPCIRootDev))->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 = calloc(cnt + 1, sizeof(char));
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 {
691 prompt = calloc(256, sizeof(char));
692 if (!prompt) {
693 stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
694 return -1;
695 }
696 BVRef bvr;
697 if (( bvr = ((BVRef)(uint32_t)get_env(envgBootVolume)))) {
698 name = calloc(80, sizeof(char));
699 if (!name) {
700 stop("Couldn't allocate memory for the device name\n"); //TODO: Find a better stategie
701 return -1;
702 }
703 getBootVolumeDescription(bvr, name, 79, false);
704
705 snprintf(prompt, 256,"Press ENTER to start up from %s, or press any key to enter startup options.", name);
706 free(name);
707 } else snprintf(prompt, 256,"Press ENTER to start up, or press any key to enter startup options.");
708
709}
710
711if (getIntForKey( kCDROMOptionKey, &optionKey, DEFAULT_BOOT_CONFIG )) {
712// The key specified is a special key.
713} else {
714// Default to F8.
715optionKey = 0x4200;
716}
717
718// If the timeout is zero then it must have been set above due to the
719// early catch of F8 which means the user wants to set boot options
720// which we ought to interpret as meaning he wants to boot the CD.
721if (timeout != 0) {
722key = countdown(prompt, kMenuTopRow, timeout, &optionKey);
723} else {
724key = optionKey;
725}
726
727if (prompt != NULL) {
728free(prompt);
729}
730
731clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
732
733 do {
734 // Hit the option key ?
735 if (key == optionKey) {
736
737 if (key != 0x1C0D) {
738 gBootMode &= ~kBootModeQuiet;
739 safe_set_env(envgBootMode,gBootMode);
740 timeout = 0;
741 break;
742 }
743
744 }
745
746 key = key & 0xFF;
747
748 // Try booting hard disk if user pressed 'h'
749 if (biosDevIsCDROM((int)get_env(envgBIOSDev)) && key == 'h') {
750 BVRef bvr;
751
752 // Look at partitions hosting OS X other than the CD-ROM
753 for (bvr = getBvChain(); bvr; bvr=bvr->next) {
754 if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != (int)get_env(envgBIOSDev)) {
755safe_set_env(envgBootVolume, (uint32_t)bvr);
756 }
757 }
758 }
759 goto done;
760
761 } while (0);
762
763}
764
765if (get_env(envgBootMode) & kBootModeQuiet) {
766// No input allowed from user.
767goto done;
768}
769
770if (firstRun && timeout > 0 ) {
771
772 key = countdown("Press ENTER to start up, or press any key to enter startup options.", kMenuTopRow, timeout, &optionKey);
773
774 if (key == 0x1C0D) {
775 goto done;
776
777 }
778 else if (key == 0)
779 {
780 // If the user is holding down a modifier key,
781 // enter safe mode.
782
783 if ((readKeyboardShiftFlags() & 0x0F) != 0) {
784 gBootMode |= kBootModeSafe;
785 safe_set_env(envgBootMode,gBootMode);
786 }
787 goto done;
788 }
789}
790int devcnt = (int)get_env(envgDeviceCount);
791
792if (devcnt) {
793// Allocate memory for an array of menu items.
794menuItems = calloc(devcnt,sizeof(MenuItem));
795if (menuItems == NULL) {
796goto done;
797}
798
799// Associate a menu item for each BVRef.
800for (bvr=getBvChain(), i=devcnt-1, selectIndex=0; bvr; bvr=bvr->next) {
801if (bvr->visible) {
802getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
803menuItems[i].param = (void *) bvr;
804if (bvr == menuBVR) {
805selectIndex = i;
806}
807i--;
808}
809}
810}
811
812// Clear screen and hide the blinking cursor.
813clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
814changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
815
816nextRow = kMenuTopRow;
817/*showPrompt = true;*/
818
819if (devcnt) {
820printf("Use \30\31 keys to select the startup volume.");
821showMenu( menuItems, devcnt, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
822nextRow += min( devcnt, kMenuMaxItems ) + 3;
823}
824
825// Show the boot prompt.
826showPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
827showBootPrompt( nextRow, showPrompt );
828
829do {
830
831key = getc();
832updateMenu( key, (void **) &menuBVR );
833newShowPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
834
835if (newShowPrompt != showPrompt)
836{
837showPrompt = newShowPrompt;
838showBootPrompt( nextRow, showPrompt );
839}
840
841if (showPrompt)
842{
843updateBootArgs(key);
844}
845
846switch (key) {
847case kReturnKey:
848if (*gBootArgs == '?') {
849char * argPtr = gBootArgs;
850
851// Skip the leading "?" character.
852argPtr++;
853getNextArg(&argPtr, booterCommand);
854getNextArg(&argPtr, booterParam);
855
856/*
857 * TODO: this needs to be refactored.
858 */
859#if UNUSED
860if (strncmp( booterCommand, "video", sizeof("video") ) == 0)
861{
862printVBEModeInfo();
863}
864else
865#endif
866if ( strncmp( booterCommand, "memory", sizeof("memory") ) == 0)
867{
868printMemoryInfo();
869}
870else if (strncmp(booterCommand, "lspci", sizeof( "lspci")) == 0)
871{
872lspci();
873}
874else if (strncmp(booterCommand, "more", sizeof("more")) == 0)
875{
876showTextFile(booterParam);
877}
878else if (strncmp(booterCommand, "rd", sizeof("rd")) == 0)
879{
880if (execute_hook("processRAMDiskCommand", (void*)argPtr, &booterParam, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
881showMessage("ramdisk module not found, please install RamdiskLoader.dylib in /Extra/modules/");
882}
883else if (strncmp(booterCommand, "norescan", sizeof("norescan")) == 0)
884{
885if (get_env(envgEnableCDROMRescan))
886{
887 safe_set_env(envgEnableCDROMRescan,false);
888break;
889}
890}
891else
892{
893showHelp();
894}
895key = 0;
896showBootPrompt(nextRow, showPrompt);
897break;
898}
899safe_set_env(envgBootVolume, (uint32_t)menuBVR);
900setRootVolume(menuBVR);
901 safe_set_env(envgBIOSDev,menuBVR->biosdev);
902break;
903
904case kEscapeKey:
905clearBootArgs();
906break;
907
908case kF5Key:
909// New behavior:
910// Clear gBootVolume to restart the loop
911// if the user enabled rescanning the optical drive.
912// Otherwise boot the default boot volume.
913if (get_env(envgEnableCDROMRescan)) {
914//gBootVolume = NULL;
915safe_set_env(envgBootVolume, (uint32_t)NULL);
916clearBootArgs();
917}
918break;
919
920case kF10Key:
921 safe_set_env(envgScanSingleDrive, false);
922
923 scanDisks();
924
925//gBootVolume = NULL;
926safe_set_env(envgBootVolume, (uint32_t)NULL);
927
928clearBootArgs();
929break;
930
931default:
932key = 0;
933break;
934}
935} while (0 == key);
936
937done:
938if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
939clearScreenRows(kMenuTopRow, kScreenLastRow);
940changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
941}
942 safe_set_env(envShouldboot, false);
943
944if (menuItems) {
945free(menuItems);
946menuItems = NULL;
947}
948return 0;
949}
950
951//==========================================================================
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 ( ((BVRef)(uint32_t)get_env(envgBootVolume)) )
1003 {
1004#ifndef NO_MULTIBOOT_SUPPORT
1005 if (!( ((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagNativeBoot ))
1006 {
1007 readBootSector( ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev, ((BVRef)(uint32_t)get_env(envgBootVolume))->part_boff,
1008 (void *) 0x7c00 );
1009
1010 //
1011 // Setup edx, and signal intention to chain load the
1012 // foreign booter.
1013 //
1014
1015extern unsigned char chainbootdev;
1016extern unsigned char chainbootflag;
1017
1018 chainbootdev = ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev;
1019 chainbootflag = 1;
1020
1021 return 1;
1022 }
1023#endif
1024 setRootVolume(((BVRef)(uint32_t)get_env(envgBootVolume)));
1025
1026 }
1027 // If no boot volume fail immediately because we're just going to fail
1028 // trying to load the config file anyway.
1029 else
1030return -1;
1031
1032 // Load config table specified by the user, or use the default.
1033
1034 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1035val = 0;
1036cnt = 0;
1037 }
1038
1039 // Load com.apple.Boot.plist from the selected volume
1040 // and use its contents to override default bootConfig.
1041 // This is not a mandatory opeartion anymore.
1042
1043 loadOverrideConfig();
1044
1045 // Load System com.apple.boot.plist config file
1046loadSystemConfig();
1047
1048#if virtualM || PCI_FIX // we can simply make an option for this fix
1049 addBootArg("npci=0x2000");
1050#endif
1051#if verbose
1052 addBootArg("-v");
1053#endif
1054
1055 // Use the kernel name specified by the user, or fetch the name
1056 // in the config table, or use the default if not specified.
1057 // Specifying a kernel name on the command line, or specifying
1058 // a non-default kernel name in the config file counts as
1059 // overriding the kernel, which causes the kernelcache not
1060 // to be used.
1061
1062 safe_set_env(envgOverrideKernel,false);
1063 if (( kernel = extractKernelName((char **)&cp) )) {
1064strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
1065 safe_set_env(envgOverrideKernel,true);
1066
1067 } else {
1068 if ( getValueForKey( kKernelNameKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1069 strlcpy( bootInfo->bootFile, val, sizeof(bootInfo->bootFile) );
1070 if (strncmp( bootInfo->bootFile, kDefaultKernel, sizeof(kDefaultKernel) ) != 0) {
1071 safe_set_env(envgOverrideKernel,true);
1072 }
1073 } else if (((BVRef)(uint32_t)get_env(envgBootVolume))->kernelfound == true) {
1074strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
1075 } else {
1076
1077 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);
1078 sleep(1);
1079 return -1;
1080 }
1081 }
1082
1083 ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1084 argP = bootArgs->CommandLine;
1085
1086 // Get config table kernel flags, if not ignored.
1087 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1088!getValueForKey( kKernelFlagsKey, &val, &cnt, DEFAULT_BOOT_CONFIG )) {
1089 val = "";
1090 cnt = 0;
1091 }
1092
1093 configKernelFlags = newString(val);
1094
1095{
1096bool isSafeMode = false;
1097if (configKernelFlags) {
1098isSafeMode = getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt);
1099}
1100
1101if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1102(isSafeMode == false)) {
1103if (get_env(envgBootMode) & kBootModeSafe) {
1104copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining);
1105}
1106}
1107}
1108
1109if (configKernelFlags) {
1110// Store the merged kernel flags and boot args.
1111
1112cnt = strlen(configKernelFlags);
1113if (cnt) {
1114if (cnt > ArgCntRemaining) {
1115printf("Warning: boot arguments too long, truncating\n");
1116cnt = ArgCntRemaining;
1117}
1118strncpy(argP, configKernelFlags, cnt);
1119argP[cnt++] = ' ';
1120ArgCntRemaining -= cnt;
1121}
1122}
1123
1124 userCnt = strlen(cp);
1125 if (userCnt > ArgCntRemaining) {
1126printf("Warning: boot arguments too long, truncating\n");
1127userCnt = ArgCntRemaining;
1128 }
1129 strncpy(&argP[cnt], cp, userCnt);
1130 argP[cnt+userCnt] = '\0';
1131
1132if(!get_env(envShouldboot))
1133{
1134bool gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ||
1135getValueForKey( kSingleUserModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG );
1136safe_set_env(envgVerboseMode, gVerboseMode);
1137
1138long gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) ?
1139kBootModeSafe : kBootModeNormal;
1140 safe_set_env(envgBootMode,gBootMode);
1141
1142
1143 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1144 gBootMode = kBootModeSafe;
1145 safe_set_env(envgBootMode,gBootMode);
1146
1147}
1148}
1149
1150if ( getValueForKey( kMKextCacheKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) )
1151{
1152 char * MKextName = (char*)(uint32_t)get_env(envMKextName);
1153 strlcpy(MKextName,val,Cache_len_name);
1154}
1155
1156if (configKernelFlags)
1157{
1158free(configKernelFlags);
1159}
1160safe_set_env(envArgCntRemaining,ArgCntRemaining);
1161 return 0;
1162}
1163
1164//==========================================================================
1165// Load the help file and display the file contents on the screen.
1166
1167void showTextBuffer(char *buf, int size)
1168{
1169char*bp;
1170intline;
1171intline_offset;
1172intc;
1173
1174
1175if(!(bp = buf)) return;
1176
1177while (size-- > 0) {
1178if (*bp == '\n') {
1179*bp = '\0';
1180}
1181bp++;
1182}
1183*bp = '\1';
1184line_offset = 0;
1185
1186setActiveDisplayPage(1);
1187
1188while (1) {
1189clearScreenRows(0, 24);
1190setCursorPosition(0, 0, 1);
1191bp = buf;
1192for (line = 0; *bp != '\1' && line < line_offset; line++) {
1193while (*bp != '\0') {
1194bp++;
1195}
1196bp++;
1197}
1198for (line = 0; *bp != '\1' && line < 23; line++) {
1199setCursorPosition(0, line, 1);
1200printf("%s\n", bp);
1201while (*bp != '\0') {
1202bp++;
1203}
1204bp++;
1205}
1206
1207setCursorPosition(0, 23, 1);
1208if (*bp == '\1') {
1209printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1210} else {
1211printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1212}
1213
1214c = getc();
1215if (c == 'q' || c == 'Q') {
1216break;
1217}
1218if ((c == 'p' || c == 'P') && line_offset > 0) {
1219line_offset -= 23;
1220}
1221if (c == ' ') {
1222if (*bp == '\1') {
1223break;
1224} else {
1225line_offset += 23;
1226}
1227}
1228}
1229setActiveDisplayPage(0);
1230}
1231
1232void showHelp(void)
1233{
1234#if EMBED_HELP==0
1235int fd = -1;
1236char dirspec[512];
1237char filename[512];
1238snprintf(filename, sizeof(filename), "BootHelp.txt");
1239
1240// Check Extra on booting partition
1241snprintf(dirspec, sizeof(dirspec),"/Extra/%s",filename);
1242fd=open (dirspec,0);
1243if (fd<0)
1244{// Fall back to booter partition
1245snprintf(dirspec, sizeof(dirspec),"bt(0,0)/Extra/%s",filename);
1246fd=open (dirspec,0);
1247if (fd<0)
1248{
1249printf("BootHelp not found: %s\n", filename);
1250return;
1251}
1252}
1253int BootHelp_txt_len = file_size (fd);
1254void *BootHelp_txt=calloc(BootHelp_txt_len, sizeof(char));
1255if (BootHelp_txt)
1256{
1257if (read (fd, BootHelp_txt, BootHelp_txt_len)!=BootHelp_txt_len)
1258{
1259printf("Couldn't read BootHelp %s\n",dirspec);
1260free (BootHelp_txt);
1261close (fd);
1262return;
1263}
1264
1265close (fd);
1266}
1267#endif
1268showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1269}
1270
1271void showMessage(char * message)
1272{
1273showTextBuffer(message, strlen(message));
1274}
1275
1276void showTextFile(const char * filename)
1277{
1278#define MAX_TEXT_FILE_SIZE 65536
1279char*buf;
1280intfd;
1281intsize;
1282
1283if ((fd = open_bvdev("bt(0,0)", filename)) < 0) {
1284printf("\nFile not found: %s\n", filename);
1285sleep(2);
1286return;
1287}
1288
1289size = file_size(fd);
1290if (size > MAX_TEXT_FILE_SIZE) {
1291size = MAX_TEXT_FILE_SIZE;
1292}
1293buf = calloc(size,sizeof(char));
1294 if (!buf) {
1295 printf("Couldn't allocate memory for the buf in showTextFile\n");
1296 return ;
1297 }
1298read(fd, buf, size);
1299close(fd);
1300showTextBuffer(buf, size);
1301free(buf);
1302}
1303
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

Archive Download this file

Revision: 2182