Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1913