コード例 #1
0
ファイル: boot.c プロジェクト: AppleLife/RevoBoot
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");
		}
コード例 #2
0
ファイル: boot.c プロジェクト: aosm/boot
void boot(int biosdev)
{
    int      status;
    char     *bootFile;
    unsigned long adler32;
    BOOL     quiet;
    BOOL     firstRun = YES;
    BVRef    bvChain;

    zeroBSS();

    // Initialize malloc

    malloc_init(0, 0, 0, malloc_error);

    // Enable A20 gate before accessing memory above 1Mb.

    enableA20();

    // Set reminder to unload the PXE base code. Neglect to unload
    // the base code will result in a hang or kernel panic.

    gUnloadPXEOnExit = 1;

    // Record the device that the booter was loaded from.

    gBIOSDev = biosdev & kBIOSDevMask;

    // Initialize boot info structure.

    initKernBootStruct( gBIOSDev );

    // Setup VGA text mode.
    // Not sure if it is safe to call setVideoMode() before the
    // config table has been loaded. Call video_mode() instead.

    video_mode( 2 );  // 80x25 mono text mode.

    // Scan hardware configuration.

    scanHardware();

    // First get info for boot volume.
    bvChain = scanBootVolumes(gBIOSDev, 0);

    // Record default boot device.
    gBootVolume = selectBootVolume(bvChain);
    bootArgs->kernDev = MAKEKERNDEV(gBIOSDev,
                                    BIOS_DEV_UNIT(gBootVolume),
                                    gBootVolume->part_no );

    // Load default config file from boot device.
    status = loadSystemConfig(0, 0);

    if ( getBoolForKey( kQuietBootKey, &quiet ) && quiet ) {
        gBootMode |= kBootModeQuiet;
    }

    // Parse args, load and start kernel.

    while (1)
    {
        const char *val;
        int len;
        int trycache;
        long flags, cachetime, kerneltime, exttime;
        int ret = -1;

        // Initialize globals.

        sysConfigValid = 0;
        gErrors        = 0;

        status = getBootOptions(firstRun);
        firstRun = NO;
        if (status == -1) continue;

        status = processBootOptions();
        if ( status ==  1 ) break;
        if ( status == -1 ) continue;

        // Found and loaded a config file. Proceed with boot.


        // Reset cache name.
        bzero(gCacheNameAdler, sizeof(gCacheNameAdler));

        if ( getValueForKey( kRootDeviceKey, &val, &len ) == YES ) {
            if (*val == '*') {
                val++;
                len--;
            }
            strncpy( gCacheNameAdler + 64, val, len );
            sprintf(gCacheNameAdler + 64 + len, ",%s", bootArgs->bootFile);
        } else {
            strcpy(gCacheNameAdler + 64, bootArgs->bootFile);
        }
        adler32 = Adler32(gCacheNameAdler, sizeof(gCacheNameAdler));

        if (getValueForKey(kKernelCacheKey, &val, &len) == YES) {
            strlcpy(gBootKernelCacheFile, val, len+1);
        } else {
            sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePath, adler32);
        }

        // Check for cache file.


        trycache = (((gBootMode & kBootModeSafe) == 0) &&
                    (gOverrideKernel == NO) &&
                    (gBootFileType == kBlockDeviceType) &&
                    (gMKextName[0] == '\0') &&
                    (gBootKernelCacheFile[0] != '\0'));

        printf("Loading Darwin/x86\n");

        if (trycache) do {
      
            // if we haven't found the kernel yet, don't use the cache
            ret = GetFileInfo(NULL, bootArgs->bootFile, &flags, &kerneltime);
            if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
                trycache = 0;
                break;
            }
            ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
            if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
                || (cachetime < kerneltime)) {
                trycache = 0;
                break;
            }
            ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
            if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
                && (cachetime < exttime)) {
                trycache = 0;
                break;
            }
            if (kerneltime > exttime) {
                exttime = kerneltime;
            }
            if (cachetime != (exttime + 1)) {
                trycache = 0;
                break;
            }
        } while (0);

        do {
            if (trycache) {
                bootFile = gBootKernelCacheFile;
                verbose("Loading kernel cache %s\n", bootFile);
                ret = LoadFile(bootFile);
                if (ret >= 0) {
                    break;
                }
            }
            bootFile = bootArgs->bootFile;
            verbose("Loading kernel %s\n", bootFile);
            ret = LoadFile(bootFile);
        } while (0);

        clearActivityIndicator();
#if DEBUG
        printf("Pausing...");
        sleep(8);
