Chameleon

Chameleon Svn Source Tree

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

  • Property svn:eol-style set to native
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 "fdisk.h"
28#include "ramdisk.h"
29#include "gui.h"
30#include "embedded.h"
31#include "pci.h"
32
33static bool shouldboot = false;
34
35extern int multiboot_timeout;
36extern int multiboot_timeout_set;
37
38extern BVRef bvChain;
39//extern intmenucount;
40
41extern intgDeviceCount;
42
43intselectIndex = 0;
44MenuItem * menuItems = NULL;
45
46enum {
47 kMenuTopRow = 5,
48 kMenuMaxItems = 10,
49 kScreenLastRow = 24
50};
51
52//==========================================================================
53
54typedef struct {
55 int x;
56 int y;
57 int type;
58} CursorState;
59
60static void changeCursor( int col, int row, int type, CursorState * cs )
61{
62 if (cs) getCursorPositionAndType( &cs->x, &cs->y, &cs->type );
63 setCursorType( type );
64 setCursorPosition( col, row, 0 );
65}
66
67static void moveCursor( int col, int row )
68{
69 setCursorPosition( col, row, 0 );
70}
71
72static void restoreCursor( const CursorState * cs )
73{
74 setCursorPosition( cs->x, cs->y, 0 );
75 setCursorType( cs->type );
76}
77
78//==========================================================================
79
80/* Flush keyboard buffer; returns TRUE if any of the flushed
81 * characters was F8.
82 */
83
84static bool flushKeyboardBuffer(void)
85{
86 bool status = false;
87
88 while ( readKeyboardStatus() ) {
89 if (bgetc() == 0x4200) status = true;
90 }
91 return status;
92}
93
94//==========================================================================
95
96static int countdown( const char * msg, int row, int timeout )
97{
98 unsigned long time;
99 int ch = 0;
100 int col = strlen(msg) + 1;
101
102 flushKeyboardBuffer();
103
104 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
105 {
106if( bootArgs->Video.v_display == VGA_TEXT_MODE )
107{
108moveCursor( 0, row );
109printf(msg);
110
111} else {
112
113position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
114
115char dummy[80];
116getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
117drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
118drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
119
120// make this screen the new background
121memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
122
123}
124} else {
125if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
126{
127moveCursor( 0, row );
128printf(msg);
129
130} else {
131
132position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
133
134char dummy[80];
135getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
136drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
137drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
138
139// make this screen the new background
140memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
141
142}
143}
144
145int multi_buff = 18 * (timeout);
146 int multi = ++multi_buff;
147
148 int lasttime=0;
149
150 for ( time = time18(), timeout++; timeout > 0; )
151 {
152if( time18() > lasttime)
153{
154multi--;
155lasttime=time18();
156}
157
158 if (ch = readKeyboardStatus())
159 break;
160
161 // Count can be interrupted by holding down shift,
162 // control or alt key
163 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
164{
165 ch = 1;
166 break;
167 }
168
169 if ( time18() >= time )
170 {
171 time += 18;
172 timeout--;
173
174 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
175 {
176if( bootArgs->Video.v_display == VGA_TEXT_MODE )
177{
178moveCursor( col, row );
179printf("(%d) ", timeout);
180}
181} else {
182if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
183{
184moveCursor( col, row );
185printf("(%d) ", timeout);
186}
187}
188 }
189
190 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
191 {
192if( bootArgs->Video.v_display == GRAPHICS_MODE )
193{
194drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
195gui.redraw = true;
196updateVRAM();
197}
198} else {
199if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
200{
201drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
202gui.redraw = true;
203updateVRAM();
204}
205}
206
207 }
208
209 flushKeyboardBuffer();
210
211 return ch;
212}
213
214//==========================================================================
215
216static char gBootArgs[BOOT_STRING_LEN];
217static char * gBootArgsPtr = gBootArgs;
218static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
219static char booterCommand[BOOT_STRING_LEN];
220static char booterParam[BOOT_STRING_LEN];
221
222static void clearBootArgs(void)
223{
224gBootArgsPtr = gBootArgs;
225memset(gBootArgs, '\0', BOOT_STRING_LEN);
226
227 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
228 {
229if (bootArgs->Video.v_display == GRAPHICS_MODE) {
230clearGraphicBootPrompt();
231}
232} else {
233if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
234clearGraphicBootPrompt();
235}
236}
237
238static void addBootArg(const char * argStr)
239{
240if ( (gBootArgsPtr + strlen(argStr) + 1) < gBootArgsEnd)
241{
242*gBootArgsPtr++ = ' ';
243strcat(gBootArgs, argStr);
244gBootArgsPtr += strlen(argStr);
245}
246}
247
248//==========================================================================
249
250static void showBootPrompt(int row, bool visible)
251{
252extern char bootPrompt[];
253extern char bootRescanPrompt[];
254
255 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
256 {
257if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
258changeCursor( 0, row, kCursorTypeUnderline, 0 );
259clearScreenRows( row, kScreenLastRow );
260}
261} else {
262if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
263{
264changeCursor( 0, row, kCursorTypeUnderline, 0 );
265clearScreenRows( row, kScreenLastRow );
266}
267}
268
269clearBootArgs();
270
271if (visible) {
272 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
273 {
274if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
275if (gEnableCDROMRescan) {
276printf( bootRescanPrompt );
277} else {
278printf( bootPrompt );
279}
280}
281} else {
282if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
283if (gEnableCDROMRescan)
284printf( bootRescanPrompt );
285else
286printf( bootPrompt );
287}
288} else {
289 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
290 {
291if (bootArgs->Video.v_display == GRAPHICS_MODE) {
292clearGraphicBootPrompt();
293} else {
294printf("Press Enter to start up the foreign OS. ");
295}
296} else {
297if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
298clearGraphicBootPrompt();
299else
300printf("Press Enter to start up the foreign OS. ");
301}
302}
303}
304
305//==========================================================================
306
307static void updateBootArgs( int key )
308{
309 key &= kASCIIKeyMask;
310
311 switch ( key )
312 {
313 case kBackspaceKey:
314 if ( gBootArgsPtr > gBootArgs )
315 {
316 int x, y, t;
317 getCursorPositionAndType( &x, &y, &t );
318 if ( x == 0 && y )
319 {
320 x = 80; y--;
321 }
322 if (x)
323x--;
324 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
325 {
326if( bootArgs->Video.v_display == VGA_TEXT_MODE )
327{
328setCursorPosition( x, y, 0 );
329putca(' ', 0x07, 1);
330} else
331updateGraphicBootPrompt(kBackspaceKey);
332} else {
333if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
334{
335setCursorPosition( x, y, 0 );
336putca(' ', 0x07, 1);
337} else
338updateGraphicBootPrompt(kBackspaceKey);
339}
340
341*gBootArgsPtr-- = '\0';
342}
343
344break;
345
346 default:
347 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
348 {
349 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
350 {
351if( bootArgs->Video.v_display == VGA_TEXT_MODE )
352putchar(key); // echo to screen
353else
354updateGraphicBootPrompt(key);
355} else {
356if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
357putchar(key); // echo to screen
358else
359updateGraphicBootPrompt(key);
360}
361*gBootArgsPtr++ = key;
362}
363
364break;
365 }
366}
367
368//==========================================================================
369
370static const MenuItem * gMenuItems = NULL;
371
372static int gMenuItemCount;
373static int gMenuRow;
374static int gMenuHeight;
375static int gMenuTop;
376static int gMenuBottom;
377static int gMenuSelection;
378
379static int gMenuStart;
380static int gMenuEnd;
381
382static void printMenuItem( const MenuItem * item, int highlight )
383{
384 printf(" ");
385
386 if ( highlight )
387 putca(' ', 0x70, strlen(item->name) + 4);
388 else
389 putca(' ', 0x07, 40);
390
391 printf(" %40s\n", item->name);
392}
393
394//==========================================================================
395
396static void showMenu( const MenuItem * items, int count,
397 int selection, int row, int height )
398{
399 int i;
400 CursorState cursorState;
401
402 if ( items == NULL || count == 0 )
403return;
404
405 // head and tail points to the start and the end of the list.
406 // top and bottom points to the first and last visible items
407 // in the menu window.
408
409 gMenuItems= items;
410 gMenuRow= row;
411 gMenuHeight= height;
412 gMenuItemCount= count;
413 gMenuTop= 0;
414 gMenuBottom= min( count, height ) - 1;
415 gMenuSelection= selection;
416
417 gMenuStart= 0;
418 gMenuEnd = min( count, gui.maxdevices ) - 1;
419
420// If the selected item is not visible, shift the list down.
421
422 if ( gMenuSelection > gMenuBottom )
423 {
424 gMenuTop += ( gMenuSelection - gMenuBottom );
425 gMenuBottom = gMenuSelection;
426 }
427
428if ( gMenuSelection > gMenuEnd )
429 {
430gMenuStart += ( gMenuSelection - gMenuEnd );
431 gMenuEnd = gMenuSelection;
432 }
433
434// Draw the visible items.
435
436 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
437 {
438if( bootArgs->Video.v_display == GRAPHICS_MODE )
439
440drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
441
442else {
443
444changeCursor( 0, row, kCursorTypeHidden, &cursorState );
445
446for ( i = gMenuTop; i <= gMenuBottom; i++ )
447{
448printMenuItem( &items[i], (i == gMenuSelection) );
449}
450
451restoreCursor( &cursorState );
452}
453} else {
454if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
455drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
456else {
457
458changeCursor( 0, row, kCursorTypeHidden, &cursorState );
459
460for ( i = gMenuTop; i <= gMenuBottom; i++ )
461{
462printMenuItem( &items[i], (i == gMenuSelection) );
463}
464
465restoreCursor( &cursorState );
466}
467}
468}
469
470//==========================================================================
471
472static int updateMenu( int key, void ** paramPtr )
473{
474 int moved = 0;
475
476 union {
477 struct {
478 unsigned int
479selectionUp : 1,
480selectionDown : 1,
481scrollUp : 1,
482scrollDown : 1;
483 } f;
484 unsigned int w;
485 } draw = {{0}};
486
487 if ( gMenuItems == NULL )
488return 0;
489
490 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
491 {
492if( bootArgs->Video.v_display == GRAPHICS_MODE )
493{
494int res;
495
496// set navigation keys for horizontal layout as defaults
497int previous= 0x4B00;// left arrow
498int subsequent= 0x4D00;// right arrow
499int menu= 0x5000;// down arrow
500
501if ( gui.layout == VerticalLayout )
502{
503// set navigation keys for vertical layout
504previous= 0x4800;// up arrow
505subsequent= 0x5000;// down arrow
506menu= 0x4B00;// right arrow
507}
508
509if ( key == previous )
510{
511if ( gMenuSelection > gMenuTop )
512draw.f.selectionUp = 1;
513else if ( gMenuTop > 0 )
514draw.f.scrollDown = 1;
515
516}
517
518else if ( key == subsequent )
519{
520if ( gMenuSelection != gMenuBottom)
521draw.f.selectionDown = 1;
522else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
523draw.f.scrollUp = 1;
524}
525
526else if ( key == menu )
527{
528if ( gui.menu.draw )
529updateInfoMenu(key);
530else
531drawInfoMenu();
532}
533
534else if ( gui.menu.draw )
535{
536res = updateInfoMenu(key);
537
538if ( res == CLOSE_INFO_MENU )
539gui.menu.draw = false;
540else
541{
542shouldboot = ( res != DO_NOT_BOOT );
543
544if ( shouldboot )
545gui.menu.draw = false;
546
547switch (res)
548{
549case BOOT_NORMAL:
550gVerboseMode = false;
551gBootMode = kBootModeNormal;
552break;
553
554case BOOT_VERBOSE:
555gVerboseMode = true;
556gBootMode = kBootModeNormal;
557addBootArg(kVerboseModeFlag);
558break;
559
560case BOOT_IGNORECACHE:
561gVerboseMode = false;
562gBootMode = kBootModeNormal;
563addBootArg(kIgnoreCachesFlag);
564break;
565
566case BOOT_SINGLEUSER:
567gVerboseMode = true;
568gBootMode = kBootModeNormal;
569addBootArg(kSingleUserModeFlag);
570break;
571}
572
573}
574
575}
576
577} else {
578switch ( key )
579{
580case 0x4800: // Up Arrow
581if ( gMenuSelection != gMenuTop )
582draw.f.selectionUp = 1;
583else if ( gMenuTop > 0 )
584draw.f.scrollDown = 1;
585break;
586
587case 0x5000: // Down Arrow
588if ( gMenuSelection != gMenuBottom )
589draw.f.selectionDown = 1;
590else if ( gMenuBottom < (gMenuItemCount - 1) )
591draw.f.scrollUp = 1;
592break;
593}
594}
595
596} else {
597if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
598{
599int res;
600
601// set navigation keys for horizontal layout as defaults
602int previous= 0x4B00;// left arrow
603int subsequent= 0x4D00;// right arrow
604int menu= 0x5000;// down arrow
605
606if ( gui.layout == VerticalLayout )
607{
608// set navigation keys for vertical layout
609previous= 0x4800;// up arrow
610subsequent= 0x5000;// down arrow
611menu= 0x4B00;// right arrow
612}
613
614if ( key == previous )
615{
616if ( gMenuSelection > gMenuTop )
617draw.f.selectionUp = 1;
618else if ( gMenuTop > 0 )
619draw.f.scrollDown = 1;
620
621}
622
623else if ( key == subsequent )
624{
625if ( gMenuSelection != gMenuBottom)
626draw.f.selectionDown = 1;
627else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
628draw.f.scrollUp = 1;
629}
630
631else if ( key == menu )
632{
633if ( gui.menu.draw )
634updateInfoMenu(key);
635else
636drawInfoMenu();
637}
638
639else if ( gui.menu.draw )
640{
641res = updateInfoMenu(key);
642
643if ( res == CLOSE_INFO_MENU )
644gui.menu.draw = false;
645else
646{
647shouldboot = ( res != DO_NOT_BOOT );
648
649if ( shouldboot )
650gui.menu.draw = false;
651
652switch (res)
653{
654case BOOT_NORMAL:
655gVerboseMode = false;
656gBootMode = kBootModeNormal;
657break;
658
659case BOOT_VERBOSE:
660gVerboseMode = true;
661gBootMode = kBootModeNormal;
662addBootArg(kVerboseModeFlag);
663break;
664
665case BOOT_IGNORECACHE:
666gVerboseMode = false;
667gBootMode = kBootModeNormal;
668addBootArg(kIgnoreCachesFlag);
669break;
670
671case BOOT_SINGLEUSER:
672gVerboseMode = true;
673gBootMode = kBootModeNormal;
674addBootArg(kSingleUserModeFlag);
675break;
676}
677
678}
679
680}
681
682} else {
683switch ( key )
684{
685case 0x4800: // Up Arrow
686if ( gMenuSelection != gMenuTop )
687draw.f.selectionUp = 1;
688else if ( gMenuTop > 0 )
689draw.f.scrollDown = 1;
690break;
691
692case 0x5000: // Down Arrow
693if ( gMenuSelection != gMenuBottom )
694draw.f.selectionDown = 1;
695else if ( gMenuBottom < (gMenuItemCount - 1) )
696draw.f.scrollUp = 1;
697break;
698}
699}
700}
701
702 if ( draw.w )
703 {
704 if ( draw.f.scrollUp )
705 {
706 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1);
707 gMenuTop++; gMenuBottom++;
708gMenuStart++; gMenuEnd++;
709 draw.f.selectionDown = 1;
710 }
711
712 if ( draw.f.scrollDown )
713 {
714 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1);
715 gMenuTop--; gMenuBottom--;
716 gMenuStart--; gMenuEnd--;
717 draw.f.selectionUp = 1;
718 }
719
720 if ( draw.f.selectionUp || draw.f.selectionDown )
721 {
722
723CursorState cursorState;
724
725// Set cursor at current position, and clear inverse video.
726
727 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
728 {
729if( bootArgs->Video.v_display == VGA_TEXT_MODE )
730{
731changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
732printMenuItem( &gMenuItems[gMenuSelection], 0 );
733}
734} else {
735if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
736{
737changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
738printMenuItem( &gMenuItems[gMenuSelection], 0 );
739}
740}
741
742if ( draw.f.selectionUp )
743{
744gMenuSelection--;
745if(( gMenuSelection - gMenuStart) == -1 )
746{
747gMenuStart--;
748gMenuEnd--;
749}
750
751} else {
752gMenuSelection++;
753if(( gMenuSelection - ( gui.maxdevices - 1) - gMenuStart) > 0 )
754{
755gMenuStart++;
756gMenuEnd++;
757}
758}
759
760if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
761{
762if( bootArgs->Video.v_display == VGA_TEXT_MODE )
763{
764moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
765printMenuItem( &gMenuItems[gMenuSelection], 1 );
766restoreCursor( &cursorState );
767
768} else
769
770drawDeviceList (gMenuStart, gMenuEnd, gMenuSelection);
771} else {
772if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
773{
774moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
775printMenuItem( &gMenuItems[gMenuSelection], 1 );
776restoreCursor( &cursorState );
777
778} else
779drawDeviceList (gMenuStart, gMenuEnd, gMenuSelection);
780}
781
782}
783
784 *paramPtr = gMenuItems[gMenuSelection].param;
785 moved = 1;
786 }
787
788return moved;
789}
790
791//==========================================================================
792
793static void skipblanks( const char ** cpp )
794{
795 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
796}
797
798//==========================================================================
799
800static const char * extractKernelName( char ** cpp )
801{
802 char * kn = *cpp;
803 char * cp = *cpp;
804 char c;
805
806 // Convert char to lower case.
807
808 c = *cp | 0x20;
809
810 // Must start with a letter or a '/'.
811
812 if ( (c < 'a' || c > 'z') && ( c != '/' ) )
813 return 0;
814
815 // Keep consuming characters until we hit a separator.
816
817 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
818 cp++;
819
820 // Only SPACE or TAB separator is accepted.
821 // Reject everything else.
822
823 if (*cp == '=')
824 return 0;
825
826 // Overwrite the separator, and move the pointer past
827 // the kernel name.
828
829 if (*cp != '\0') *cp++ = '\0';
830 *cpp = cp;
831
832 return kn;
833}
834
835//==========================================================================
836
837static void
838printMemoryInfo(void)
839{
840 int line;
841 int i;
842 MemoryRange *mp = bootInfo->memoryMap;
843
844 // Activate and clear page 1
845 setActiveDisplayPage(1);
846 clearScreenRows(0, 24);
847 setCursorPosition( 0, 0, 1 );
848
849 printf("BIOS reported memory ranges:\n");
850 line = 1;
851 for (i=0; i<bootInfo->memoryMapCount; i++) {
852 printf("Base 0x%08x%08x, ",
853 (unsigned long)(mp->base >> 32),
854 (unsigned long)(mp->base));
855 printf("length 0x%08x%08x, type %d\n",
856 (unsigned long)(mp->length >> 32),
857 (unsigned long)(mp->length),
858 mp->type);
859 if (line++ > 20) {
860 pause();
861 line = 0;
862 }
863 mp++;
864 }
865 if (line > 0) {
866 pause();
867 }
868
869 setActiveDisplayPage(0);
870}
871
872char *getMemoryInfoString()
873{
874 int i;
875 MemoryRange *mp = bootInfo->memoryMap;
876char *buff = malloc(sizeof(char)*1024);
877if(!buff) return 0;
878
879char info[] = "BIOS reported memory ranges:\n";
880sprintf(buff, "%s", info);
881 for (i=0; i<bootInfo->memoryMapCount; i++) {
882 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
883(unsigned long)(mp->base >> 32),
884(unsigned long)(mp->base));
885 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
886(unsigned long)(mp->length >> 32),
887(unsigned long)(mp->length),
888mp->type);
889 mp++;
890 }
891return buff;
892}
893
894//==========================================================================
895
896void lspci(void)
897{
898 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
899 {
900if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
901setActiveDisplayPage(1);
902clearScreenRows(0, 24);
903setCursorPosition(0, 0, 1);
904}
905} else {
906if(bootArgsSnow->Video.v_display == VGA_TEXT_MODE)
907{
908setActiveDisplayPage(1);
909clearScreenRows(0, 24);
910setCursorPosition(0, 0, 1);
911}
912}
913
914dump_pci_dt(root_pci_dev->children);
915
916pause();
917
918 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
919 {
920if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
921setActiveDisplayPage(0);
922}
923} else {
924if(bootArgsSnow->Video.v_display == VGA_TEXT_MODE)
925setActiveDisplayPage(0);
926}
927}
928
929//==========================================================================
930
931int getBootOptions(bool firstRun)
932{
933int i;
934int key;
935int nextRow;
936int timeout;
937int bvCount;
938BVRef bvr;
939BVRef menuBVR;
940bool showPrompt, newShowPrompt, isCDROM;
941
942// Initialize default menu selection entry.
943gBootVolume = menuBVR = selectBootVolume(bvChain);
944
945if (biosDevIsCDROM(gBIOSDev)) {
946isCDROM = true;
947} else {
948isCDROM = false;
949}
950
951// ensure we're in graphics mode if gui is setup
952if (gui.initialised)
953 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
954 {
955if (bootArgs->Video.v_display == VGA_TEXT_MODE)
956{
957setVideoMode(GRAPHICS_MODE, 0);
958}
959} else {
960if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
961setVideoMode( GRAPHICS_MODE, 0 );
962}
963
964// Clear command line boot arguments
965clearBootArgs();
966
967// Allow user to override default timeout.
968if (multiboot_timeout_set) {
969timeout = multiboot_timeout;
970} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
971/* If there is no timeout key in the file use the default timeout
972 which is different for CDs vs. hard disks. However, if not booting
973 a CD and no config file could be loaded set the timeout
974 to zero which causes the menu to display immediately.
975 This way, if no partitions can be found, that is the disk is unpartitioned
976 or simply cannot be read) then an empty menu is displayed.
977 If some partitions are found, for example a Windows partition, then
978 these will be displayed in the menu as foreign partitions.
979 */
980if (isCDROM) {
981timeout = kCDBootTimeout;
982} else {
983timeout = sysConfigValid ? kBootTimeout : 0;
984}
985}
986
987if (timeout < 0) {
988gBootMode |= kBootModeQuiet;
989}
990
991// If the user is holding down a modifier key, enter safe mode.
992if ((readKeyboardShiftFlags() & 0x0F) != 0) {
993gBootMode |= kBootModeSafe;
994}
995
996// Checking user pressed keys
997bool f8press = false, spress = false, vpress = false;
998while (readKeyboardStatus()) {
999key = bgetc ();
1000if (key == 0x4200) f8press = true;
1001if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
1002if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
1003}
1004// If user typed F8, abort quiet mode, and display the menu.
1005if (f8press) {
1006gBootMode &= ~kBootModeQuiet;
1007timeout = 0;
1008}
1009// If user typed 'v' or 'V', boot in verbose mode.
1010if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
1011addBootArg(kVerboseModeFlag);
1012}
1013// If user typed 's' or 'S', boot in single user mode.
1014if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
1015addBootArg(kSingleUserModeFlag);
1016}
1017
1018 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1019 {
1020if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
1021setCursorPosition(0, 0, 0);
1022clearScreenRows(0, kScreenLastRow);
1023if (!(gBootMode & kBootModeQuiet)) {
1024// Display banner and show hardware info.
1025printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
1026printf(getVBEInfoString());
1027}
1028changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
1029verbose("Scanning device %x...", gBIOSDev);
1030}
1031} else {
1032if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
1033{
1034setCursorPosition( 0, 0, 0 );
1035clearScreenRows( 0, kScreenLastRow );
1036
1037if ( ! ( gBootMode & kBootModeQuiet ) )
1038{
1039// Display banner and show hardware info.
1040printf( bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024 );
1041printf( getVBEInfoString() );
1042}
1043
1044changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1045verbose("Scanning device %x...", gBIOSDev);
1046
1047}
1048}
1049
1050// When booting from CD, default to hard drive boot when possible.
1051if (isCDROM && firstRun) {
1052const char *val;
1053char *prompt = NULL;
1054char *name = NULL;
1055int cnt;
1056int optionKey;
1057
1058if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig)) {
1059prompt = malloc(cnt + 1);
1060strncat(prompt, val, cnt);
1061} else {
1062name = malloc(80);
1063getBootVolumeDescription(gBootVolume, name, 79, false);
1064prompt = malloc(256);
1065sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
1066free(name);
1067}
1068
1069if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig )) {
1070// The key specified is a special key.
1071} else {
1072// Default to F8.
1073optionKey = 0x4200;
1074}
1075
1076// If the timeout is zero then it must have been set above due to the
1077// early catch of F8 which means the user wants to set boot options
1078// which we ought to interpret as meaning he wants to boot the CD.
1079if (timeout != 0) {
1080key = countdown(prompt, kMenuTopRow, timeout);
1081} else {
1082key = optionKey;
1083}
1084
1085if (prompt != NULL) {
1086free(prompt);
1087}
1088
1089clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
1090
1091// Hit the option key ?
1092if (key == optionKey) {
1093gBootMode &= ~kBootModeQuiet;
1094timeout = 0;
1095} else {
1096key = key & 0xFF;
1097
1098// Try booting hard disk if user pressed 'h'
1099if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
1100BVRef bvr;
1101
1102// Look at partitions hosting OS X other than the CD-ROM
1103for (bvr = bvChain; bvr; bvr=bvr->next) {
1104if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
1105gBootVolume = bvr;
1106}
1107}
1108}
1109goto done;
1110}
1111}
1112
1113if (gBootMode & kBootModeQuiet) {
1114// No input allowed from user.
1115goto done;
1116}
1117
1118if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
1119// If the user is holding down a modifier key,
1120// enter safe mode.
1121if ((readKeyboardShiftFlags() & 0x0F) != 0) {
1122gBootMode |= kBootModeSafe;
1123}
1124goto done;
1125}
1126
1127if (gDeviceCount) {
1128// Allocate memory for an array of menu items.
1129menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
1130if (menuItems == NULL) {
1131goto done;
1132}
1133
1134// Associate a menu item for each BVRef.
1135for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
1136if (bvr->visible) {
1137getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
1138menuItems[i].param = (void *) bvr;
1139if (bvr == menuBVR) {
1140selectIndex = i;
1141}
1142i--;
1143}
1144}
1145}
1146
1147 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1148 {
1149if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1150// redraw the background buffer
1151gui.logo.draw = true;
1152drawBackground();
1153gui.devicelist.draw = true;
1154gui.redraw = true;
1155if (!(gBootMode & kBootModeQuiet)) {
1156bool showBootBanner = true;
1157
1158// Check if "Boot Banner"=N switch is present in config file.
1159getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
1160if (showBootBanner) {
1161// Display banner and show hardware info.
1162gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
1163}
1164
1165// redraw background
1166memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
1167}
1168} else {
1169// Clear screen and hide the blinking cursor.
1170clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1171changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1172}
1173} else {
1174if (bootArgsSnow->Video.v_display == GRAPHICS_MODE) {
1175// redraw the background buffer
1176gui.logo.draw = true;
1177drawBackground();
1178gui.devicelist.draw = true;
1179gui.redraw = true;
1180if (!(gBootMode & kBootModeQuiet)) {
1181bool showBootBanner = true;
1182
1183// Check if "Boot Banner"=N switch is present in config file.
1184getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig);
1185if (showBootBanner) {
1186// Display banner and show hardware info.
1187gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
1188}
1189
1190// redraw background
1191memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
1192}
1193} else {
1194// Clear screen and hide the blinking cursor.
1195clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1196changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1197}
1198}
1199
1200nextRow = kMenuTopRow;
1201showPrompt = true;
1202
1203if (gDeviceCount) {
1204 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1205 {
1206if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
1207printf("Use \30\31 keys to select the startup volume.");
1208}
1209} else {
1210if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
1211printf("Use \30\31 keys to select the startup volume.");
1212}
1213showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1214nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
1215}
1216
1217// Show the boot prompt.
1218showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1219showBootPrompt( nextRow, showPrompt );
1220
1221do {
1222 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1223 {
1224if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1225// redraw background
1226memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1227// reset cursor co-ords
1228gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
1229}
1230} else {
1231if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
1232{
1233// redraw background
1234memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
1235
1236// reset cursor co-ords
1237gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
1238
1239}
1240}
1241key = getc();
1242updateMenu( key, (void **) &menuBVR );
1243newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1244
1245if (newShowPrompt != showPrompt) {
1246showPrompt = newShowPrompt;
1247showBootPrompt( nextRow, showPrompt );
1248}
1249
1250if (showPrompt) {
1251updateBootArgs(key);
1252}
1253
1254switch (key) {
1255case kReturnKey:
1256if (gui.menu.draw) {
1257key=0;
1258break;
1259}
1260if (*gBootArgs == '?') {
1261char * argPtr = gBootArgs;
1262
1263// Skip the leading "?" character.
1264argPtr++;
1265getNextArg(&argPtr, booterCommand);
1266getNextArg(&argPtr, booterParam);
1267
1268/*
1269 * TODO: this needs to be refactored.
1270 */
1271if (strcmp( booterCommand, "video" ) == 0) {
1272if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1273{
1274if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1275showInfoBox(getVBEInfoString(), getVBEModeInfoString());
1276} else {
1277printVBEModeInfo();
1278}
1279} else {
1280if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
1281showInfoBox( getVBEInfoString(), getVBEModeInfoString() );
1282else
1283printVBEModeInfo();
1284}
1285} else if ( strcmp( booterCommand, "memory" ) == 0) {
1286if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1287{
1288if (bootArgs->Video.v_display == GRAPHICS_MODE ) {
1289showInfoBox("Memory Map", getMemoryInfoString());
1290} else {
1291printMemoryInfo();
1292}
1293} else {
1294if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
1295showInfoBox( "Memory Map", getMemoryInfoString() );
1296else
1297printMemoryInfo();
1298}
1299} else if (strcmp(booterCommand, "lspci") == 0) {
1300lspci();
1301} else if (strcmp(booterCommand, "more") == 0) {
1302showTextFile(booterParam);
1303} else if (strcmp(booterCommand, "rd") == 0) {
1304processRAMDiskCommand(&argPtr, booterParam);
1305} else if (strcmp(booterCommand, "norescan") == 0) {
1306if (gEnableCDROMRescan) {
1307gEnableCDROMRescan = false;
1308break;
1309}
1310} else {
1311showHelp();
1312}
1313key = 0;
1314showBootPrompt(nextRow, showPrompt);
1315break;
1316}
1317gBootVolume = menuBVR;
1318setRootVolume(menuBVR);
1319gBIOSDev = menuBVR->biosdev;
1320break;
1321
1322case kEscapeKey:
1323clearBootArgs();
1324break;
1325
1326case kF5Key:
1327// New behavior:
1328// Clear gBootVolume to restart the loop
1329// if the user enabled rescanning the optical drive.
1330// Otherwise boot the default boot volume.
1331if (gEnableCDROMRescan) {
1332gBootVolume = NULL;
1333clearBootArgs();
1334}
1335break;
1336
1337case kF10Key:
1338gScanSingleDrive = false;
1339scanDisks(gBIOSDev, &bvCount);
1340gBootVolume = NULL;
1341clearBootArgs();
1342break;
1343
1344case kTabKey:
1345// New behavior:
1346// Switch between text & graphic interfaces
1347// Only Permitted if started in graphics interface
1348if (useGUI) {
1349if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1350{
1351if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1352setVideoMode(VGA_TEXT_MODE, 0);
1353
1354setCursorPosition(0, 0, 0);
1355clearScreenRows(0, kScreenLastRow);
1356
1357// Display banner and show hardware info.
1358printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
1359printf(getVBEInfoString());
1360
1361clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
1362changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
1363
1364nextRow = kMenuTopRow;
1365showPrompt = true;
1366
1367if (gDeviceCount) {
1368printf("Use \30\31 keys to select the startup volume.");
1369showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
1370nextRow += min(gDeviceCount, kMenuMaxItems) + 3;
1371}
1372
1373showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1374showBootPrompt(nextRow, showPrompt);
1375//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1376} else {
1377gui.redraw = true;
1378setVideoMode(GRAPHICS_MODE, 0);
1379updateVRAM();
1380}
1381} else {
1382if (bootArgsSnow->Video.v_display == GRAPHICS_MODE)
1383{
1384setVideoMode( VGA_TEXT_MODE, 0 );
1385
1386setCursorPosition( 0, 0, 0 );
1387clearScreenRows( 0, kScreenLastRow );
1388
1389// Display banner and show hardware info.
1390printf( bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024 );
1391printf( getVBEInfoString() );
1392
1393clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
1394changeCursor( 0, kMenuTopRow, kCursorTypeHidden, 0 );
1395
1396nextRow = kMenuTopRow;
1397showPrompt = true;
1398
1399if ( gDeviceCount )
1400{
1401printf("Use \30\31 keys to select the startup volume.");
1402showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
1403nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
1404}
1405
1406showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
1407showBootPrompt( nextRow, showPrompt );
1408
1409//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1410
1411}
1412else
1413{
1414gui.redraw = true;
1415setVideoMode( GRAPHICS_MODE, 0 );
1416updateVRAM();
1417}
1418}
1419}
1420key = 0;
1421break;
1422
1423default:
1424key = 0;
1425break;
1426}
1427} while (0 == key);
1428
1429done:
1430if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1431{
1432if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
1433clearScreenRows(kMenuTopRow, kScreenLastRow);
1434changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
1435}
1436} else {
1437if( bootArgsSnow->Video.v_display == VGA_TEXT_MODE )
1438{
1439clearScreenRows( kMenuTopRow, kScreenLastRow );
1440changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
1441}
1442}
1443shouldboot = false;
1444gui.menu.draw = false;
1445if (menuItems) {
1446free(menuItems);
1447menuItems = NULL;
1448}
1449return 0;
1450}
1451
1452//==========================================================================
1453
1454extern unsigned char chainbootdev;
1455extern unsigned char chainbootflag;
1456
1457bool copyArgument(const char *argName, const char *val, int cnt, char **argP, int *cntRemainingP)
1458{
1459 int argLen = argName ? strlen(argName) : 0;
1460 int len = argLen + cnt + 1; // +1 to account for space
1461
1462 if (len > *cntRemainingP) {
1463 error("Warning: boot arguments too long, truncating\n");
1464 return false;
1465 }
1466
1467 if (argName) {
1468 strncpy( *argP, argName, argLen );
1469 *argP += argLen;
1470 *argP[0] = '=';
1471 (*argP)++;
1472 len++; // +1 to account for '='
1473 }
1474 strncpy( *argP, val, cnt );
1475 *argP += cnt;
1476 *argP[0] = ' ';
1477 (*argP)++;
1478
1479 *cntRemainingP -= len;
1480 return true;
1481}
1482
1483//
1484// Returns TRUE if an argument was copied, FALSE otherwise
1485bool
1486processBootArgument(
1487 const char *argName, // The argument to search for
1488 const char *userString, // Typed-in boot arguments
1489 const char *kernelFlags, // Kernel flags from config table
1490 const char *configTable,
1491 char **argP, // Output value
1492 int *cntRemainingP, // Output count
1493 char *foundVal // found value
1494 )
1495{
1496 const char *val;
1497 int cnt;
1498 bool found = false;
1499
1500 if (getValueForBootKey(userString, argName, &val, &cnt)) {
1501 // Don't copy; these values will be copied at the end of argument processing.
1502 found = true;
1503 } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) {
1504 // Don't copy; these values will be copied at the end of argument processing.
1505 found = true;
1506 } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) {
1507 copyArgument(argName, val, cnt, argP, cntRemainingP);
1508 found = true;
1509 }
1510 if (found && foundVal) {
1511 strlcpy(foundVal, val, cnt+1);
1512 }
1513 return found;
1514}
1515
1516// Maximum config table value size
1517#define VALUE_SIZE 2048
1518
1519int
1520processBootOptions()
1521{
1522 const char * cp = gBootArgs;
1523 const char * val = 0;
1524 const char * kernel;
1525 int cnt;
1526 int userCnt;
1527 int cntRemaining;
1528 char * argP;
1529 char uuidStr[64];
1530 bool uuidSet = false;
1531 char * configKernelFlags;
1532 char * valueBuffer;
1533
1534 valueBuffer = malloc(VALUE_SIZE);
1535
1536 skipblanks( &cp );
1537
1538 // Update the unit and partition number.
1539
1540 if ( gBootVolume )
1541 {
1542 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1543 {
1544 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1545 (void *) 0x7c00 );
1546
1547 //
1548 // Setup edx, and signal intention to chain load the
1549 // foreign booter.
1550 //
1551
1552 chainbootdev = gBootVolume->biosdev;
1553 chainbootflag = 1;
1554
1555 return 1;
1556 }
1557
1558 setRootVolume(gBootVolume);
1559
1560 }
1561 // If no boot volume fail immediately because we're just going to fail
1562 // trying to load the config file anyway.
1563 else
1564return -1;
1565
1566 // Load config table specified by the user, or use the default.
1567
1568 if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1569val = 0;
1570cnt = 0;
1571 }
1572
1573 // Load com.apple.Boot.plist from the selected volume
1574 // and use its contents to override default bootConfig.
1575 // This is not a mandatory opeartion anymore.
1576
1577 loadOverrideConfig(&bootInfo->overrideConfig);
1578
1579 // Use the kernel name specified by the user, or fetch the name
1580 // in the config table, or use the default if not specified.
1581 // Specifying a kernel name on the command line, or specifying
1582 // a non-default kernel name in the config file counts as
1583 // overriding the kernel, which causes the kernelcache not
1584 // to be used.
1585
1586 gOverrideKernel = false;
1587 if (( kernel = extractKernelName((char **)&cp) )) {
1588 strcpy( bootInfo->bootFile, kernel );
1589 gOverrideKernel = true;
1590 } else {
1591 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1592 strlcpy( bootInfo->bootFile, val, cnt+1 );
1593 if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) {
1594 gOverrideKernel = true;
1595 }
1596 } else {
1597 strcpy( bootInfo->bootFile, kDefaultKernel );
1598 }
1599 }
1600
1601 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1602 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1603argP = bootArgs->CommandLine;
1604else
1605argP = bootArgsSnow->CommandLine;
1606
1607 // Get config table kernel flags, if not ignored.
1608 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1609!getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1610 val = "";
1611 cnt = 0;
1612 }
1613 configKernelFlags = malloc(cnt + 1);
1614 strlcpy(configKernelFlags, val, cnt + 1);
1615
1616 //rooting via /chosen/ now, no need anymore
1617 // if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1618 if (!processBootArgument(kNoUseBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1619 // boot-uuid was set either on the command-line
1620 // or in the config file.
1621 uuidSet = true;
1622 } else {
1623
1624 //
1625 // Try an alternate method for getting the root UUID on boot helper partitions.
1626 //
1627 if (gBootVolume->flags & kBVFlagBooter)
1628 {
1629 if((loadHelperConfig(&bootInfo->helperConfig) == 0)
1630 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1631 {
1632getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1633copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1634uuidSet = true;
1635 }
1636 }
1637
1638 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1639 verbose("Setting boot-uuid to: %s\n", uuidStr);
1640 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1641 uuidSet = true;
1642 }
1643 }
1644
1645// if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1646if (processBootArgument(kNoUseBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1647 cnt = 0;
1648 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1649 valueBuffer[0] = '*';
1650 cnt++;
1651 strlcpy(valueBuffer + 1, val, cnt);
1652 val = valueBuffer;
1653 } else {
1654 if (uuidSet) {
1655 val = "*uuid";
1656 cnt = 5;
1657 } else {
1658 // Don't set "rd=.." if there is no boot device key
1659 // and no UUID.
1660 val = "";
1661 cnt = 0;
1662 }
1663 }
1664 if (cnt > 0) {
1665 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1666 }
1667 strlcpy( gRootDevice, val, (cnt + 1));
1668 }
1669
1670 /*
1671 * Removed. We don't need this anymore.
1672 *
1673 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1674 getPlatformName(gPlatformName);
1675 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1676 }
1677 */
1678
1679 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1680 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1681 if (gBootMode & kBootModeSafe) {
1682 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1683 }
1684 }
1685
1686 // Store the merged kernel flags and boot args.
1687
1688 cnt = strlen(configKernelFlags);
1689 if (cnt) {
1690 if (cnt > cntRemaining) {
1691 error("Warning: boot arguments too long, truncating\n");
1692 cnt = cntRemaining;
1693 }
1694 strncpy(argP, configKernelFlags, cnt);
1695 argP[cnt++] = ' ';
1696 cntRemaining -= cnt;
1697 }
1698 userCnt = strlen(cp);
1699 if (userCnt > cntRemaining) {
1700error("Warning: boot arguments too long, truncating\n");
1701userCnt = cntRemaining;
1702 }
1703 strncpy(&argP[cnt], cp, userCnt);
1704 argP[cnt+userCnt] = '\0';
1705
1706if(!shouldboot)
1707{
1708gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1709getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1710
1711gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1712kBootModeSafe : kBootModeNormal;
1713
1714 if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1715 gBootMode = kBootModeSafe;
1716}
1717}
1718
1719if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) )
1720{
1721strlcpy(gMKextName, val, cnt + 1);
1722}
1723
1724 free(configKernelFlags);
1725 free(valueBuffer);
1726
1727 return 0;
1728}
1729
1730
1731//==========================================================================
1732// Load the help file and display the file contents on the screen.
1733
1734static void showTextBuffer(char *buf, int size)
1735{
1736char*bp;
1737intline;
1738intline_offset;
1739intc;
1740
1741 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1742 {
1743if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1744showInfoBox( "Press q to quit\n",buf );
1745return;
1746}
1747} else {
1748if( bootArgsSnow->Video.v_display == GRAPHICS_MODE )
1749{
1750showInfoBox( "Press q to quit\n",buf );
1751return;
1752}
1753}
1754
1755bp = buf;
1756while (size-- > 0) {
1757if (*bp == '\n') {
1758*bp = '\0';
1759}
1760bp++;
1761}
1762*bp = '\1';
1763line_offset = 0;
1764
1765setActiveDisplayPage(1);
1766
1767while (1) {
1768clearScreenRows(0, 24);
1769setCursorPosition(0, 0, 1);
1770bp = buf;
1771for (line = 0; *bp != '\1' && line < line_offset; line++) {
1772while (*bp != '\0') {
1773bp++;
1774}
1775bp++;
1776}
1777for (line = 0; *bp != '\1' && line < 23; line++) {
1778setCursorPosition(0, line, 1);
1779printf("%s\n", bp);
1780while (*bp != '\0') {
1781bp++;
1782}
1783bp++;
1784}
1785
1786setCursorPosition(0, 23, 1);
1787if (*bp == '\1') {
1788printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1789} else {
1790printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1791}
1792
1793c = getc();
1794if (c == 'q' || c == 'Q') {
1795break;
1796}
1797if ((c == 'p' || c == 'P') && line_offset > 0) {
1798line_offset -= 23;
1799}
1800if (c == ' ') {
1801if (*bp == '\1') {
1802break;
1803} else {
1804line_offset += 23;
1805}
1806}
1807}
1808setActiveDisplayPage(0);
1809}
1810
1811void showHelp(void)
1812{
1813 if ((gMacOSVersion[0] == '1') && (gMacOSVersion[1] == '0') && (gMacOSVersion[2] == '.') && (gMacOSVersion[3] >= '7'))
1814 {
1815if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1816showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1817} else {
1818showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1819}
1820} else {
1821if (bootArgsSnow->Video.v_display == GRAPHICS_MODE) {
1822showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1823} else {
1824showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1825}
1826}
1827}
1828
1829void showTextFile(const char * filename)
1830{
1831#define MAX_TEXT_FILE_SIZE 65536
1832char*buf;
1833intfd;
1834intsize;
1835
1836if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1837printf("\nFile not found: %s\n", filename);
1838sleep(2);
1839return;
1840}
1841
1842size = file_size(fd);
1843if (size > MAX_TEXT_FILE_SIZE) {
1844size = MAX_TEXT_FILE_SIZE;
1845}
1846buf = malloc(size);
1847read(fd, buf, size);
1848close(fd);
1849showTextBuffer(buf, size);
1850free(buf);
1851}
1852
1853// This is a very simplistic prompting scheme that just grabs two hex characters
1854// Eventually we need to do something more user-friendly like display a menu
1855// based off of the Multiboot device list
1856
1857int selectAlternateBootDevice(int bootdevice)
1858{
1859int key;
1860int newbootdevice;
1861int digitsI = 0;
1862char *end;
1863char digits[3] = {0,0,0};
1864
1865// We've already printed the current boot device so user knows what it is
1866printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1867printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1868do {
1869key = getc();
1870switch (key & kASCIIKeyMask) {
1871case kBackspaceKey:
1872if (digitsI > 0) {
1873int x, y, t;
1874getCursorPositionAndType(&x, &y, &t);
1875// Assume x is not 0;
1876x--;
1877setCursorPosition(x,y,0); // back up one char
1878// Overwrite with space without moving cursor position
1879putca(' ', 0x07, 1);
1880digitsI--;
1881} else {
1882// TODO: Beep or something
1883}
1884break;
1885
1886case kReturnKey:
1887digits[digitsI] = '\0';
1888newbootdevice = strtol(digits, &end, 16);
1889if (end == digits && *end == '\0') {
1890// User entered empty string
1891printf("\nUsing default boot device %x\n", bootdevice);
1892key = 0;
1893} else if(end != digits && *end == '\0') {
1894bootdevice = newbootdevice;
1895printf("\n");
1896key = 0; // We gots da boot device
1897} else {
1898printf("\nCouldn't parse. try again: ");
1899digitsI = 0;
1900}
1901break;
1902
1903default:
1904if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1905putc(key & kASCIIKeyMask);
1906digits[digitsI++] = key & kASCIIKeyMask;
1907} else {
1908// TODO: Beep or something
1909}
1910break;
1911};
1912} while (key != 0);
1913
1914return bootdevice;
1915}
1916
1917bool promptForRescanOption(void)
1918{
1919printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1920if (getc() == kReturnKey) {
1921return true;
1922} else {
1923return false;
1924}
1925}
1926

Archive Download this file

Revision: 755