- IOReturn err;
- OSData * data;
- OSObject * obj;
- OSString * str;
- bool dsSSD;
-
- IOHibernateVars * vars = &gIOHibernateVars;
-
- if (vars->fileVars && vars->fileVars->fileRef)
- // already on the way down
- return (kIOReturnSuccess);
-
- gIOHibernateState = kIOHibernateStateInactive;
-
- gIOHibernateDebugFlags = 0;
- if (kIOLogHibernate & gIOKitDebug)
- gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
-
- if (IOService::getPMRootDomain()->getHibernateSettings(
- &gIOHibernateMode, &gIOHibernateFreeRatio, &gIOHibernateFreeTime))
- if (kIOHibernateModeSleep & gIOHibernateMode)
- // default to discard clean for safe sleep
- gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
- | kIOHibernateModeDiscardCleanActive);
-
- if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey)))
- {
- if ((str = OSDynamicCast(OSString, obj)))
- strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
- sizeof(gIOHibernateFilename));
- obj->release();
- }
-
- if (!gIOHibernateMode || !gIOHibernateFilename[0])
- return (kIOReturnUnsupported);
-
- HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
-
-
- do
- {
- vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
- 4 * page_size, page_size);
- vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
- 2 * kDefaultIOSize, page_size);
-
- if (!vars->srcBuffer || !vars->ioBuffer)
- {
- err = kIOReturnNoMemory;
- break;
- }
-
- err = IOPolledFileOpen(gIOHibernateFilename, vars->ioBuffer,
- &vars->fileVars, &vars->fileExtents, &data);
- if (KERN_SUCCESS != err)
- {
- HIBLOG("IOPolledFileOpen(%x)\n", err);
- break;
- }
- if (vars->fileVars->fileRef)
- {
- // invalidate the image file
- gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
- int err = kern_write_file(vars->fileVars->fileRef, 0,
- (caddr_t) gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
- if (KERN_SUCCESS != err)
- HIBLOG("kern_write_file(%d)\n", err);
- }
-
- bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
- gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
-
- dsSSD = (vars->fileVars->solid_state
- && (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
-
- if (dsSSD)
- {
- gIOHibernateCurrentHeader->options |=
- kIOHibernateOptionSSD
- | kIOHibernateOptionColor;
- }
- else
- {
- gIOHibernateCurrentHeader->options |= kIOHibernateOptionProgress;
- }
-
- boolean_t encryptedswap;
- AbsoluteTime startTime, endTime;
- uint64_t nsec;
-
- clock_get_uptime(&startTime);
- err = hibernate_setup(gIOHibernateCurrentHeader,
- gIOHibernateFreeRatio, gIOHibernateFreeTime,
- dsSSD,
- &vars->page_list, &vars->page_list_wired, &encryptedswap);
- clock_get_uptime(&endTime);
- SUB_ABSOLUTETIME(&endTime, &startTime);
- absolutetime_to_nanoseconds(endTime, &nsec);
- HIBLOG("hibernate_setup(%d) took %qd ms\n", err, nsec / 1000000ULL);
-
- if (KERN_SUCCESS != err)
- break;
-
- if (encryptedswap)
- gIOHibernateMode ^= kIOHibernateModeEncrypt;
-
- if (kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
- {
- vars->videoAllocSize = kVideoMapSize;
- if (KERN_SUCCESS != kmem_alloc_pageable(kernel_map, &vars->videoMapping, vars->videoAllocSize))
- vars->videoMapping = 0;
- }
-
- // generate crypt keys
- for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++)
- vars->wiredCryptKey[i] = random();
- for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++)
- vars->cryptKey[i] = random();
-
- // set nvram
-
- IORegistryEntry * regEntry;
- if (!gIOOptionsEntry)
- {
- regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
- gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
- if (regEntry && !gIOOptionsEntry)
- regEntry->release();
- }
- if (!gIOChosenEntry)
- gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-
- if (gIOOptionsEntry)
- {
- const OSSymbol * sym;
-
- sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
- if (sym)
- {
- gIOOptionsEntry->setProperty(sym, data);
- sym->release();
- }
- data->release();
-
-#if defined(__ppc__)
- size_t len;
- char valueString[16];
-
- vars->saveBootDevice = gIOOptionsEntry->copyProperty(kIOSelectedBootDeviceKey);
- if (gIOChosenEntry)
- {
- OSData * bootDevice = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOBootPathKey));
- if (bootDevice)
- {
- sym = OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey);
- OSString * str2 = OSString::withCStringNoCopy((const char *) bootDevice->getBytesNoCopy());
- if (sym && str2)
- gIOOptionsEntry->setProperty(sym, str2);
- if (sym)
- sym->release();
- if (str2)
- str2->release();
- }
- data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMemorySignatureKey));
- if (data)
- {
- vars->haveFastBoot = true;
-
- len = snprintf(valueString, sizeof(valueString), "0x%lx", *((UInt32 *)data->getBytesNoCopy()));
- data = OSData::withBytes(valueString, len + 1);
- sym = OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey);
- if (sym && data)
- gIOOptionsEntry->setProperty(sym, data);
- if (sym)
- sym->release();
- if (data)
- data->release();
- }
- data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
- if (data)
- gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
- }
-#endif /* __ppc__ */
-#if defined(__i386__) || defined(__x86_64__)
- struct AppleRTCHibernateVars
- {
- uint8_t signature[4];
- uint32_t revision;
- uint8_t booterSignature[20];
- uint8_t wiredCryptKey[16];
- };
- AppleRTCHibernateVars rtcVars;
-
- rtcVars.signature[0] = 'A';
- rtcVars.signature[1] = 'A';
- rtcVars.signature[2] = 'P';
- rtcVars.signature[3] = 'L';
- rtcVars.revision = 1;
- bcopy(&vars->wiredCryptKey[0], &rtcVars.wiredCryptKey[0], sizeof(rtcVars.wiredCryptKey));
- if (gIOHibernateBootSignature[0])
- {
- char c;
- uint8_t value = 0;
- for (uint32_t i = 0;
- (c = gIOHibernateBootSignature[i]) && (i < (sizeof(rtcVars.booterSignature) << 1));
- i++)
- {
- if (c >= 'a')
- c -= 'a' - 10;
- else if (c >= 'A')
- c -= 'A' - 10;
- else if (c >= '0')
- c -= '0';
- else
- continue;
- value = (value << 4) | c;
- if (i & 1)
- rtcVars.booterSignature[i >> 1] = value;
- }
- }
- data = OSData::withBytes(&rtcVars, sizeof(rtcVars));
- if (data)
- {
- if (!gIOHibernateRTCVariablesKey)
- gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
- if (gIOHibernateRTCVariablesKey)
- IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey, data);
-
- if( gIOOptionsEntry )
- {
- if( gIOHibernateMode & kIOHibernateModeSwitch )
- {
- const OSSymbol *sym;
- sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey);
- if( sym )
- {
- gIOOptionsEntry->setProperty(sym, data); /* intentional insecure backup of rtc boot vars */
- sym->release();
- }
- }
- }
-
- data->release();
- }
- if (gIOChosenEntry)
- {
- data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
- if (data)
- gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
- {
- // set BootNext
-
- if (!gIOHibernateBoot0082Data)
- {
- data = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-device-path"));
- if (data)
- {
- // AppleNVRAM_EFI_LOAD_OPTION
- struct {
- uint32_t Attributes;
- uint16_t FilePathLength;
- uint16_t Desc;
- } loadOptionHeader;
- loadOptionHeader.Attributes = 1;
- loadOptionHeader.FilePathLength = data->getLength();
- loadOptionHeader.Desc = 0;
- gIOHibernateBoot0082Data = OSData::withCapacity(sizeof(loadOptionHeader) + loadOptionHeader.FilePathLength);
- if (gIOHibernateBoot0082Data)
- {
- gIOHibernateBoot0082Data->appendBytes(&loadOptionHeader, sizeof(loadOptionHeader));
- gIOHibernateBoot0082Data->appendBytes(data);
- }
- }
- }
- if (!gIOHibernateBoot0082Key)
- gIOHibernateBoot0082Key = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
- if (!gIOHibernateBootNextKey)
- gIOHibernateBootNextKey = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
- if (!gIOHibernateBootNextData)
- {
- uint16_t bits = 0x0082;
- gIOHibernateBootNextData = OSData::withBytes(&bits, sizeof(bits));
- }
- if (gIOHibernateBoot0082Key && gIOHibernateBoot0082Data && gIOHibernateBootNextKey && gIOHibernateBootNextData)
- {
- gIOHibernateBootNextSave = gIOOptionsEntry->copyProperty(gIOHibernateBootNextKey);
- gIOOptionsEntry->setProperty(gIOHibernateBoot0082Key, gIOHibernateBoot0082Data);
- gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextData);
- }
- }
- }
-#else /* !i386 && !x86_64 */
- if (kIOHibernateModeEncrypt & gIOHibernateMode)
- {
- data = OSData::withBytes(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
- sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
- if (sym && data)
- gIOOptionsEntry->setProperty(sym, data);
- if (sym)
- sym->release();
- if (data)
- data->release();
- if (false && gIOHibernateBootSignature[0])
- {
- data = OSData::withCapacity(16);
- sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
- if (sym && data)
- {
- char c;
- uint8_t value = 0;
- for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++)
- {
- if (c >= 'a')
- c -= 'a' - 10;
- else if (c >= 'A')
- c -= 'A' - 10;
- else if (c >= '0')
- c -= '0';
- else
- continue;
- value = (value << 4) | c;
- if (i & 1)
- data->appendBytes(&value, sizeof(value));
- }
- gIOOptionsEntry->setProperty(sym, data);
- }
- if (sym)
- sym->release();
- if (data)
- data->release();
- }
- }
- if (!vars->haveFastBoot)
- {
- // set boot volume to zero
- IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
- if (platform && (kIOReturnSuccess == platform->readXPRAM(kXPRamAudioVolume,
- &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume))))
- {
- uint8_t newVolume;
- newVolume = vars->saveBootAudioVolume & 0xf8;
- platform->writeXPRAM(kXPRamAudioVolume,
- &newVolume, sizeof(newVolume));
- }
- }
-#endif /* !i386 && !x86_64 */