#endif

        if (ret < 0) {
            error("Can't find %s\n", bootFile);

            if ( gBootFileType == kBIOSDevTypeFloppy )
            {
                // floppy in drive, but failed to load kernel.
                gBIOSDev = kBIOSDevTypeHardDrive;
                initKernBootStruct( gBIOSDev );
                printf("Attempting to load from hard drive...");
            }
            else if ( gBootFileType == kNetworkDeviceType )
            {
                // Return control back to PXE. Don't unload PXE base code.
                gUnloadPXEOnExit = 0;
                break;
            }
        } else {
            /* Won't return if successful. */
            ret = ExecKernel((void *)kLoadAddr);
        }

    } /* while(1) */
    
    if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
	nbpUnloadBaseCode();
    }
}
コード例 #3
0
ファイル: boot.c プロジェクト: AmesianX/Chameleon
//==========================================================================
// LoadKernelCache - Try to load Kernel Cache.
// return the length of the loaded cache file or -1 on error
long LoadKernelCache(const char* cacheFile, void **binary) {
	char		kernelCacheFile[512];
	char		kernelCachePath[512];
	long		flags, time, cachetime, kerneltime, exttime, ret=-1;
    unsigned long adler32;

    if((gBootMode & kBootModeSafe) != 0)
    {
		verbose("Kernel Cache ignored.\n");
		return -1;
    }

	// Use specify kernel cache file if not empty
	if (cacheFile[0] != 0)
	{
		strlcpy(kernelCacheFile, cacheFile, sizeof(kernelCacheFile));
	}
	else
	{
		// Lion, Mountain Lion and Mavericks prelink kernel cache file
		if ((checkOSVersion("10.7")) || (checkOSVersion("10.8")) || (checkOSVersion("10.9")))
		{
			sprintf(kernelCacheFile, "%skernelcache", kDefaultCachePathSnow);
		}
		// Snow Leopard prelink kernel cache file
		else if (checkOSVersion("10.6")) {
			sprintf(kernelCacheFile, "kernelcache_%s", (archCpuType == CPU_TYPE_I386)
					? "i386" : "x86_64");
			int lnam = strlen(kernelCacheFile) + 9; //with adler32

			char* name;
			long prev_time = 0;

			struct dirstuff* cacheDir = opendir(kDefaultCachePathSnow);

			while(readdir(cacheDir, (const char**)&name, &flags, &time) >= 0)
			{
				if (((flags & kFileTypeMask) != kFileTypeDirectory) && time > prev_time
					&& strstr(name, kernelCacheFile) && (name[lnam] != '.'))
				{
					sprintf(kernelCacheFile, "%s%s", kDefaultCachePathSnow, name);
					prev_time = time;
				}
			}
		}
		else {
			// Reset cache name.
			bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
			sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);
			adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
			sprintf(kernelCacheFile, "%s.%08lX", kDefaultCachePathLeo, adler32);
		}
	}

	// Check if the kernel cache file exists
	ret = -1;

	// If boot from a boot helper partition check the kernel cache file on it
	if (gBootVolume->flags & kBVFlagBooter) {
		sprintf(kernelCachePath, "com.apple.boot.P%s", kernelCacheFile);
		ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
		if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
		{
			sprintf(kernelCachePath, "com.apple.boot.R%s", kernelCacheFile);
			ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
			if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat))
			{
				sprintf(kernelCachePath, "com.apple.boot.S%s", kernelCacheFile);
				ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
				if ((flags & kFileTypeMask) != kFileTypeFlat)
					ret = -1;
			}
		}
	}
	// If not found, use the original kernel cache path.
	if (ret == -1) {
		strcpy(kernelCachePath, kernelCacheFile);
		ret = GetFileInfo(NULL, kernelCachePath, &flags, &cachetime);
		if ((flags & kFileTypeMask) != kFileTypeFlat)
			ret = -1;
	}

	// Exit if kernel cache file wasn't found
	if (ret == -1) {
		verbose("No Kernel Cache File '%s' found\n", kernelCacheFile);
		return -1;
	}

	// Check if the kernel cache file is more recent (mtime)
	// than the kernel file or the S/L/E directory
	ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
	// Check if the kernel file is more recent than the cache file
	if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat)
		&& (kerneltime > cachetime)) {
		verbose("Kernel file (%s) is more recent than KernelCache (%s), ignoring KernelCache\n",
				bootInfo->bootFile, kernelCacheFile);
		return -1;
	}

	ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
	// Check if the S/L/E directory time is more recent than the cache file
	if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
		&& (exttime > cachetime)) {
		verbose("/System/Library/Extensions is more recent than KernelCache (%s), ignoring KernelCache\n",
				kernelCacheFile);
		return -1;
	}

	// Since the kernel cache file exists and is the most recent try to load it
	verbose("Loading kernel cache %s\n", kernelCachePath);

	ret = LoadThinFatFile(kernelCachePath, binary);
	return ret; // ret contain the length of the binary
}
コード例 #4
0
//==========================================================================
// The 'main' function for the booter. Called by boot0 when booting
// from a block device, or by the network booter.
//
// arguments:
//	 biosdev - Value passed from boot1/NBP to specify the device
//			   that the booter was loaded from.
//
// If biosdev is kBIOSDevNetwork, then this function will return if
// booting was unsuccessful. This allows the PXE firmware to try the
// next boot device on its list.
void common_boot(int biosdev)
{
	bool	 		quiet;
	bool	 		firstRun = true;
	bool	 		instantMenu;
	bool	 		rescanPrompt;
	char	 		*bootFile;
	int				status;
	unsigned int	allowBVFlags = kBVFlagSystemVolume | kBVFlagForeignBoot;
	unsigned int	denyBVFlags = kBVFlagEFISystem;
	unsigned long	adler32;
	
	// Set reminder to unload the PXE base code. Neglect to unload
	// the base code will result in a hang or kernel panic.
	gUnloadPXEOnExit = true;
	
	// Record the device that the booter was loaded from.
	gBIOSDev = biosdev & kBIOSDevMask;
	
	// Initialize boot info structure.
	initKernBootStruct();
	
	initBooterLog();
	
	// Setup VGA text mode.
	// Not sure if it is safe to call setVideoMode() before the
	// config table has been loaded. Call video_mode() instead.
#if DEBUG
	printf("before video_mode\n");
#endif
	video_mode( 2 );  // 80x25 mono text mode.
#if DEBUG
	printf("after video_mode\n");
#endif
	
	// Scan and record the system's hardware information.
	scan_platform();
	
	// First get info for boot volume.
	scanBootVolumes(gBIOSDev, 0);
	bvChain = getBVChainForBIOSDev(gBIOSDev);
	setBootGlobals(bvChain);
	
	// Load boot.plist config file
	status = loadChameleonConfig(&bootInfo->chameleonConfig);
	
	if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->chameleonConfig) && quiet) {
		gBootMode |= kBootModeQuiet;
	}
	
	// Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
	if (getBoolForKey(kInstantMenuKey, &instantMenu, &bootInfo->chameleonConfig) && instantMenu) {
		firstRun = false;
	}
	
	// Loading preboot ramdisk if exists.
	loadPrebootRAMDisk();
	
	// Disable rescan option by default
	gEnableCDROMRescan = false;
	
	// Enable it with Rescan=y in system config
	if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->chameleonConfig)
		&& gEnableCDROMRescan) {
		gEnableCDROMRescan = true;
	}
	
	// Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
	rescanPrompt = false;
	if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->chameleonConfig)
		&& rescanPrompt && biosDevIsCDROM(gBIOSDev))
	{
		gEnableCDROMRescan = promptForRescanOption();
	}
	
	// Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
	if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->chameleonConfig)
		&& gScanSingleDrive) {
		gScanSingleDrive = true;
	}
	
	// Create a list of partitions on device(s).
	if (gScanSingleDrive) {
		scanBootVolumes(gBIOSDev, &bvCount);
	} else {
		scanDisks(gBIOSDev, &bvCount);
	}
	
	// Create a separated bvr chain using the specified filters.
	bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
	
	gBootVolume = selectBootVolume(bvChain);
	
	// Intialize module system 
	init_module_system();
		
