Chameleon

Chameleon Svn Source Tree

Root/branches/slice/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 "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();
822key = 0;
823}
824break;
825
826case kF10Key:
827gScanSingleDrive = false;
828scanDisks(gBIOSDev, &bvCount);
829gBootVolume = NULL;
830clearBootArgs();
831key = 0;
832break;
833#endif
834default:
835key = 0;
836break;
837}
838} while (0 == key);
839
840done:
841if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
842clearScreenRows(kMenuTopRow, kScreenLastRow);
843changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
844}
845shouldboot = false;
846if (menuItems) {
847free(menuItems);
848menuItems = NULL;
849}
850return 0;
851}
852
853//==========================================================================
854
855extern unsigned char chainbootdev;
856extern unsigned char chainbootflag;
857
858bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
859{
860 int argLen = argName ? strlen(argName) : 0;
861 int len = argLen + cnt + 1; // +1 to account for space
862
863 if (len > *cntRemainingP) {
864 error("Warning: boot arguments too long, truncating\n");
865 return false;
866 }
867
868 if (argName) {
869 strncpy( *argP, argName, argLen );
870 *argP += argLen;
871 *argP[0] = '=';
872 (*argP)++;
873 len++; // +1 to account for '='
874 }
875 strncpy( *argP, val, cnt );
876 *argP += cnt;
877 *argP[0] = ' ';
878 (*argP)++;
879
880 *cntRemainingP -= len;
881 return true;
882}
883
884//
885// Returns TRUE if an argument was copied, FALSE otherwise
886bool
887processBootArgument(
888 const char *argName, // The argument to search for
889 const char *userString, // Typed-in boot arguments
890 const char *kernelFlags, // Kernel flags from config table
891 const char *configTable,
892 char **argP, // Output value
893 int *cntRemainingP, // Output count
894 char *foundVal // found value
895 )
896{
897 const char *val;
898 int cnt;
899 bool found = false;
900
901 if (getValueForBootKey(userString, argName, &val, &cnt)) {
902 // Don't copy; these values will be copied at the end of argument processing.
903 found = true;
904 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
905 // Don't copy; these values will be copied at the end of argument processing.
906 found = true;
907 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
908 copyArgument(argName, val, cnt, argP, cntRemainingP);
909 found = true;
910 }
911 if (found && foundVal) {
912 strlcpy(foundVal, val, cnt+1);
913 }
914 return found;
915}
916
917// Maximum config table value size
918#define VALUE_SIZE 2048
919
920int
921processBootOptions()
922{
923 const char * cp = gBootArgs;
924 const char * val = 0;
925 const char * kernel;
926 int cnt;
927 int userCnt;
928 int cntRemaining;
929 char * argP;
930 char uuidStr[64];
931 bool uuidSet = false;
932 char * configKernelFlags;
933 char * valueBuffer;
934
935 valueBuffer = malloc(VALUE_SIZE);
936
937 skipblanks( &cp );
938
939 // Update the unit and partition number.
940
941 if ( gBootVolume )
942 {
943 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
944 {
945 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
946 (void *) 0x7c00 );
947
948 //
949 // Setup edx, and signal intention to chain load the
950 // foreign booter.
951 //
952
953 chainbootdev = gBootVolume->biosdev;
954 chainbootflag = 1;
955
956 return 1;
957 }
958
959 setRootVolume(gBootVolume);
960
961 }
962 // If no boot volume fail immediately because we're just going to fail
963 // trying to load the config file anyway.
964 else
965return -1;
966
967 // Load config table specified by the user, or use the default.
968
969 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
970val = 0;
971cnt = 0;
972 }
973
974 // Load com.apple.Boot.plist from the selected volume
975 // and use its contents to override default bootConfig.
976 // This is not a mandatory operation anymore.
977
978 loadOverrideConfig(&bootInfo->overrideConfig);
979
980 // Use the kernel name specified by the user, or fetch the name
981 // in the config table, or use the default if not specified.
982 // Specifying a kernel name on the command line, or specifying
983 // a non-default kernel name in the config file counts as
984 // overriding the kernel, which causes the kernelcache not
985 // to be used.
986
987 gOverrideKernel = false;
988 if (( kernel = extractKernelName((char **)&cp) )) {
989 strcpy( bootInfo->bootFile, kernel );
990 gOverrideKernel = true;
991 } else {
992 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
993 strlcpy( bootInfo->bootFile, val, cnt+1 );
994 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
995 gOverrideKernel = true;
996 }
997 } else {
998 strcpy( bootInfo->bootFile, kDefaultKernel );
999 }
1000 }
1001
1002 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1003 argP = bootArgs->CommandLine;
1004
1005 // Get config table kernel flags, if not ignored.
1006 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1007!getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1008 val = "";
1009 cnt = 0;
1010 }
1011 configKernelFlags = malloc(cnt + 1);
1012 strlcpy(configKernelFlags, val, cnt + 1);
1013
1014 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1015 // boot-uuid was set either on the command-line
1016 // or in the config file.
1017 uuidSet = true;
1018 } else {
1019
1020 //
1021 // Try an alternate method for getting the root UUID on boot helper partitions.
1022 //
1023 if (gBootVolume->flags & kBVFlagBooter)
1024 {
1025 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1026 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1027 {
1028getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1029copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1030uuidSet = true;
1031 }
1032 }
1033
1034 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1035 verbose("Setting boot-uuid to: %s\n", uuidStr);
1036 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1037 uuidSet = true;
1038 }
1039 }
1040
1041 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1042 cnt = 0;
1043 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1044 valueBuffer[0] = '*';
1045 cnt++;
1046 strlcpy(valueBuffer + 1, val, cnt);
1047 val = valueBuffer;
1048 } else {
1049 if (uuidSet) {
1050 val = "*uuid";
1051 cnt = 5;
1052 } else {
1053 // Don't set "rd=.." if there is no boot device key
1054 // and no UUID.
1055 val = "";
1056 cnt = 0;
1057 }
1058 }
1059 if (cnt > 0) {
1060 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1061 }
1062 strlcpy( gRootDevice, val, (cnt + 1));
1063 }
1064
1065 /*
1066 * Removed. We don't need this anymore.
1067 *
1068 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1069 getPlatformName(gPlatformName);
1070 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1071 }
1072 */
1073
1074 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1075 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1076 if (gBootMode & kBootModeSafe) {
1077 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1078 }
1079 }
1080
1081 // Store the merged kernel flags and boot args.
1082
1083 cnt = strlen(configKernelFlags);
1084 if (cnt) {
1085 if (cnt > cntRemaining) {
1086 error("Warning: boot arguments too long, truncating\n");
1087 cnt = cntRemaining;
1088 }
1089 strncpy(argP, configKernelFlags, cnt);
1090 argP[cnt++] = ' ';
1091 cntRemaining -= cnt;
1092 }
1093 userCnt = strlen(cp);
1094 if (userCnt > cntRemaining) {
1095error("Warning: boot arguments too long, truncating\n");
1096userCnt = cntRemaining;
1097 }
1098 strncpy(&argP[cnt], cp, userCnt);
1099 argP[cnt+userCnt] = '\0';
1100
1101if(!shouldboot)
1102{
1103gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1104getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1105
1106gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1107kBootModeSafe : kBootModeNormal;
1108
1109 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1110 gBootMode = kBootModeSafe;
1111}
1112}
1113
1114if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1115{
1116strlcpy(gMKextName, val, cnt + 1);
1117}
1118
1119 free(configKernelFlags);
1120 free(valueBuffer);
1121
1122 return 0;
1123}
1124
1125#ifndef OPTION_ROM
1126
1127//==========================================================================
1128// Load the help file and display the file contents on the screen.
1129
1130void showTextBuffer(char *buf, int size)
1131{
1132char*bp;
1133intline;
1134intline_offset;
1135intc;
1136//Slice - why not?
1137#if NOTYET
1138if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1139showInfoBox( "Press q to quit\n",buf );
1140return;
1141}
1142#endif
1143bp = buf;
1144while (size-- > 0) {
1145if (*bp == '\n') {
1146*bp = '\0';
1147}
1148bp++;
1149}
1150*bp = '\1';
1151line_offset = 0;
1152
1153setActiveDisplayPage(1);
1154
1155while (1) {
1156clearScreenRows(0, 24);
1157setCursorPosition(0, 0, 1);
1158bp = buf;
1159for (line = 0; *bp != '\1' && line < line_offset; line++) {
1160while (*bp != '\0') {
1161bp++;
1162}
1163bp++;
1164}
1165for (line = 0; *bp != '\1' && line < 23; line++) {
1166setCursorPosition(0, line, 1);
1167printf("%s\n", bp);
1168while (*bp != '\0') {
1169bp++;
1170}
1171bp++;
1172}
1173
1174setCursorPosition(0, 23, 1);
1175if (*bp == '\1') {
1176printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1177} else {
1178printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1179}
1180
1181c = getc();
1182if (c == 'q' || c == 'Q') {
1183break;
1184}
1185if ((c == 'p' || c == 'P') && line_offset > 0) {
1186line_offset -= 23;
1187}
1188if (c == ' ') {
1189if (*bp == '\1') {
1190break;
1191} else {
1192line_offset += 23;
1193}
1194}
1195}
1196setActiveDisplayPage(0);
1197}
1198
1199void showHelp(void)
1200{
1201#if 1
1202#define BOOT_HELP_PATH "/Extra/BootHelp.txt"
1203
1204#ifdef EMBED_THEME
1205if( bootArgs->Video.v_display == GRAPHICS_MODE )
1206{
1207showInfoBox( "Help. Press q to quit.\n" , (char *)BootHelp_txt );
1208return;
1209}
1210#endif
1211 showTextFile(BOOT_HELP_PATH);
1212#else
1213if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1214showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1215} else {
1216showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1217}
1218#endif
1219}
1220
1221void showTextFile(const char * filename)
1222{
1223#define MAX_TEXT_FILE_SIZE 65536
1224char*buf;
1225intfd;
1226intsize;
1227
1228if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1229printf("\nFile not found: %s\n", filename);
1230sleep(2);
1231return;
1232}
1233
1234size = file_size(fd);
1235if (size > MAX_TEXT_FILE_SIZE) {
1236size = MAX_TEXT_FILE_SIZE;
1237}
1238buf = malloc(size);
1239read(fd, buf, size);
1240close(fd);
1241showTextBuffer(buf, size);
1242free(buf);
1243}
1244#endif
1245
1246// This is a very simplistic prompting scheme that just grabs two hex characters
1247// Eventually we need to do something more user-friendly like display a menu
1248// based off of the Multiboot device list
1249#ifdef UNUSED
1250int selectAlternateBootDevice(int bootdevice)
1251{
1252int key;
1253int newbootdevice;
1254int digitsI = 0;
1255char *end;
1256char digits[3] = {0,0,0};
1257
1258// We've already printed the current boot device so user knows what it is
1259printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1260printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1261do {
1262key = getc();
1263switch (key & kASCIIKeyMask) {
1264case kBackspaceKey:
1265if (digitsI > 0) {
1266int x, y, t;
1267getCursorPositionAndType(&x, &y, &t);
1268// Assume x is not 0;
1269x--;
1270setCursorPosition(x,y,0); // back up one char
1271 // Overwrite with space without moving cursor position
1272putca(' ', 0x07, 1);
1273digitsI--;
1274} else {
1275// TODO: Beep or something
1276}
1277break;
1278
1279case kReturnKey:
1280digits[digitsI] = '\0';
1281newbootdevice = strtol(digits, &end, 16);
1282if (end == digits && *end == '\0') {
1283// User entered empty string
1284printf("\nUsing default boot device %x\n", bootdevice);
1285key = 0;
1286} else if(end != digits && *end == '\0') {
1287bootdevice = newbootdevice;
1288printf("\n");
1289key = 0; // We gots da boot device
1290} else {
1291printf("\nCouldn't parse. try again: ");
1292digitsI = 0;
1293}
1294break;
1295
1296default:
1297if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1298putc(key & kASCIIKeyMask);
1299digits[digitsI++] = key & kASCIIKeyMask;
1300} else {
1301// TODO: Beep or something
1302}
1303break;
1304};
1305} while (key != 0);
1306
1307return bootdevice;
1308}
1309#endif
1310
1311#ifndef OPTION_ROM
1312bool promptForRescanOption(void)
1313{
1314printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1315if (getc() == kReturnKey) {
1316return true;
1317} else {
1318return false;
1319}
1320}
1321#endif
1322

Archive Download this file

Revision: 721