Example #1
0
static bool flushKeyboardBuffer(void)
{
    bool status = false;

    while ( readKeyboardStatus() ) {
        if (bgetc() == 0x4200) status = true;
    }
    return status;
}
Example #2
0
static BOOL flushKeyboardBuffer()
{
    BOOL status = FALSE;

    while ( readKeyboardStatus() ) {
        if (bgetc() == 0x4200) status = TRUE;
    }
    return status;
}
Example #3
0
int bgetc(void)
{
    /*  Poll for the next character.  Most real BIOS do not need this as the
        INT 16h,AH=0h function will block until one is received.
        Unfortunately, Apple's EFI CSM will never wake up.  This idea is lifted
        from the grub-a20.patch to GRUB's stage2/asm.S file.
     */
	while(!readKeyboardStatus());

	bb.intno = 0x16;
	bb.eax.r.h = 0x00;
	bios(&bb);

	return bb.eax.rr;
}
Example #4
0
static int countdown( const char * msg, register int row, register int timeout, int *optionKey )
{
    register unsigned long time;
    int ch  = 0;
    register int col = strlen(msg) + 1;
	
    
    flushKeyboardBuffer();
	
	moveCursor( 0, row );
	printf("%s",msg);
	
    for ( time = time18(), timeout++; timeout > 0; )
    {
		if ((ch = readKeyboardStatus())){
			*optionKey = ch;            
            break;
		}
        // Count can be interrupted by holding down shift,
        // control or alt key
        if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
		{
            ch = 1;
			
            break;
        }
		
        if ( time18() >= time )
        {
            time += 18;
            timeout--;
			
			moveCursor( col, row );            
			printf("(%d)", timeout);
#ifdef ShowCurrentDate            
            printf("\n\n\n\nCurrent Date : %s", Date());
#endif
        }
    }
	
    flushKeyboardBuffer();
    
    return ch;
}
Example #5
0
static int countdown( const char * msg, int row, int timeout )
{
    unsigned long time;
    int ch  = 0;
    int col = strlen(msg) + 1;

    flushKeyboardBuffer();

    moveCursor( 0, row );
    printf(msg);

    for ( time = time18(), timeout++; timeout > 0; )
    {
        if (ch = readKeyboardStatus())
            break;

        // Count can be interrupted by holding down shift,
        // control or alt key
        if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 ) {
            ch = 1;
            break;
        }

        if ( time18() >= time )
        {
            time += 18;
            timeout--;
            moveCursor( col, row );
            printf("(%d) ", timeout);
        }
    }

    flushKeyboardBuffer();

    return ch;
}
Example #6
0
static int countdown( const char * msg, int row, int timeout )
{
    unsigned long time;
    int ch  = 0;
    int col = strlen(msg) + 1;
	
    flushKeyboardBuffer();

	if( bootArgs->Video.v_display == VGA_TEXT_MODE )
	{
		moveCursor( 0, row );
		printf(msg);

	} else {

		position_t p = pos( gui.screen.width / 2 + 1 , ( gui.devicelist.pos.y + 3 ) + ( ( gui.devicelist.height - gui.devicelist.iconspacing ) / 2 ) );
	
		char dummy[80];
		getBootVolumeDescription( gBootVolume, dummy, sizeof(dummy) - 1, true );
		drawDeviceIcon( gBootVolume, gui.screen.pixmap, p, true );
		drawStrCenteredAt( (char *) msg, &font_small, gui.screen.pixmap, gui.countdown.pos );
		
		// make this screen the new background
		memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
		
	}

	int multi_buff = 18 * (timeout);
    int multi = ++multi_buff;

    int lasttime=0;

    for ( time = time18(), timeout++; timeout > 0; )
    {
		if( time18() > lasttime)
		{
			multi--; 
			lasttime=time18();
		}		
  
        if (ch = readKeyboardStatus())
            break;

        // Count can be interrupted by holding down shift,
        // control or alt key
        if ( ( readKeyboardShiftFlags() & 0x0F ) != 0 )
		{
            ch = 1;
            break;
        }

        if ( time18() >= time )
        {
            time += 18;
            timeout--;

			if( bootArgs->Video.v_display == VGA_TEXT_MODE )
			{
				moveCursor( col, row );
				printf("(%d) ", timeout);
			}
        }
	
		if( bootArgs->Video.v_display == GRAPHICS_MODE )
		{
			drawProgressBar( gui.screen.pixmap, 100, gui.progressbar.pos , ( multi * 100 / multi_buff ) );
			gui.redraw = true;
			updateVRAM();
		}

    }

    flushKeyboardBuffer();

    return ch;
}
Example #7
0
int getBootOptions(bool firstRun)
{
	int     i;
	int     key;
	int     nextRow;
	int     timeout;
	int     bvCount;
	BVRef   bvr;
	BVRef   menuBVR;
	bool    showPrompt, newShowPrompt, isCDROM;

	// Initialize default menu selection entry.
	gBootVolume = menuBVR = selectBootVolume(bvChain);

	if (biosDevIsCDROM(gBIOSDev)) {
		isCDROM = true;
	} else {
		isCDROM = false;
	}

	// ensure we're in graphics mode if gui is setup
	if (gui.initialised && bootArgs->Video.v_display == VGA_TEXT_MODE)
	{
		setVideoMode(GRAPHICS_MODE, 0);
	}

	// Clear command line boot arguments
	clearBootArgs();

	// Allow user to override default timeout.
	if (multiboot_timeout_set) {
		timeout = multiboot_timeout;
	} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->bootConfig)) {
		/*  If there is no timeout key in the file use the default timeout
		    which is different for CDs vs. hard disks.  However, if not booting
		    a CD and no config file could be loaded set the timeout
		    to zero which causes the menu to display immediately.
		    This way, if no partitions can be found, that is the disk is unpartitioned
		    or simply cannot be read) then an empty menu is displayed.
		    If some partitions are found, for example a Windows partition, then
		    these will be displayed in the menu as foreign partitions.
		 */
		if (isCDROM) {
			timeout = kCDBootTimeout;
		} else {
			timeout = sysConfigValid ? kBootTimeout : 0;
		}
	}

	if (timeout < 0) {
		gBootMode |= kBootModeQuiet;
	}

	// If the user is holding down a modifier key, enter safe mode.
	if ((readKeyboardShiftFlags() & 0x0F) != 0) {
		gBootMode |= kBootModeSafe;
	}

	//	 18seven's Quick-args macro
		bool f8 = false, altf = false, shiftf = false, alts = false, 
		altv = false, altx = false; // x32 = false,  x64 = false;
		while (readKeyboardStatus())
		{
			key = bgetc ();
			if (key == 0x4200) f8 = true;
			if (key == 0x2100) altf = true;
			if (key == 0x0046) shiftf = true;
			if (key == 0x1F00) alts = true;
			if (key == 0x2F00) altv = true;
			if (key == 0x2D00) altx = true;
/*			if (key == 0x0004) x32 = true;
			if (key == 0x0007) x64 = true;
*/		}

	// If user typed F8, abort quiet mode, and display the menu.
	if (f8) {
		gBootMode &= ~kBootModeQuiet;
		timeout = 0;
	}

	// If user typed 'alt-v', boot in verbose mode.
	if ((gBootMode & kBootModeQuiet) && firstRun && altv) {
		addBootArg(kVerboseModeFlag);
	}

	// If user typed 'alt-s', boot in single user mode.
	if ((gBootMode & kBootModeQuiet) && firstRun && alts) {
		addBootArg(kSingleUserModeFlag);
	}

	if ((gBootMode & kBootModeQuiet) && firstRun && altf) {
		addBootArg(kIgnoreCachesFlag);
	}

	if ((gBootMode & kBootModeQuiet) && firstRun && shiftf) {
		addBootArg(kIgnoreBootFileFlag);
	}

	if ((gBootMode & kBootModeQuiet) && firstRun && altx) {
		addBootArg(kSafeModeFlag);
	}