#if DEBUG
	printf(" Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n",
			 gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
	printf(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n",
			 gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
	getchar();
#endif
	
	useGUI = true;
	// Override useGUI default
	getBoolForKey(kGUIKey, &useGUI, &bootInfo->chameleonConfig);
	if (useGUI && initGUI())
	{
		// initGUI() returned with an error, disabling GUI.
		useGUI = false;
	}
	
	setBootGlobals(bvChain);
	
	// Parse args, load and start kernel.
	while (1)
	{
		bool		tryresume, tryresumedefault, forceresume;
		bool		usecache = false;//true;
		const char	*val;
		int			len, trycache, ret = -1;
		long		flags, cachetime, kerneltime, exttime, sleeptime, time;
		void		*binary = (void *)kLoadAddr;
		
		// additional variable for testing alternate kernel image locations on boot helper partitions.
		char		bootFileSpec[512];
		
		// Initialize globals.
		sysConfigValid = false;
		gErrors		   = false;
		
		status = getBootOptions(firstRun);
		firstRun = false;
		if (status == -1) continue;
		 
		status = processBootOptions();
		// Status == 1 means to chainboot
		if ( status ==	1 ) break;
		// Status == -1 means that the config file couldn't be loaded or that gBootVolume is NULL
		if ( status == -1 )
		{
			// gBootVolume == NULL usually means the user hit escape.
			if (gBootVolume == NULL)
			{
				freeFilteredBVChain(bvChain);
				
				if (gEnableCDROMRescan)
					rescanBIOSDevice(gBIOSDev);
				
				bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
				setBootGlobals(bvChain);
				setupDeviceList(&bootInfo->themeConfig);
			}
			continue;
		}
		
		// Other status (e.g. 0) means that we should proceed with boot.
		
		// Turn off any GUI elements
		if ( bootArgs->Video.v_display == GRAPHICS_MODE )
		{
			gui.devicelist.draw = false;
			gui.bootprompt.draw = false;
			gui.menu.draw = false;
			gui.infobox.draw = false;
			gui.logo.draw = false;
			drawBackground();
			updateVRAM();
		}
		
		// Find out which version mac os we're booting.
		getOSVersion();
		
		if (platformCPUFeature(CPU_FEATURE_EM64T)) {
			archCpuType = CPU_TYPE_X86_64;
		} else {
			archCpuType = CPU_TYPE_I386;
		}
		
		if (getValueForKey(karch, &val, &len, &bootInfo->chameleonConfig)) {
			if (strncmp(val, "i386", 4) == 0) {
				archCpuType = CPU_TYPE_I386;
			}
		}
		
		if (getValueForKey(kKernelArchKey, &val, &len, &bootInfo->chameleonConfig)) {
			if (strncmp(val, "i386", 4) == 0) {
				archCpuType = CPU_TYPE_I386;
			}
		}
		
		// Notify modules that we are attempting to boot
		execute_hook("PreBoot", NULL, NULL, NULL, NULL);
		
		if (!getBoolForKey (kWake, &tryresume, &bootInfo->chameleonConfig)) {
			tryresume = true;
			tryresumedefault = true;
		} else {
			tryresumedefault = false;
		}
		
		if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->chameleonConfig)) {
			forceresume = false;
		}
		
		if (forceresume) {
			tryresume = true;
			tryresumedefault = false;
		}
		
		while (tryresume) {
			const char *tmp;
			BVRef bvr;
			if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->chameleonConfig))
				val = "/private/var/vm/sleepimage";
			
			// Do this first to be sure that root volume is mounted
			ret = GetFileInfo(0, val, &flags, &sleeptime);
			
			if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
				break;
			
			// Can't check if it was hibernation Wake=y is required
			if (bvr->modTime == 0 && tryresumedefault)
				break;
			
			if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
				break;
			
			if (!forceresume && ((sleeptime+3)<bvr->modTime)) {
#if DEBUG	
				printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",
						bvr->modTime-sleeptime);
#endif				  
				break;
			}
			
			HibernateBoot((char *)val);
			break;
		}
		
		getBoolForKey(kUseKernelCache, &usecache, &bootInfo->chameleonConfig);
		if (usecache) {
			if( getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->chameleonConfig) || getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig) ) {
				if (val[0] == '\\')
				{
					len--;
					val++;
				}
				strlcpy(gBootKernelCacheFile, val, len + 1);
                verbose("Using kernel cache: \"%s\" \n", gBootKernelCacheFile);
                //sleep(5);
			}
			else {
				// Lion and Mountain Lion prelink kernel cache file␊
				if ((checkOSVersion("10.7")) || (checkOSVersion("10.8"))) {
					sprintf(gBootKernelCacheFile, "%skernelcache", kDefaultCachePathSnow);
				}
				// Snow Leopard
				else if (checkOSVersion("10.6")) {
					sprintf(gBootKernelCacheFile, "kernelcache_%s", (archCpuType == CPU_TYPE_I386)
							? "i386" : "x86_64");
					int lnam = sizeof(gBootKernelCacheFile) + 9; //with adler32
					
					char* name;
					long prev_time = 0;
					
					struct dirstuff* cacheDir = opendir(kDefaultCachePathSnow);
					
					while(readdir(cacheDir, (const char**)&name, &flags, &time) >= 0)
					{
						if (((flags & kFileTypeMask) != kFileTypeDirectory) && time > prev_time
							&& strstr(name, gBootKernelCacheFile) && (name[lnam] != '.'))
						{
							sprintf(gBootKernelCacheFile, "%s%s", kDefaultCachePathSnow, name);
							prev_time = time;
						}
					}
				}
				else {
					// Reset cache name.
					bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
					
					sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);
					
					adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
					
					sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePathLeo, adler32);
				}
			}
		}
		
		// Check for cache file.
		trycache = (usecache && 
					((gBootMode & kBootModeSafe) == 0) &&
					!gOverrideKernel &&
					(gBootFileType == kBlockDeviceType) &&
					(gMKextName[0] == '\0') &&
					(gBootKernelCacheFile[0] != '\0'));
        
        verbose("trycache: %d\n", trycache);
		
		verbose("Loading Darwin %s\n", gMacOSVersion);
		
		if (trycache) do {
            verbose("bootInfo->bootFile: \"%s\" \n", bootInfo->bootFile);
			ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
			if (ret != 0) kerneltime = 0;
			else if ((flags & kFileTypeMask) != kFileTypeFlat) {
				trycache = 0;
                verbose("trycache0 : 1\n");
				break;
			}
			
			ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
			if ((ret != 0)) {
				trycache = 0;
                verbose("trycache0 : 2.1 \"%s\" \n", gBootKernelCacheFile);
				break;
			}
			else if ( ((flags & kFileTypeMask) != kFileTypeFlat) ) {
				trycache = 0;
                verbose("trycache0 : 2.2\n");
				break;
			}
			else if ( (cachetime < kerneltime) ) {
				trycache = 0;
                verbose("trycache0 : 2.3\n");
				break;
			}
			
			ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
			if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
				&& (cachetime < exttime)) {
				trycache = 0;
                verbose("trycache0 : 3\n");
				break;
			}
			
			if (ret == 0 && kerneltime > exttime) {
				exttime = kerneltime;
			}
			
			if (ret == 0 && cachetime < (exttime + 1)) {
				trycache = 0;
                verbose("trycache0 : 4\n");
				break;
			}
		} while (0);

        // sleep(5);

		do {
			if (trycache) {
				bootFile = gBootKernelCacheFile;
				
				verbose("Loading kernel cache %s\n", bootFile);
				
				if ((checkOSVersion("10.7")) || (checkOSVersion("10.8"))) {
					ret = LoadThinFatFile(bootFile, &binary);
				}
				else {
					ret = LoadFile(bootFile);
					binary = (void *)kLoadAddr;
				}
				
				if (ret >= 0)
					break;
				
				verbose("Kernel cache did not load %s\n ", bootFile);
			}
			
			if ((checkOSVersion("10.7")) || (checkOSVersion("10.8"))) {
				bootFile = gBootKernelCacheFile;
			}
			else {
				sprintf(bootFile, "\%s", bootInfo->bootFile);
			}
			
			// Try to load kernel image from alternate locations on boot helper partitions.
			sprintf(bootFileSpec, "com.apple.boot.P%s", bootFile);
			ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
			if (ret == -1)
			{
				sprintf(bootFileSpec, "com.apple.boot.R%s", bootFile);
				ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
				if (ret == -1)
				{
					sprintf(bootFileSpec, "com.apple.boot.S%s", bootFile);
					ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
					if (ret == -1)
					{
						// No alternate location found, using the original kernel image path.
						strcpy(bootFileSpec, bootInfo->bootFile);
					}
				}
			}
			
			if ((checkOSVersion("10.7")) || (checkOSVersion("10.8")))
			{
				//Lion, dont load kernel if haz cache
				if (!trycache) 
				{
					verbose("Loading kernel %s\n", bootFileSpec);
					ret = LoadThinFatFile(bootFileSpec, &binary);
					if (ret <= 0 && archCpuType == CPU_TYPE_X86_64) 
					{
						archCpuType = CPU_TYPE_I386;
						ret = LoadThinFatFile(bootFileSpec, &binary);				
					}
				} 
				else ret = 1;
			} 
			else 
			{
				//Snow Leopard or older
				verbose("Loading kernel %s\n", bootFileSpec);
				ret = LoadThinFatFile(bootFileSpec, &binary);
				if (ret <= 0 && archCpuType == CPU_TYPE_X86_64) 
				{
					archCpuType = CPU_TYPE_I386;
					ret = LoadThinFatFile(bootFileSpec, &binary);				
				}
			}
		} while (0);
		
		clearActivityIndicator();
		
