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

Archive Download this file

Revision: 1972