Chameleon

Chameleon Svn Source Tree

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

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

Archive Download this file

Revision: 1654