Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 521