Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 2154