#if DEBUG
		printf("Pausing...");
		sleep(8);
#endif
		
		if (ret <= 0) {
			printf("Can't find %s\n", bootFile);
			
			sleep(1);
			
			if (gBootFileType == kNetworkDeviceType) {
				// Return control back to PXE. Don't unload PXE base code.
				gUnloadPXEOnExit = false;
				break;
			}
		} else {
			/* Won't return if successful. */
			ret = ExecKernel(binary);
		}
	}
	
	// chainboot
	if (status == 1) {
		// if we are already in graphics-mode,
		if (getVideoMode() == GRAPHICS_MODE) {
			setVideoMode(VGA_TEXT_MODE, 0); // switch back to text mode.
		}
	}
	
	if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit) {
		nbpUnloadBaseCode();
	}
}
コード例 #5
0
ファイル: boot.c プロジェクト: AlexSeverinov/Chameleon
//==========================================================================
// The 'main' function for the booter. Called by boot0 when booting
// from a block device, or by the network booter.
//
// arguments:
//   biosdev - Value passed from boot1/NBP to specify the device
//             that the booter was loaded from.
//
// If biosdev is kBIOSDevNetwork, then this function will return if
// booting was unsuccessful. This allows the PXE firmware to try the
// next boot device on its list.
void common_boot(int biosdev)
{
    const char		*val;
    char		*bootFile;
    unsigned long	adler32;
    int			status;
    int			cnt;
    bool		quiet;
    bool		firstRun = true;
    bool		instantMenu;
    bool		rescanPrompt;

    // Record the device that the booter was loaded from.
    gBIOSDev = biosdev & kBIOSDevMask;

    // Initialize boot info structure.
    initKernBootStruct();

    // Setup VGA text mode.
    // Not sure if it is safe to call setVideoMode() before the
    // config table has been loaded. Call video_mode() instead.
#if DEBUG
    printf("before video_mode\n");
#endif
    video_mode( 2 );  // 80x25 mono text mode.
#if DEBUG
    printf("after video_mode\n");
#endif

    // First get info for boot volume.
    scanBootVolumes(gBIOSDev, 0);
    bvChain = getBVChainForBIOSDev(gBIOSDev);
    setBootGlobals(bvChain);
    
    // Load boot.plist config file
    status = loadSystemConfig(&bootInfo->bootConfig);

    if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->bootConfig) && quiet) {
        gBootMode |= kBootModeQuiet;
    }

    // Get verbosity at early stage to allow a quiet booter
    if (getValueForKey(kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig)) {
	    if (getValueForBootKey(val, kVerboseModeFlag, &val, &cnt)) {
		    gVerboseMode = true;
	    }
    }

    // Scan and record the system's hardware information.
    scan_platform();

    // Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
    if (getBoolForKey(kInsantMenuKey, &instantMenu, &bootInfo->bootConfig) && instantMenu) {
        firstRun = false;
    }

    // Loading preboot ramdisk if exists.
    loadPrebootRAMDisk();

    // Disable rescan option by default
    gEnableCDROMRescan = false;

    // Enable it with Rescan=y in system config
    if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->bootConfig) && gEnableCDROMRescan) {
        gEnableCDROMRescan = true;
    }

    // Ask the user for Rescan option by setting "Rescan Prompt"=y in system config.
    rescanPrompt = false;
    if (getBoolForKey(kRescanPromptKey, &rescanPrompt , &bootInfo->bootConfig) && rescanPrompt && biosDevIsCDROM(gBIOSDev)) {
        gEnableCDROMRescan = promptForRescanOption();
    }

    // Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
    if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->bootConfig) && gScanSingleDrive) {
        gScanSingleDrive = true;
    }

    // Create a list of partitions on device(s).
    if (gScanSingleDrive) {
      scanBootVolumes(gBIOSDev, &bvCount);
    } else {
      scanDisks(gBIOSDev, &bvCount);
    }

    // Create a separated bvr chain using the specified filters.
    bvChain = newFilteredBVChain(0x80, 0xFF, kBVFlagSystemVolume|kBVFlagForeignBoot, kBVFlagEFISystem, &gDeviceCount);

    gBootVolume = selectBootVolume(bvChain);