/*
	if ((gBootMode & kBootModeQuiet) && firstRun && x32) {
		addBootArg(k32BitModeFlag);
	}

	if ((gBootMode & kBootModeQuiet) && firstRun && x64) {
		addBootArg(k64BitModeFlag);
	}
*/
	if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
		setCursorPosition(0, 0, 0);
		clearScreenRows(0, kScreenLastRow);
		if (!(gBootMode & kBootModeQuiet)) {
			// Display banner and show hardware info.
			printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
			printf(getVBEInfoString());
		}
		changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
		verbose("Scanning device %x...", gBIOSDev);
	}

	// When booting from CD, default to hard drive boot when possible.
	if (isCDROM && firstRun) {
		const char *val;
		char *prompt = NULL;
		char *name = NULL;
		int cnt;
		int optionKey;

		if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->bootConfig)) {
			prompt = malloc(cnt + 1);
			strncat(prompt, val, cnt);
		} else {
			name = malloc(80);
			getBootVolumeDescription(gBootVolume, name, 79, false);
			prompt = malloc(256);
			sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
			free(name);
		}

		if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->bootConfig )) {
			// The key specified is a special key.
		} else {
			// Default to F8.
			optionKey = 0x4200;
		}

		// If the timeout is zero then it must have been set above due to the
		// early catch of F8 which means the user wants to set boot options
		// which we ought to interpret as meaning he wants to boot the CD.
		if (timeout != 0) {
			key = countdown(prompt, kMenuTopRow, timeout);
		} else {
			key = optionKey;
		}

		if (prompt != NULL) {
			free(prompt);
		}

		clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );

		// Hit the option key ?
		if (key == optionKey) {
			gBootMode &= ~kBootModeQuiet;
			timeout = 0;
		} else {
			key = key & 0xFF;

			// Try booting hard disk if user pressed 'h'
			if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
				BVRef bvr;

				// Look at partitions hosting OS X other than the CD-ROM
				for (bvr = bvChain; bvr; bvr=bvr->next) {
					if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
						gBootVolume = bvr;
					}
				}
			}
			goto done;
		}
	}

	if (gBootMode & kBootModeQuiet) {
		// No input allowed from user.
		goto done;
	}

	if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
		// If the user is holding down a modifier key,
		// enter safe mode.
		if ((readKeyboardShiftFlags() & 0x0F) != 0) {
			gBootMode |= kBootModeSafe;
		}
		goto done;
	}

	if (gDeviceCount) {
		// Allocate memory for an array of menu items.
		menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
		if (menuItems == NULL) {
			goto done;
		}

		// Associate a menu item for each BVRef.
		for (bvr=bvChain, i=gDeviceCount-1, selectIndex=0; bvr; bvr=bvr->next) {
			if (bvr->visible) {
				getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
				menuItems[i].param = (void *) bvr;
				if (bvr == menuBVR) {
					selectIndex = i;
				}
				i--;
			}
		}
	}

	if (bootArgs->Video.v_display == GRAPHICS_MODE) {
		// redraw the background buffer
		gui.logo.draw = true;
		drawBackground();
		gui.devicelist.draw = true;
		gui.redraw = true;
		if (!(gBootMode & kBootModeQuiet)) {
			bool showBootBanner = true;
 
			// Check if "Boot Banner"=N switch is present in config file.
			getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig); 
			if (showBootBanner) {
				// Display banner and show hardware info.
				gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
			}

			// redraw background
			memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
		}
	} else {
		// Clear screen and hide the blinking cursor.
		clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
		changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
	}

	nextRow = kMenuTopRow;
	showPrompt = true;

	if (gDeviceCount) {
		if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
			printf("Use \30\31 keys to select the startup volume.");
		}
		showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
		nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
	}

	// Show the boot prompt.
	showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
	showBootPrompt( nextRow, showPrompt );
	
	do {
		if (bootArgs->Video.v_display == GRAPHICS_MODE) {
			// redraw background
			memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
			// reset cursor co-ords
			gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
		}
		key = getc();
		updateMenu( key, (void **) &menuBVR );
		newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);

		if (newShowPrompt != showPrompt) {
			showPrompt = newShowPrompt;
			showBootPrompt( nextRow, showPrompt );
		}

		if (showPrompt) {
			updateBootArgs(key);
		}

		switch (key) {
		case kReturnKey:
			if (gui.menu.draw) { 
				key=0;
				break;
			}
			if (*gBootArgs == '?') {
				char * argPtr = gBootArgs;

				// Skip the leading "?" character.
				argPtr++;
				getNextArg(&argPtr, booterCommand);
				getNextArg(&argPtr, booterParam);

				/*
				* TODO: this needs to be refactored.
				*/
				if (strcmp( booterCommand, "video" ) == 0) {
					if (bootArgs->Video.v_display == GRAPHICS_MODE) {
						showInfoBox(getVBEInfoString(), getVBEModeInfoString());
					} else {
						printVBEModeInfo();
					}
				} else if ( strcmp( booterCommand, "memory" ) == 0) {
					if (bootArgs->Video.v_display == GRAPHICS_MODE ) {
						showInfoBox("Memory Map", getMemoryInfoString());
					} else {
						printMemoryInfo();
					}
				} else if (strcmp(booterCommand, "lspci") == 0) {
					lspci();
				} else if (strcmp(booterCommand, "more") == 0) {
					showTextFile(booterParam);
				} else if (strcmp(booterCommand, "rd") == 0) {
					processRAMDiskCommand(&argPtr, booterParam);
				} else if (strcmp(booterCommand, "norescan") == 0) {
					if (gEnableCDROMRescan) {
						gEnableCDROMRescan = false;
						break;
					}
				} else {
					showHelp();
				}
				key = 0;
				showBootPrompt(nextRow, showPrompt);
				break;
			}
			gBootVolume = menuBVR;
			setRootVolume(menuBVR);
			gBIOSDev = menuBVR->biosdev;
			break;

		case kEscapeKey:
			clearBootArgs();
			break;
		
		case kF2Key:
			
			/*
			 * AutoResolution - Reapply the patch if Graphics Mode was incorrect or EDID Info was insane
			 */
			
			if ((gAutoResolution == TRUE) && map)
			{
				// get the new Graphics Mode key
				processBootOptions();
				
				UInt32 params[4];
				params[3] = 0;
				//Has the target Resolution Changed ?
				int count = getNumberArrayFromProperty(kGraphicsModeKey, params, 4);
				if ( count < 3 )
					getResolution(params);
				
				if ((params[0] != 0) && (params[1] != 0)
				&& (params[0] != map->currentX) && (params[1] != map->currentY))
				{
				
					//Go back to TEXT mode while we change  the mode
					if (bootArgs->Video.v_display == GRAPHICS_MODE)
					{
						CursorState cursorState;
						
						setVideoMode(VGA_TEXT_MODE, 0);
						
						setCursorPosition(0, 0, 0);
						clearScreenRows(0, kScreenLastRow);
						changeCursor( 0, 0, kCursorTypeHidden, &cursorState );
						
						//Reapply patch in case resolution have changed
						
						patchVbios(map, params[0], params[1], params[2], 0, 0);
						
						if (useGUI && (gui.initialised == true))
							initGUI();
						// Make sure all values are set
						if (bootArgs->Video.v_display != GRAPHICS_MODE)
							bootArgs->Video.v_display = GRAPHICS_MODE;
						
						if (!useGUI)
							useGUI = true;
						
						// redraw the background buffer
						drawBackground();
						gui.devicelist.draw = true;
						gui.redraw = true;
						if (!(gBootMode & kBootModeQuiet))
						{
							bool showBootBanner = true;
							
							// Check config file.
							getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->bootConfig); 
							if (showBootBanner)
								// Display banner and show hardware info.
								gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
								
							// redraw background
							memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
						}
						
						nextRow = kMenuTopRow;
						showPrompt = true;
						
						if (gDeviceCount)
						{
							showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
							nextRow += min( gDeviceCount, kMenuMaxItems ) + 3;
						}
						
						// Show the boot prompt.
						showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
						showBootPrompt( nextRow, showPrompt );
						
						//this is used to avoid resetting the incorrect mode while quiting the boot menu
						map->hasSwitched = true;
					}
				}
				clearBootArgs();
				key = 0;
			}
			break;

		case kF5Key:
			// New behavior:
			// Clear gBootVolume to restart the loop
			// if the user enabled rescanning the optical drive.
			// Otherwise boot the default boot volume.
			if (gEnableCDROMRescan) {
				gBootVolume = NULL;
				clearBootArgs();
			}
			break;

		case kF10Key:
			gScanSingleDrive = false;
			scanDisks(gBIOSDev, &bvCount);
			gBootVolume = NULL;
			clearBootArgs();
			break;

		case kTabKey:
			// New behavior:
			// Switch between text & graphic interfaces
			// Only Permitted if started in graphics interface
			if (useGUI)
			{
				setVideoMode(VGA_TEXT_MODE, 0);

				setCursorPosition(0, 0, 0);
				clearScreenRows(0, kScreenLastRow);

				// Display banner and show hardware info.
				printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
				printf(getVBEInfoString());

				clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
				changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);

				nextRow = kMenuTopRow;
				showPrompt = true;

				if (gDeviceCount)
				{
					printf("Use \30\31 keys to select the startup volume.");
					showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
					nextRow += min(gDeviceCount, kMenuMaxItems) + 3;
				}

				showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
				showBootPrompt(nextRow, showPrompt);
				//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
				
				/*
				 * AutoResolution - make sure all values are set
				 */
				
				bootArgs->Video.v_display = VGA_TEXT_MODE;
				useGUI = false;
			}
			else
			{
				gui.redraw = true;
				setVideoMode(GRAPHICS_MODE, 0);
				
				/*
				 * AutoResolution - make sure all values are set
				 */
				bootArgs->Video.v_display = GRAPHICS_MODE;
				useGUI = true;
				
				updateVRAM();
			}
			key = 0;
			break;

		default:
			key = 0;
			break;
		}
	} while (0 == key);

