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" //Azi:sysversion
34
35#include "autoresolution.h" //Azi:autoresolution - "was" included on boot.h, which is everywere!! -> gui.h -> graphics.h
36
37bool showBootBanner = true;
38static bool shouldboot = false;
39
40char gMacOSVersion[8]; //Azi:sysversion
41
42extern int multiboot_timeout;
43extern int multiboot_timeout_set;
44
45extern BVRef bvChain;
46//extern intmenucount;
47
48extern intgDeviceCount;
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 ) +
119( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
120
121char dummy[80];
122getBootVolumeDescription( gBootVolume, dummy, 80, true );
123drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
124drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
125
126// make this screen the new background
127memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
128
129}
130
131int multi_buff = 18 * (timeout);
132 int multi = ++multi_buff;
133
134 int lasttime=0;
135
136 for ( time = time18(), timeout++; timeout > 0; )
137 {
138if( time18() > lasttime)
139{
140multi--;
141lasttime=time18();
142}
143
144 if (ch = readKeyboardStatus())
145 break;
146
147 // Count can be interrupted by holding down shift,
148 // control or alt key
149 if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
150{
151 ch = 1;
152 break;
153 }
154
155 if ( time18() >= time )
156 {
157 time += 18;
158 timeout--;
159
160if( bootArgs->Video.v_display == VGA_TEXT_MODE )
161{
162moveCursor( col, row );
163printf("(%d) ", timeout);
164}
165 }
166
167if( bootArgs->Video.v_display == GRAPHICS_MODE )
168{
169drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
170gui.redraw = true;
171updateVRAM();
172}
173
174 }
175
176 flushKeyboardBuffer();
177
178 return ch;
179}
180
181//==========================================================================
182
183static char gBootArgs[BOOT_STRING_LEN];
184static char * gBootArgsPtr = gBootArgs;
185static char * gBootArgsEnd = gBootArgs + BOOT_STRING_LEN - 1;
186static char booterCommand[BOOT_STRING_LEN];
187static char booterParam[BOOT_STRING_LEN];
188
189static void clearBootArgs(void)
190{
191gBootArgsPtr = gBootArgs;
192memset(gBootArgs, '\0', BOOT_STRING_LEN);
193
194if (bootArgs->Video.v_display == GRAPHICS_MODE) {
195clearGraphicBootPrompt();
196}
197}
198
199//==========================================================================
200
201static void showBootPrompt(int row, bool visible)
202{
203extern char bootPrompt[];
204extern char bootRescanPrompt[];
205
206if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
207changeCursor( 0, row, kCursorTypeUnderline, 0 );
208clearScreenRows( row, kScreenLastRow );
209}
210
211clearBootArgs();
212
213if (visible) {
214if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
215if (gEnableCDROMRescan) {
216printf( bootRescanPrompt );
217} else {
218printf( bootPrompt );
219}
220}
221} else {
222if (bootArgs->Video.v_display == GRAPHICS_MODE) {
223clearGraphicBootPrompt();
224} else {
225printf("Press Enter to start up the foreign OS. ");
226}
227}
228}
229
230//==========================================================================
231
232static void updateBootArgs( int key )
233{
234 key &= kASCIIKeyMask;
235
236 switch ( key )
237 {
238 case kBackspaceKey:
239 if ( gBootArgsPtr > gBootArgs )
240 {
241 int x, y, t;
242 getCursorPositionAndType( &x, &y, &t );
243 if ( x == 0 && y )
244 {
245 x = 80; y--;
246 }
247 if (x)
248x--;
249if( bootArgs->Video.v_display == VGA_TEXT_MODE )
250{
251setCursorPosition( x, y, 0 );
252putca(' ', 0x07, 1);
253} else
254updateGraphicBootPrompt(kBackspaceKey);
255
256*gBootArgsPtr-- = '\0';
257}
258
259break;
260
261 default:
262 if ( key >= ' ' && gBootArgsPtr < gBootArgsEnd)
263 {
264if( bootArgs->Video.v_display == VGA_TEXT_MODE )
265putchar(key); // echo to screen
266else
267updateGraphicBootPrompt(key);
268*gBootArgsPtr++ = key;
269}
270
271break;
272 }
273}
274
275//==========================================================================
276
277static const MenuItem * gMenuItems = NULL;
278
279static int gMenuItemCount;
280static int gMenuRow;
281static int gMenuHeight;
282static int gMenuTop;
283static int gMenuBottom;
284static int gMenuSelection;
285
286static int gMenuStart;
287static int gMenuEnd;
288
289static void printMenuItem( const MenuItem * item, int highlight )
290{
291 printf(" ");
292
293 if ( highlight )
294 putca(' ', 0x70, strlen(item->name) + 4);
295 else
296 putca(' ', 0x07, 40);
297
298 printf(" %40s\n", item->name);
299}
300
301//==========================================================================
302
303static void showMenu( const MenuItem * items, int count,
304 int selection, int row, int height )
305{
306 int i;
307 CursorState cursorState;
308
309 if ( items == NULL || count == 0 )
310return;
311
312 // head and tail points to the start and the end of the list.
313 // top and bottom points to the first and last visible items
314 // in the menu window.
315
316 gMenuItems= items;
317 gMenuRow= row;
318 gMenuHeight= height;
319 gMenuItemCount= count;
320 gMenuTop= 0;
321 gMenuBottom= min( count, height ) - 1;
322 gMenuSelection= selection;
323
324 gMenuStart= 0;
325 gMenuEnd = min( count, gui.maxdevices ) - 1;
326
327// If the selected item is not visible, shift the list down.
328
329 if ( gMenuSelection > gMenuBottom )
330 {
331 gMenuTop += ( gMenuSelection - gMenuBottom );
332 gMenuBottom = gMenuSelection;
333 }
334
335if ( gMenuSelection > gMenuEnd )
336 {
337gMenuStart += ( gMenuSelection - gMenuEnd );
338 gMenuEnd = gMenuSelection;
339 }
340
341// Draw the visible items.
342
343if( bootArgs->Video.v_display == GRAPHICS_MODE )
344
345drawDeviceList(gMenuStart, gMenuEnd, gMenuSelection);
346
347else {
348
349changeCursor( 0, row, kCursorTypeHidden, &cursorState );
350
351for ( i = gMenuTop; i <= gMenuBottom; i++ )
352{
353printMenuItem( &items[i], (i == gMenuSelection) );
354}
355
356restoreCursor( &cursorState );
357 }
358}
359
360//==========================================================================
361
362static int updateMenu( int key, void ** paramPtr )
363{
364 int moved = 0;
365
366 union {
367 struct {
368 unsigned int
369 selectionUp : 1,
370 selectionDown : 1,
371 scrollUp : 1,
372 scrollDown : 1;
373 } f;
374 unsigned int w;
375 } draw = {{0}};
376
377 if ( gMenuItems == NULL )
378return 0;
379
380if( bootArgs->Video.v_display == GRAPHICS_MODE )
381{
382int res;
383
384// set navigation keys for horizontal layout as defaults
385int previous= 0x4B00;// left arrow
386int subsequent= 0x4D00;// right arrow
387int menu= 0x5000;// down arrow
388
389if ( gui.layout == VerticalLayout )
390{
391// set navigation keys for vertical layout
392previous= 0x4800;// up arrow
393subsequent= 0x5000;// down arrow
394menu= 0x4B00;// right arrow
395}
396
397if ( key == previous )
398{
399if ( gMenuSelection > gMenuTop )
400draw.f.selectionUp = 1;
401else if ( gMenuTop > 0 )
402draw.f.scrollDown = 1;
403
404}
405
406else if ( key == subsequent )
407{
408if ( gMenuSelection != gMenuBottom)
409draw.f.selectionDown = 1;
410else if ( gMenuBottom < ( gMenuItemCount - 1 ) )
411draw.f.scrollUp = 1;
412}
413
414else if ( key == menu )
415{
416if ( gui.menu.draw )
417updateInfoMenu(key);
418else
419drawInfoMenu();
420}
421
422else if ( gui.menu.draw )
423{
424res = updateInfoMenu(key);
425
426if ( res == CLOSE_INFO_MENU )
427gui.menu.draw = false;
428else
429{
430shouldboot = ( res != DO_NOT_BOOT );
431
432if ( shouldboot )
433gui.menu.draw = false;
434
435switch (res)
436{
437case BOOT_NORMAL:
438gVerboseMode = false;
439gBootMode = kBootModeNormal;
440break;
441
442case BOOT_VERBOSE:
443gVerboseMode = true;
444gBootMode = kBootModeNormal;
445*gBootArgsPtr++ = '-';
446*gBootArgsPtr++ = 'v';
447break;
448
449case BOOT_IGNORECACHE:
450gVerboseMode = false;
451gBootMode = kBootModeNormal;
452*gBootArgsPtr++ = '-';
453*gBootArgsPtr++ = 'f';
454break;
455
456case BOOT_SINGLEUSER:
457gVerboseMode = true;
458gBootMode = kBootModeNormal;
459*gBootArgsPtr++ = '-';
460*gBootArgsPtr++ = 's';
461break;
462}
463
464}
465
466}
467
468} else {
469switch ( key )
470{
471 case 0x4800: // Up Arrow
472if ( gMenuSelection != gMenuTop )
473draw.f.selectionUp = 1;
474else if ( gMenuTop > 0 )
475draw.f.scrollDown = 1;
476break;
477
478case 0x5000: // Down Arrow
479if ( gMenuSelection != gMenuBottom )
480draw.f.selectionDown = 1;
481else if ( gMenuBottom < (gMenuItemCount - 1) )
482draw.f.scrollUp = 1;
483break;
484}
485}
486
487 if ( draw.w )
488 {
489 if ( draw.f.scrollUp )
490 {
491 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, 1);
492 gMenuTop++; gMenuBottom++;
493gMenuStart++; gMenuEnd++;
494 draw.f.selectionDown = 1;
495 }
496
497 if ( draw.f.scrollDown )
498 {
499 scollPage(0, gMenuRow, 40, gMenuRow + gMenuHeight - 1, 0x07, 1, -1);
500 gMenuTop--; gMenuBottom--;
501 gMenuStart--; gMenuEnd--;
502 draw.f.selectionUp = 1;
503 }
504
505 if ( draw.f.selectionUp || draw.f.selectionDown )
506 {
507
508CursorState cursorState;
509
510// Set cursor at current position, and clear inverse video.
511
512if( bootArgs->Video.v_display == VGA_TEXT_MODE )
513{
514changeCursor( 0, gMenuRow + gMenuSelection - gMenuTop, kCursorTypeHidden, &cursorState );
515printMenuItem( &gMenuItems[gMenuSelection], 0 );
516}
517
518if ( draw.f.selectionUp )
519{
520gMenuSelection--;
521if(( gMenuSelection - gMenuStart) == -1 )
522{
523gMenuStart--;
524gMenuEnd--;
525}
526
527} else {
528gMenuSelection++;
529if(( gMenuSelection - ( gui.maxdevices - 1) - gMenuStart) > 0 )
530{
531gMenuStart++;
532gMenuEnd++;
533}
534 }
535
536if( bootArgs->Video.v_display == VGA_TEXT_MODE )
537 {
538moveCursor( 0, gMenuRow + gMenuSelection - gMenuTop );
539printMenuItem( &gMenuItems[gMenuSelection], 1 );
540restoreCursor( &cursorState );
541
542 } else
543
544drawDeviceList (gMenuStart, gMenuEnd, gMenuSelection);
545
546}
547
548 *paramPtr = gMenuItems[gMenuSelection].param;
549 moved = 1;
550 }
551
552return moved;
553}
554
555//==========================================================================
556
557static void skipblanks( const char ** cpp )
558{
559 while ( **(cpp) == ' ' || **(cpp) == '\t' ) ++(*cpp);
560}
561
562//==========================================================================
563
564static const char * extractKernelName( char ** cpp )
565{
566 char * kn = *cpp;
567 char * cp = *cpp;
568 char c;
569
570 // Convert char to lower case.
571
572 c = *cp | 0x20;
573
574 // Must start with a letter or a '/'.
575
576 if ( (c < 'a' || c > 'z') && ( c != '/' ) )
577 return 0;
578
579 // Keep consuming characters until we hit a separator.
580
581 while ( *cp && (*cp != '=') && (*cp != ' ') && (*cp != '\t') )
582 cp++;
583
584 // Only SPACE or TAB separator is accepted.
585 // Reject everything else.
586
587 if (*cp == '=')
588 return 0;
589
590 // Overwrite the separator, and move the pointer past
591 // the kernel name.
592
593 if (*cp != '\0') *cp++ = '\0';
594 *cpp = cp;
595
596 return kn;
597}
598
599//==========================================================================
600
601static void
602printMemoryInfo(void)
603{
604 int line;
605 int i;
606 MemoryRange *mp = bootInfo->memoryMap;
607
608 // Activate and clear page 1
609 setActiveDisplayPage(1);
610 clearScreenRows(0, 24);
611 setCursorPosition( 0, 0, 1 );
612
613 printf("BIOS reported memory ranges:\n");
614 line = 1;
615 for (i=0; i<bootInfo->memoryMapCount; i++) {
616 printf("Base 0x%08x%08x, ",
617 (unsigned long)(mp->base >> 32),
618 (unsigned long)(mp->base));
619 printf("length 0x%08x%08x, type %d\n",
620 (unsigned long)(mp->length >> 32),
621 (unsigned long)(mp->length),
622 mp->type);
623 if (line++ > 20) {
624 pause();
625 line = 0;
626 }
627 mp++;
628 }
629 if (line > 0) {
630 pause();
631 }
632
633 setActiveDisplayPage(0);
634}
635
636char *getMemoryInfoString()
637{
638 int i;
639 MemoryRange *mp = bootInfo->memoryMap;
640char *buff = malloc(sizeof(char)*1024);
641if(!buff) return 0;
642
643char info[] = "BIOS reported memory ranges:\n";
644sprintf(buff, "%s", info);
645 for (i=0; i<bootInfo->memoryMapCount; i++) {
646 sprintf( buff+strlen(buff), "Base 0x%08x%08x, ",
647 (unsigned long)(mp->base >> 32),
648 (unsigned long)(mp->base));
649 sprintf( buff+strlen(buff), "length 0x%08x%08x, type %d\n",
650 (unsigned long)(mp->length >> 32),
651 (unsigned long)(mp->length),
652 mp->type);
653 mp++;
654 }
655return buff;
656}
657
658//==========================================================================
659
660void lspci(void)
661{
662if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
663setActiveDisplayPage(1);
664clearScreenRows(0, 24);
665setCursorPosition(0, 0, 1);
666}
667
668dump_pci_dt(root_pci_dev->children);
669
670pause();
671
672if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
673setActiveDisplayPage(0);
674}
675}
676
677//==========================================================================
678
679int getBootOptions(bool firstRun)
680{
681int i;
682int key;
683int nextRow;
684int timeout;
685int bvCount;
686BVRef bvr;
687BVRef menuBVR;
688bool showPrompt, newShowPrompt, isCDROM;
689
690// Initialize default menu selection entry.
691gBootVolume = menuBVR = selectBootVolume(bvChain);
692
693if (biosDevIsCDROM(gBIOSDev)) {
694isCDROM = true;
695} else {
696isCDROM = false;
697}
698
699// ensure we're in graphics mode if gui is setup
700if (gui.initialised) {
701if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
702setVideoMode(GRAPHICS_MODE, 0);
703}
704}
705
706// Allow user to override default timeout.
707if (multiboot_timeout_set) {
708timeout = multiboot_timeout;
709} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
710/* If there is no timeout key in the file use the default timeout
711 which is different for CDs vs. hard disks. However, if not booting
712 a CD and no config file could be loaded set the timeout
713 to zero which causes the menu to display immediately.
714 This way, if no partitions can be found, that is the disk is unpartitioned
715 or simply cannot be read) then an empty menu is displayed.
716 If some partitions are found, for example a Windows partition, then
717 these will be displayed in the menu as foreign partitions.
718 */
719if (isCDROM) {
720timeout = kCDBootTimeout;
721} else {
722timeout = sysConfigValid ? kBootTimeout : 0;
723}
724}
725
726if (timeout < 0) {
727gBootMode |= kBootModeQuiet;
728}
729
730// If the user is holding down a modifier key, enter safe mode.
731if ((readKeyboardShiftFlags() & 0x0F) != 0) {
732gBootMode |= kBootModeSafe; //Azi: Mek has this commented out.
733}
734
735// If user typed F8, abort quiet mode, and display the menu.
736{
737bool f8press = false, spress = false, vpress = false;
738int key;
739while (readKeyboardStatus()) {
740key = bgetc ();
741if (key == 0x4200) f8press = true;
742if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
743if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
744}
745if (f8press) {
746gBootMode &= ~kBootModeQuiet;
747timeout = 0;
748}
749if ((gBootMode & kBootModeQuiet) && firstRun && vpress && (gBootArgsPtr + 3 < gBootArgsEnd)) {
750*(gBootArgsPtr++) = ' ';
751*(gBootArgsPtr++) = '-';
752*(gBootArgsPtr++) = 'v';
753}
754if ((gBootMode & kBootModeQuiet) && firstRun && spress && (gBootArgsPtr + 3 < gBootArgsEnd)) {
755*(gBootArgsPtr++) = ' ';
756*(gBootArgsPtr++) = '-';
757*(gBootArgsPtr++) = 's';
758}
759}
760clearBootArgs();
761
762if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
763setCursorPosition(0, 0, 0);
764clearScreenRows(0, kScreenLastRow);
765if (!(gBootMode & kBootModeQuiet)) {
766// Display banner and show hardware info.
767printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
768printf(getVBEInfoString());
769}
770changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
771verbose("Scanning device %x...", gBIOSDev);
772}
773
774// When booting from CD, default to hard drive boot when possible.
775if (isCDROM && firstRun) {
776const char *val;
777char *prompt;
778char *name;
779int cnt;
780int optionKey;
781
782if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig)) {
783cnt += 1;
784prompt = malloc(cnt);
785strlcpy(prompt, val, cnt);
786} else {
787name = malloc(80);
788getBootVolumeDescription(gBootVolume, name, 80, false);
789prompt = malloc(256);
790sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
791free(name);
792cnt = 0;
793}
794
795if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig )) {
796// The key specified is a special key.
797} else if (getValueForKey( kCDROMOptionKey, &val, &cnt, &bootInfo->bootConfig ) && cnt >= 1) {
798optionKey = val[0];
799} else {
800// Default to F8.
801optionKey = 0x4200;
802}
803
804// If the timeout is zero then it must have been set above due to the
805// early catch of F8 which means the user wants to set boot options
806// which we ought to interpret as meaning he wants to boot the CD.
807if (timeout != 0) {
808key = countdown(prompt, kMenuTopRow, timeout);
809} else {
810key = optionKey;
811}
812
813if (cnt) {
814free(prompt);
815}
816
817clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
818
819// Hit the option key ?
820if (key == optionKey) {
821gBootMode &= ~kBootModeQuiet;
822timeout = 0;
823} else {
824key = key & 0xFF;
825
826// Try booting hard disk if user pressed 'h'
827if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
828BVRef bvr;
829
830// Look at partitions hosting OS X other than the CD-ROM
831for (bvr = bvChain; bvr; bvr=bvr->next) {
832if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
833gBootVolume = bvr;
834}
835}
836}
837goto done;
838}
839}
840
841if (gBootMode & kBootModeQuiet) {
842// No input allowed from user.
843goto done;
844}
845
846if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
847// If the user is holding down a modifier key,
848// enter safe mode.
849if ((readKeyboardShiftFlags() & 0x0F) != 0) {
850gBootMode |= kBootModeSafe;
851}
852goto done;
853}
854
855if (gDeviceCount) {
856// Allocate memory for an array of menu items.
857menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
858if (menuItems == NULL) {
859goto done;
860}
861
862// Associate a menu item for each BVRef.
863for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
864if (bvr->visible) {
865getBootVolumeDescription(bvr, menuItems[i].name, 80, true);
866menuItems[i].param = (void *) bvr;
867if (bvr == menuBVR) {
868selectIndex = i;
869}
870i--;
871}
872}
873}
874
875if (bootArgs->Video.v_display == GRAPHICS_MODE) {
876// redraw the background buffer
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;
1267const char*value; //Azi:sysversion
1268int len; //Azi:sysversion
1269 int cnt;
1270int userCnt;
1271 int cntRemaining;
1272 char * argP;
1273 char uuidStr[64];
1274 bool uuidSet = false;
1275 char * configKernelFlags;
1276 char * valueBuffer;
1277config_file_t systemVersion;//Azi:sysversion - system.plist of booting partition
1278
1279 valueBuffer = malloc(VALUE_SIZE);
1280
1281 skipblanks( &cp );
1282
1283 // Update the unit and partition number.
1284
1285 if ( gBootVolume )
1286 {
1287 if (!( gBootVolume->flags & kBVFlagNativeBoot ))
1288 {
1289 readBootSector( gBootVolume->biosdev, gBootVolume->part_boff,
1290 (void *) 0x7c00 );
1291
1292 //
1293 // Setup edx, and signal intention to chain load the
1294 // foreign booter.
1295 //
1296
1297 chainbootdev = gBootVolume->biosdev;
1298 chainbootflag = 1;
1299
1300 return 1;
1301 }
1302 setRootVolume( gBootVolume );
1303 }
1304 // If no boot volume fail immediately because we're just going to fail
1305 // trying to load the config file anyway.
1306 else
1307 return -1;
1308
1309// Needed to enable search for override Boot.plist on OS specific folders
1310// from loadOverrideConfig(). Find out which version mac os we're booting.
1311if (!loadConfigFile("/System/Library/CoreServices/SystemVersion.plist", &systemVersion))
1312{
1313if (getValueForKey(kProductVersion, &value, &len, &systemVersion))
1314{
1315// getValueForKey uses const char for val
1316// so copy it and trim
1317strncpy(gMacOSVersion, value, MIN(len, 4));
1318gMacOSVersion[MIN(len, 4)] = '\0';
1319}
1320} // doesn't print to screen here!
1321
1322//Azi: implemented at loadOverrideConfig.
1323 // Load config table specified by the user, or use the default.
1324 //if (!getValueForBootKey(cp, "config", &val, &cnt)) {
1325 // val = 0;
1326 // cnt = 0;
1327 //}
1328
1329 // Load com.apple.Boot.plist from the selected volume
1330 // and use its contents to override default bootConfig.
1331 // This is not a mandatory operation anymore.
1332
1333 loadOverrideConfig(&bootInfo->overrideConfig);
1334
1335 // Use the kernel name specified by the user, or fetch the name
1336 // in the config table, or use the default if not specified.
1337 // Specifying a kernel name on the command line, or specifying
1338 // a non-default kernel name in the config file counts as
1339 // overriding the kernel, which causes the kernelcache not
1340 // to be used.
1341
1342 gOverrideKernel = false;
1343 if (( kernel = extractKernelName((char **)&cp) )) {
1344 strcpy( bootInfo->bootFile, kernel );
1345 gOverrideKernel = true;
1346 } else {
1347 if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1348 strlcpy( bootInfo->bootFile, val, cnt+1 );
1349 if (strcmp( bootInfo->bootFile, kDefaultKernelName ) != 0) {
1350 gOverrideKernel = true;
1351 }
1352 } else {
1353 strcpy( bootInfo->bootFile, kDefaultKernelName );
1354 }
1355 }
1356
1357 cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space
1358 argP = bootArgs->CommandLine;
1359
1360 // Get config table kernel flags, if not ignored.
1361 if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) ||
1362!getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) {
1363 val = "";
1364 cnt = 0;
1365 }
1366 configKernelFlags = malloc(cnt + 1);
1367 strlcpy(configKernelFlags, val, cnt + 1);
1368
1369 if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) {
1370 // boot-uuid was set either on the command-line or in the config file.
1371 uuidSet = true;
1372 } else {
1373 // Try an alternate method for getting the root UUID on boot helper partitions.
1374 if (gBootVolume->flags & kBVFlagBooter)
1375 {
1376 if ((loadHelperConfig(&bootInfo->helperConfig) == 0)
1377 && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) )
1378 {
1379 getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig);
1380 copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining);
1381 uuidSet = true;
1382 }
1383 }
1384
1385 if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) {
1386 verbose("Setting boot-uuid to: %s\n", uuidStr);
1387 copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining);
1388 uuidSet = true;
1389 }
1390 }
1391
1392 if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) {
1393 cnt = 0;
1394 if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) {
1395 valueBuffer[0] = '*';
1396 cnt++;
1397 strlcpy(valueBuffer + 1, val, cnt);
1398 val = valueBuffer;
1399 } else {
1400 if (uuidSet) {
1401 val = "*uuid";
1402 cnt = 5;
1403 } else {
1404 // Don't set "rd=.." if there is no boot device key
1405 // and no UUID.
1406 val = "";
1407 cnt = 0;
1408 }
1409 }
1410 if (cnt > 0) {
1411 copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining);
1412 }
1413 strlcpy( gRootDevice, val, (cnt + 1));
1414 }
1415
1416 /*
1417 * Removed. We don't need this anymore.
1418 *
1419 if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) {
1420 getPlatformName(gPlatformName);
1421 copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining);
1422 }
1423 */
1424
1425 if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) &&
1426 !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) {
1427 if (gBootMode & kBootModeSafe) {
1428 copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining);
1429 }
1430 }
1431
1432 // Store the merged kernel flags and boot args.
1433
1434 cnt = strlen(configKernelFlags);
1435 if (cnt) {
1436 if (cnt > cntRemaining) {
1437 error("Warning: boot arguments too long, truncating\n");
1438 cnt = cntRemaining;
1439 }
1440 strncpy(argP, configKernelFlags, cnt);
1441 argP[cnt++] = ' ';
1442 cntRemaining -= cnt;
1443 }
1444 userCnt = strlen(cp);
1445 if (userCnt > cntRemaining) {
1446 error("Warning: boot arguments too long, truncating\n");
1447 userCnt = cntRemaining;
1448 }
1449 strncpy(&argP[cnt], cp, userCnt);
1450 argP[cnt+userCnt] = '\0';
1451
1452 if(!shouldboot)
1453 {
1454 gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) ||
1455 getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig );
1456
1457 gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ?
1458 kBootModeSafe : kBootModeNormal;
1459
1460 if ( getValueForKey( kOldSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) {
1461 gBootMode = kBootModeSafe;
1462 }
1463
1464 if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) ) {
1465 strlcpy(gMKextName, val, cnt + 1);
1466 }
1467
1468 }
1469
1470 free(configKernelFlags);
1471 free(valueBuffer);
1472
1473 return 0;
1474}
1475
1476
1477//==========================================================================
1478// Load the help file and display the file contents on the screen.
1479
1480static void showTextBuffer(char *buf, int size)
1481{
1482char*bp;
1483intline;
1484intline_offset;
1485intc;
1486
1487if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1488showInfoBox( "Press q to quit\n",buf );
1489return;
1490}
1491
1492 bp = buf;
1493 while (size-- > 0) {
1494if (*bp == '\n') {
1495*bp = '\0';
1496}
1497bp++;
1498 }
1499 *bp = '\1';
1500 line_offset = 0;
1501
1502 setActiveDisplayPage(1);
1503
1504 while (1) {
1505clearScreenRows(0, 24);
1506setCursorPosition(0, 0, 1);
1507bp = buf;
1508for (line = 0; *bp != '\1' && line < line_offset; line++) {
1509while (*bp != '\0') {
1510bp++;
1511}
1512bp++;
1513}
1514for (line = 0; *bp != '\1' && line < 23; line++) {
1515setCursorPosition(0, line, 1);
1516printf("%s\n", bp);
1517while (*bp != '\0') {
1518bp++;
1519}
1520bp++;
1521}
1522
1523setCursorPosition(0, 23, 1);
1524if (*bp == '\1') {
1525printf("[Type %sq or space to quit viewer]", (line_offset > 0) ? "p for previous page, " : "");
1526} else {
1527printf("[Type %s%sq to quit viewer]", (line_offset > 0) ? "p for previous page, " : "", (*bp != '\1') ? "space for next page, " : "");
1528}
1529
1530c = getc();
1531if (c == 'q' || c == 'Q') {
1532break;
1533}
1534if ((c == 'p' || c == 'P') && line_offset > 0) {
1535line_offset -= 23;
1536}
1537if (c == ' ') {
1538if (*bp == '\1') {
1539break;
1540} else {
1541line_offset += 23;
1542}
1543}
1544 }
1545 setActiveDisplayPage(0);
1546}
1547
1548void showHelp(void)
1549{
1550if (bootArgs->Video.v_display == GRAPHICS_MODE) {
1551showInfoBox("Help. Press q to quit.\n", (char *)BootHelp_txt);
1552} else {
1553showTextBuffer((char *)BootHelp_txt, BootHelp_txt_len);
1554}
1555}
1556
1557void showTextFile(const char * filename) //Azi: ?more - check this...
1558{
1559#define MAX_TEXT_FILE_SIZE 65536
1560char*buf;
1561intfd;
1562intsize;
1563
1564if ((fd = open_bvdev("bt(0,0)", filename, 0)) < 0) {
1565printf("\nFile not found: %s\n", filename);
1566sleep(2);
1567return;
1568}
1569
1570 size = file_size(fd);
1571 if (size > MAX_TEXT_FILE_SIZE) {
1572size = MAX_TEXT_FILE_SIZE;
1573}
1574 buf = malloc(size);
1575 read(fd, buf, size);
1576 close(fd);
1577showTextBuffer(buf, size);
1578free(buf);
1579}
1580
1581// This is a very simplistic prompting scheme that just grabs two hex characters
1582// Eventually we need to do something more user-friendly like display a menu
1583// based off of the Multiboot device list
1584
1585int selectAlternateBootDevice(int bootdevice)
1586{
1587int key;
1588int newbootdevice;
1589int digitsI = 0;
1590char *end;
1591char digits[3] = {0,0,0};
1592
1593// We've already printed the current boot device so user knows what it is
1594printf("Typical boot devices are 80 (First HD), 81 (Second HD)\n");
1595printf("Enter two-digit hexadecimal boot device [%02x]: ", bootdevice);
1596do {
1597key = getc();
1598switch (key & kASCIIKeyMask) {
1599case kBackspaceKey:
1600if (digitsI > 0) {
1601int x, y, t;
1602getCursorPositionAndType(&x, &y, &t);
1603// Assume x is not 0;
1604x--;
1605setCursorPosition(x,y,0); // back up one char
1606// Overwrite with space without moving cursor position
1607putca(' ', 0x07, 1);
1608digitsI--;
1609} else {
1610// TODO: Beep or something
1611}
1612break;
1613
1614case kReturnKey:
1615digits[digitsI] = '\0';
1616newbootdevice = strtol(digits, &end, 16);
1617if (end == digits && *end == '\0') {
1618// User entered empty string
1619printf("\nUsing default boot device %x\n", bootdevice);
1620key = 0;
1621} else if(end != digits && *end == '\0') {
1622bootdevice = newbootdevice;
1623printf("\n");
1624key = 0; // We gots da boot device
1625} else {
1626printf("\nCouldn't parse. try again: ");
1627digitsI = 0;
1628}
1629break;
1630
1631default:
1632if (isxdigit(key & kASCIIKeyMask) && digitsI < 2) {
1633putc(key & kASCIIKeyMask);
1634digits[digitsI++] = key & kASCIIKeyMask;
1635} else {
1636// TODO: Beep or something
1637}
1638break;
1639};
1640} while (key != 0);
1641
1642return bootdevice;
1643}
1644
1645bool promptForRescanOption(void)
1646{
1647printf("\nWould you like to enable media rescan option?\nPress ENTER to enable or any key to skip.\n");
1648if (getc() == kReturnKey) {
1649return true;
1650} else {
1651return false;
1652}
1653}
1654

Archive Download this file

Revision: 380