Chameleon

Chameleon Svn Source Tree

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

Source at commit 535 created 13 years 7 months ago.
By meklort, Removed unneeded code when embeded in an option rom
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//==========================================================================
453
454void printMemoryInfo(void)
455{
456 int line;
457 int i;
458 MemoryRange *mp = bootInfo->memoryMap;
459
460 // Activate and clear page 1
461 setActiveDisplayPage(1);
462 clearScreenRows(0, 24);
463 setCursorPosition( 0, 0, 1 );
464
465 printf("BIOS reported memory ranges:\n");
466 line = 1;
467 for (i=0; i<bootInfo->memoryMapCount; i++) {
468 printf("Base 0x%08x%08x, ",
469 (unsigned long)(mp->base >> 32),
470 (unsigned long)(mp->base));
471 printf("length 0x%08x%08x, type %d\n",
472 (unsigned long)(mp->length >> 32),
473 (unsigned long)(mp->length),
474 mp->type);
475 if (line++ > 20) {
476 pause();
477 line = 0;
478 }
479 mp++;
480 }
481 if (line > 0) {
482 pause();
483 }
484
485 setActiveDisplayPage(0);
486}
487
488char *getMemoryInfoString()
489{
490 int i;
491 MemoryRange *mp = bootInfo->memoryMap;
492char *buff = malloc(sizeof(char)*1024);
493if(!buff) return 0;
494
495char info[] = "BIOS reported memory ranges:\n";
496sprintf(buff, "%s", info);
497 for (i=0; i<bootInfo->memoryMapCount; i++) {
498 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
499(unsigned long)(mp->base >> 32),
500(unsigned long)(mp->base));
501 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
502(unsigned long)(mp->length >> 32),
503(unsigned long)(mp->length),
504mp->type);
505 mp++;
506 }
507return buff;
508}
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
529//==========================================================================
530
531int getBootOptions(bool firstRun)
532{
533int i;
534int key;
535int nextRow;
536int timeout;
537#ifndef OPTION_ROM
538int bvCount;
539#endif
540BVRef bvr;
541BVRef menuBVR;
542bool showPrompt, newShowPrompt, isCDROM;
543
544// Initialize default menu selection entry.
545gBootVolume = menuBVR = selectBootVolume(bvChain);
546
547if (biosDevIsCDROM(gBIOSDev)) {
548isCDROM = true;
549} else {
550isCDROM = false;
551}
552
553// Clear command line boot arguments
554clearBootArgs();
555
556// Allow user to override default timeout.
557#ifdef UNUSED
558if (multiboot_timeout_set) {
559timeout = multiboot_timeout;
560} else
561#endif
562if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
563/* If there is no timeout key in the file use the default timeout
564 which is different for CDs vs. hard disks. However, if not booting
565 a CD and no config file could be loaded set the timeout
566 to zero which causes the menu to display immediately.
567 This way, if no partitions can be found, that is the disk is unpartitioned
568 or simply cannot be read) then an empty menu is displayed.
569 If some partitions are found, for example a Windows partition, then
570 these will be displayed in the menu as foreign partitions.
571 */
572if (isCDROM) {
573timeout = kCDBootTimeout;
574} else {
575timeout = sysConfigValid ? kBootTimeout : 0;
576}
577}
578
579if (timeout < 0) {
580gBootMode |= kBootModeQuiet;
581}
582
583// If the user is holding down a modifier key, enter safe mode.
584if ((readKeyboardShiftFlags() & 0x0F) != 0) {
585
586//gBootMode |= kBootModeSafe;
587}
588
589// Checking user pressed keys
590bool f8press = false, spress = false, vpress = false;
591while (readKeyboardStatus()) {
592key = bgetc ();
593if (key == 0x4200) f8press = true;
594if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
595if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
596}
597// If user typed F8, abort quiet mode, and display the menu.
598if (f8press) {
599gBootMode &= ~kBootModeQuiet;
600timeout = 0;
601}
602// If user typed 'v' or 'V', boot in verbose mode.
603if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
604addBootArg(kVerboseModeFlag);
605}
606// If user typed 's' or 'S', boot in single user mode.
607if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
608addBootArg(kSingleUserModeFlag);
609}
610
611setCursorPosition(0, 0, 0);
612clearScreenRows(0, kScreenLastRow);
613if (!(gBootMode & kBootModeQuiet)) {
614// Display banner and show hardware info.
615printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
616printf(getVBEInfoString());
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 */
764if (strcmp( booterCommand, "video" ) == 0)
765{
766printVBEModeInfo();
767}
768else if ( strcmp( booterCommand, "memory" ) == 0)
769{
770printMemoryInfo();
771}
772else if (strcmp(booterCommand, "lspci") == 0)
773{
774lspci();
775}
776#ifndef OPTION_ROM
777else if (strcmp(booterCommand, "more") == 0)
778{
779showTextFile(booterParam);
780}
781else if (strcmp(booterCommand, "rd") == 0)
782{
783processRAMDiskCommand(&argPtr, booterParam);
784}
785else if (strcmp(booterCommand, "norescan") == 0)
786{
787if (gEnableCDROMRescan)
788{
789gEnableCDROMRescan = false;
790break;
791}
792}
793else
794{
795showHelp();
796}
797#endif
798key = 0;
799showBootPrompt(nextRow, showPrompt);
800break;
801}
802gBootVolume = menuBVR;
803setRootVolume(menuBVR);
804gBIOSDev = menuBVR->biosdev;
805break;
806
807case kEscapeKey:
808clearBootArgs();
809break;
810#ifndef OPTION_ROM
811case kF5Key:
812// New behavior:
813// Clear gBootVolume to restart the loop
814// if the user enabled rescanning the optical drive.
815// Otherwise boot the default boot volume.
816if (gEnableCDROMRescan) {
817gBootVolume = NULL;
818clearBootArgs();
819}
820break;
821
822case kF10Key:
823gScanSingleDrive = false;
824scanDisks(gBIOSDev, &bvCount);
825gBootVolume = NULL;
826clearBootArgs();
827break;
828#endif
829default:
830key = 0;
831break;
832}
833} while (0 == key);
834
835done:
836if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
837clearScreenRows(kMenuTopRow, kScreenLastRow);
838changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
839}
840shouldboot = false;
841if (menuItems) {
842free(menuItems);
843menuItems = NULL;
844}
845return 0;
846}
847
848//==========================================================================
849
850extern unsigned char chainbootdev;
851extern unsigned char chainbootflag;
852
853bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
854{
855 int argLen = argName ? strlen(argName) : 0;
856 int len = argLen + cnt + 1; // +1 to account for space
857
858 if (len > *cntRemainingP) {
859 error("Warning: boot arguments too long, truncating\n");
860 return false;
861 }
862
863 if (argName) {
864 strncpy( *argP, argName, argLen );
865 *argP += argLen;
866 *argP[0] = '=';
867 (*argP)++;
868 len++; // +1 to account for '='
869 }
870 strncpy( *argP, val, cnt );
871 *argP += cnt;
872 *argP[0] = ' ';
873 (*argP)++;
874
875 *cntRemainingP -= len;
876 return true;
877}
878
879//
880// Returns TRUE if an argument was copied, FALSE otherwise
881bool
882processBootArgument(
883 const char *argName, // The argument to search for
884 const char *userString, // Typed-in boot arguments
885 const char *kernelFlags, // Kernel flags from config table
886 const char *configTable,
887 char **argP, // Output value
888 int *cntRemainingP, // Output count
889 char *foundVal // found value
890 )
891{
892 const char *val;
893 int cnt;
894 bool found = false;
895
896 if (getValueForBootKey(userString, argName, &val, &cnt)) {
897 // Don't copy; these values will be copied at the end of argument processing.
898 found = true;
899 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
900 // Don't copy; these values will be copied at the end of argument processing.
901 found = true;
902 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
903 copyArgument(argName, val, cnt, argP, cntRemainingP);
904 found = true;
905 }
906 if (found && foundVal) {
907 strlcpy(foundVal, val, cnt+1);
908 }
909 return found;
910}
911
912// Maximum config table value size
913#define VALUE_SIZE 2048
914
915int
916processBootOptions()
917{
918 const char * cp = gBootArgs;
919 const char * val = 0;
920 const char * kernel;
921 int cnt;
922 int userCnt;
923 int cntRemaining;
924 char * argP;
925 char uuidStr[64];
926 bool uuidSet = false;
927 char * configKernelFlags;
928 char * valueBuffer;
929
930 valueBuffer = malloc(VALUE_SIZE);
931
932 skipblanks( &cp );
933
934 // Update the unit and partition number.
935
936 if ( gBootVolume )
937 {
938 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
939 {
940 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
941 (void *) 0x7c00 );
942
943 //
944 // Setup edx, and signal intention to chain load the
945 // foreign booter.
946 //
947
948 chainbootdev = gBootVolume->biosdev;
949 chainbootflag = 1;
950
951 return 1;
952 }
953
954 setRootVolume(gBootVolume);
955
956 }
957 // If no boot volume fail immediately because we're just going to fail
958 // trying to load the config file anyway.
959 else
960return -1;
961
962 // Load config table specified by the user, or use the default.
963
964 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
965val = 0;
966cnt = 0;
967 }
968
969 // Load com.apple.Boot.plist from the selected volume
970 // and use its contents to override default bootConfig.
971 // This is not a mandatory opeartion anymore.
972
973 loadOverrideConfig(&bootInfo->overrideConfig);
974
975 // Use the kernel name specified by the user, or fetch the name
976 // in the config table, or use the default if not specified.
977 // Specifying a kernel name on the command line, or specifying
978 // a non-default kernel name in the config file counts as
979 // overriding the kernel, which causes the kernelcache not
980 // to be used.
981
982 gOverrideKernel = false;
983 if (( kernel = extractKernelName((char **)&cp) )) {
984 strcpy( bootInfo->bootFile, kernel );
985 gOverrideKernel = true;
986 } else {
987 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
988 strlcpy( bootInfo->bootFile, val, cnt+1 );
989 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
990 gOverrideKernel = true;
991 }
992 } else {
993 strcpy( bootInfo->bootFile, kDefaultKernel );
994 }
995 }
996
997 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
998 argP = bootArgs->CommandLine;
999
1000 // Get config table kernel flags, if not ignored.
1001 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1002!getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1003 val = "";
1004 cnt = 0;
1005 }
1006 configKernelFlags = malloc(cnt + 1);
1007 strlcpy(configKernelFlags, val, cnt + 1);
1008
1009 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1010 // boot-uuid was set either on the command-line
1011 // or in the config file.
1012 uuidSet = true;
1013 } else {
1014
1015 //
1016 // Try an alternate method for getting the root UUID on boot helper partitions.
1017 //
1018 if (gBootVolume->flags & kBVFlagBooter)
1019 {
1020 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1021 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1022 {
1023getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1024copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1025uuidSet = true;
1026 }
1027 }
1028
1029 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1030 verbose("Setting boot-uuid to: %s\n", uuidStr);
1031 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1032 uuidSet = true;
1033 }
1034 }
1035
1036 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1037 cnt = 0;
1038 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1039 valueBuffer[0] = '*';
1040 cnt++;
1041 strlcpy(valueBuffer + 1, val, cnt);
1042 val = valueBuffer;
1043 } else {
1044 if (uuidSet) {
1045 val = "*uuid";
1046 cnt = 5;
1047 } else {
1048 // Don't set "rd=.." if there is no boot device key
1049 // and no UUID.
1050 val = "";
1051 cnt = 0;
1052 }
1053 }
1054 if (cnt > 0) {
1055 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1056 }
1057 strlcpy( gRootDevice, val, (cnt + 1));
1058 }
1059
1060 /*
1061 * Removed. We don't need this anymore.
1062 *
1063 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1064 getPlatformName(gPlatformName);
1065 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1066 }
1067 */
1068
1069 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1070 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1071 if (gBootMode & kBootModeSafe) {
1072 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1073 }
1074 }
1075
1076 // Store the merged kernel flags and boot args.
1077
1078 cnt = strlen(configKernelFlags);
1079 if (cnt) {
1080 if (cnt > cntRemaining) {
1081 error("Warning: boot arguments too long, truncating\n");
1082 cnt = cntRemaining;
1083 }
1084 strncpy(argP, configKernelFlags, cnt);
1085 argP[cnt++] = ' ';
1086 cntRemaining -= cnt;
1087 }
1088 userCnt = strlen(cp);
1089 if (userCnt > cntRemaining) {
1090error("Warning: boot arguments too long, truncating\n");
1091userCnt = cntRemaining;
1092 }
1093 strncpy(&argP[cnt], cp, userCnt);
1094 argP[cnt+userCnt] = '\0';
1095
1096if(!shouldboot)
1097{
1098gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1099getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1100
1101gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1102kBootModeSafe : kBootModeNormal;
1103
1104 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1105 gBootMode = kBootModeSafe;
1106}
1107}
1108
1109if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1110{
1111strlcpy(gMKextName, val, cnt + 1);
1112}
1113
1114 free(configKernelFlags);
1115 free(valueBuffer);
1116
1117 return 0;
1118}
1119
1120#ifndef OPTION_ROM
1121
1122//==========================================================================
1123// Load the help file and display the file contents on the screen.
1124
1125void showTextBuffer(char *buf, int size)
1126{
1127char*bp;
1128intline;
1129intline_offset;
1130intc;
1131
1132
1133bp = buf;
1134while (size-- > 0) {
1135if (*bp == '\n') {
1136*bp = '\0';
1137}
1138bp++;
1139}
1140*bp = '\1';
1141line_offset = 0;
1142
1143setActiveDisplayPage(1);
1144
1145while (1) {
1146clearScreenRows(0, 24);
1147setCursorPosition(0, 0, 1);
1148bp = buf;
1149for (line = 0; *bp != '\1' && line < line_offset; line++) {
1150while (*bp != '\0') {
1151bp++;
1152}
1153bp++;
1154}
1155for (line = 0; *bp != '\1' && line < 23; line++) {
1156setCursorPosition(0, line, 1);
1157printf("%s\n", bp);
1158while (*bp != '\0') {
1159bp++;
1160}
1161bp++;
1162}
1163
1164setCursorPosition(0, 23, 1);
1165if (*bp == '\1') {
1166printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1167} else {
1168printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1169}
1170
1171c = getc();
1172if (c == 'q' || c == 'Q') {
1173break;
1174}
1175if ((c == 'p' || c == 'P') && line_offset > 0) {
1176line_offset -= 23;
1177}
1178if (c == ' ') {
1179if (*bp == '\1') {
1180break;
1181} else {
1182line_offset += 23;
1183}
1184}
1185}
1186setActiveDisplayPage(0);
1187}
1188
1189void showHelp(void)
1190{
1191showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1192}
1193
1194void showTextFile(const char * filename)
1195{
1196#define MAX_TEXT_FILE_SIZE 65536
1197char*buf;
1198intfd;
1199intsize;
1200
1201if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1202printf("\nFile not found: %s\n", filename);
1203sleep(2);
1204return;
1205}
1206
1207size = file_size(fd);
1208if (size > MAX_TEXT_FILE_SIZE) {
1209size = MAX_TEXT_FILE_SIZE;
1210}
1211buf = malloc(size);
1212read(fd, buf, size);
1213close(fd);
1214showTextBuffer(buf, size);
1215free(buf);
1216}
1217#endif
1218
1219// This is a very simplistic prompting scheme that just grabs two hex characters
1220// Eventually we need to do something more user-friendly like display a menu
1221// based off of the Multiboot device list
1222#ifdef UNUSED
1223int selectAlternateBootDevice(int bootdevice)
1224{
1225int key;
1226int newbootdevice;
1227int digitsI = 0;
1228char *end;
1229char digits[3] = {0,0,0};
1230
1231// We've already printed the current boot device so user knows what it is
1232printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1233printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1234do {
1235key = getc();
1236switch (key & kASCIIKeyMask) {
1237case kBackspaceKey:
1238if (digitsI > 0) {
1239int x, y, t;
1240getCursorPositionAndType(&x, &y, &t);
1241// Assume x is not 0;
1242x--;
1243setCursorPosition(x,y,0); // back up one char
1244 // Overwrite with space without moving cursor position
1245putca(' ', 0x07, 1);
1246digitsI--;
1247} else {
1248// TODO: Beep or something
1249}
1250break;
1251
1252case kReturnKey:
1253digits[digitsI] = '\0';
1254newbootdevice = strtol(digits, &end, 16);
1255if (end == digits && *end == '\0') {
1256// User entered empty string
1257printf("\nUsing default boot device %x\n", bootdevice);
1258key = 0;
1259} else if(end != digits && *end == '\0') {
1260bootdevice = newbootdevice;
1261printf("\n");
1262key = 0; // We gots da boot device
1263} else {
1264printf("\nCouldn't parse. try again: ");
1265digitsI = 0;
1266}
1267break;
1268
1269default:
1270if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1271putc(key & kASCIIKeyMask);
1272digits[digitsI++] = key & kASCIIKeyMask;
1273} else {
1274// TODO: Beep or something
1275}
1276break;
1277};
1278} while (key != 0);
1279
1280return bootdevice;
1281}
1282#endif
1283
1284#ifdef OPTION_ROM
1285bool promptForRescanOption(void)
1286{
1287printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1288if (getc() == kReturnKey) {
1289return true;
1290} else {
1291return false;
1292}
1293}
1294#endif
1295

Archive Download this file

Revision: 535