#if DEBUG
    printf(" Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
    printf(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
    getc();
#endif

    useGUI = true;
    // Override useGUI default
    getBoolForKey(kGUIKey, &useGUI, &bootInfo->bootConfig);
    if (useGUI) {
	if (gVerboseMode) {
		printf("Switching to GUI mode in 3 seconds...\n");
		sleep(3);
	}
	initGUI();
        /* XXX AsereBLN handle error */
    }

    setBootGlobals(bvChain);

    // Parse args, load and start kernel.
    while (1) {
        const char *val;
        int len;
        int trycache;
        long flags, cachetime, kerneltime, exttime, sleeptime, time;
        int ret = -1;
        void *binary = (void *)kLoadAddr;
        bool tryresume;
        bool tryresumedefault;
        bool forceresume;

        config_file_t    systemVersion;		// system.plist of booting partition

        // additional variable for testing alternate kernel image locations on boot helper partitions.
        char     bootFileSpec[512];
		
        // Initialize globals.
        sysConfigValid = false;
        gErrors        = false;

	getBootOptions(firstRun);
        firstRun = false;

        status = processBootOptions();
        // Status==1 means to chainboot
        if ( status ==  1 ) break;
        // Status==-1 means that the config file couldn't be loaded or that gBootVolume is NULL
        if ( status == -1 )
        {
          // gBootVolume == NULL usually means the user hit escape.
          if(gBootVolume == NULL)
          {
            freeFilteredBVChain(bvChain);

            if (gEnableCDROMRescan)
              rescanBIOSDevice(gBIOSDev);
              
            bvChain = newFilteredBVChain(0x80, 0xFF, kBVFlagSystemVolume|kBVFlagForeignBoot, kBVFlagEFISystem, &gDeviceCount);
            setBootGlobals(bvChain);
          }
          continue;
        }
		
        // Other status (e.g. 0) means that we should proceed with boot.
		
		if( bootArgs->Video.v_display == GRAPHICS_MODE )
			drawBackground();
			
        // Found and loaded a config file. Proceed with boot.

		// Turn off any GUI elements
		if( bootArgs->Video.v_display == GRAPHICS_MODE )
		{
			gui.devicelist.draw = false;
			gui.bootprompt.draw = false;
			gui.menu.draw = false;
			gui.infobox.draw = false;
			drawBackground();
			updateVRAM();
		}
		
		// Find out which version mac os we're booting.
		if (!loadConfigFile("System/Library/CoreServices/SystemVersion.plist", &systemVersion)) {
			if (getValueForKey(kProductVersion, &val, &len, &systemVersion)) {	
				// getValueForKey uses const char for val
				// so copy it and trim
				strncpy(gMacOSVersion, val, MIN(len, 4));
				gMacOSVersion[MIN(len, 4)] = '\0';
			}
		}

		if (platformCPUFeature(CPU_FEATURE_EM64T)) {
			archCpuType = CPU_TYPE_X86_64;
		} else {
			archCpuType = CPU_TYPE_I386;
		}
		if (getValueForKey(karch, &val, &len, &bootInfo->bootConfig)) {
			if (strncmp(val, "i386", 4) == 0) {
				archCpuType = CPU_TYPE_I386;
			}
		}
		if (getValueForKey(k32BitModeFlag, &val, &len, &bootInfo->bootConfig)) {
			archCpuType = CPU_TYPE_I386;
		}
		
		if (!getBoolForKey (kWake, &tryresume, &bootInfo->bootConfig)) {
			tryresume = true;
			tryresumedefault = true;
		} else {
			tryresumedefault = false;
		}

		if (!getBoolForKey (kForceWake, &forceresume, &bootInfo->bootConfig)) {
			forceresume = false;
		}
		
		if (forceresume) {
			tryresume = true;
			tryresumedefault = false;
		}
		
		while (tryresume) {
			const char *tmp;
			BVRef bvr;
			if (!getValueForKey(kWakeImage, &val, &len, &bootInfo->bootConfig))
				val="/private/var/vm/sleepimage";
			
			// Do this first to be sure that root volume is mounted
			ret = GetFileInfo(0, val, &flags, &sleeptime);

			if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
				break;
			
			// Can't check if it was hibernation Wake=y is required
			if (bvr->modTime == 0 && tryresumedefault)
				break;
			
			if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
				break;
			
			if (!forceresume && sleeptime+3<bvr->modTime) {
				printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override\n",bvr->modTime-sleeptime);
				break;
			}
				
			HibernateBoot((char *)val);
			break;
		}

        // Reset cache name.
        bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);

        sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile);

        adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));

        if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig)) {
            strlcpy(gBootKernelCacheFile, val, len+1);
        } else {
            sprintf(gBootKernelCacheFile, "%s.%08lX", kDefaultCachePath, adler32);
        }

        // Check for cache file.
        trycache = (((gBootMode & kBootModeSafe) == 0) &&
                    !gOverrideKernel &&
                    (gMKextName[0] == '\0') &&
                    (gBootKernelCacheFile[0] != '\0'));

		verbose("Loading Darwin %s\n", gMacOSVersion);
		
        if (trycache) do {
      
            // if we haven't found the kernel yet, don't use the cache
            ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
            if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)) {
                trycache = 0;
                break;
            }
            ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
            if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
                || (cachetime < kerneltime)) {
                trycache = 0;
                break;
            }
            ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
            if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
                && (cachetime < exttime)) {
                trycache = 0;
                break;
            }
            if (kerneltime > exttime) {
                exttime = kerneltime;
            }
            if (cachetime != (exttime + 1)) {
                trycache = 0;
                break;
            }
        } while (0);

        do {
            if (trycache) {
                bootFile = gBootKernelCacheFile;
                verbose("Loading kernel cache %s\n", bootFile);
                ret = LoadFile(bootFile);
                binary = (void *)kLoadAddr;
                if (ret >= 0) {
                    break;
                }
            }
            bootFile = bootInfo->bootFile;

            // Try to load kernel image from alternate locations on boot helper partitions.
            sprintf(bootFileSpec, "com.apple.boot.P/%s", bootFile);
            ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
  	  	    if (ret == -1)
  	  	    {
              sprintf(bootFileSpec, "com.apple.boot.R/%s", bootFile);
              ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
              if (ret == -1)
              {
                sprintf(bootFileSpec, "com.apple.boot.S/%s", bootFile);
                ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
                if (ret == -1)
                {
                  // Not found any alternate locations, using the original kernel image path.
                  strcpy(bootFileSpec, bootFile);
                }
              }
            }
            			
            verbose("Loading kernel %s\n", bootFileSpec);
            ret = LoadThinFatFile(bootFileSpec, &binary);
            if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
            {
              archCpuType = CPU_TYPE_I386;
              ret = LoadThinFatFile(bootFileSpec, &binary);				
            }
			
        } while (0);

        clearActivityIndicator();
#if DEBUG
        printf("Pausing...");
        sleep(8);
