Chameleon

Chameleon Svn Source Tree

Root/branches/cparm/i386/boot2/options.c

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

Archive Download this file

Revision: 1977