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; }
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(); } }
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; }