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 unsigned 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
335if ( 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;
353default:
354break;
355}
356
357 if ( draw.w )
358 {
359 if ( draw.f.scrollUp )
360 {
361 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1);
362 gMenuTop++; gMenuBottom++;
363gMenuStart++; gMenuEnd++;
364 draw.f.selectionDown = 1;
365 }
366
367 if ( draw.f.scrollDown )
368 {
369 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1);
370 gMenuTop--; gMenuBottom--;
371 gMenuStart--; gMenuEnd--;
372 draw.f.selectionUp = 1;
373 }
374
375 if ( draw.f.selectionUp || draw.f.selectionDown )
376 {
377
378CursorState cursorState;
379
380// Set cursor at current position, and clear inverse video.
381changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
382printMenuItem( &gMenuItems[gMenuSelection], 0 );
383
384if ( draw.f.selectionUp )
385{
386gMenuSelection--;
387if(( gMenuSelection - gMenuStart) == -1 )
388{
389gMenuStart--;
390gMenuEnd--;
391}
392
393} else {
394gMenuSelection++;
395if(( gMenuSelection - ( gMenuEnd - 1) - gMenuStart) > 0 )
396{
397gMenuStart++;
398gMenuEnd++;
399}
400}
401
402moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
403printMenuItem( &gMenuItems[gMenuSelection], 1 );
404restoreCursor( &cursorState );
405
406}
407
408 *paramPtr = gMenuItems[gMenuSelection].param;
409 moved = 1;
410 }
411
412return moved;
413}
414
415//==========================================================================
416
417static void skipblanks( const char ** cpp )
418{
419 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
420}
421
422//==========================================================================
423
424static const char * extractKernelName( char ** cpp )
425{
426 char * kn = *cpp;
427 char * cp = *cpp;
428 char c;
429
430 // Convert char to lower case.
431
432 c = *cp | 0x20;
433
434 // Must start with a letter or a '/'.
435
436 if ( (c < 'a' || c > 'z') && ( c != '/' ) ) return 0;
437
438 // Keep consuming characters until we hit a separator.
439
440 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
441{
442 cp++;
443}
444 // Only SPACE or TAB separator is accepted.
445 // Reject everything else.
446
447 if (*cp == '=') return 0;
448
449 // Overwrite the separator, and move the pointer past
450 // the kernel name.
451
452 if (*cp != '\0') *cp++ = '\0';
453 *cpp = cp;
454
455 return kn;
456}
457
458#ifndef OPTION_ROM
459//==========================================================================
460
461void printMemoryInfo(void)
462{
463 int line;
464 unsigned long i;
465 MemoryRange *mp = bootInfo->memoryMap;
466
467 // Activate and clear page 1
468 setActiveDisplayPage(1);
469 clearScreenRows(0, 24);
470 setCursorPosition( 0, 0, 1 );
471
472 printf("BIOS reported memory ranges:\n");
473 line = 1;
474 for (i=0; i<bootInfo->memoryMapCount; i++) {
475 printf("Base 0x%08x%08x, ",
476 (unsigned long)(mp->base >> 32),
477 (unsigned long)(mp->base));
478 printf("length 0x%08x%08x, type %d\n",
479 (unsigned long)(mp->length >> 32),
480 (unsigned long)(mp->length),
481 mp->type);
482 if (line++ > 20) {
483 pause();
484 line = 0;
485 }
486 mp++;
487 }
488 if (line > 0) {
489 pause();
490 }
491
492 setActiveDisplayPage(0);
493}
494
495char *getMemoryInfoString()
496{
497 unsigned long i;
498 MemoryRange *mp = bootInfo->memoryMap;
499char *buff = malloc(sizeof(char)*1024);
500if(!buff) return 0;
501
502char info[] = "BIOS reported memory ranges:\n";
503sprintf(buff, "%s", info);
504 for (i=0; i<bootInfo->memoryMapCount; i++) {
505 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
506(unsigned long)(mp->base >> 32),
507(unsigned long)(mp->base));
508 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
509(unsigned long)(mp->length >> 32),
510(unsigned long)(mp->length),
511mp->type);
512 mp++;
513 }
514return buff;
515}
516//==========================================================================
517
518void lspci(void)
519{
520if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
521setActiveDisplayPage(1);
522clearScreenRows(0, 24);
523setCursorPosition(0, 0, 1);
524}
525
526dump_pci_dt(root_pci_dev->children);
527
528pause();
529
530if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
531setActiveDisplayPage(0);
532}
533}
534#endif
535
536//==========================================================================
537
538int getBootOptions(bool firstRun)
539{
540int i;
541int key;
542int nextRow;
543int timeout;
544#if UNUSED
545int bvCount;
546#endif
547BVRef bvr;
548BVRef menuBVR;
549bool showPrompt, newShowPrompt, isCDROM;
550
551// Initialize default menu selection entry.
552gBootVolume = menuBVR = selectBootVolume(bvChain);
553
554if (biosDevIsCDROM(gBIOSDev)) {
555isCDROM = true;
556} else {
557isCDROM = false;
558}
559
560// Clear command line boot arguments
561clearBootArgs();
562
563// Allow user to override default timeout.
564#if UNUSED
565if (multiboot_timeout_set) {
566timeout = multiboot_timeout;
567} else
568#endif
569if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
570/* If there is no timeout key in the file use the default timeout
571 which is different for CDs vs. hard disks. However, if not booting
572 a CD and no config file could be loaded set the timeout
573 to zero which causes the menu to display immediately.
574 This way, if no partitions can be found, that is the disk is unpartitioned
575 or simply cannot be read) then an empty menu is displayed.
576 If some partitions are found, for example a Windows partition, then
577 these will be displayed in the menu as foreign partitions.
578 */
579if (isCDROM) {
580timeout = kCDBootTimeout;
581} else {
582timeout = sysConfigValid ? kBootTimeout : 0;
583}
584}
585
586if (timeout < 0) {
587gBootMode |= kBootModeQuiet;
588}
589
590// If the user is holding down a modifier key, enter safe mode.
591if ((readKeyboardShiftFlags() & 0x0F) != 0) {
592
593//gBootMode |= kBootModeSafe;
594}
595
596// Checking user pressed keys
597bool f8press = false, spress = false, vpress = false;
598while (readKeyboardStatus()) {
599key = bgetc ();
600if (key == 0x4200) f8press = true;
601if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
602if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
603}
604// If user typed F8, abort quiet mode, and display the menu.
605if (f8press) {
606gBootMode &= ~kBootModeQuiet;
607timeout = 0;
608}
609// If user typed 'v' or 'V', boot in verbose mode.
610if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
611addBootArg(kVerboseModeFlag);
612}
613// If user typed 's' or 'S', boot in single user mode.
614if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
615addBootArg(kSingleUserModeFlag);
616}
617
618setCursorPosition(0, 0, 0);
619clearScreenRows(0, kScreenLastRow);
620if (!(gBootMode & kBootModeQuiet)) {
621// Display banner and show hardware info.
622printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
623}
624changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
625verbose("Scanning device %x...", gBIOSDev);
626
627// When booting from CD, default to hard drive boot when possible.
628if (isCDROM && firstRun) {
629const char *val;
630char *prompt = NULL;
631char *name = NULL;
632int cnt;
633int optionKey;
634
635if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig)) {
636prompt = malloc(cnt + 1);
637strncat(prompt, val, cnt);
638} else {
639name = malloc(80);
640getBootVolumeDescription(gBootVolume, name, 79, false);
641prompt = malloc(256);
642sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
643free(name);
644}
645
646if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig )) {
647// The key specified is a special key.
648} else {
649// Default to F8.
650optionKey = 0x4200;
651}
652
653// If the timeout is zero then it must have been set above due to the
654// early catch of F8 which means the user wants to set boot options
655// which we ought to interpret as meaning he wants to boot the CD.
656if (timeout != 0) {
657key = countdown(prompt, kMenuTopRow, timeout);
658} else {
659key = optionKey;
660}
661
662if (prompt != NULL) {
663free(prompt);
664}
665
666clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
667
668// Hit the option key ?
669if (key == optionKey) {
670gBootMode &= ~kBootModeQuiet;
671timeout = 0;
672} else {
673key = key & 0xFF;
674
675// Try booting hard disk if user pressed 'h'
676if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
677BVRef bvr;
678
679// Look at partitions hosting OS X other than the CD-ROM
680for (bvr = bvChain; bvr; bvr=bvr->next) {
681if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
682gBootVolume = bvr;
683}
684}
685}
686goto done;
687}
688}
689
690if (gBootMode & kBootModeQuiet) {
691// No input allowed from user.
692goto done;
693}
694
695if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
696// If the user is holding down a modifier key,
697// enter safe mode.
698if ((readKeyboardShiftFlags() & 0x0F) != 0) {
699gBootMode |= kBootModeSafe;
700}
701goto done;
702}
703
704if (gDeviceCount) {
705// Allocate memory for an array of menu items.
706menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
707if (menuItems == NULL) {
708goto done;
709}
710
711// Associate a menu item for each BVRef.
712for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
713if (bvr->visible) {
714getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
715menuItems[i].param = (void *) bvr;
716if (bvr == menuBVR) {
717selectIndex = i;
718}
719i--;
720}
721}
722}
723
724// Clear screen and hide the blinking cursor.
725clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
726changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
727
728nextRow = kMenuTopRow;
729showPrompt = true;
730
731if (gDeviceCount) {
732printf("Use \30\31 keys to select the startup volume.");
733showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
734nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
735}
736
737// Show the boot prompt.
738showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
739showBootPrompt( nextRow, showPrompt );
740
741do {
742key = getc();
743updateMenu( key, (void **) &menuBVR );
744newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
745
746if (newShowPrompt != showPrompt)
747{
748showPrompt = newShowPrompt;
749showBootPrompt( nextRow, showPrompt );
750}
751
752if (showPrompt)
753{
754updateBootArgs(key);
755}
756
757switch (key) {
758case kReturnKey:
759if (*gBootArgs == '?') {
760char * argPtr = gBootArgs;
761
762// Skip the leading "?" character.
763argPtr++;
764getNextArg(&argPtr, booterCommand);
765getNextArg(&argPtr, booterParam);
766
767/*
768 * TODO: this needs to be refactored.
769 */
770#ifndef OPTION_ROM
771#if UNUSED
772if (strcmp( booterCommand, "video" ) == 0)
773{
774printVBEModeInfo();
775}
776else
777#endif
778if ( strcmp( booterCommand, "memory" ) == 0)
779{
780printMemoryInfo();
781}
782else if (strcmp(booterCommand, "lspci") == 0)
783{
784lspci();
785}
786else if (strcmp(booterCommand, "more") == 0)
787{
788showTextFile(booterParam);
789}
790else if (strcmp(booterCommand, "rd") == 0)
791{
792if (execute_hook("processRAMDiskCommand", (void*)argPtr, &booterParam, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
793showMessage("ramdisk module not found, please install RamdiskLoader.dylib in /Extra/modules/");
794}
795else if (strcmp(booterCommand, "norescan") == 0)
796{
797if (gEnableCDROMRescan)
798{
799gEnableCDROMRescan = false;
800break;
801}
802}
803else
804{
805showHelp();
806}
807#endif
808key = 0;
809showBootPrompt(nextRow, showPrompt);
810break;
811}
812gBootVolume = menuBVR;
813setRootVolume(menuBVR);
814gBIOSDev = menuBVR->biosdev;
815break;
816
817case kEscapeKey:
818clearBootArgs();
819break;
820#ifndef OPTION_ROM
821case kF5Key:
822// New behavior:
823// Clear gBootVolume to restart the loop
824// if the user enabled rescanning the optical drive.
825// Otherwise boot the default boot volume.
826if (gEnableCDROMRescan) {
827gBootVolume = NULL;
828clearBootArgs();
829}
830break;
831
832case kF10Key:
833gScanSingleDrive = false;
834#if UNUSED
835 scanDisks(gBIOSDev, &bvCount);
836#else
837 scanDisks();
838#endif
839gBootVolume = NULL;
840clearBootArgs();
841break;
842#endif
843default:
844key = 0;
845break;
846}
847} while (0 == key);
848
849done:
850if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
851clearScreenRows(kMenuTopRow, kScreenLastRow);
852changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
853}
854shouldboot = false;
855if (menuItems) {
856free(menuItems);
857menuItems = NULL;
858}
859return 0;
860}
861
862//==========================================================================
863
864extern unsigned char chainbootdev;
865extern unsigned char chainbootflag;
866
867bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
868{
869 int argLen = argName ? strlen(argName) : 0;
870 int len = argLen + cnt + 1; // +1 to account for space
871
872 if (len > *cntRemainingP) {
873 error("Warning: boot arguments too long, truncating\n");
874 return false;
875 }
876
877 if (argName) {
878 strncpy( *argP, argName, argLen );
879 *argP += argLen;
880 *argP[0] = '=';
881 (*argP)++;
882 len++; // +1 to account for '='
883 }
884 strncpy( *argP, val, cnt );
885 *argP += cnt;
886 *argP[0] = ' ';
887 (*argP)++;
888
889 *cntRemainingP -= len;
890 return true;
891}
892
893int ArgCntRemaining;
894
895int
896processBootOptions()
897{
898 const char * cp = gBootArgs;
899 const char * val = 0;
900 const char * kernel;
901 int cnt;
902 int userCnt;
903 char * argP;
904 char * configKernelFlags;
905
906 skipblanks( &cp );
907
908 // Update the unit and partition number.
909
910 if ( gBootVolume )
911 {
912 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
913 {
914 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
915 (void *) 0x7c00 );
916
917 //
918 // Setup edx, and signal intention to chain load the
919 // foreign booter.
920 //
921
922 chainbootdev = gBootVolume->biosdev;
923 chainbootflag = 1;
924
925 return 1;
926 }
927
928 setRootVolume(gBootVolume);
929
930 }
931 // If no boot volume fail immediately because we're just going to fail
932 // trying to load the config file anyway.
933 else
934return -1;
935
936 // Load config table specified by the user, or use the default.
937
938 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
939val = 0;
940cnt = 0;
941 }
942
943 // Load com.apple.Boot.plist from the selected volume
944 // and use its contents to override default bootConfig.
945 // This is not a mandatory opeartion anymore.
946
947 loadOverrideConfig(&bootInfo->overrideConfig);
948
949 // Use the kernel name specified by the user, or fetch the name
950 // in the config table, or use the default if not specified.
951 // Specifying a kernel name on the command line, or specifying
952 // a non-default kernel name in the config file counts as
953 // overriding the kernel, which causes the kernelcache not
954 // to be used.
955
956 gOverrideKernel = false;
957 if (( kernel = extractKernelName((char **)&cp) )) {
958 strcpy( bootInfo->bootFile, kernel );
959 gOverrideKernel = true;
960 } else {
961 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
962 strlcpy( bootInfo->bootFile, val, cnt+1 );
963 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
964 gOverrideKernel = true;
965 }
966 } else {
967 strcpy( bootInfo->bootFile, kDefaultKernel );
968 }
969 }
970
971 ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
972 argP = bootArgs->CommandLine;
973
974 // Get config table kernel flags, if not ignored.
975 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
976!getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
977 val = "";
978 cnt = 0;
979 }
980
981 configKernelFlags = malloc(cnt + 1);
982 strlcpy(configKernelFlags, val, cnt + 1);
983
984
985 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
986 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
987 if (gBootMode & kBootModeSafe) {
988 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining);
989 }
990 }
991
992 // Store the merged kernel flags and boot args.
993
994 cnt = strlen(configKernelFlags);
995 if (cnt) {
996 if (cnt > ArgCntRemaining) {
997 error("Warning: boot arguments too long, truncating\n");
998 cnt = ArgCntRemaining;
999 }
1000 strncpy(argP, configKernelFlags, cnt);
1001 argP[cnt++] = ' ';
1002 ArgCntRemaining -= cnt;
1003 }
1004 userCnt = strlen(cp);
1005 if (userCnt > ArgCntRemaining) {
1006error("Warning: boot arguments too long, truncating\n");
1007userCnt = ArgCntRemaining;
1008 }
1009 strncpy(&argP[cnt], cp, userCnt);
1010 argP[cnt+userCnt] = '\0';
1011
1012if(!shouldboot)
1013{
1014gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1015getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1016
1017gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1018kBootModeSafe : kBootModeNormal;
1019
1020 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1021 gBootMode = kBootModeSafe;
1022}
1023}
1024
1025if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1026{
1027strlcpy(gMKextName, val, cnt + 1);
1028}
1029
1030 free(configKernelFlags);
1031
1032 return 0;
1033}
1034
1035#ifndef OPTION_ROM
1036
1037//==========================================================================
1038// Load the help file and display the file contents on the screen.
1039
1040void showTextBuffer(char *buf, int size)
1041{
1042char*bp;
1043intline;
1044intline_offset;
1045intc;
1046
1047
1048bp = buf;
1049while (size-- > 0) {
1050if (*bp == '\n') {
1051*bp = '\0';
1052}
1053bp++;
1054}
1055*bp = '\1';
1056line_offset = 0;
1057
1058setActiveDisplayPage(1);
1059
1060while (1) {
1061clearScreenRows(0, 24);
1062setCursorPosition(0, 0, 1);
1063bp = buf;
1064for (line = 0; *bp != '\1' && line < line_offset; line++) {
1065while (*bp != '\0') {
1066bp++;
1067}
1068bp++;
1069}
1070for (line = 0; *bp != '\1' && line < 23; line++) {
1071setCursorPosition(0, line, 1);
1072printf("%s\n", bp);
1073while (*bp != '\0') {
1074bp++;
1075}
1076bp++;
1077}
1078
1079setCursorPosition(0, 23, 1);
1080if (*bp == '\1') {
1081printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1082} else {
1083printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1084}
1085
1086c = getc();
1087if (c == 'q' || c == 'Q') {
1088break;
1089}
1090if ((c == 'p' || c == 'P') && line_offset > 0) {
1091line_offset -= 23;
1092}
1093if (c == ' ') {
1094if (*bp == '\1') {
1095break;
1096} else {
1097line_offset += 23;
1098}
1099}
1100}
1101setActiveDisplayPage(0);
1102}
1103
1104void showHelp(void)
1105{
1106#if EMBED_HELP==0
1107int fd = -1;
1108char dirspec[512];
1109char filename[512];
1110sprintf(filename, "BootHelp.txt");
1111
1112// Check Extra on booting partition
1113sprintf(dirspec,"/Extra/%s",filename);
1114fd=open (dirspec);
1115if (fd<0)
1116{// Fall back to booter partition
1117sprintf(dirspec,"bt(0,0)/Extra/%s",filename);
1118fd=open (dirspec);
1119if (fd<0)
1120{
1121printf("BootHelp not found: %s\n", filename);
1122return;
1123}
1124}
1125int BootHelp_txt_len = file_size (fd);
1126void *BootHelp_txt=malloc(BootHelp_txt_len);
1127if (BootHelp_txt)
1128{
1129if (read (fd, BootHelp_txt, BootHelp_txt_len)!=BootHelp_txt_len)
1130{
1131printf("Couldn't read BootHelp %s\n",dirspec);
1132free (BootHelp_txt);
1133close (fd);
1134return;
1135}
1136
1137close (fd);
1138}
1139#endif
1140showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1141}
1142
1143void showMessage(char * message)
1144{
1145showTextBuffer(message, strlen(message));
1146}
1147
1148void showTextFile(const char * filename)
1149{
1150#define MAX_TEXT_FILE_SIZE 65536
1151char*buf;
1152intfd;
1153intsize;
1154
1155if ((fd = open_bvdev("bt(0,0)", filename)) < 0) {
1156printf("\nFile not found: %s\n", filename);
1157sleep(2);
1158return;
1159}
1160
1161size = file_size(fd);
1162if (size > MAX_TEXT_FILE_SIZE) {
1163size = MAX_TEXT_FILE_SIZE;
1164}
1165buf = malloc(size);
1166read(fd, buf, size);
1167close(fd);
1168showTextBuffer(buf, size);
1169free(buf);
1170}
1171#endif
1172
1173#ifndef OPTION_ROM
1174bool promptForRescanOption(void)
1175{
1176printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1177if (getc() == kReturnKey) {
1178return true;
1179} else {
1180return false;
1181}
1182}
1183#endif
1184

Archive Download this file

Revision: 1119