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
57//==========================================================================
58
59void changeCursor( int col, int row, int type, CursorState * cs )
60{
61 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
62 setCursorType( type );
63 setCursorPosition( col, row, 0 );
64}
65
66void moveCursor( int col, int row )
67{
68 setCursorPosition( col, row, 0 );
69}
70
71void restoreCursor( const CursorState * cs )
72{
73 setCursorPosition( cs->x, cs->y, 0 );
74 setCursorType( cs->type );
75}
76
77//==========================================================================
78
79/* Flush keyboard buffer; returns TRUE if any of the flushed
80 * characters was F8.
81 */
82
83bool flushKeyboardBuffer(void)
84{
85 bool status = false;
86
87 while ( readKeyboardStatus() ) {
88 if (bgetc() == 0x4200) status = true;
89 }
90 return status;
91}
92
93//==========================================================================
94
95static int countdown( const char * msg, int row, int timeout )
96{
97 unsigned long time;
98 int ch = 0;
99 int col = strlen(msg) + 1;
100
101 flushKeyboardBuffer();
102
103moveCursor( 0, row );
104printf(msg);
105
106int multi_buff = 18 * (timeout);
107 int multi = ++multi_buff;
108
109 int lasttime=0;
110
111 for ( time = time18(), timeout++; timeout > 0; )
112 {
113if( time18() > lasttime)
114{
115multi--;
116lasttime=time18();
117}
118
119 if (ch = readKeyboardStatus())
120 break;
121
122 // Count can be interrupted by holding down shift,
123 // control or alt key
124 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
125{
126 ch = 1;
127 break;
128 }
129
130 if ( time18() >= time )
131 {
132 time += 18;
133 timeout--;
134
135moveCursor( col, row );
136printf("(%d) ", timeout);
137 }
138 }
139
140 flushKeyboardBuffer();
141
142 return ch;
143}
144
145//==========================================================================
146
147 char gBootArgs[BOOT_STRING_LEN];
148 char * gBootArgsPtr = gBootArgs;
149 char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
150 char booterCommand[BOOT_STRING_LEN];
151 char booterParam[BOOT_STRING_LEN];
152
153void clearBootArgs(void)
154{
155gBootArgsPtr = gBootArgs;
156memset(gBootArgs, '\0', BOOT_STRING_LEN);
157}
158
159void addBootArg(const char * argStr)
160{
161if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
162{
163*gBootArgsPtr++ = ' ';
164strcat(gBootArgs, argStr);
165gBootArgsPtr += strlen(argStr);
166}
167}
168
169//==========================================================================
170
171static void showBootPrompt(int row, bool visible)
172{
173extern char bootPrompt[];
174#ifndef OPTION_ROM
175extern char bootRescanPrompt[];
176#endif
177
178changeCursor( 0, row, kCursorTypeUnderline, 0 );
179clearScreenRows( row, kScreenLastRow );
180
181clearBootArgs();
182
183if (visible) {
184#ifndef OPTION_ROM
185if (gEnableCDROMRescan)
186{
187printf( bootRescanPrompt );
188}
189else
190#endif
191{
192printf( bootPrompt );
193}
194} else {
195printf("Press Enter to start up the foreign OS. ");
196}
197}
198
199//==========================================================================
200
201static void updateBootArgs( int key )
202{
203 key &= kASCIIKeyMask;
204
205 switch ( key )
206 {
207 case kBackspaceKey:
208 if ( gBootArgsPtr > gBootArgs )
209 {
210 int x, y, t;
211 getCursorPositionAndType( &x, &y, &t );
212 if ( x == 0 && y )
213 {
214 x = 80; y--;
215 }
216 if (x)
217{
218x--;
219}
220
221setCursorPosition( x, y, 0 );
222putca(' ', 0x07, 1);
223
224*gBootArgsPtr-- = '\0';
225}
226
227break;
228
229 default:
230 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
231 {
232putchar(key); // echo to screen
233*gBootArgsPtr++ = key;
234}
235
236break;
237 }
238}
239
240//==========================================================================
241
242 const MenuItem * gMenuItems = NULL;
243
244 int gMenuItemCount;
245 int gMenuRow;
246 int gMenuHeight;
247 int gMenuTop;
248 int gMenuBottom;
249 int gMenuSelection;
250
251 int gMenuStart;
252 int gMenuEnd;
253
254void printMenuItem( const MenuItem * item, int highlight )
255{
256 printf(" ");
257
258 if ( highlight )
259 putca(' ', 0x70, strlen(item->name) + 4);
260 else
261 putca(' ', 0x07, 40);
262
263 printf(" %40s\n", item->name);
264}
265
266//==========================================================================
267
268static void showMenu( const MenuItem * items, int count,
269 int selection, int row, int height )
270{
271 int i;
272 CursorState cursorState;
273
274 if ( items == NULL || count == 0 )
275return;
276
277 // head and tail points to the start and the end of the list.
278 // top and bottom points to the first and last visible items
279 // in the menu window.
280
281 gMenuItems= items;
282 gMenuRow= row;
283 gMenuHeight= height;
284 gMenuItemCount= count;
285 gMenuTop= 0;
286 gMenuBottom= min( count, height ) - 1;
287 gMenuSelection= selection;
288
289 gMenuStart= 0;
290 gMenuEnd = count; //min( count, gui.maxdevices ) - 1;
291
292// If the selected item is not visible, shift the list down.
293
294 if ( gMenuSelection > gMenuBottom )
295 {
296 gMenuTop += ( gMenuSelection - gMenuBottom );
297 gMenuBottom = gMenuSelection;
298 }
299
300if ( gMenuSelection > gMenuEnd )
301 {
302gMenuStart += ( gMenuSelection - gMenuEnd );
303 gMenuEnd = gMenuSelection;
304 }
305
306// Draw the visible items.
307
308changeCursor( 0, row, kCursorTypeHidden, &cursorState );
309
310for ( i = gMenuTop; i <= gMenuBottom; i++ )
311{
312printMenuItem( &items[i], (i == gMenuSelection) );
313}
314
315restoreCursor( &cursorState );
316}
317
318//==========================================================================
319
320static int updateMenu( int key, void ** paramPtr )
321{
322 int moved = 0;
323
324 union {
325 struct {
326 unsigned int
327selectionUp : 1,
328selectionDown : 1,
329scrollUp : 1,
330scrollDown : 1;
331 } f;
332 unsigned int w;
333 } draw = {{0}};
334
335 if ( gMenuItems == NULL )
336return 0;
337
338switch ( key )
339{
340case 0x4800: // Up Arrow
341if ( gMenuSelection != gMenuTop )
342draw.f.selectionUp = 1;
343else if ( gMenuTop > 0 )
344draw.f.scrollDown = 1;
345break;
346
347case 0x5000: // Down Arrow
348if ( gMenuSelection != gMenuBottom )
349draw.f.selectionDown = 1;
350else if ( gMenuBottom < (gMenuItemCount - 1) )
351draw.f.scrollUp = 1;
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 int 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 int 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#ifndef OPTION_ROM
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) == 0)
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;
832scanDisks(gBIOSDev, &bvCount);
833gBootVolume = NULL;
834clearBootArgs();
835break;
836#endif
837default:
838key = 0;
839break;
840}
841} while (0 == key);
842
843done:
844if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
845clearScreenRows(kMenuTopRow, kScreenLastRow);
846changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
847}
848shouldboot = false;
849if (menuItems) {
850free(menuItems);
851menuItems = NULL;
852}
853return 0;
854}
855
856//==========================================================================
857
858extern unsigned char chainbootdev;
859extern unsigned char chainbootflag;
860
861bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
862{
863 int argLen = argName ? strlen(argName) : 0;
864 int len = argLen + cnt + 1; // +1 to account for space
865
866 if (len > *cntRemainingP) {
867 error("Warning: boot arguments too long, truncating\n");
868 return false;
869 }
870
871 if (argName) {
872 strncpy( *argP, argName, argLen );
873 *argP += argLen;
874 *argP[0] = '=';
875 (*argP)++;
876 len++; // +1 to account for '='
877 }
878 strncpy( *argP, val, cnt );
879 *argP += cnt;
880 *argP[0] = ' ';
881 (*argP)++;
882
883 *cntRemainingP -= len;
884 return true;
885}
886
887int ArgCntRemaining;
888
889int
890processBootOptions()
891{
892 const char * cp = gBootArgs;
893 const char * val = 0;
894 const char * kernel;
895 int cnt;
896 int userCnt;
897 char * argP;
898 char * configKernelFlags;
899
900 skipblanks( &cp );
901
902 // Update the unit and partition number.
903
904 if ( gBootVolume )
905 {
906 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
907 {
908 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
909 (void *) 0x7c00 );
910
911 //
912 // Setup edx, and signal intention to chain load the
913 // foreign booter.
914 //
915
916 chainbootdev = gBootVolume->biosdev;
917 chainbootflag = 1;
918
919 return 1;
920 }
921
922 setRootVolume(gBootVolume);
923
924 }
925 // If no boot volume fail immediately because we're just going to fail
926 // trying to load the config file anyway.
927 else
928return -1;
929
930 // Load config table specified by the user, or use the default.
931
932 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
933val = 0;
934cnt = 0;
935 }
936
937 // Load com.apple.Boot.plist from the selected volume
938 // and use its contents to override default bootConfig.
939 // This is not a mandatory opeartion anymore.
940
941 loadOverrideConfig(&bootInfo->overrideConfig);
942
943 // Use the kernel name specified by the user, or fetch the name
944 // in the config table, or use the default if not specified.
945 // Specifying a kernel name on the command line, or specifying
946 // a non-default kernel name in the config file counts as
947 // overriding the kernel, which causes the kernelcache not
948 // to be used.
949
950 gOverrideKernel = false;
951 if (( kernel = extractKernelName((char **)&cp) )) {
952 strcpy( bootInfo->bootFile, kernel );
953 gOverrideKernel = true;
954 } else {
955 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
956 strlcpy( bootInfo->bootFile, val, cnt+1 );
957 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
958 gOverrideKernel = true;
959 }
960 } else {
961 strcpy( bootInfo->bootFile, kDefaultKernel );
962 }
963 }
964
965 ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
966 argP = bootArgs->CommandLine;
967
968 // Get config table kernel flags, if not ignored.
969 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
970!getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
971 val = "";
972 cnt = 0;
973 }
974
975 configKernelFlags = malloc(cnt + 1);
976 strlcpy(configKernelFlags, val, cnt + 1);
977
978
979 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
980 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
981 if (gBootMode & kBootModeSafe) {
982 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining);
983 }
984 }
985
986 // Store the merged kernel flags and boot args.
987
988 cnt = strlen(configKernelFlags);
989 if (cnt) {
990 if (cnt > ArgCntRemaining) {
991 error("Warning: boot arguments too long, truncating\n");
992 cnt = ArgCntRemaining;
993 }
994 strncpy(argP, configKernelFlags, cnt);
995 argP[cnt++] = ' ';
996 ArgCntRemaining -= cnt;
997 }
998 userCnt = strlen(cp);
999 if (userCnt > ArgCntRemaining) {
1000error("Warning: boot arguments too long, truncating\n");
1001userCnt = ArgCntRemaining;
1002 }
1003 strncpy(&argP[cnt], cp, userCnt);
1004 argP[cnt+userCnt] = '\0';
1005
1006if(!shouldboot)
1007{
1008gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1009getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1010
1011gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1012kBootModeSafe : kBootModeNormal;
1013
1014 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1015 gBootMode = kBootModeSafe;
1016}
1017}
1018
1019if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1020{
1021strlcpy(gMKextName, val, cnt + 1);
1022}
1023
1024 free(configKernelFlags);
1025
1026 return 0;
1027}
1028
1029#ifndef OPTION_ROM
1030
1031//==========================================================================
1032// Load the help file and display the file contents on the screen.
1033
1034void showTextBuffer(char *buf, int size)
1035{
1036char*bp;
1037intline;
1038intline_offset;
1039intc;
1040
1041
1042bp = buf;
1043while (size-- > 0) {
1044if (*bp == '\n') {
1045*bp = '\0';
1046}
1047bp++;
1048}
1049*bp = '\1';
1050line_offset = 0;
1051
1052setActiveDisplayPage(1);
1053
1054while (1) {
1055clearScreenRows(0, 24);
1056setCursorPosition(0, 0, 1);
1057bp = buf;
1058for (line = 0; *bp != '\1' && line < line_offset; line++) {
1059while (*bp != '\0') {
1060bp++;
1061}
1062bp++;
1063}
1064for (line = 0; *bp != '\1' && line < 23; line++) {
1065setCursorPosition(0, line, 1);
1066printf("%s\n", bp);
1067while (*bp != '\0') {
1068bp++;
1069}
1070bp++;
1071}
1072
1073setCursorPosition(0, 23, 1);
1074if (*bp == '\1') {
1075printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1076} else {
1077printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1078}
1079
1080c = getc();
1081if (c == 'q' || c == 'Q') {
1082break;
1083}
1084if ((c == 'p' || c == 'P') && line_offset > 0) {
1085line_offset -= 23;
1086}
1087if (c == ' ') {
1088if (*bp == '\1') {
1089break;
1090} else {
1091line_offset += 23;
1092}
1093}
1094}
1095setActiveDisplayPage(0);
1096}
1097
1098void showHelp(void)
1099{
1100#if EMBED_HELP==0
1101int fd = -1;
1102char dirspec[512];
1103char filename[512];
1104sprintf(filename, "BootHelp.txt");
1105
1106// Check Extra on booting partition
1107sprintf(dirspec,"/Extra/%s",filename);
1108fd=open (dirspec,0);
1109if (fd<0)
1110{// Fall back to booter partition
1111sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
1112fd=open (dirspec,0);
1113if (fd<0)
1114{
1115printf("BootHelp not found: %s\n", filename);
1116return;
1117}
1118}
1119int BootHelp_txt_len = file_size (fd);
1120void *BootHelp_txt=malloc(BootHelp_txt_len);
1121if (BootHelp_txt)
1122{
1123if (read (fd, BootHelp_txt, BootHelp_txt_len)!=BootHelp_txt_len)
1124{
1125printf("Couldn't read BootHelp %s\n",dirspec);
1126free (BootHelp_txt);
1127close (fd);
1128return;
1129}
1130
1131close (fd);
1132}
1133#endif
1134showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1135}
1136
1137void showMessage(char * message)
1138{
1139showTextBuffer(message, strlen(message));
1140}
1141
1142void showTextFile(const char * filename)
1143{
1144#define MAX_TEXT_FILE_SIZE 65536
1145char*buf;
1146intfd;
1147intsize;
1148
1149if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1150printf("\nFile not found: %s\n", filename);
1151sleep(2);
1152return;
1153}
1154
1155size = file_size(fd);
1156if (size > MAX_TEXT_FILE_SIZE) {
1157size = MAX_TEXT_FILE_SIZE;
1158}
1159buf = malloc(size);
1160read(fd, buf, size);
1161close(fd);
1162showTextBuffer(buf, size);
1163free(buf);
1164}
1165#endif
1166
1167#ifndef OPTION_ROM
1168bool promptForRescanOption(void)
1169{
1170printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1171if (getc() == kReturnKey) {
1172return true;
1173} else {
1174return false;
1175}
1176}
1177#endif
1178

Archive Download this file

Revision: 789