// // Returns TRUE if an argument was copied, FALSE otherwise bool processBootArgument( const char *argName, // The argument to search for const char *userString, // Typed-in boot arguments const char *kernelFlags, // Kernel flags from config table const char *configTable, char **argP, // Output value int *cntRemainingP, // Output count char *foundVal // found value ) { const char *val; int cnt; bool found = false; if (getValueForBootKey(userString, argName, &val, &cnt)) { // Don't copy; these values will be copied at the end of argument processing. found = true; } else if (getValueForBootKey(kernelFlags, argName, &val, &cnt)) { // Don't copy; these values will be copied at the end of argument processing. found = true; } else if (getValueForKey(argName, &val, &cnt, &bootInfo->bootConfig)) { copyArgument(argName, val, cnt, argP, cntRemainingP); found = true; } if (found && foundVal) { strlcpy(foundVal, val, cnt+1); } return found; }
bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config ) { const char *overrideVal; int overrideSize; bool override, ret; if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) { return true; } ret = getValueForConfigTableKey(config, key, val, size); // Try to find alternate keys in bootInfo->chameleonConfig (if config can be overriden) // and prefer its values with the exceptions for // "Kernel"="mach_kernel" and "Kernel Flags"="". if (config->canOverride) { if (getValueForConfigTableKey(&bootInfo->chameleonConfig, key, &overrideVal, &overrideSize)) { override = true; // NOTE: Values are defined by apple as being in com.apple.Boot.plist // kHelperRootUUIDKey, kKernelArchKey, kMKextCacheKey, kKernelCacheKey, kKernelNameKey, kKernelFlagsKey if (ret && (strcmp(key, kKernelNameKey) == 0) && (overrideSize == 0)) { override = false; } if (ret && (strcmp(key, kKernelFlagsKey) == 0) && (overrideSize == 0)) { override = false; }
bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config ) { const char *overrideVal; int overrideSize; bool override, ret; if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) return true; ret = getValueForConfigTableKey(config, key, val, size); // Try to find alternate keys in bootInfo->overrideConfig // and prefer its values with the exceptions for // "Kernel"="mach_kernel" and "Kernel Flags"="". if (config->canOverride) { if (getValueForConfigTableKey(&bootInfo->overrideConfig, key, &overrideVal, &overrideSize)) { override = true; if (ret && (strcmp(key, "Kernel") == 0) && (strcmp(overrideVal, "mach_kernel") == 0)) override = false; if (ret && (strcmp(key, "Kernel Flags") == 0) && (overrideSize == 0)) override = false; if (override) { *val = overrideVal; *size = overrideSize; return true; } } }
bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config ) { if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) return true; return getValueForConfigTableKey(config, key, val, size); }
BOOL getValueForKey( const char *key, const char **val, int *size ) { if (getValueForBootKey(bootArgs->CommandLine, key, val, size)) return YES; else if (getValueForConfigTableKey(bootInfo->config, key, val, size)) return YES; return NO; }
BOOL getValueForKey( char *key, char **val, int *size ) { if (getValueForBootKey(bootArgs->bootString, key, val, size)) return YES; else if (getValueForStringTableKey(bootArgs->config, key, val, size)) return YES; return NO; }
int processBootOptions() { const char * cp = gBootArgs; const char * val = 0; const char * kernel; int cnt; int userCnt; int cntRemaining; char * argP; char uuidStr[64]; bool uuidSet = false; char * configKernelFlags; char * valueBuffer; valueBuffer = malloc(VALUE_SIZE); skipblanks( &cp ); // Update the unit and partition number. if ( gBootVolume ) { if (!( gBootVolume->flags & kBVFlagNativeBoot )) { readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, (void *) 0x7c00 ); // // Setup edx, and signal intention to chain load the // foreign booter. // chainbootdev = gBootVolume->biosdev; chainbootflag = 1; return 1; } setRootVolume(gBootVolume); } // If no boot volume fail immediately because we're just going to fail // trying to load the config file anyway. else return -1; // Load config table specified by the user, or use the default. if (!getValueForBootKey(cp, "config", &val, &cnt)) { val = 0; cnt = 0; } // Load com.apple.Boot.plist from the selected volume // and use its contents to override default bootConfig. // This is not a mandatory operation anymore. loadOverrideConfig(&bootInfo->overrideConfig); // Use the kernel name specified by the user, or fetch the name // in the config table, or use the default if not specified. // Specifying a kernel name on the command line, or specifying // a non-default kernel name in the config file counts as // overriding the kernel, which causes the kernelcache not // to be used. gOverrideKernel = false; if (( kernel = extractKernelName((char **)&cp) )) { strcpy( bootInfo->bootFile, kernel ); gOverrideKernel = true; } else { if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) { strlcpy( bootInfo->bootFile, val, cnt+1 ); if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) { gOverrideKernel = true; } } else { strcpy( bootInfo->bootFile, kDefaultKernel ); } } cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space argP = bootArgs->CommandLine; // Get config table kernel flags, if not ignored. if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) || !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) { val = ""; cnt = 0; } configKernelFlags = malloc(cnt + 1); strlcpy(configKernelFlags, val, cnt + 1); if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) { // boot-uuid was set either on the command-line // or in the config file. uuidSet = true; } else { // // Try an alternate method for getting the root UUID on boot helper partitions. // if (gBootVolume->flags & kBVFlagBooter) { if((loadHelperConfig(&bootInfo->helperConfig) == 0) && getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig) ) { getValueForKey(kHelperRootUUIDKey, &val, &cnt, &bootInfo->helperConfig); copyArgument(kBootUUIDKey, val, cnt, &argP, &cntRemaining); uuidSet = true; } } if (!uuidSet && gBootVolume->fs_getuuid && gBootVolume->fs_getuuid (gBootVolume, uuidStr) == 0) { verbose("Setting boot-uuid to: %s\n", uuidStr); copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining); uuidSet = true; } } if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) { cnt = 0; if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->bootConfig)) { valueBuffer[0] = '*'; cnt++; strlcpy(valueBuffer + 1, val, cnt); val = valueBuffer; } else { if (uuidSet) { val = "*uuid"; cnt = 5; } else { // Don't set "rd=.." if there is no boot device key // and no UUID. val = ""; cnt = 0; } } if (cnt > 0) { copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining); } strlcpy( gRootDevice, val, (cnt + 1)); } /* * Removed. We don't need this anymore. * if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) { getPlatformName(gPlatformName); copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining); } */ if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) && !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) { if (gBootMode & kBootModeSafe) { copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining); } } // Store the merged kernel flags and boot args. cnt = strlen(configKernelFlags); if (cnt) { if (cnt > cntRemaining) { error("Warning: boot arguments too long, truncating\n"); cnt = cntRemaining; } strncpy(argP, configKernelFlags, cnt); argP[cnt++] = ' '; cntRemaining -= cnt; } userCnt = strlen(cp); if (userCnt > cntRemaining) { error("Warning: boot arguments too long, truncating\n"); userCnt = cntRemaining; } strncpy(&argP[cnt], cp, userCnt); argP[cnt+userCnt] = '\0'; if(!shouldboot) { gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->bootConfig ) || getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->bootConfig ); gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->bootConfig ) ) ? kBootModeSafe : kBootModeNormal; if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->bootConfig ) ) { gBootMode = kBootModeSafe; } } if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) ) { strlcpy(gMKextName, val, cnt + 1); } free(configKernelFlags); free(valueBuffer); return 0; }
int processBootOptions() { const char *cp = gBootArgs; const char *val = 0; const char *kernel; int cnt; int userCnt; int cntRemaining; char *argP; char *configKernelFlags; char *valueBuffer; valueBuffer = malloc(VALUE_SIZE); skipblanks( &cp ); // Update the unit and partition number. if ( gBootVolume ) { if (!( gBootVolume->flags & kBVFlagNativeBoot )) { readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, (void *) 0x7c00 ); // // Setup edx, and signal intention to chain load the // foreign booter. // chainbootdev = gBootVolume->biosdev; chainbootflag = 1; return 1; } setRootVolume(gBootVolume); } // If no boot volume fail immediately because we're just going to fail // trying to load the config file anyway. else { return -1; } // Find out which version mac os we're booting. strncpy(gMacOSVersion, gBootVolume->OSVersion, sizeof(gMacOSVersion)); // Load config table specified by the user, or use the default. if (!getValueForBootKey(cp, "config", &val, &cnt)) { val = 0; cnt = 0; } // Load com.apple.Boot.plist from the selected volume // and use its contents to override default bootConfig. loadSystemConfig(&bootInfo->bootConfig); loadChameleonConfig(&bootInfo->chameleonConfig, NULL); // Use the kernel name specified by the user, or fetch the name // in the config table, or use the default if not specified. // Specifying a kernel name on the command line, or specifying // a non-default kernel name in the config file counts as // overriding the kernel, which causes the kernelcache not // to be used. gOverrideKernel = false; if (( kernel = extractKernelName((char **)&cp) )) { strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) ); } else { if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) { strlcpy( bootInfo->bootFile, val, cnt+1 ); } else { if( YOSEMITE ) // is 10.10 { strlcpy( bootInfo->bootFile, kOSXKernel, sizeof(bootInfo->bootFile) ); //printf(HEADER "/System/Library/Kernels/%s\n", bootInfo->bootFile); } else { // OSX is not 10.10 strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) ); //printf(HEADER "/%s\n", bootInfo->bootFile); } } } if (!YOSEMITE) // not 10.10 so 10.9 and previus { if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) { //printf(HEADER "org.chameleon.Boot.plist found path for custom '%s' found!\n", bootInfo->bootFile); gOverrideKernel = true; } } else { // OSX is 10.10 if (strcmp( bootInfo->bootFile, kOSXKernel ) != 0) { //printf(HEADER "org.chameleon.Boot.plist found path for custom '%s' found!\n", bootInfo->bootFile); gOverrideKernel = true; } } // Ermac : Inject "kext-dev-mode=1" if OS X 10.10 is detected if( YOSEMITE ) // is 10.10 { addBootArg("kext-dev-mode=1"); } cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space argP = bootArgs->CommandLine; // Get config kernel flags, if not ignored. if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) || !getValueForKey( kKernelFlagsKey, &val, &cnt, &bootInfo->bootConfig )) { val = ""; cnt = 0; } configKernelFlags = malloc(cnt + 1); strlcpy(configKernelFlags, val, cnt + 1); // boot-uuid can be set either on the command-line or in the config file if (!processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gBootUUIDString, sizeof(gBootUUIDString))) { // // Try an alternate method for getting the root UUID on boot helper partitions. // if (gBootVolume->flags & kBVFlagBooter) { // Load the configuration store in the boot helper partition if (loadHelperConfig(&bootInfo->helperConfig) == 0) { val = getStringForKey(kHelperRootUUIDKey, &bootInfo->helperConfig); if (val != NULL) { strlcpy(gBootUUIDString, val, sizeof(gBootUUIDString)); } } } /* // Try to get the volume uuid string if (!strlen(gBootUUIDString) && gBootVolume->fs_getuuid) { gBootVolume->fs_getuuid(gBootVolume, gBootUUIDString); } */ // If we have the volume uuid add it to the commandline arguments if (strlen(gBootUUIDString)) { copyArgument(kBootUUIDKey, gBootUUIDString, strlen(gBootUUIDString), &argP, &cntRemaining); } // Try to get the volume uuid string if (!strlen(gBootUUIDString) && gBootVolume->fs_getuuid) { gBootVolume->fs_getuuid(gBootVolume, gBootUUIDString); DBG("boot-uuid: %s\n", gBootUUIDString); } } if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice, ROOT_DEVICE_SIZE)) { cnt = 0; if ( getValueForKey( kBootDeviceKey, &val, &cnt, &bootInfo->chameleonConfig)) { valueBuffer[0] = '*'; cnt++; strlcpy(valueBuffer + 1, val, cnt); val = valueBuffer; } else { /* if (strlen(gBootUUIDString)) { val = "*uuid"; cnt = 5; } else { */ // Don't set "rd=.." if there is no boot device key // and no UUID. val = ""; cnt = 0; /* } */ } if (cnt > 0) { copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining); } strlcpy( gRootDevice, val, (cnt + 1)); } /* * Removed. We don't need this anymore. * if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName, sizeof(gCacheNameAdler))) { getPlatformName(gPlatformName); copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining); } */ if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) && !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) { if (gBootMode & kBootModeSafe) { copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining); } } // Store the merged kernel flags and boot args. cnt = strlen(configKernelFlags); if (cnt) { if (cnt > cntRemaining) { error("Warning: boot arguments too long, truncating\n"); cnt = cntRemaining; } strncpy(argP, configKernelFlags, cnt); argP[cnt++] = ' '; cntRemaining -= cnt; } userCnt = strlen(cp); if (userCnt > cntRemaining) { error("Warning: boot arguments too long, truncating\n"); userCnt = cntRemaining; } strncpy(&argP[cnt], cp, userCnt); argP[cnt+userCnt] = '\0'; if(!shouldboot) { gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) || getValueForKey( kSingleUserModeFlag, &val, &cnt, &bootInfo->chameleonConfig ); gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) ? kBootModeSafe : kBootModeNormal; if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, &bootInfo->chameleonConfig ) ) { gBootMode = kBootModeSafe; } } if ( getValueForKey( kMKextCacheKey, &val, &cnt, &bootInfo->bootConfig ) ) { strlcpy(gMKextName, val, cnt + 1); } else { gMKextName[0]=0; } free(configKernelFlags); free(valueBuffer); return 0; }
// This is the meat of our implementation. It grabs the boot device from // the multiboot_info and returns it as is. If it fails it returns // BAD_BOOT_DEVICE. We can call an awful lot of libsa and libsaio but // we need to take care not to call anything that requires malloc because // it won't be initialized until boot() does it. static inline uint32_t multiboot(int multiboot_magic, struct multiboot_info *mi) { if(multiboot_magic != MULTIBOOT_INFO_MAGIC) { printf("Wrong Multiboot magic\n"); sleep(2); return BAD_BOOT_DEVICE; } printf("Multiboot info @0x%x\n", (uint32_t)mi); if(mi->mi_flags & MULTIBOOT_INFO_HAS_LOADER_NAME) printf("Loaded by %s\n", mi->mi_loader_name); // Multiboot puts boot device in high byte // Normal booter wants it in low byte int bootdevice = mi->mi_boot_device_drive; bool doSelectDevice = false; if(mi->mi_flags & MULTIBOOT_INFO_HAS_BOOT_DEVICE) { printf("Boot device 0x%x\n", bootdevice); } else { printf("Multiboot info does not include chosen boot device\n"); doSelectDevice = true; bootdevice = BAD_BOOT_DEVICE; } if(mi->mi_flags & MULTIBOOT_INFO_HAS_CMDLINE) { const char *val; int size; if(getValueForBootKey(mi->mi_cmdline, "biosdev", &val, &size)) { char *endptr; int intVal = strtol(val, &endptr, 16 /* always hex */); if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t')) { printf("Boot device overridden to %02x with biosdev=%s\n", intVal, val); bootdevice = intVal; doSelectDevice = false; } else doSelectDevice = true; } if(getValueForBootKey(mi->mi_cmdline, "timeout", &val, &size)) { char *endptr; int intVal = strtol(val, &endptr, 0); if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t')) { printf("Timeout overridden to %d with timeout=%s\n", intVal, val); multiboot_timeout = intVal; multiboot_timeout_set = 1; } } if(getValueForBootKey(mi->mi_cmdline, "partno", &val, &size)) { char *endptr; int intVal = strtol(val, &endptr, 0); if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t')) { printf("Default partition overridden to %d with partno=%s\n", intVal, val); multiboot_partition = intVal; multiboot_partition_set = 1; } } if(getValueForBootKey(mi->mi_cmdline, "skip_partno", &val, &size)) { char *endptr; int intVal = strtol(val, &endptr, 0); if(*val != '\0' && (*endptr == '\0' || *endptr == ' ' || *endptr == '\t')) { printf("Skipping partition %d with skip_partno=%s\n", intVal, val); multiboot_skip_partition = intVal; multiboot_skip_partition_set = 1; } } } if(doSelectDevice) { bootdevice = selectAlternateBootDevice(bootdevice); } if(bootdevice == BAD_BOOT_DEVICE) sleep(2); // pause for a second before halting return bootdevice; }
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"); }
int processBootOptions(void) { char *cp_cache = (char*)(uint32_t)get_env(envgBootArgs); if (cp_cache) { bzero(gBootArgs,sizeof(gBootArgs)); strlcpy(gBootArgs, cp_cache,sizeof(gBootArgs)); } const char * cp = gBootArgs; const char * val = 0; const char * kernel; int cnt; int userCnt; char * argP; char * configKernelFlags; int ArgCntRemaining; skipblanks( &cp ); // Update the unit and partition number. if ( ((BVRef)(uint32_t)get_env(envgBootVolume)) ) { #ifndef NO_MULTIBOOT_SUPPORT if (!( ((BVRef)(uint32_t)get_env(envgBootVolume))->flags & kBVFlagNativeBoot )) { readBootSector( ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev, ((BVRef)(uint32_t)get_env(envgBootVolume))->part_boff, (void *) 0x7c00 ); // // Setup edx, and signal intention to chain load the // foreign booter. // extern unsigned char chainbootdev; extern unsigned char chainbootflag; chainbootdev = ((BVRef)(uint32_t)get_env(envgBootVolume))->biosdev; chainbootflag = 1; return 1; } #endif setRootVolume(((BVRef)(uint32_t)get_env(envgBootVolume))); } // If no boot volume fail immediately because we're just going to fail // trying to load the config file anyway. else return -1; // Load config table specified by the user, or use the default. if (!getValueForBootKey(cp, "config", &val, &cnt)) { val = 0; cnt = 0; } // Load com.apple.Boot.plist from the selected volume // and use its contents to override default bootConfig. // This is not a mandatory opeartion anymore. loadOverrideConfig(); // Load System com.apple.boot.plist config file loadSystemConfig(); #if virtualM || PCI_FIX // we can simply make an option for this fix addBootArg("npci=0x2000"); #endif #if verbose addBootArg("-v"); #endif // Use the kernel name specified by the user, or fetch the name // in the config table, or use the default if not specified. // Specifying a kernel name on the command line, or specifying // a non-default kernel name in the config file counts as // overriding the kernel, which causes the kernelcache not // to be used. safe_set_env(envgOverrideKernel,false); if (( kernel = extractKernelName((char **)&cp) )) { strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) ); safe_set_env(envgOverrideKernel,true); } else { if ( getValueForKey( kKernelNameKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) { strlcpy( bootInfo->bootFile, val, sizeof(bootInfo->bootFile) ); if (strncmp( bootInfo->bootFile, kDefaultKernel, sizeof(kDefaultKernel) ) != 0) { safe_set_env(envgOverrideKernel,true); } } else if (((BVRef)(uint32_t)get_env(envgBootVolume))->kernelfound == true) { strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) ); } else { printf("No kernel found on this volume : hd(%d,%d)\n", BIOS_DEV_UNIT(((BVRef)(uint32_t)get_env(envgBootVolume))), ((BVRef)(uint32_t)get_env(envgBootVolume))->part_no); sleep(1); return -1; } } ArgCntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space argP = bootArgs->CommandLine; // Get config table kernel flags, if not ignored. if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) || !getValueForKey( kKernelFlagsKey, &val, &cnt, DEFAULT_BOOT_CONFIG )) { val = ""; cnt = 0; } configKernelFlags = newString(val); { bool isSafeMode = false; if (configKernelFlags) { isSafeMode = getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt); } if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) && (isSafeMode == false)) { if (get_env(envgBootMode) & kBootModeSafe) { copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &ArgCntRemaining); } } } if (configKernelFlags) { // Store the merged kernel flags and boot args. cnt = strlen(configKernelFlags); if (cnt) { if (cnt > ArgCntRemaining) { printf("Warning: boot arguments too long, truncating\n"); cnt = ArgCntRemaining; } strncpy(argP, configKernelFlags, cnt); argP[cnt++] = ' '; ArgCntRemaining -= cnt; } } userCnt = strlen(cp); if (userCnt > ArgCntRemaining) { printf("Warning: boot arguments too long, truncating\n"); userCnt = ArgCntRemaining; } strncpy(&argP[cnt], cp, userCnt); argP[cnt+userCnt] = '\0'; if(!get_env(envShouldboot)) { bool gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) || getValueForKey( kSingleUserModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ); safe_set_env(envgVerboseMode, gVerboseMode); long gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) ? kBootModeSafe : kBootModeNormal; safe_set_env(envgBootMode,gBootMode); if ( getValueForKey( kIgnoreCachesFlag, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) { gBootMode = kBootModeSafe; safe_set_env(envgBootMode,gBootMode); } } if ( getValueForKey( kMKextCacheKey, &val, &cnt, DEFAULT_BOOT_CONFIG ) ) { char * MKextName = (char*)(uint32_t)get_env(envMKextName); strlcpy(MKextName,val,Cache_len_name); } if (configKernelFlags) { free(configKernelFlags); } safe_set_env(envArgCntRemaining,ArgCntRemaining); return 0; }
int processBootOptions() { const char * cp = gBootArgs; const char * val = 0; const char * kernel; int cnt; int userCnt; int cntRemaining; char * argP; char uuidStr[64]; BOOL uuidSet = NO; char * configKernelFlags; char * valueBuffer; valueBuffer = (char *)malloc(VALUE_SIZE); skipblanks( &cp ); // Update the unit and partition number. if ( gBootVolume ) { if ( gBootVolume->flags & kBVFlagForeignBoot ) { readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, (void *) 0x7c00 ); // // Setup edx, and signal intention to chain load the // foreign booter. // chainbootdev = gBootVolume->biosdev; chainbootflag = 1; return 1; } bootInfo->kernDev &= ~((B_UNITMASK << B_UNITSHIFT ) | (B_PARTITIONMASK << B_PARTITIONSHIFT)); bootInfo->kernDev |= MAKEKERNDEV( 0, /* unit */ BIOS_DEV_UNIT(gBootVolume), /* partition */ gBootVolume->part_no ); } // Load config table specified by the user, or use the default. if (getValueForBootKey( cp, "config", &val, &cnt ) == FALSE) { val = 0; cnt = 0; } loadSystemConfig(val, cnt); if ( !sysConfigValid ) return -1; // Use the kernel name specified by the user, or fetch the name // in the config table, or use the default if not specified. // Specifying a kernel name on the command line, or specifying // a non-default kernel name in the config file counts as // overriding the kernel, which causes the kernelcache not // to be used. gOverrideKernel = NO; if (( kernel = extractKernelName((char **)&cp) )) { strcpy( bootInfo->bootFile, kernel ); gOverrideKernel = YES; } else { if ( getValueForKey( kKernelNameKey, &val, &cnt ) ) { strlcpy( bootInfo->bootFile, val, cnt+1 ); if (strcmp( bootInfo->bootFile, kDefaultKernel ) != 0) { gOverrideKernel = YES; } } else { strcpy( bootInfo->bootFile, kDefaultKernel ); } } cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space argP = bootArgs->CommandLine; // Get config table kernel flags, if not ignored. if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) == TRUE || getValueForKey( kKernelFlagsKey, &val, &cnt ) == FALSE) { val = ""; cnt = 0; } configKernelFlags = (char *)malloc(cnt + 1); strlcpy(configKernelFlags, val, cnt + 1); if (processBootArgument(kBootUUIDKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, 0)) { // boot-uuid was set either on the command-line // or in the config file. uuidSet = YES; } else { if (GetFSUUID(bootInfo->bootFile, uuidStr) == 0) { verbose("Setting boot-uuid to: %s\n", uuidStr); copyArgument(kBootUUIDKey, uuidStr, strlen(uuidStr), &argP, &cntRemaining); uuidSet = YES; } } if (!processBootArgument(kRootDeviceKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gRootDevice)) { cnt = 0; if ( getValueForKey( kBootDeviceKey, &val, &cnt)) { valueBuffer[0] = '*'; cnt++; strlcpy(valueBuffer + 1, val, cnt); val = valueBuffer; } else { if (uuidSet) { val = "*uuid"; cnt = 5; } else { // Don't set "rd=.." if there is no boot device key // and no UUID. val = ""; cnt = 0; } } if (cnt > 0) { copyArgument( kRootDeviceKey, val, cnt, &argP, &cntRemaining); } strlcpy( gRootDevice, val, (cnt + 1)); } if (!processBootArgument(kPlatformKey, cp, configKernelFlags, bootInfo->config, &argP, &cntRemaining, gPlatformName)) { getPlatformName(gPlatformName); copyArgument(kPlatformKey, gPlatformName, strlen(gPlatformName), &argP, &cntRemaining); } if (!getValueForBootKey(cp, kSafeModeFlag, &val, &cnt) && !getValueForBootKey(configKernelFlags, kSafeModeFlag, &val, &cnt)) { if (gBootMode & kBootModeSafe) { copyArgument(0, kSafeModeFlag, strlen(kSafeModeFlag), &argP, &cntRemaining); } } // Store the merged kernel flags and boot args. cnt = strlen(configKernelFlags); if (cnt) { if (cnt > cntRemaining) { error("Warning: boot arguments too long, truncating\n"); cnt = cntRemaining; } strncpy(argP, configKernelFlags, cnt); argP[cnt++] = ' '; cntRemaining -= cnt; } userCnt = strlen(cp); if (userCnt > cntRemaining) { error("Warning: boot arguments too long, truncating\n"); userCnt = cntRemaining; } strncpy(&argP[cnt], cp, userCnt); argP[cnt+userCnt] = '\0'; gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt ) || getValueForKey( kSingleUserModeFlag, &val, &cnt ); gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt ) ) ? kBootModeSafe : kBootModeNormal; if ( getValueForKey( kOldSafeModeFlag, &val, &cnt ) ) { gBootMode = kBootModeSafe; } if ( getValueForKey( kMKextCacheKey, &val, &cnt ) ) { strlcpy(gMKextName, val, cnt + 1); } free(configKernelFlags); free(valueBuffer); return 0; }
int processBootOptions() { const char * cp = gBootArgs; const char * val = 0; const char * kernel; int cnt; int userCnt; int cntRemaining; char * argP; skipblanks( &cp ); // Update the unit and partition number. if ( gBootVolume ) { if ( gBootVolume->flags & kBVFlagForeignBoot ) { readBootSector( gBootVolume->biosdev, gBootVolume->part_boff, (void *) 0x7c00 ); // // Setup edx, and signal intention to chain load the // foreign booter. // chainbootdev = gBootVolume->biosdev; chainbootflag = 1; return 1; } bootArgs->kernDev &= ~((B_UNITMASK << B_UNITSHIFT ) | (B_PARTITIONMASK << B_PARTITIONSHIFT)); bootArgs->kernDev |= MAKEKERNDEV( 0, /* unit */ BIOS_DEV_UNIT(gBootVolume), /* partition */ gBootVolume->part_no ); } // Load config table specified by the user, or use the default. if (getValueForBootKey( cp, "config", &val, &cnt ) == FALSE) { val = 0; cnt = 0; } loadSystemConfig(val, cnt); if ( !sysConfigValid ) return -1; // Use the kernel name specified by the user, or fetch the name // in the config table, or use the default if not specified. // Specifying a kernel name on the command line, or specifying // a non-default kernel name in the config file counts as // overriding the kernel, which causes the kernelcache not // to be used. gOverrideKernel = NO; if (( kernel = extractKernelName((char **)&cp) )) { strcpy( bootArgs->bootFile, kernel ); gOverrideKernel = YES; } else { if ( getValueForKey( kKernelNameKey, &val, &cnt ) ) { strlcpy( bootArgs->bootFile, val, cnt+1 ); if (strcmp( bootArgs->bootFile, kDefaultKernel ) != 0) { gOverrideKernel = YES; } } else { strcpy( bootArgs->bootFile, kDefaultKernel ); } } cntRemaining = BOOT_STRING_LEN - 2; // save 1 for NULL, 1 for space // Check to see if we need to specify root device. // If user types "rd=.." on the boot line, it overrides // the boot device key in the boot arguments file. // argP = bootArgs->bootString; if ( getValueForBootKey( cp, kRootDeviceKey, &val, &cnt ) == FALSE && getValueForKey( kRootDeviceKey, &val, &cnt ) == FALSE ) { if ( getValueForKey( kBootDeviceKey, &val, &cnt ) ) { strcpy( argP, "rd=*" ); argP += 4; strlcpy( argP, val, cnt+1); cntRemaining -= cnt; argP += cnt; *argP++ = ' '; } } // Check to see if we should ignore saved kernel flags. if (getValueForBootKey(cp, kIgnoreBootFileFlag, &val, &cnt) == FALSE) { if (getValueForKey( kKernelFlagsKey, &val, &cnt ) == FALSE) { val = 0; cnt = 0; } } // Store the merged kernel flags and boot args. if (cnt > cntRemaining) { error("Warning: boot arguments too long, truncated\n"); cnt = cntRemaining; } if (cnt) { strncpy(argP, val, cnt); argP[cnt++] = ' '; } cntRemaining = cntRemaining - cnt; userCnt = strlen(cp); if (userCnt > cntRemaining) { error("Warning: boot arguments too long, truncated\n"); userCnt = cntRemaining; } strncpy(&argP[cnt], cp, userCnt); argP[cnt+userCnt] = '\0'; gVerboseMode = getValueForKey( kVerboseModeFlag, &val, &cnt ) || getValueForKey( kSingleUserModeFlag, &val, &cnt ); gBootMode = ( getValueForKey( kSafeModeFlag, &val, &cnt ) ) ? kBootModeSafe : kBootModeNormal; if ( getValueForKey( kPlatformKey, &val, &cnt ) ) { strlcpy(gPlatformName, val, cnt + 1); } else { strcpy(gPlatformName, "ACPI"); } if ( getValueForKey( kMKextCacheKey, &val, &cnt ) ) { strlcpy(gMKextName, val, cnt + 1); } return 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) { 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 } } }