#endif

        if (ret <= 0) {
			printf("Can't find %s\n", bootFile);

			if(gui.initialised) {
				sleep(1);
				drawBackground();
				gui.devicelist.draw = true;
				gui.redraw = true;
			}
        } else {
            /* Won't return if successful. */
            ret = ExecKernel(binary);
        }
    }
    
    // chainboot
    if (status==1) {
	if (getVideoMode() == GRAPHICS_MODE) {	// if we are already in graphics-mode,
		setVideoMode(VGA_TEXT_MODE, 0);	// switch back to text mode
	}
    }
}
コード例 #6
0
void loadCustomRomSettings(const QString & _strIniFolder, const char * _strRomName)
{
	QSettings settings(_strIniFolder + "/" + strCustomSettingsFileName, QSettings::IniFormat);
	config.version = settings.value("version").toInt();
	if (config.version != CONFIG_VERSION_CURRENT)
		return;

	const QByteArray bytes(_strRomName);
	bool bASCII = true;
	for (int i = 0; i < bytes.length() && bASCII; ++i)
		bASCII = bytes.at(i) >= 0;

	const QString romName = bASCII ? QString::fromLatin1(_strRomName).toUpper() : QString::number(Adler32(0xFFFFFFFF, bytes.data(), bytes.length()), 16).toUpper();
	if (settings.childGroups().indexOf(romName) < 0)
		return;

	settings.beginGroup(romName);
	_loadSettings(settings);
	settings.endGroup();
}
コード例 #7
0
//==========================================================================
// The 'main' function for the booter. Called by boot0 when booting
// from a block device, or by the network booter.
//
// arguments:
//   biosdev - Value passed from boot1/NBP to specify the device
//             that the booter was loaded from.
//
// If biosdev is kBIOSDevNetwork, then this function will return if
// booting was unsuccessful. This allows the PXE firmware to try the
// next boot device on its list.
void common_boot(int biosdev)
{
    int      status;
    char     *bootFile;
    unsigned long adler32;
    bool     quiet;
    bool     firstRun = true;
    bool     instantMenu;
    bool     rescanPrompt = false;
    unsigned int allowBVFlags = kBVFlagSystemVolume|kBVFlagForeignBoot;
    unsigned int denyBVFlags = kBVFlagEFISystem;

    // Set reminder to unload the PXE base code. Neglect to unload
    // the base code will result in a hang or kernel panic.
    gUnloadPXEOnExit = true;

    // Record the device that the booter was loaded from.
    gBIOSDev = biosdev & kBIOSDevMask;

    // Initialize boot info structure.
    initKernBootStruct();

	initBooterLog();

    // Setup VGA text mode.
    // Not sure if it is safe to call setVideoMode() before the
    // config table has been loaded. Call video_mode() instead.
#if DEBUG
    printf("before video_mode\n"); //Azi: this one is not printing... i remember it did.. check trunk.
#endif
    video_mode( 2 );  // 80x25 mono text mode.
#if DEBUG
    printf("after video_mode\n");
#endif

    // Scan and record the system's hardware information.
    scan_platform();

    // First get info for boot volume.
    scanBootVolumes(gBIOSDev, 0);
    bvChain = getBVChainForBIOSDev(gBIOSDev);
	//Azi: initialising gBIOSBootVolume & gBootVolume (Startup volume) for the first time.. i think!?
	// also, kDefaultPartitionKey is checked here, on selectBootVolume.
    setBootGlobals(bvChain);
	msglog("setBootGlobals:\n Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
    msglog(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);

	// Boot Volume is set as Root at this point so, pointing to Extra, /Extra or bt(0,0)/Extra
	// is exactly the same.	Review bt(0,0)/bla bla paths......			(Reviewing...)
	
	//Azi: works as expected but... trying this because Kernel=mach_kernel doesn't work on a
	// override Boot.plist; this makes it impossible to override e.g. Kernel=bt(0,0)mach_kernel
	// on the main Boot.plist, when loading kernel from ramdisk btAliased.
	loadPrebootRAMDisk();
	
    // Load boot.plist config file
    //Azi: on this first check, boot.plist acts as both "booter config file"
    // and bootargs/options "carrier".*****
    status = loadSystemConfig(&bootInfo->bootConfig);

    if (getBoolForKey(kQuietBootKey, &quiet, &bootInfo->bootConfig) && quiet) {
        gBootMode |= kBootModeQuiet;
    }

    // Override firstRun to get to the boot menu instantly by setting "Instant Menu"=y in system config
    if (getBoolForKey(kInstantMenuKey, &instantMenu, &bootInfo->bootConfig) && instantMenu) {
        firstRun = false;
    }

	// Loading preboot ramdisk if exists.
//	loadPrebootRAMDisk(); //Azi: this needs to be done before load_all_modules()
	// because of btAlias...			(Reviewing...)

	// Intialize module system
	if (init_module_system())
	{
		load_all_modules();
	}

    // Disable rescan option by default
    gEnableCDROMRescan = false;

    // If we're loading the booter from optical media...			(Reviewing...)
	if (biosDevIsCDROM(gBIOSDev))
	{
		// ... ask the user for Rescan option by setting "Rescan Prompt"=y in system config...
		if (getBoolForKey(kRescanPromptKey, &rescanPrompt, &bootInfo->bootConfig) && rescanPrompt)
		{
	        gEnableCDROMRescan = promptForRescanOption();
	    }
		else // ... or enable it with Rescan=y in system config.
	    if (getBoolForKey(kRescanKey, &gEnableCDROMRescan, &bootInfo->bootConfig) && gEnableCDROMRescan)
		{
	        gEnableCDROMRescan = true;
	    }
	}

	//Azi: Is this a cdrom only thing?			(Reviewing...)
    // Enable touching a single BIOS device only if "Scan Single Drive"=y is set in system config.
    if (getBoolForKey(kScanSingleDriveKey, &gScanSingleDrive, &bootInfo->bootConfig) && gScanSingleDrive)
	{
		scanBootVolumes(gBIOSDev, &bvCount);
    }
	else
	{
		//Azi: scanDisks uses scanBootVolumes.
		scanDisks(gBIOSDev, &bvCount);
	}
	
    // Create a separated bvr chain using the specified filters.
    bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);

    gBootVolume = selectBootVolume(bvChain);

//#if DEBUG
//printf
    msglog(":something...???\n Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
    msglog(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);
//    getchar();
//#endif

    useGUI = true;
    // Override useGUI default
    getBoolForKey(kGUIKey, &useGUI, &bootInfo->bootConfig);

	// AutoResolution - Azi: default to false
	// http://forum.voodooprojects.org/index.php/topic,1227.0.html
	gAutoResolution = false;
	
	// Check if user enabled AutoResolution on Boot.plist...
	getBoolForKey(kAutoResolutionKey, &gAutoResolution, &bootInfo->bootConfig);
	
	// Patch the Video Bios with the extracted resolution, before initGui.
	if (gAutoResolution == true)
	{
		initAutoRes();
	}

    if (useGUI && initGUI())
	{
		// initGUI() returned with an error, disabling GUI.
		useGUI = false;
	}

    setBootGlobals(bvChain);
	msglog("setBootGlobals:\n Default: %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBootVolume, gBootVolume->biosdev, gBootVolume->part_no, gBootVolume->flags);
    msglog(" bt(0,0): %d, ->biosdev: %d, ->part_no: %d ->flags: %d\n", gBIOSBootVolume, gBIOSBootVolume->biosdev, gBIOSBootVolume->part_no, gBIOSBootVolume->flags);

    // Parse args, load and start kernel.
    while (1) {
        const char *val;
        int len;
        int trycache;
		long flags, cachetime, kerneltime, exttime, sleeptime, time;
        int ret = -1;
        void *binary = (void *)kLoadAddr;
        bool tryresume;
        bool tryresumedefault;
        bool forceresume;
		bool ignoreKC = false;

        // additional variable for testing alternate kernel image locations on boot helper partitions.
        char     bootFileSpec[512];
		
        // Initialize globals.

        sysConfigValid = false;
        gErrors        = false;

        status = getBootOptions(firstRun);
        firstRun = false;
        if (status == -1) continue;

		//Azi: test (gBootVolume == NULL) - so far Ok!
		// test with optical media again...?
		// Turn off any GUI elements, draw background and update VRAM.
		if ( bootArgs->Video.v_display == GRAPHICS_MODE )
		{
			gui.devicelist.draw = false;
			gui.bootprompt.draw = false;
			gui.menu.draw = false;
			gui.infobox.draw = false;
			gui.logo.draw = false;
			drawBackground();
			updateVRAM();
		}

		status = processBootOptions();

		//Azi: AutoResolution -  closing Vbios here without restoring, causes an allocation error,
		// if the user tries to boot, after a e.g."Can't find bla_kernel" msg.
		// Doing it on execKernel() instead.

		// Status == 1 means to chainboot
		if ( status ==	1 ) break;
		
		// Status == -1 means that gBootVolume is NULL. Config file is not mandatory anymore! 
		if ( status == -1 )
		{
			// gBootVolume == NULL usually means the user hit escape.			(Reviewing...)
			if (gBootVolume == NULL)
			{
				freeFilteredBVChain(bvChain);
				
				if (gEnableCDROMRescan)
					rescanBIOSDevice(gBIOSDev);
				
				bvChain = newFilteredBVChain(0x80, 0xFF, allowBVFlags, denyBVFlags, &gDeviceCount);
				setBootGlobals(bvChain);
				setupDeviceList(&bootInfo->themeConfig);
			}
			continue;
		}
		
        // Other status (e.g. 0) means that we should proceed with boot.

		// If cpu handles 64 bit instructions...
		if (platformCPUFeature(CPU_FEATURE_EM64T))
		{
			// use x86_64 kernel arch,...
			archCpuType = CPU_TYPE_X86_64;
		}
		else
		{
			// else use i386 kernel arch.
			archCpuType = CPU_TYPE_I386;
		}
		// If user override...
		if (getValueForKey(kArchKey, &val, &len, &bootInfo->bootConfig))
		{
			// matches i386...
			if (strncmp(val, "i386", 4) == 0)
			{
				// use i386 kernel arch.
				archCpuType = CPU_TYPE_I386;
			}
		}
		
		if (!getBoolForKey (kWakeKey, &tryresume, &bootInfo->bootConfig)) {
			tryresume = true;
			tryresumedefault = true;
		} else {
			tryresumedefault = false;
		}

		if (!getBoolForKey (kForceWakeKey, &forceresume, &bootInfo->bootConfig)) {
			forceresume = false;
		}
		
		if (forceresume) {
			tryresume = true;
			tryresumedefault = false;
		}
		
		while (tryresume) {
			const char *tmp;
			BVRef bvr;
			if (!getValueForKey(kWakeKeyImageKey, &val, &len, &bootInfo->bootConfig))
				val="/private/var/vm/sleepimage";
			
			// Do this first to be sure that root volume is mounted
			ret = GetFileInfo(0, val, &flags, &sleeptime);

			if ((bvr = getBootVolumeRef(val, &tmp)) == NULL)
				break;
			
			// Can't check if it was hibernation Wake=y is required
			if (bvr->modTime == 0 && tryresumedefault)
				break;
			
			if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
				break;
			
			if (!forceresume && ((sleeptime+3)<bvr->modTime)) {
				//Azi: no need for printf at this point - reminder
				printf ("Hibernate image is too old by %d seconds. Use ForceWake=y to override.\n",bvr->modTime-sleeptime);
				break;
			}
				
			HibernateBoot((char *)val);
			break;
		}

//Azi:kernelcache stuff
		bool patchKernel = false;
		getBoolForKey(kKPatcherKey, &patchKernel, &bootInfo->bootConfig);
		//Azi: avoiding having to use -f to ignore kernel cache
		//Azi: ignore kernel cache but still use kext cache (E/E.mkext & S/L/E.mkext). - explain...
		getBoolForKey(kUseKCKey, &ignoreKC, &bootInfo->bootConfig); // equivalent to UseKernelCache
		if (ignoreKC)
		{
			verbose("KC: cache ignored by user.\n");
			// make sure the damn thing get's zeroed, just in case... :)*
			bzero(gBootKernelCacheFile, sizeof(gBootKernelCacheFile));
		}
		else if (patchKernel) // to be moved..?
		{
			verbose("KC: kernel patcher enabled, ignore cache.\n");
			bzero(gBootKernelCacheFile, sizeof(gBootKernelCacheFile));
		}
		else if (getValueForKey(kKernelCacheKey, &val, &len, &bootInfo->bootConfig))
		{
            strlcpy(gBootKernelCacheFile, val, len + 1);
			verbose("KC: path set by user = %s\n", gBootKernelCacheFile);
			//Azi: bypass time check when user sets path ???
			// cache is still ignored if time doesn't match... (e.g. booter on usb stick)
        }
		else
		{
			// Reset cache name.
			bzero(gCacheNameAdler + 64, sizeof(gCacheNameAdler) - 64);
			
			// kextcache_main.c: Construct entry from UUID of boot volume...(reminder)
			// assemble ?string? to generate adler from...
//			sprintf(gCacheNameAdler + 64, "%s,%s", gRootDevice, bootInfo->bootFile); - OLD
			const char *ProductName = getStringForKey("SMproductname", &bootInfo->smbiosConfig);
			sprintf(gCacheNameAdler, ProductName); // well, at least the smbios.plist can be loaded this early...
			// to set/get "ProductName" this early, booter needs complete rewrite!!
			// see DHP's Revolution booter rework example!
		//	verbose("KC: gCacheNameAdler 1 = %s\n", gCacheNameAdler);
			//Azi: check the validity of this, e.g. on Helper Partitions
			sprintf(gCacheNameAdler + 64, "%s", "\\System\\Library\\CoreServices\\boot.efi");
		//	verbose("KC: gCacheNameAdler 2 = %s\n", gCacheNameAdler + 64);
			sprintf(gCacheNameAdler + (64 + 38), "%s", bootInfo->bootFile);
		//	verbose("KC: gCacheNameAdler 3 = %s\n", gCacheNameAdler + (64 + 38));

			// generate adler
			adler32 = Adler32((unsigned char *)gCacheNameAdler, sizeof(gCacheNameAdler));
		//	verbose("KC: Adler32 = %08X\n", adler32);
//Azi: no check for OS version here ?? - yes there is :)
			// append arch and/or adler (checksum) to kc path...
			if (gMacOSVersion[3] <= '5')
			{
				sprintf(gBootKernelCacheFile, "%s.%08lX", kCachePathTigerLeopard, adler32);
		//		verbose("KC: adler added to path = %s\n", gBootKernelCacheFile);
			}
			else
			{
				sprintf(gBootKernelCacheFile, "%s_%s.%08X", kCachePathSnowLion,
						(archCpuType == CPU_TYPE_I386) ? "i386" : "x86_64", adler32);
		//		verbose("KC: arch & adler added to path = %s\n", gBootKernelCacheFile);
			}
        }

        // Check for cache file.
		//Azi: trycache is done if...
        trycache = ( ( (gBootMode & kBootModeSafe) == 0) //... we're not booting in safe mode (-x arg),
					&& !gOverrideKernel // we're not overriding default kernel "name",
					&& (gBootFileType == kBlockDeviceType) // we're booting from local storage device,
					&& (gMKextName[0] == '\0') // "MKext Cache" key IS NOT in use, and
					&& (gBootKernelCacheFile[0] != '\0') ); // gBootKernelCacheFile is populated.
					// we could add the use of "kernelpatcher" to this bunch..??

//		verbose("Loading Darwin %s\n", gMacOSVersion); //Azi: move?? to getOSVersion? :)
		
        if (trycache) do
		{
			verbose("KC: checking kernel cache (system prelinked kernel)...\n");
            // if we haven't found the kernel yet, don't use the cache
            ret = GetFileInfo(NULL, bootInfo->bootFile, &flags, &kerneltime);
            if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat))
            {
				verbose("KC: no kernel found (shouldn't happen?!?)\n");
                trycache = 0; // ignore kernel cache...
                break;
            }
			verbose("KC: kerneltime = %d\n", kerneltime);
			
            ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
            if ((ret != 0) || ((flags & kFileTypeMask) != kFileTypeFlat)
                || (cachetime < kerneltime))
            {
				if (cachetime <= 100) // confirm: 100 = inexistent path, -xxxxxxxxx = wrong name
				// not confirming... i also get -xxxxxxxxx with inexisting prelinked kernel
					verbose("KC: cachetime  = %d, kernel cache path/adler is incorrect, ignoring it. ??? \n",
							cachetime);
				else
					verbose("KC: cachetime  = %d, kernel cache is older than the kernel, ignoring it.\n",
							cachetime);
                trycache = 0;
                break;
            }
			verbose("KC: cachetime  = %d\n", cachetime);
			
            ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
            if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeDirectory)
                && (cachetime < exttime))
            {
				verbose("KC: exttime    = %d, kernel cache is older than S/L/E, ignoring it.\n", exttime);
                trycache = 0;
                break;
            }
			verbose("KC: exttime    = %d\n", exttime);
			
            if (kerneltime > exttime) // if S/L/E is older than the kernel...
            {
				verbose("KC: S/L/E is older than the kernel, matching exttime with kerneltime...\n");
                exttime = kerneltime;
            }
			verbose("KC: exttime +1 = %d\n", exttime + 1);
			
            if (cachetime != (exttime + 1))
            {
				verbose("KC: kernel cache time is diff from S/L/E time, ignoring it.\n");
                trycache = 0;
                break;
            }
			verbose("KC: kernel cache found and up to date, will be used.\n");

        } while (0);

        do
        {
			// Load kernel cache if not ignored.
            if (trycache)
            {
                bootFile = gBootKernelCacheFile;
                verbose("Loading kernel cache %s\n", bootFile);

                ret = LoadFile(bootFile);
                binary = (void *)kLoadAddr;

                if (ret >= 0)
                {
                    break;
                }
            }

            bootFile = bootInfo->bootFile;

            // Try to load kernel image from alternate locations on boot helper partitions.
            sprintf(bootFileSpec, "com.apple.boot.P/%s", bootFile);
            ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
  	  	    if (ret == -1)
  	  	    {
				sprintf(bootFileSpec, "com.apple.boot.R/%s", bootFile);
				ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
				if (ret == -1)
				{
					sprintf(bootFileSpec, "com.apple.boot.S/%s", bootFile);
					ret = GetFileInfo(NULL, bootFileSpec, &flags, &time); 
					if (ret == -1)
					{
						// No alternate location found, using the original kernel image path.
						strcpy(bootFileSpec, bootFile);
					}
				}
            }
            			
            verbose("Loading kernel %s\n", bootFileSpec);
            ret = LoadThinFatFile(bootFileSpec, &binary);
            if (ret <= 0 && archCpuType == CPU_TYPE_X86_64)
            {
				archCpuType = CPU_TYPE_I386;
				ret = LoadThinFatFile(bootFileSpec, &binary);				
            }
			
        } while (0);

        clearActivityIndicator();
/*#if DEBUG
        printf("Pausing...");
        sleep(8);
#endif
Azi: annoying stuff :P */
        if (ret <= 0)
		{
			printf("Can't find %s\n", bootFile);

			sleep(1);

            if (gBootFileType == kNetworkDeviceType) {
                // Return control back to PXE. Don't unload PXE base code.
                gUnloadPXEOnExit = false;
                break;
            }
        }
		else
		{
            // Won't return if successful.
            ret = ExecKernel(binary);
        }
    } // while (1)
    
    // chainboot
    if (status==1) {
		if (getVideoMode() == GRAPHICS_MODE) {	// if we are already in graphics-mode,
			setVideoMode(VGA_TEXT_MODE, 0);	// switch back to text mode
		}
    }
	
    if ((gBootFileType == kNetworkDeviceType) && gUnloadPXEOnExit)
	{
		nbpUnloadBaseCode();
    }
}