Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 575