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

Archive Download this file

Revision: 1595