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

Archive Download this file

Revision: 448