done:
	if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
		clearScreenRows(kMenuTopRow, kScreenLastRow);
		changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
	}
	shouldboot = false;
	gui.menu.draw = false;
	if (menuItems) {
		free(menuItems);
		menuItems = NULL;
	}
	return 0;
}
Example #8
0
int getBootOptions(bool firstRun)
{
	int     i;
	int     key;
	int     nextRow;
	int     timeout;
	int     bvCount;
	BVRef   bvr;
	BVRef   menuBVR;
	bool    showPrompt, newShowPrompt, isCDROM;

	// Initialize default menu selection entry.
	gBootVolume = menuBVR = selectBootVolume(bvChain);

	if (biosDevIsCDROM(gBIOSDev)) {
		isCDROM = true;
	} else {
		isCDROM = false;
	}

	// ensure we're in graphics mode if gui is setup
	if (firstRun && gui.initialised && bootArgs->Video.v_display == VGA_TEXT_MODE)
	{
		setVideoMode(GRAPHICS_MODE, 0);
	}

	// Clear command line boot arguments
	clearBootArgs();

	// Allow user to override default timeout.
	if (multiboot_timeout_set) {
		timeout = multiboot_timeout;
	} else if (!getIntForKey(kTimeoutKey, &timeout, &bootInfo->chameleonConfig)) {
		/*  If there is no timeout key in the file use the default timeout
		    which is different for CDs vs. hard disks.  However, if not booting
		    a CD and no config file could be loaded set the timeout
		    to zero which causes the menu to display immediately.
		    This way, if no partitions can be found, that is the disk is unpartitioned
		    or simply cannot be read) then an empty menu is displayed.
		    If some partitions are found, for example a Windows partition, then
		    these will be displayed in the menu as foreign partitions.
		 */
		if (isCDROM) {
			timeout = kCDBootTimeout;
		} else {
			timeout = sysConfigValid ? kBootTimeout : 0;
		}
	}

	if (timeout < 0) {
		gBootMode |= kBootModeQuiet;
	}

	// If the user is holding down a modifier key, enter safe mode.
	if ((readKeyboardShiftFlags() & 0x0F) != 0) {
		gBootMode |= kBootModeSafe;
	}

	// Checking user pressed keys
	bool f8press = false, spress = false, vpress = false;
	while (readKeyboardStatus()) {
		key = bgetc ();
		if (key == 0x4200) f8press = true;
		if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
		if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
	}
	// If user typed F8, abort quiet mode, and display the menu.
	if (f8press) {
		gBootMode &= ~kBootModeQuiet;
		timeout = 0;
	}
	// If user typed 'v' or 'V', boot in verbose mode.
	if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
		addBootArg(kVerboseModeFlag);
	}
	// If user typed 's' or 'S', boot in single user mode.
	if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
		addBootArg(kSingleUserModeFlag);
	}

	if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
		setCursorPosition(0, 0, 0);
		clearScreenRows(0, kScreenLastRow);
		if (!(gBootMode & kBootModeQuiet)) {
			// Display banner and show hardware info.
			printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
			printf(getVBEInfoString());
		}
		changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
		verbose("Scanning device %x...", gBIOSDev);
	}

	// When booting from CD, default to hard drive boot when possible. 
	if (isCDROM && firstRun) {
		const char *val;
		char *prompt = NULL;
		char *name = NULL;
		int cnt;
		int optionKey;

		if (getValueForKey(kCDROMPromptKey, &val, &cnt, &bootInfo->chameleonConfig)) {
			prompt = malloc(cnt + 1);
			strncat(prompt, val, cnt);
		} else {
			name = malloc(80);
			getBootVolumeDescription(gBootVolume, name, 79, false);
			prompt = malloc(256);
			sprintf(prompt, "Press any key to start up from %s, or press F8 to enter startup options.", name);
			free(name);
		}

		if (getIntForKey( kCDROMOptionKey, &optionKey, &bootInfo->chameleonConfig )) {
			// The key specified is a special key.
		} else {
			// Default to F8.
			optionKey = 0x4200;
		}

		// If the timeout is zero then it must have been set above due to the
		// early catch of F8 which means the user wants to set boot options
		// which we ought to interpret as meaning he wants to boot the CD.
		if (timeout != 0) {
			key = countdown(prompt, kMenuTopRow, timeout);
		} else {
			key = optionKey;
		}

		if (prompt != NULL) {
			free(prompt);
		}

		clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );

		// Hit the option key ?
		if (key == optionKey) {
			gBootMode &= ~kBootModeQuiet;
			timeout = 0;
		} else {
			key = key & 0xFF;

			// Try booting hard disk if user pressed 'h'
			if (biosDevIsCDROM(gBIOSDev) && key == 'h') {
				BVRef bvr;

				// Look at partitions hosting OS X other than the CD-ROM
				for (bvr = bvChain; bvr; bvr=bvr->next) {
					if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != gBIOSDev) {
						gBootVolume = bvr;
					}
				}
			}
			goto done;
		}
	}

	if (gBootMode & kBootModeQuiet) {
		// No input allowed from user.
		goto done;
	}

	if (firstRun && timeout > 0 && countdown("Press any key to enter startup options.", kMenuTopRow, timeout) == 0) {
		// If the user is holding down a modifier key,
		// enter safe mode.
		if ((readKeyboardShiftFlags() & 0x0F) != 0) {
			gBootMode |= kBootModeSafe;
		}
		goto done;
	}

	if (gDeviceCount > 0) {
		// Allocate memory for an array of menu items.
		menuItems = malloc(sizeof(MenuItem) * gDeviceCount);
		if (menuItems == NULL) {
			goto done;
		}

		// Associate a menu item for each BVRef.
		for (bvr=bvChain, i=gDeviceCount-1, selectIndex=-1; bvr; bvr=bvr->next) {
			if (bvr->visible) {
				getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
				menuItems[i].param = (void *) bvr;
				if (bvr == menuBVR) {
					selectIndex = i;
				}
				i--;
			}
		}
		// Jief : In case the default partition (returned by selectBootVolume) is not in the menu
		if ( selectIndex == -1 )
		{
			selectIndex = 0;

			// gDeviceCount is actually > 0, so menuItems[selectIndex] exists
			menuBVR = (BVRef)(menuItems[selectIndex].param);
			// what happen is bvChain is empty ?
		}
	}

	if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
		// redraw the background buffer
		gui.logo.draw = true;
		drawBackground();
		gui.devicelist.draw = true;
		gui.redraw = true;
		if (!(gBootMode & kBootModeQuiet)) {
 
			// Check if "Boot Banner"=N switch is present in config file.
			getBoolForKey(kBootBannerKey, &showBootBanner, &bootInfo->chameleonConfig); 
			if (showBootBanner) {
				// Display banner and show hardware info.
				gprintf(&gui.screen, bootBanner + 1, (bootInfo->convmem + bootInfo->extmem) / 1024);
			}

			// redraw background
			memcpy(gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4);
		}
	} else {
		// Clear screen and hide the blinking cursor.
		clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
		changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
	}

	nextRow = kMenuTopRow;
	showPrompt = true;

	if (gDeviceCount) {
		if( bootArgs->Video.v_display == VGA_TEXT_MODE ) {
			printf("Use \30\31 keys to select the startup volume.");
		}
		showMenu( menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
		nextRow += MIN( gDeviceCount, kMenuMaxItems ) + 3;
	}

	// Show the boot prompt.
	showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
	showBootPrompt( nextRow, showPrompt );
	
	do {
		if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
			// redraw background
			memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
			// reset cursor co-ords
			gui.debug.cursor = pos( gui.screen.width - 160 , 10 );
		}
		key = getchar();
		updateMenu( key, (void **) &menuBVR );
		newShowPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);

		if (newShowPrompt != showPrompt) {
			showPrompt = newShowPrompt;
			showBootPrompt( nextRow, showPrompt );
		}

		if (showPrompt) {
			updateBootArgs(key);
		}

		switch (key) {
		case KEY_ENTER:
			if (gui.menu.draw) { 
				key=0;
				break;
			}
			if (*gBootArgs == '?') {
				char * argPtr = gBootArgs;

				// Skip the leading "?" character.
				argPtr++;
				getNextArg(&argPtr, booterCommand);
				getNextArg(&argPtr, booterParam);

				/*
				* TODO: this needs to be refactored.
				*/
				if (strcmp( booterCommand, "video" ) == 0) {
					if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
						showInfoBox(getVBEInfoString(), getVBEModeInfoString());
					} else {
						printVBEModeInfo();
					}
				} else if ( strcmp( booterCommand, "memory" ) == 0) {
					if (bootArgs->Video.v_display != VGA_TEXT_MODE ) {
						showInfoBox("Memory Map", getMemoryInfoString());
					} else {
						printMemoryInfo();
					}
				} else if (strcmp(booterCommand, "lspci") == 0) {
					lspci();
				} else if (strcmp(booterCommand, "log") == 0) {
			                showTextBuffer(msgbuf, strlen(msgbuf));
				} else if (strcmp(booterCommand, "more") == 0) {
					showTextFile(booterParam);
				} else if (strcmp(booterCommand, "rd") == 0) {
					processRAMDiskCommand(&argPtr, booterParam);
				} else if (strcmp(booterCommand, "norescan") == 0) {
					if (gEnableCDROMRescan) {
						gEnableCDROMRescan = false;
						break;
					}
				} else {
					showHelp();
				}
				key = 0;
				showBootPrompt(nextRow, showPrompt);
				break;
			}
			gBootVolume = menuBVR;
			setRootVolume(menuBVR);
			gBIOSDev = menuBVR->biosdev;
			break;

		case KEY_ESC:
			clearBootArgs();
			break;

		case KEY_F5:
			// New behavior:
			// Clear gBootVolume to restart the loop
			// if the user enabled rescanning the optical drive.
			// Otherwise boot the default boot volume.
			if (gEnableCDROMRescan) {
				gBootVolume = NULL;
				clearBootArgs();
			}
			break;

		case KEY_F10:
			gScanSingleDrive = false;
			scanDisks(gBIOSDev, &bvCount);
			gBootVolume = NULL;
			clearBootArgs();
			break;

		case KEY_TAB:
			// New behavior:
			// Switch between text & graphic interfaces
			// Only Permitted if started in graphics interface
			if (useGUI) {
				if (bootArgs->Video.v_display != VGA_TEXT_MODE) {
					setVideoMode(VGA_TEXT_MODE, 0);

					setCursorPosition(0, 0, 0);
					clearScreenRows(0, kScreenLastRow);

					// Display banner and show hardware info.
					printf(bootBanner, (bootInfo->convmem + bootInfo->extmem) / 1024);
					printf(getVBEInfoString());

					clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
					changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);

					nextRow = kMenuTopRow;
					showPrompt = true;

					if (gDeviceCount) {
						printf("Use \30\31 keys to select the startup volume.");
						showMenu(menuItems, gDeviceCount, selectIndex, kMenuTopRow + 2, kMenuMaxItems);
						nextRow += MIN(gDeviceCount, kMenuMaxItems) + 3;
					}

					showPrompt = (gDeviceCount == 0) || (menuBVR->flags & kBVFlagNativeBoot);
					showBootPrompt(nextRow, showPrompt);
					//changeCursor( 0, kMenuTopRow, kCursorTypeUnderline, 0 );
				} else {
					gui.redraw = true;
					setVideoMode(GRAPHICS_MODE, 0);
					updateVRAM();
                    			updateGraphicBootPrompt();
				}
			}
			key = 0;
			break;

		default:
			key = 0;
			break;
		}
	} while (0 == key);

