Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 451