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(); } }
//========================================================================== //Initializes the runtime. Right now this means zeroing the BSS and initializing malloc. // void initialize_runtime(void) { zeroBSS(); malloc_init(0, 0, 0, malloc_error); }
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"); }