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.
588gBootVolume = menuBVR = selectBootVolume(getBvChain());
589
590if (biosDevIsCDROM((int)get_env(envgBIOSDev))) {
591isCDROM = true;
592} else {
593isCDROM = false;
594}
595
596// Clear command line boot arguments
597clearBootArgs();
598
599// Allow user to override default timeout.
600#if UNUSED
601if (multiboot_timeout_set) {
602timeout = multiboot_timeout;
603} else
604#endif
605if (!getIntForKey(kTimeoutKey, &timeout, DEFAULT_BOOT_CONFIG)) {
606/* If there is no timeout key in the file use the default timeout
607 which is different for CDs vs. hard disks. However, if not booting
608 a CD and no config file could be loaded set the timeout
609 to zero which causes the menu to display immediately.
610 This way, if no partitions can be found, that is the disk is unpartitioned
611 or simply cannot be read) then an empty menu is displayed.
612 If some partitions are found, for example a Windows partition, then
613 these will be displayed in the menu as foreign partitions.
614 */
615if (isCDROM) {
616timeout = kCDBootTimeout;
617} else {
618timeout = get_env(envSysConfigValid) ? kBootTimeout : 0;
619}
620}
621
622 long gBootMode = (long)get_env(envgBootMode);
623
624if (timeout < 0) {
625gBootMode |= kBootModeQuiet;
626 safe_set_env(envgBootMode,gBootMode);
627
628}
629
630// If the user is holding down a modifier key, enter safe mode.
631if ((readKeyboardShiftFlags() & 0x0F) != 0) {
632
633gBootMode |= kBootModeSafe;
634 safe_set_env(envgBootMode,gBootMode);
635
636}
637
638// Checking user pressed keys
639bool f8press = false, spress = false, vpress = false;
640while (readKeyboardStatus()) {
641key = bgetc ();
642if (key == 0x4200) f8press = true;
643if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
644if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
645}
646// If user typed F8, abort quiet mode, and display the menu.
647if (f8press) {
648gBootMode &= ~kBootModeQuiet;
649 safe_set_env(envgBootMode,gBootMode);
650
651timeout = 0;
652}
653// If user typed 'v' or 'V', boot in verbose mode.
654if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
655addBootArg(kVerboseModeFlag);
656}
657// If user typed 's' or 'S', boot in single user mode.
658if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
659addBootArg(kSingleUserModeFlag);
660}
661
662setCursorPosition(0, 0, 0);
663clearScreenRows(0, kScreenLastRow);
664if (!(gBootMode & kBootModeQuiet)) {
665// Display banner and show hardware info.
666 char * bootBanner = (char*)(uint32_t)get_env(envBootBanner);
667
668printf(bootBanner, (int)(get_env(envConvMem) + get_env(envExtMem)) / 1024);
669}
670changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
671msglog("Scanning device %x...", (uint32_t)get_env(envgBIOSDev));
672
673// When booting from CD, default to hard drive boot when possible.
674if (isCDROM && firstRun) {
675const char *val;
676char *prompt = NULL;
677char *name = NULL;
678int cnt;
679
680if (getValueForKey(kCDROMPromptKey, &val, &cnt, DEFAULT_BOOT_CONFIG)) {
681prompt = malloc(cnt + 1);
682 if (!prompt) {
683 stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
684 return -1;
685 }
686strncat(prompt, val, cnt);
687} else {
688name = malloc(80);
689 if (!name) {
690 stop("Couldn't allocate memory for the device name\n"); //TODO: Find a better stategie
691 return -1;
692 }
693getBootVolumeDescription(gBootVolume, name, 79, false);
694prompt = malloc(256);
695 if (!prompt) {
696 free(name);
697 stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
698 return -1;
699 }
700sprintf(prompt, "Press ENTER to start up from %s, or press any key to enter startup options.", name);
701free(name);
702}
703
704if (getIntForKey( kCDROMOptionKey, &optionKey, DEFAULT_BOOT_CONFIG )) {
705// The key specified is a special key.
706} else {
707// Default to F8.
708optionKey = 0x4200;
709}
710
711// If the timeout is zero then it must have been set above due to the
712// early catch of F8 which means the user wants to set boot options
713// which we ought to interpret as meaning he wants to boot the CD.
714if (timeout != 0) {
715key = countdown(prompt, kMenuTopRow, timeout, &optionKey);
716} else {
717key = optionKey;
718}
719
720if (prompt != NULL) {
721free(prompt);
722}
723
724clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
725
726 do {
727 // Hit the option key ?
728 if (key == optionKey) {
729
730 if (key != 0x1C0D) {
731 gBootMode &= ~kBootModeQuiet;
732 safe_set_env(envgBootMode,gBootMode);
733 timeout = 0;
734 break;
735 }
736
737 }
738
739 key = key & 0xFF;
740
741 // Try booting hard disk if user pressed 'h'
742 if (biosDevIsCDROM((int)get_env(envgBIOSDev)) && key == 'h') {
743 BVRef bvr;
744
745 // Look at partitions hosting OS X other than the CD-ROM
746 for (bvr = getBvChain(); bvr; bvr=bvr->next) {
747 if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != (int)get_env(envgBIOSDev)) {
748 gBootVolume = bvr;
749 }
750 }
751 }
752 goto done;
753
754 } while (0);
755
756}
757
758if (get_env(envgBootMode) & kBootModeQuiet) {
759// No input allowed from user.
760goto done;
761}
762
763if (firstRun && timeout > 0 ) {
764
765 key = countdown("Press ENTER to start up, or press any key to enter startup options.", kMenuTopRow, timeout, &optionKey);
766
767 if (key == 0x1C0D) {
768 goto done;
769
770 }
771 else if (key == 0)
772 {
773 // If the user is holding down a modifier key,
774 // enter safe mode.
775
776 if ((readKeyboardShiftFlags() & 0x0F) != 0) {
777 gBootMode |= kBootModeSafe;
778 safe_set_env(envgBootMode,gBootMode);
779 }
780 goto done;
781 }
782}
783int devcnt = (int)get_env(envgDeviceCount);
784
785if (devcnt) {
786// Allocate memory for an array of menu items.
787menuItems = malloc(sizeof(MenuItem) * devcnt);
788if (menuItems == NULL) {
789goto done;
790}
791
792// Associate a menu item for each BVRef.
793for (bvr=getBvChain(), i=devcnt-1, selectIndex=0; bvr; bvr=bvr->next) {
794if (bvr->visible) {
795getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
796menuItems[i].param = (void *) bvr;
797if (bvr == menuBVR) {
798selectIndex = i;
799}
800i--;
801}
802}
803}
804
805// Clear screen and hide the blinking cursor.
806clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
807changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
808
809nextRow = kMenuTopRow;
810/*showPrompt = true;*/
811
812if (devcnt) {
813printf("Use \30\31 keys to select the startup volume.");
814showMenu( menuItems, devcnt, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
815nextRow += min( devcnt, kMenuMaxItems ) + 3;
816}
817
818// Show the boot prompt.
819showPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
820showBootPrompt( nextRow, showPrompt );
821
822do {
823
824key = getc();
825updateMenu( key, (void **) &menuBVR );
826newShowPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
827
828if (newShowPrompt != showPrompt)
829{
830showPrompt = newShowPrompt;
831showBootPrompt( nextRow, showPrompt );
832}
833
834if (showPrompt)
835{
836updateBootArgs(key);
837}
838
839switch (key) {
840case kReturnKey:
841if (*gBootArgs == '?') {
842char * argPtr = gBootArgs;
843
844// Skip the leading "?" character.
845argPtr++;
846getNextArg(&argPtr, booterCommand);
847getNextArg(&argPtr, booterParam);
848
849/*
850 * TODO: this needs to be refactored.
851 */
852#if UNUSED
853if (strcmp( booterCommand, "video" ) == 0)
854{
855printVBEModeInfo();
856}
857else
858#endif
859if ( strcmp( booterCommand, "memory" ) == 0)
860{
861printMemoryInfo();
862}
863else if (strcmp(booterCommand, "lspci") == 0)
864{
865lspci();
866}
867else if (strcmp(booterCommand, "more") == 0)
868{
869showTextFile(booterParam);
870}
871else if (strcmp(booterCommand, "rd") == 0)
872{
873if (execute_hook("processRAMDiskCommand", (void*)argPtr, &booterParam, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
874showMessage("ramdisk module not found, please install RamdiskLoader.dylib in /Extra/modules/");
875}
876else if (strcmp(booterCommand, "norescan") == 0)
877{
878if (get_env(envgEnableCDROMRescan))
879{
880 safe_set_env(envgEnableCDROMRescan,false);
881break;
882}
883}
884else
885{
886showHelp();
887}
888key = 0;
889showBootPrompt(nextRow, showPrompt);
890break;
891}
892gBootVolume = menuBVR;
893setRootVolume(menuBVR);
894 safe_set_env(envgBIOSDev,menuBVR->biosdev);
895break;
896
897case kEscapeKey:
898clearBootArgs();
899break;
900
901case kF5Key:
902// New behavior:
903// Clear gBootVolume to restart the loop
904// if the user enabled rescanning the optical drive.
905// Otherwise boot the default boot volume.
906if (get_env(envgEnableCDROMRescan)) {
907gBootVolume = NULL;
908clearBootArgs();
909}
910break;
911
912case kF10Key:
913 safe_set_env(envgScanSingleDrive, false);
914
915 scanDisks();
916
917gBootVolume = NULL;
918clearBootArgs();
919break;
920
921default:
922key = 0;
923break;
924}
925} while (0 == key);
926
927done:
928if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
929clearScreenRows(kMenuTopRow, kScreenLastRow);
930changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
931}
932 safe_set_env(envShouldboot, false);
933
934if (menuItems) {
935free(menuItems);
936menuItems = NULL;
937}
938return 0;
939}
940
941//==========================================================================
942
943extern unsigned char chainbootdev;
944extern unsigned char chainbootflag;
945
946bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
947{
948 int argLen = argName ? strlen(argName) : 0;
949 int len = argLen + cnt + 1; // +1 to account for space
950
951 if (len > *cntRemainingP) {
952 error("Warning: boot arguments too long, truncating\n");
953 return false;
954 }
955
956 if (argName) {
957 strncpy( *argP, argName, argLen );
958 *argP += argLen;
959 *argP[0] = '=';
960 (*argP)++;
961 len++; // +1 to account for '='
962 }
963 strncpy( *argP, val, cnt );
964 *argP += cnt;
965 *argP[0] = ' ';
966 (*argP)++;
967
968 *cntRemainingP -= len;
969 return true;
970}
971
972int
973processBootOptions(void)
974{
975char *cp_cache = (char*)(uint32_t)get_env(envgBootArgs);
976if (cp_cache)
977{
978bzero(gBootArgs,sizeof(gBootArgs));
979strlcpy(gBootArgs, cp_cache,sizeof(gBootArgs));
980}
981
982 const char * cp = gBootArgs;
983 const char * val = 0;
984 const char * kernel;
985 int cnt;
986 int userCnt;
987 char * argP;
988 char * configKernelFlags;
989int ArgCntRemaining;
990
991 skipblanks( &cp );
992
993 // Update the unit and partition number.
994
995 if ( gBootVolume )
996 {
997 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
998 {
999 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1000 (void *) 0x7c00 );
1001
1002 //
1003 // Setup edx, and signal intention to chain load the
1004 // foreign booter.
1005 //
1006
1007 chainbootdev = gBootVolume->biosdev;
1008 chainbootflag = 1;
1009
1010 return 1;
1011 }
1012
1013 setRootVolume(gBootVolume);
1014
1015 }
1016 // If no boot volume fail immediately because we're just going to fail
1017 // trying to load the config file anyway.
1018 else
1019return -1;
1020
1021 // Load config table specified by the user, or use the default.
1022
1023 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1024val = 0;
1025cnt = 0;
1026 }
1027
1028 // Load com.apple.Boot.plist from the selected volume
1029 // and use its contents to override default bootConfig.
1030 // This is not a mandatory opeartion anymore.
1031
1032 loadOverrideConfig();
1033
1034 // Load System com.apple.boot.plist config file
1035loadSystemConfig();
1036
1037#if virtualM || PCI_FIX // we can simply make an option for this fix
1038 addBootArg("npci=0x2000");
1039#endif
1040#if verbose
1041 addBootArg("-v");
1042#endif
1043
1044 // Use the kernel name specified by the user, or fetch the name
1045 // in the config table, or use the default if not specified.
1046 // Specifying a kernel name on the command line, or specifying
1047 // a non-default kernel name in the config file counts as
1048 // overriding the kernel, which causes the kernelcache not
1049 // to be used.
1050
1051 safe_set_env(envgOverrideKernel,false);
1052 if (( kernel = extractKernelName((char **)&cp) )) {
1053strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
1054 safe_set_env(envgOverrideKernel,true);
1055
1056 } else {
1057 if ( getValueForKey( kKernelNameKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1058 strlcpy( bootInfo->bootFile, val, sizeof(bootInfo->bootFile) );
1059 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1060 safe_set_env(envgOverrideKernel,true);
1061 }
1062 } else if (gBootVolume->kernelfound == true) {
1063strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
1064 } else {
1065
1066 printf("No kernel found on this volume : hd(%d,%d)\n", BIOS_DEV_UNIT(gBootVolume), gBootVolume->part_no);
1067 sleep(1);
1068 return -1;
1069 }
1070 }
1071
1072 ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1073 argP = bootArgs->CommandLine;
1074
1075 // Get config table kernel flags, if not ignored.
1076 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1077!getValueForKey( kKernelFlagsKey, &val, &cnt, DEFAULT_BOOT_CONFIG )) {
1078 val = "";
1079 cnt = 0;
1080 }
1081
1082 configKernelFlags = newString(val);
1083
1084{
1085bool isSafeMode = false;
1086if (configKernelFlags) {
1087isSafeMode = getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt);
1088}
1089
1090if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1091(isSafeMode == false)) {
1092if (get_env(envgBootMode) & kBootModeSafe) {
1093copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining);
1094}
1095}
1096}
1097
1098if (configKernelFlags) {
1099// Store the merged kernel flags and boot args.
1100
1101cnt = strlen(configKernelFlags);
1102if (cnt) {
1103if (cnt > ArgCntRemaining) {
1104printf("Warning: boot arguments too long, truncating\n");
1105cnt = ArgCntRemaining;
1106}
1107strncpy(argP, configKernelFlags, cnt);
1108argP[cnt++] = ' ';
1109ArgCntRemaining -= cnt;
1110}
1111}
1112
1113 userCnt = strlen(cp);
1114 if (userCnt > ArgCntRemaining) {
1115printf("Warning: boot arguments too long, truncating\n");
1116userCnt = ArgCntRemaining;
1117 }
1118 strncpy(&argP[cnt], cp, userCnt);
1119 argP[cnt+userCnt] = '\0';
1120
1121if(!get_env(envShouldboot))
1122{
1123gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ||
1124getValueForKey( kSingleUserModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG );
1125
1126long gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) ?
1127kBootModeSafe : kBootModeNormal;
1128 safe_set_env(envgBootMode,gBootMode);
1129
1130
1131 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) {
1132 gBootMode = kBootModeSafe;
1133 safe_set_env(envgBootMode,gBootMode);
1134
1135}
1136}
1137
1138if ( getValueForKey( kMKextCacheKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) )
1139{
1140 char * MKextName = (char*)(uint32_t)get_env(envMKextName);
1141 strlcpy(MKextName,val,Cache_len_name);
1142}
1143
1144if (configKernelFlags)
1145{
1146free(configKernelFlags);
1147}
1148safe_set_env(envArgCntRemaining,ArgCntRemaining);
1149 return 0;
1150}
1151
1152//==========================================================================
1153// Load the help file and display the file contents on the screen.
1154
1155void showTextBuffer(char *buf, int size)
1156{
1157char*bp;
1158intline;
1159intline_offset;
1160intc;
1161
1162
1163if(!(bp = buf)) return;
1164
1165while (size-- > 0) {
1166if (*bp == '\n') {
1167*bp = '\0';
1168}
1169bp++;
1170}
1171*bp = '\1';
1172line_offset = 0;
1173
1174setActiveDisplayPage(1);
1175
1176while (1) {
1177clearScreenRows(0, 24);
1178setCursorPosition(0, 0, 1);
1179bp = buf;
1180for (line = 0; *bp != '\1' && line < line_offset; line++) {
1181while (*bp != '\0') {
1182bp++;
1183}
1184bp++;
1185}
1186for (line = 0; *bp != '\1' && line < 23; line++) {
1187setCursorPosition(0, line, 1);
1188printf("%s\n", bp);
1189while (*bp != '\0') {
1190bp++;
1191}
1192bp++;
1193}
1194
1195setCursorPosition(0, 23, 1);
1196if (*bp == '\1') {
1197printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1198} else {
1199printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1200}
1201
1202c = getc();
1203if (c == 'q' || c == 'Q') {
1204break;
1205}
1206if ((c == 'p' || c == 'P') && line_offset > 0) {
1207line_offset -= 23;
1208}
1209if (c == ' ') {
1210if (*bp == '\1') {
1211break;
1212} else {
1213line_offset += 23;
1214}
1215}
1216}
1217setActiveDisplayPage(0);
1218}
1219
1220void showHelp(void)
1221{
1222#if EMBED_HELP==0
1223int fd = -1;
1224char dirspec[512];
1225char filename[512];
1226sprintf(filename, "BootHelp.txt");
1227
1228// Check Extra on booting partition
1229sprintf(dirspec,"/Extra/%s",filename);
1230fd=open (dirspec);
1231if (fd<0)
1232{// Fall back to booter partition
1233sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
1234fd=open (dirspec);
1235if (fd<0)
1236{
1237printf("BootHelp not found: %s\n", filename);
1238return;
1239}
1240}
1241int BootHelp_txt_len = file_size (fd);
1242void *BootHelp_txt=malloc(BootHelp_txt_len);
1243if (BootHelp_txt)
1244{
1245if (read (fd, BootHelp_txt, BootHelp_txt_len)!=BootHelp_txt_len)
1246{
1247printf("Couldn't read BootHelp %s\n",dirspec);
1248free (BootHelp_txt);
1249close (fd);
1250return;
1251}
1252
1253close (fd);
1254}
1255#endif
1256showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1257}
1258
1259void showMessage(char * message)
1260{
1261showTextBuffer(message, strlen(message));
1262}
1263
1264void showTextFile(const char * filename)
1265{
1266#define MAX_TEXT_FILE_SIZE 65536
1267char*buf;
1268intfd;
1269intsize;
1270
1271if ((fd = open_bvdev("bt(0,0)", filename)) < 0) {
1272printf("\nFile not found: %s\n", filename);
1273sleep(2);
1274return;
1275}
1276
1277size = file_size(fd);
1278if (size > MAX_TEXT_FILE_SIZE) {
1279size = MAX_TEXT_FILE_SIZE;
1280}
1281buf = malloc(size);
1282 if (!buf) {
1283 printf("Couldn't allocate memory for the buf in showTextFile\n");
1284 return ;
1285 }
1286read(fd, buf, size);
1287close(fd);
1288showTextBuffer(buf, size);
1289free(buf);
1290}
1291
1292bool promptForRescanOption(void)
1293{
1294printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1295if (getc() == kReturnKey) {
1296return true;
1297} else {
1298return false;
1299}
1300}
1301

Archive Download this file

Revision: 1931