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

Archive Download this file

Revision: 1468