done:
	if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
		clearScreenRows(kMenuTopRow, kScreenLastRow);
		changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
	}
	shouldboot = false;
	gui.menu.draw = false;
	if (menuItems) {
		free(menuItems);
		menuItems = NULL;
	}
	execute_hook("BootOptions", gBootArgs, gBootArgsPtr, NULL, NULL);
	return 0;
}
Example #9
0
void boot(int biosdev)
{
    zeroBSS();
    mallocInit(0, 0, 0, mallocError);

#if MUST_ENABLE_A20
    // Enable A20 gate before accessing memory above 1 MB.
	if (fastEnableA20() != 0)
	{
		enableA20(); // Fast enable failed. Try legacy method.
	}
#endif

	bool	haveCABootPlist	= false;
	bool	quietBootMode	= true;

	void *fileLoadBuffer = (void *)kLoadAddr;

	char bootFile[256];
	char rootUUID[37];

	char * kernelFlags = NULL;

	const char * val;

	int length	= 0;
	int kernelFlagsLength = 0;

	bootFile[0] = '\0';
	rootUUID[0] = '\0';

#if PRE_LINKED_KERNEL_SUPPORT
	bool	mayUseKernelCache	= false;

	long flags, cachetime;
#endif

	initPlatform(biosdev);	// Passing on the boot drive.

#if DEBUG_STATE_ENABLED
	// Don't switch graphics mode / show boot logo when DEBUG is set to 1.
	printf("\ngArchCPUType (CPU): %s\n", (gArchCPUType == CPU_TYPE_X86_64) ? "x86_64" : "i386");
	sleep(3); // Silent sleep.
#else
	showBootLogo();
#endif

	// A bit ugly maybe, but this will be changed sometime soon.
	while (readKeyboardStatus())
	{
		int key = (bgetc() & 0xff);

		if ((key |= 0x20) == 'r')
		{
			gPlatform.BootRecoveryHD = true;
		}
	}

	initPartitionChain();

	#define loadCABootPlist() loadSystemConfig(&bootInfo->bootConfig)

	// Loading: /Library/Preferences/SystemConfiguration/com.apple.Boot.plist
	// TODO: Check if everything works <i>without</i> having this plist.
	if (loadCABootPlist() == STATE_SUCCESS)
	{
		_BOOT_DEBUG_DUMP("com.apple.Boot.plist located.\n");

		// Load successful. Change state accordantly.
		haveCABootPlist = true;	// Checked <i>before</i> calling key functions.

		// Check the value of <key>Kernel Flags</key> for stuff we are interested in.
		// Note: We need to know about: arch= and the boot flags: -s, -v, -f and -x

		if (getValueForKey(kKernelFlagsKey, &val, &kernelFlagsLength, &bootInfo->bootConfig))
		{
			// "Kernel Flags" key found. Check length to see if we have anything to work with.
			if (kernelFlagsLength)
			{
				kernelFlagsLength++;

				// Yes. Allocate memory for it and copy the kernel flags into it.
				kernelFlags = malloc(kernelFlagsLength);
				strlcpy(kernelFlags, val, kernelFlagsLength);

				// Is 'arch=<i386/x86_64>' specified as kernel flag?
				if (getValueForBootKey(kernelFlags, "arch", &val, &length)) //  && len >= 4)
				{
					gArchCPUType = (strncmp(val, "x86_64", 6) == 0) ? CPU_TYPE_X86_64 : CPU_TYPE_I386;

					_BOOT_DEBUG_DUMP("gArchCPUType (c.a.B.plist): %s\n",  (gArchCPUType == CPU_TYPE_X86_64) ? "x86_64" : "i386");
				}
				
				// Check for -v (verbose) and -s (single user mode) flags.
				gVerboseMode =	getValueForBootKey(kernelFlags, kVerboseModeFlag, &val, &length) || 
								getValueForBootKey(kernelFlags, kSingleUserModeFlag, &val, &length);
				
				if (gVerboseMode)
				{
#if DEBUG_BOOT == false
					setVideoMode(VGA_TEXT_MODE);
#endif
				}

				// Check for -x (safe) and -f (flush cache) flags.
				if (getValueForBootKey(kernelFlags, kSafeModeFlag, &val, &length) || 
					getValueForBootKey(kernelFlags, kIgnoreCachesFlag, &val, &length))
				{
					gBootMode = kBootModeSafe;
				}

				// Is 'boot-uuid=<value>' specified as kernel flag?
				if (getValueForBootKey(kernelFlags, kBootUUIDKey, &val, &length) && length == 36)
				{
					_BOOT_DEBUG_DUMP("Target boot-uuid=<%s>\n", val);

					// Yes. Copy its value into rootUUID.
					strlcpy(rootUUID, val, 37);
				}
				/* else
				{
					strlcpy(rootUUID, "3453E0E5-017B-38AD-A0AA-D0BBD8565D6", 37);
					_BOOT_DEBUG_DUMP("Target boot-uuid=<%s>\n", rootUUID);
				} */
			}
		}

#if PRE_LINKED_KERNEL_SUPPORT
		/* Look for 'Kernel Cache' key. */
		if (getValueForKey(kKernelCacheKey, &val, &length, &bootInfo->bootConfig))
		{
			_BOOT_DEBUG_DUMP("Kernel Cache set to: %s\n", val);

			// Key found. Check if the given filepath/name exists.
			if (length && GetFileInfo(NULL, val, &flags, &cachetime) == 0)
			{
				// File located. Init kernelCacheFile so that we can use it as boot file.
				gPlatform.KernelCachePath = strdup(val);

				// Set flag to inform the load process to skip parts of the code.
				gPlatform.KernelCacheSpecified = true;

				_BOOT_DEBUG_DUMP("kernelcache file found.\n");
			}

			_BOOT_DEBUG_ELSE_DUMP("Error: kernelcache file not found.\n");
		}

		// _BOOT_DEBUG_ELSE_DUMP("No 'Kernel Cache' key given.\n");
#endif
		/* Enable touching of a single BIOS device by setting 'Scan Single Drive' to yes.
		if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->bootConfig) && gScanSingleDrive)
		{
			gScanSingleDrive = true;
		} */
	}
	else
	{
		_BOOT_DEBUG_DUMP("No com.apple.Boot.plist found.\n");
	}
	
	// Was a target drive (per UUID) specified in com.apple.Boot.plist?
	if (rootUUID[0] == '\0')
	{
		_BOOT_DEBUG_DUMP("No UUID specified in com.apple.Boot.plist\n");

		// No, so are we booting from a System Volume?
		if (gPlatform.BootVolume->flags & kBVFlagSystemVolume)
		{
			_BOOT_DEBUG_DUMP("Booting from a System Volume, getting UUID.\n");

			// Yes, then let's get the UUID.
			if (HFSGetUUID(gPlatform.BootVolume, rootUUID) == STATE_SUCCESS)
			{
				_BOOT_DEBUG_DUMP("Success [%s]\n", rootUUID);
			}
		}
		else // Booting from USB-stick or SDboot media.
		{
			_BOOT_DEBUG_DUMP("Booting from a Non System Volume, getting UUID.\n");

			// Get target System Volume and UUID in one go.
			BVRef rootVolume = getTargetRootVolume(rootUUID);

			if (rootVolume)
			{
				_BOOT_DEBUG_DUMP("Success [%s]\n", rootUUID);

				gPlatform.RootVolume = rootVolume;
			}
		}

		// This should never happen, but just to be sure.
		if (rootUUID[0] == '\0')
		{
			_BOOT_DEBUG_DUMP("Failed to get UUID for System Volume.\n");

			if (!gVerboseMode)
			{
				// Force verbose mode when we didn't find a UUID, so 
				// that people see what is going on in times of trouble.
				gVerboseMode = true;
			}
		}
	}

	/*
	 * At this stage we know exactly what boot mode we're in, and which disk to boot from
	 * any of which may or may not have been set/changed (in com.apple.Boot.plist) into a 
	 * non-default system setting and thus is this the place to update our EFI tree.
	 */

    updateEFITree(rootUUID);

	if (haveCABootPlist) // Check boolean before doing more time consuming tasks.
	{
		if (getBoolForKey(kQuietBootKey, &quietBootMode, &bootInfo->bootConfig) && !quietBootMode)
		{
			gBootMode = kBootModeNormal; // Reversed from: gBootMode |= kBootModeQuiet;
		}
	}

    // Parse args, load and start kernel.
    while (1)
    {
		// Initialize globals.

		sysConfigValid = 0;
		gErrors        = 0;

		int retStatus = -1;

		getAndProcessBootArguments(kernelFlags);

		// Initialize bootFile (defaults to: mach_kernel).
		strcpy(bootFile, bootInfo->bootFile);

#if PRE_LINKED_KERNEL_SUPPORT

		_BOOT_DEBUG_DUMP("gBootMode = %d\n", gBootMode);

		// Preliminary checks to prevent us from doing useless things.
		mayUseKernelCache = ((gBootMode & kBootModeSafe) == 0);

		_BOOT_DEBUG_DUMP("mayUseKernelCache = %s\n", mayUseKernelCache ? "true" : "false");

		/* 
		 * A pre-linked kernel, or kernelcache, requires you to have all essential kexts for your
		 * configuration, including FakeSMC.kext in: /System/Library/Extensions/ 
		 * Not in /Extra/Extensions/ because this directory will be ignored, completely when a 
		 * pre-linked kernel or kernelcache is used!
		 *
		 * Note: Not following this word of advise will render your system incapable of booting!
		 */
		
		if (mayUseKernelCache == false)
		{
			_BOOT_DEBUG_DUMP("Warning: kernelcache will be ignored!\n");

			// True when 'Kernel Cache' is set in com.apple.Boot.plist
			if (gPlatform.KernelCacheSpecified == true)
			{
				sprintf(bootFile, "%s", bootInfo->bootFile);
			}
		}
		else
		{
			// True when 'Kernel Cache' is set in com.apple.Boot.plist
			if (gPlatform.KernelCacheSpecified == true)
			{
				_BOOT_DEBUG_DUMP("kernelcache: %s\n", gPlatform.KernelCachePath);

				/*
				 * Starting with Lion, we can take a shortcut by simply pointing 
				 * the 'bootFile' to the kernel cache and we are done.
				 */

				sprintf(bootFile, "%s", gPlatform.KernelCachePath);
			}

			/*
			 * We might have been fired up from a USB thumbdrive (kickstart boot) and 
			 * thus we have to check the kernel cache path first (might not be there).
			 */

			else if (GetFileInfo(NULL, gPlatform.KernelCachePath, &flags, &cachetime) == 0)
			{

#if ((MAKE_TARGET_OS & LION) == LION) // Also for Mountain Lion, which has bit 2 set like Lion.

				_BOOT_DEBUG_DUMP("Checking for kernelcache...\n");

				if (GetFileInfo(gPlatform.KernelCachePath, (char *)kKernelCache, &flags, &cachetime) == 0)
				{
					sprintf(bootFile, "%s/%s", gPlatform.KernelCachePath, kKernelCache);

					_BOOT_DEBUG_DUMP("Kernelcache located.\n");
				}

				_BOOT_DEBUG_ELSE_DUMP("Failed to locate the kernelcache. Will load: %s!\n", bootInfo->bootFile);
			}

			_BOOT_DEBUG_ELSE_DUMP("Failed to locate the kernelcache (directory)!\n");
		}
#else // Not for (Mountain) Lion, go easy with the Snow Leopard.

				static char preLinkedKernelPath[128];
				static char adler32Key[PLATFORM_NAME_LEN + ROOT_PATH_LEN];

				unsigned long adler32 = 0;

				preLinkedKernelPath[0] = '\0';

				_BOOT_DEBUG_DUMP("Checking for pre-linked kernel...\n");

				// Zero out platform info (name and kernel root path).
				bzero(adler32Key, sizeof(adler32Key));
				
				// Construct key for the pre-linked kernel checksum (generated by adler32). 
				sprintf(adler32Key, gPlatform.ModelID);
				sprintf(adler32Key + PLATFORM_NAME_LEN, "%s", BOOT_DEVICE_PATH);
				sprintf(adler32Key + (PLATFORM_NAME_LEN + 38), "%s", bootInfo->bootFile);
				
				adler32 = Adler32((unsigned char *)adler32Key, sizeof(adler32Key));
				
				_BOOT_DEBUG_DUMP("adler32: %08X\n", adler32);
				
				// Create path to pre-linked kernel.
				sprintf(preLinkedKernelPath, "%s/%s_%s.%08lX", gPlatform.KernelCachePath, kKernelCache, 
						((gArchCPUType == CPU_TYPE_X86_64) ? "x86_64" : "i386"), adler32);

				// Check if this file exists.
				if ((GetFileInfo(NULL, preLinkedKernelPath, &flags, &cachetime) == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
				{
					_BOOT_DEBUG_DUMP("Pre-linked kernel cache located!\nLoading pre-linked kernel: %s\n", preLinkedKernelPath);
					
					// Returns -1 on error, or the actual filesize.
					if (LoadFile((const char *)preLinkedKernelPath))
					{
						retStatus = 1;
						fileLoadBuffer = (void *)kLoadAddr;
						bootFile[0] = 0;
					}

					_BOOT_DEBUG_ELSE_DUMP("Failed to load the pre-linked kernel. Will load: %s!\n", bootInfo->bootFile);
				}

				_BOOT_DEBUG_ELSE_DUMP("Failed to locate the pre-linked kernel!\n");
			}

			_BOOT_DEBUG_ELSE_DUMP("Failed to locate the cache directory!\n");
		}
Example #10
0
int getBootOptions(bool firstRun)
{
	int     i;
	int     key;
	int     nextRow;
	int     timeout;
#if UNUSED
	int     bvCount;
#endif
	BVRef   bvr;
	BVRef   menuBVR;
	bool    showPrompt, newShowPrompt, isCDROM;
    int     optionKey;
	
	// Initialize default menu selection entry.
	menuBVR = selectBootVolume(getBvChain());
	safe_set_env(envgBootVolume, (uint32_t)menuBVR);
	
	if (biosDevIsCDROM((int)get_env(envgBIOSDev))) {
		isCDROM = true;
	} else {
		isCDROM = false;
	}
	
	// Clear command line boot arguments
	clearBootArgs();
	
	// Allow user to override default timeout.
#if UNUSED
	if (multiboot_timeout_set) {
		timeout = multiboot_timeout;
	} else 
#endif
		if (!getIntForKey(kTimeoutKey, &timeout, DEFAULT_BOOT_CONFIG)) {
			/*  If there is no timeout key in the file use the default timeout
			 which is different for CDs vs. hard disks.  However, if not booting
			 a CD and no config file could be loaded set the timeout
			 to zero which causes the menu to display immediately.
			 This way, if no partitions can be found, that is the disk is unpartitioned
			 or simply cannot be read) then an empty menu is displayed.
			 If some partitions are found, for example a Windows partition, then
			 these will be displayed in the menu as foreign partitions.
			 */
			if (isCDROM) {
				timeout = kCDBootTimeout;
			} else {
				timeout = get_env(envSysConfigValid) ? kBootTimeout : 0;
			}
		}
	
    long gBootMode = (long)get_env(envgBootMode);
    
	if (timeout < 0) {
		gBootMode |= kBootModeQuiet;
        safe_set_env(envgBootMode,gBootMode);
		
	}
	
	// If the user is holding down a modifier key, enter safe mode.
	if ((readKeyboardShiftFlags() & 0x0F) != 0) {
		
		gBootMode |= kBootModeSafe;
        safe_set_env(envgBootMode,gBootMode);
		
	}
	
	// Checking user pressed keys
	bool f8press = false, spress = false, vpress = false;
	while (readKeyboardStatus()) {
		key = bgetc ();
		if (key == 0x4200) f8press = true;
		if ((key & 0xff) == 's' || (key & 0xff) == 'S') spress = true;
		if ((key & 0xff) == 'v' || (key & 0xff) == 'V') vpress = true;
	}
	// If user typed F8, abort quiet mode, and display the menu.
	if (f8press) {
		gBootMode &= ~kBootModeQuiet;
        safe_set_env(envgBootMode,gBootMode);
		
		timeout = 0;
	}
	// If user typed 'v' or 'V', boot in verbose mode.
	if ((gBootMode & kBootModeQuiet) && firstRun && vpress) {
		addBootArg(kVerboseModeFlag);
	}
	// If user typed 's' or 'S', boot in single user mode.
	if ((gBootMode & kBootModeQuiet) && firstRun && spress) {
		addBootArg(kSingleUserModeFlag);
	}
	
	setCursorPosition(0, 0, 0);
	clearScreenRows(0, kScreenLastRow);
	if (!(gBootMode & kBootModeQuiet)) {
		// Display banner and show hardware info.
        char * bootBanner = (char*)(uint32_t)get_env(envBootBanner);
        
		printf(bootBanner, (int)(get_env(envConvMem) + get_env(envExtMem)) / 1024);       
	}
	changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
	msglog("Scanning device %x...", (uint32_t)get_env(envgBIOSDev));
	
	// When booting from CD, default to hard drive boot when possible. 
	if (isCDROM && firstRun) {
		const char *val;
		char *prompt = NULL;
		char *name = NULL;
		int cnt;
		
		if (getValueForKey(kCDROMPromptKey, &val, &cnt, DEFAULT_BOOT_CONFIG)) {
			prompt = calloc(cnt + 1, sizeof(char));
            if (!prompt) {
                stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
                return -1;
            }
			strncat(prompt, val, cnt);
		} else {			
            prompt = calloc(256, sizeof(char));
            if (!prompt) {
                stop("Couldn't allocate memory for the prompt\n"); //TODO: Find a better stategie
                return -1;
            }
            BVRef bvr;
            if (( bvr = ((BVRef)(uint32_t)get_env(envgBootVolume)))) {
                name = calloc(80, sizeof(char));
                if (!name) {
                    stop("Couldn't allocate memory for the device name\n"); //TODO: Find a better stategie
                    return -1;
                }
                getBootVolumeDescription(bvr, name, 79, false);
                
                snprintf(prompt, 256,"Press ENTER to start up from %s, or press any key to enter startup options.", name);
                free(name);
            } else snprintf(prompt, 256,"Press ENTER to start up, or press any key to enter startup options.");
			
		}
		
		if (getIntForKey( kCDROMOptionKey, &optionKey, DEFAULT_BOOT_CONFIG )) {
			// The key specified is a special key.
		} else {
			// Default to F8.
			optionKey = 0x4200;
		}
		
		// If the timeout is zero then it must have been set above due to the
		// early catch of F8 which means the user wants to set boot options
		// which we ought to interpret as meaning he wants to boot the CD.
		if (timeout != 0) {
			key = countdown(prompt, kMenuTopRow, timeout, &optionKey);
		} else {
			key = optionKey;
		}
		
		if (prompt != NULL) {
			free(prompt);
		}
		
		clearScreenRows( kMenuTopRow, kMenuTopRow + 2 );
		
        do {
            // Hit the option key ?
            if (key == optionKey) {
				
                if (key != 0x1C0D) {
                    gBootMode &= ~kBootModeQuiet;
                    safe_set_env(envgBootMode,gBootMode);
                    timeout = 0;
                    break;
                }
                
            } 
            
            key = key & 0xFF;
            
            // Try booting hard disk if user pressed 'h'
            if (biosDevIsCDROM((int)get_env(envgBIOSDev)) && key == 'h') {
                BVRef bvr;
                
                // Look at partitions hosting OS X other than the CD-ROM
                for (bvr = getBvChain(); bvr; bvr=bvr->next) {
                    if ((bvr->flags & kBVFlagSystemVolume) && bvr->biosdev != (int)get_env(envgBIOSDev)) {
						safe_set_env(envgBootVolume, (uint32_t)bvr);
                    }
                }
            }
            goto done;
            
        } while (0);
		
	}
	
	if (get_env(envgBootMode) & kBootModeQuiet) {
		// No input allowed from user.
		goto done;
	}
	
	if (firstRun && timeout > 0 ) {
        
        key = countdown("Press ENTER to start up, or press any key to enter startup options.", kMenuTopRow, timeout, &optionKey);
        
        if (key == 0x1C0D) {
            goto done;
			
        } 
        else if (key == 0)
        {
            // If the user is holding down a modifier key,
            // enter safe mode.     
            
            if ((readKeyboardShiftFlags() & 0x0F) != 0) {
                gBootMode |= kBootModeSafe;
                safe_set_env(envgBootMode,gBootMode);
            }
            goto done;
        }
	}
	int devcnt = (int)get_env(envgDeviceCount);
    
	if (devcnt) {
		// Allocate memory for an array of menu items.
		menuItems = calloc(devcnt,sizeof(MenuItem));
		if (menuItems == NULL) {
			goto done;
		}
		
		// Associate a menu item for each BVRef.
		for (bvr=getBvChain(), i=devcnt-1, selectIndex=0; bvr; bvr=bvr->next) {
			if (bvr->visible) {
				getBootVolumeDescription(bvr, menuItems[i].name, sizeof(menuItems[i].name) - 1, true);
				menuItems[i].param = (void *) bvr;
				if (bvr == menuBVR) {
					selectIndex = i;
				}
				i--;
			}
		}
	}
	
	// Clear screen and hide the blinking cursor.
	clearScreenRows(kMenuTopRow, kMenuTopRow + 2);
	changeCursor(0, kMenuTopRow, kCursorTypeHidden, 0);
	
	nextRow = kMenuTopRow;
	/*showPrompt = true;*/
	
	if (devcnt) {
		printf("Use \30\31 keys to select the startup volume.");
		showMenu( menuItems, devcnt, selectIndex, kMenuTopRow + 2, kMenuMaxItems );
		nextRow += min( devcnt, kMenuMaxItems ) + 3;
	}
	
	// Show the boot prompt.
	showPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
	showBootPrompt( nextRow, showPrompt );
	
	do {        
        
		key = getc();
		updateMenu( key, (void **) &menuBVR );
		newShowPrompt = (devcnt == 0) || (menuBVR->flags & kBVFlagNativeBoot);
		
		if (newShowPrompt != showPrompt)
		{
			showPrompt = newShowPrompt;
			showBootPrompt( nextRow, showPrompt );
		}
		
		if (showPrompt)
		{            
			updateBootArgs(key);
		}		
        
		switch (key) {
			case kReturnKey:
				if (*gBootArgs == '?') {
					char * argPtr = gBootArgs;
					
					// Skip the leading "?" character.
					argPtr++;
					getNextArg(&argPtr, booterCommand);
					getNextArg(&argPtr, booterParam);
					
					/*
					 * TODO: this needs to be refactored.
					 */
#if UNUSED
					if (strncmp( booterCommand, "video", sizeof("video") ) == 0)
					{
						printVBEModeInfo();
					}
					else
#endif
						if ( strncmp( booterCommand, "memory", sizeof("memory") ) == 0) 
						{
							printMemoryInfo();
						}
						else if (strncmp(booterCommand, "lspci", sizeof( "lspci")) == 0) 
						{
							lspci();
						} 
						else if (strncmp(booterCommand, "more",  sizeof("more")) == 0) 
						{
							showTextFile(booterParam);
						}
						else if (strncmp(booterCommand, "rd", sizeof("rd")) == 0) 
						{
							if (execute_hook("processRAMDiskCommand", (void*)argPtr, &booterParam, NULL, NULL, NULL, NULL) != EFI_SUCCESS)
								showMessage("ramdisk module not found, please install RamdiskLoader.dylib in /Extra/modules/");
						} 
						else if (strncmp(booterCommand, "norescan", sizeof("norescan")) == 0)
						{
							if (get_env(envgEnableCDROMRescan))
							{
                                safe_set_env(envgEnableCDROMRescan,false);
								break;
							}
						}
						else
						{
							showHelp();
						}
					key = 0;
					showBootPrompt(nextRow, showPrompt);
					break;
				}
				safe_set_env(envgBootVolume, (uint32_t)menuBVR);
				setRootVolume(menuBVR);
                safe_set_env(envgBIOSDev,menuBVR->biosdev);
				break;
				
			case kEscapeKey:
				clearBootArgs();
				break;
                
			case kF5Key:
				// New behavior:
				// Clear gBootVolume to restart the loop
				// if the user enabled rescanning the optical drive.
				// Otherwise boot the default boot volume.
				if (get_env(envgEnableCDROMRescan)) {
					//gBootVolume = NULL;
					safe_set_env(envgBootVolume, (uint32_t)NULL);
					clearBootArgs();
				}
				break;
				
			case kF10Key:
                safe_set_env(envgScanSingleDrive, false);
                
                scanDisks();
                
				//gBootVolume = NULL;
				safe_set_env(envgBootVolume, (uint32_t)NULL);
				
				clearBootArgs();
				break;
                
			default:
				key = 0;
				break;
		}
	} while (0 == key);
	
done:
	if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
		clearScreenRows(kMenuTopRow, kScreenLastRow);
		changeCursor(0, kMenuTopRow, kCursorTypeUnderline, 0);
	}
    safe_set_env(envShouldboot, false);
	
	if (menuItems) {
		free(menuItems);
		menuItems = NULL;
	}
	return 0;
}
Example #11
0
void getAndProcessBootArguments(char * configKernelFlags)
{
	bool truncated = false;

	const char * cp			= gBootArgs;

	char * argP				= bootArgs->CommandLine;

	int key;
	int pressedKey			= 0;
	int cntRemaining		= BOOT_STRING_LEN - 2; // (1024 -2)
	int kernelFlagsLength	= strlen(configKernelFlags);

	int index = 1;
	int bootModes[6]			= { -1, kBootModeNormal, kBootModeNormal, -1, kBootModeSafe, kBootModeNormal };
	const char * bootFlags[6]	= { "", kVerboseModeFlag, kSingleUserModeFlag, "", kSafeModeFlag, kIgnoreCachesFlag };

	skipblanks(&cp);

    while (readKeyboardStatus())
    {
        key = (bgetc() & 0xff);

		switch (key |= 0x20)
		{
			case 'v': // Verbose booting.
				printf("V\n");
				pressedKey |= 1;
				break;

			case 's': // Single user mode.
				printf("S\n");
				pressedKey |= 2;
				break;

			case 'x': // Safe mode.
				printf("X\n");
				pressedKey |= 4;
				break;

			case 'f': // Skip MKext.
				printf("F\n");
				pressedKey |= 8;
				break;
		}
    }

	if ((pressedKey & 1) || (pressedKey & 2))
	{
		// Mandatory mode change before entering single user mode,
		// which is optional for normal and safe booting modes.
		gVerboseMode = true; // ((pressedKey & 1) || (pressedKey & 2));
	}

    for (index = 1; index < 6; index++)
	{
		int currentMode = bootModes[index];
		// printf("currentMode: %d\n", currentMode);
		// sleep(2);

		if (currentMode >= 0 && (pressedKey & index) == index)
		{
			// printf("And action...\n");
			if (gBootArgsPtr + 3 < gBootArgsEnd)
			{
				gBootMode = currentMode;
				copyArgument(0, bootFlags[index], 3, &argP, &cntRemaining);
			}

			pressedKey -= index;
		}
    }

	// Reworked copy from processBootOptions() which is no more.
	if (kernelFlagsLength)
	{
		if (kernelFlagsLength > cntRemaining)
		{
			truncated = true;
			kernelFlagsLength = cntRemaining;
		}

		// Store kernel flags.
		strncpy(argP, configKernelFlags, kernelFlagsLength);
		argP[kernelFlagsLength++] = ' ';
		cntRemaining -= kernelFlagsLength;
	}

	int bootArgsLength = strlen(cp);
    
	if (bootArgsLength > cntRemaining)
	{
		truncated = true;
		bootArgsLength = cntRemaining;
	}
    
	if (truncated)
	{
		error("Warning: boot arguments too long, truncating\n");
	}

	// Store boot args.
	strncpy(&argP[kernelFlagsLength], cp, bootArgsLength);
	argP[kernelFlagsLength + bootArgsLength] = '\0';

	if (configKernelFlags)
	{
		// Free the earlier allocated (in boot.c) / passed on Kernel Flags.
		free(configKernelFlags);
	}
}