X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6601e61aa18bf4f09af135ff61fc7f4771d23b06..935ed37a5c468c8a1c07408573c08b8b7ef80e8b:/iokit/Kernel/IOHibernateIO.cpp?ds=inline diff --git a/iokit/Kernel/IOHibernateIO.cpp b/iokit/Kernel/IOHibernateIO.cpp index 85de4c5eb..ae66cb9b8 100644 --- a/iokit/Kernel/IOHibernateIO.cpp +++ b/iokit/Kernel/IOHibernateIO.cpp @@ -1,23 +1,29 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -192,6 +198,9 @@ uint32_t gIOHibernateFreeTime = 0*1000; // max time to spend freeing pages (m static IODTNVRAM * gIOOptionsEntry; static IORegistryEntry * gIOChosenEntry; +#ifdef __i386__ +static const OSSymbol * gIOCreateEFIDevicePathSymbol; +#endif static IOPolledFileIOVars gFileVars; static IOHibernateVars gIOHibernateVars; @@ -335,21 +344,27 @@ hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_ } static vm_offset_t -hibernate_page_list_iterate(hibernate_page_list_t * list, - void ** iterator, vm_offset_t * ppnum) +hibernate_page_list_iterate(hibernate_page_list_t * list, vm_offset_t * pPage) { - uint32_t count, idx; - - idx = (uint32_t) *iterator; + uint32_t page = *pPage; + uint32_t count; + hibernate_bitmap_t * bitmap; - if (!idx) - idx = hibernate_page_list_count(list, TRUE, idx); + while ((bitmap = hibernate_page_bitmap_pin(list, &page))) + { + count = hibernate_page_bitmap_count(bitmap, TRUE, page); + if (!count) + break; + page += count; + if (page <= bitmap->last_page) + break; + } - *ppnum = idx; - count = hibernate_page_list_count(list, FALSE, idx); - idx += count; - idx += hibernate_page_list_count(list, TRUE, idx); - *iterator = (void *) idx; + *pPage = page; + if (bitmap) + count = hibernate_page_bitmap_count(bitmap, FALSE, page); + else + count = 0; return (count); } @@ -453,28 +468,39 @@ IOHibernatePollerIO(IOPolledFileIOVars * vars, } static IOReturn -IOHibernatePollerIODone(IOPolledFileIOVars * vars) +IOHibernatePollerIODone(IOPolledFileIOVars * vars, bool abortable) { - IOReturn err = kIOReturnError; - int32_t idx; + IOReturn err = kIOReturnSuccess; + int32_t idx = 0; IOPolledInterface * poller; while (-1 == vars->ioStatus) { - for (idx = 0; - (poller = (IOPolledInterface *) vars->pollers->getObject(idx)); + for (idx = 0; + (poller = (IOPolledInterface *) vars->pollers->getObject(idx)); idx++) { - err = poller->checkForWork(); - if (err) - HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err); + IOReturn newErr; + newErr = poller->checkForWork(); + if ((newErr == kIOReturnAborted) && !abortable) + newErr = kIOReturnSuccess; + if (kIOReturnSuccess == err) + err = newErr; } } - if (kIOReturnSuccess != vars->ioStatus) - HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars->ioStatus); + if (err) + { + HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err); + } + else + { + err = vars->ioStatus; + if (kIOReturnSuccess != err) + HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err); + } - return (vars->ioStatus); + return (err); } IOReturn @@ -593,7 +619,9 @@ IOPolledFileOpen( const char * filename, IOBufferMemoryDescriptor * ioBuffer, part->retain(); iter->release(); } - + if (!part) + break; + int minor, major; IORegistryEntry * next; IORegistryEntry * child; @@ -653,21 +681,42 @@ IOPolledFileOpen( const char * filename, IOBufferMemoryDescriptor * ioBuffer, *fileExtents = extentsData; // make imagePath - char str1[256]; - char str2[24]; - int len = sizeof(str1); - if ((extentsData->getLength() >= sizeof(IOPolledFileExtent)) - && part->getPath(str1, &len, gIODTPlane)) + if ((extentsData->getLength() >= sizeof(IOPolledFileExtent))) { - // (strip the plane name) - char * tail = strchr(str1, ':'); - if (!tail) - tail = str1 - 1; - data = OSData::withBytes(tail + 1, strlen(tail + 1)); - sprintf(str2, ",%qx", vars->extentMap[0]); - data->appendBytes(str2, strlen(str2)); + char str2[24]; + +#if __i386__ + if (!gIOCreateEFIDevicePathSymbol) + gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath"); + + snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start); + + err = IOService::getPlatform()->callPlatformFunction( + gIOCreateEFIDevicePathSymbol, false, + (void *) part, (void *) str2, (void *) true, + (void *) &data); +#else + char str1[256]; + int len = sizeof(str1); + + if (!part->getPath(str1, &len, gIODTPlane)) + err = kIOReturnNotFound; + else + { + snprintf(str2, sizeof(str2), ",%qx", vars->extentMap[0].start); + // (strip the plane name) + char * tail = strchr(str1, ':'); + if (!tail) + tail = str1 - 1; + data = OSData::withBytes(tail + 1, strlen(tail + 1)); + data->appendBytes(str2, strlen(str2)); + } +#endif + if (kIOReturnSuccess == err) *imagePath = data; + else + HIBLOG("error 0x%x getting path\n", err); } } while (false); @@ -774,6 +823,7 @@ IOPolledFileWrite(IOPolledFileIOVars * vars, - vars->extentPosition + vars->currentExtent->start); uint32_t length = (vars->bufferOffset); +#if CRYPTO if (cryptvars && vars->encryptStart && (vars->position > vars->encryptStart)) { uint32_t encryptLen, encryptStart; @@ -793,10 +843,11 @@ IOPolledFileWrite(IOPolledFileIOVars * vars, &cryptvars->aes_iv[0], AES_BLOCK_SIZE); } +#endif /* CRYPTO */ if (vars->io) { - err = IOHibernatePollerIODone(vars); + err = IOHibernatePollerIODone(vars, true); if (kIOReturnSuccess != err) break; } @@ -866,7 +917,7 @@ IOPolledFileRead(IOPolledFileIOVars * vars, { if (vars->io) { - err = IOHibernatePollerIODone(vars); + err = IOHibernatePollerIODone(vars, false); if (kIOReturnSuccess != err) break; } @@ -891,14 +942,15 @@ if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", } } - if (vars->extentRemaining <= vars->bufferSize) - vars->lastRead = vars->extentRemaining; - else - vars->lastRead = vars->bufferSize; - + uint64_t length; + uint64_t lastReadLength = vars->lastRead; uint64_t offset = (vars->position - vars->extentPosition + vars->currentExtent->start); - uint64_t length = (vars->lastRead); + if (vars->extentRemaining <= vars->bufferSize) + length = vars->extentRemaining; + else + length = vars->bufferSize; + vars->lastRead = length; //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length); @@ -910,20 +962,22 @@ if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize; vars->bufferOffset = 0; +#if CRYPTO if (cryptvars) { uint8_t thisVector[AES_BLOCK_SIZE]; // save initial vector for following decrypts bcopy(&cryptvars->aes_iv[0], &thisVector[0], AES_BLOCK_SIZE); - bcopy(vars->buffer + vars->bufferHalf + vars->lastRead - AES_BLOCK_SIZE, + bcopy(vars->buffer + vars->bufferHalf + lastReadLength - AES_BLOCK_SIZE, &cryptvars->aes_iv[0], AES_BLOCK_SIZE); // decrypt the buffer aes_decrypt_cbc(vars->buffer + vars->bufferHalf, &thisVector[0], - vars->lastRead / AES_BLOCK_SIZE, + lastReadLength / AES_BLOCK_SIZE, vars->buffer + vars->bufferHalf, &cryptvars->ctx.decrypt); } +#endif CRYPTO } } while (size); @@ -941,6 +995,7 @@ IOHibernateSystemSleep(void) OSObject * obj; OSString * str; OSNumber * num; + OSDictionary *sleepOverrideOptions; IOHibernateVars * vars = &gIOHibernateVars; @@ -950,23 +1005,53 @@ IOHibernateSystemSleep(void) gIOHibernateState = kIOHibernateStateInactive; - if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey))) + /* The invocation of IOPMSleepSystemWithOptions() may override + * existing hibernation settings. + */ + sleepOverrideOptions = (OSDictionary *)OSDynamicCast( OSDictionary, + IOService::getPMRootDomain()->copyProperty(kRootDomainSleepOptionsKey)); + + + /* Hibernate mode overriden by sleep otions ? */ + obj = NULL; + + if (sleepOverrideOptions) { + obj = sleepOverrideOptions->getObject(kIOHibernateModeKey); + if (obj) obj->retain(); + } + + if(!obj) { + obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey); + } + + if (obj && (num = OSDynamicCast(OSNumber, obj)) ) { - if ((num = OSDynamicCast(OSNumber, obj))) gIOHibernateMode = num->unsigned32BitValue(); if (kIOHibernateModeSleep & gIOHibernateMode) // default to discard clean for safe sleep gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive | kIOHibernateModeDiscardCleanActive); + } - obj->release(); + if (obj) obj->release(); + + /* Hibernate free rotio overriden by sleep options ? */ + obj = NULL; + + if (sleepOverrideOptions) { + obj = sleepOverrideOptions->getObject(kIOHibernateFreeRatioKey); + if (obj) obj->retain(); + } + + if(!obj) { + obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey); } - if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey))) + if (obj && (num = OSDynamicCast(OSNumber, obj))) { - if ((num = OSDynamicCast(OSNumber, obj))) gIOHibernateFreeRatio = num->unsigned32BitValue(); - obj->release(); } + if (obj) obj->release(); + if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey))) { if ((num = OSDynamicCast(OSNumber, obj))) @@ -976,19 +1061,26 @@ IOHibernateSystemSleep(void) if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey))) { if ((str = OSDynamicCast(OSString, obj))) - strcpy(gIOHibernateFilename, str->getCStringNoCopy()); + strlcpy(gIOHibernateFilename, str->getCStringNoCopy(), + sizeof(gIOHibernateFilename)); obj->release(); } + if (sleepOverrideOptions) + sleepOverrideOptions->release(); + if (!gIOHibernateMode || !gIOHibernateFilename[0]) return (kIOReturnUnsupported); HIBLOG("hibernate image path: %s\n", gIOHibernateFilename); + do { - vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(0, 4 * page_size, page_size); - vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize, page_size); + vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn, + 4 * page_size, page_size); + vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn, + 2 * kDefaultIOSize, page_size); if (!vars->srcBuffer || !vars->ioBuffer) { @@ -1054,8 +1146,6 @@ IOHibernateSystemSleep(void) if (gIOOptionsEntry) { const OSSymbol * sym; - size_t len; - char valueString[16]; sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey); if (sym) @@ -1065,6 +1155,10 @@ IOHibernateSystemSleep(void) } data->release(); +#ifdef __ppc__ + size_t len; + char valueString[16]; + vars->saveBootDevice = gIOOptionsEntry->copyProperty(kIOSelectedBootDeviceKey); if (gIOChosenEntry) { @@ -1080,7 +1174,6 @@ IOHibernateSystemSleep(void) if (str2) str2->release(); } - data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMemorySignatureKey)); if (data) { @@ -1100,7 +1193,72 @@ IOHibernateSystemSleep(void) if (data) gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy()); } - +#endif /* __ppc__ */ +#ifdef __i386__ + 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) + { + IOService::getPMRootDomain()->setProperty(kIOHibernateRTCVariablesKey, 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()); + } +#else /* !__i386__ */ if (kIOHibernateModeEncrypt & gIOHibernateMode) { data = OSData::withBytes(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey)); @@ -1111,14 +1269,14 @@ IOHibernateSystemSleep(void) sym->release(); if (data) data->release(); - if (gIOHibernateBootSignature[0]) + if (false && gIOHibernateBootSignature[0]) { data = OSData::withCapacity(16); sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey); if (sym && data) { char c; - uint8_t value; + uint8_t value = 0; for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++) { if (c >= 'a') @@ -1141,7 +1299,6 @@ IOHibernateSystemSleep(void) data->release(); } } - if (!vars->haveFastBoot) { // set boot volume to zero @@ -1155,6 +1312,7 @@ IOHibernateSystemSleep(void) &newVolume, sizeof(newVolume)); } } +#endif /* !__i386__ */ } // -- @@ -1168,27 +1326,173 @@ IOHibernateSystemSleep(void) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +DECLARE_IOHIBERNATEPROGRESSALPHA + +static void +ProgressInit(hibernate_graphics_t * display, uint8_t * screen, uint8_t * saveunder, uint32_t savelen) +{ + uint32_t rowBytes, pixelShift; + uint32_t x, y; + int32_t blob; + uint32_t alpha, in, color, result; + uint8_t * out; + uint32_t saveindex[kIOHibernateProgressCount] = { 0 }; + + rowBytes = display->rowBytes; + pixelShift = display->depth >> 4; + if (pixelShift < 1) return; + + screen += ((display->width + - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1)) + + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes; + + for (y = 0; y < kIOHibernateProgressHeight; y++) + { + out = screen + y * rowBytes; + for (blob = 0; blob < kIOHibernateProgressCount; blob++) + { + color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray; + for (x = 0; x < kIOHibernateProgressWidth; x++) + { + alpha = gIOHibernateProgressAlpha[y][x]; + result = color; + if (alpha) + { + if (0xff != alpha) + { + if (1 == pixelShift) + { + in = *((uint16_t *)out) & 0x1f; // 16 + in = (in << 3) | (in >> 2); + } + else + in = *((uint32_t *)out) & 0xff; // 32 + saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in; + result = ((255 - alpha) * in + alpha * result + 0xff) >> 8; + } + if (1 == pixelShift) + { + result >>= 3; + *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16 + } + else + *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32 + } + out += (1 << pixelShift); + } + out += (kIOHibernateProgressSpacing << pixelShift); + } + } +} + + +static void +ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select) +{ + uint32_t rowBytes, pixelShift; + uint32_t x, y; + int32_t blob, lastBlob; + uint32_t alpha, in, color, result; + uint8_t * out; + uint32_t saveindex[kIOHibernateProgressCount] = { 0 }; + + pixelShift = display->depth >> 4; + if (pixelShift < 1) + return; + + rowBytes = display->rowBytes; + + screen += ((display->width + - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1)) + + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes; + + lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1); + + screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift; + + for (y = 0; y < kIOHibernateProgressHeight; y++) + { + out = screen + y * rowBytes; + for (blob = firstBlob; blob <= lastBlob; blob++) + { + color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray; + for (x = 0; x < kIOHibernateProgressWidth; x++) + { + alpha = gIOHibernateProgressAlpha[y][x]; + result = color; + if (alpha) + { + if (0xff != alpha) + { + in = display->progressSaveUnder[blob][saveindex[blob]++]; + result = ((255 - alpha) * in + alpha * result + 0xff) / 255; + } + if (1 == pixelShift) + { + result >>= 3; + *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16 + } + else + *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32 + } + out += (1 << pixelShift); + } + out += (kIOHibernateProgressSpacing << pixelShift); + } + } +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + IOReturn IOHibernateSystemHasSlept(void) { IOHibernateVars * vars = &gIOHibernateVars; + OSObject * obj; + OSData * data; - if ((vars->previewData = OSDynamicCast(OSData, - IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey)))) + obj = IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey); + vars->previewBuffer = OSDynamicCast(IOMemoryDescriptor, obj); + if (obj && !vars->previewBuffer) + obj->release(); + + vars->consoleMapping = NULL; + if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare())) { - vars->previewBuffer = IOMemoryDescriptor::withAddress( - (void *) vars->previewData->getBytesNoCopy(), - vars->previewData->getLength(), - kIODirectionInOut); + vars->previewBuffer->release(); + vars->previewBuffer = 0; + } - if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare())) - { - vars->previewBuffer->release(); - vars->previewBuffer = 0; - } - if (!vars->previewBuffer) - vars->previewData = 0; + if (vars->previewBuffer && (data = OSDynamicCast(OSData, + IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey)))) + { + UInt32 flags = *((UInt32 *)data->getBytesNoCopy()); + HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", flags); + + IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey); + + if (kIOHibernatePreviewUpdates & flags) + { + PE_Video consoleInfo; + hibernate_graphics_t * graphicsInfo = gIOHibernateGraphicsInfo; + + IOService::getPlatform()->getConsoleInfo(&consoleInfo); + + graphicsInfo->width = consoleInfo.v_width; + graphicsInfo->height = consoleInfo.v_height; + graphicsInfo->rowBytes = consoleInfo.v_rowBytes; + graphicsInfo->depth = consoleInfo.v_depth; + vars->consoleMapping = (uint8_t *) consoleInfo.v_baseAddr; + + HIBPRINT("video %p %d %d %d\n", + vars->consoleMapping, gIOHibernateGraphicsInfo->depth, + gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height); + if (vars->consoleMapping) + ProgressInit(graphicsInfo, vars->consoleMapping, + &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder)); + } } + if (gIOOptionsEntry) gIOOptionsEntry->sync(); @@ -1227,6 +1531,7 @@ IOHibernateSystemWake(void) // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched +#ifdef __ppc__ OSData * data = OSData::withCapacity(4); if (gIOOptionsEntry && data) { @@ -1280,6 +1585,27 @@ IOHibernateSystemWake(void) // just sync the variables in case a later panic syncs nvram (it won't sync variables) gIOOptionsEntry->syncOFVariables(); } +#endif + +#ifdef __i386__ + IOService::getPMRootDomain()->removeProperty(kIOHibernateRTCVariablesKey); + + /* + * Hibernate variable is written to NVRAM on platforms in which RtcRam + * is not backed by coin cell. Remove Hibernate data from NVRAM. + */ + if (gIOOptionsEntry) { + const OSSymbol * sym = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey); + + if (sym) { + if (gIOOptionsEntry->getProperty(sym)) { + gIOOptionsEntry->removeProperty(sym); + gIOOptionsEntry->sync(); + } + sym->release(); + } + } +#endif if (vars->srcBuffer) vars->srcBuffer->release(); @@ -1300,6 +1626,13 @@ IOHibernateSystemPostWake(void) { if (gIOHibernateFileRef) { + // invalidate the image file + gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature; + int err = kern_write_file(gIOHibernateFileRef, 0, + (caddr_t) gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader)); + if (KERN_SUCCESS != err) + HIBLOG("kern_write_file(%d)\n", err); + kern_close_file_for_direct_io(gIOHibernateFileRef); gIOHibernateFileRef = 0; } @@ -1308,6 +1641,16 @@ IOHibernateSystemPostWake(void) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +SYSCTL_STRING(_kern, OID_AUTO, hibernatefile, + CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN, + gIOHibernateFilename, sizeof(gIOHibernateFilename), ""); +SYSCTL_STRING(_kern, OID_AUTO, bootsignature, + CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN, + gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), ""); +SYSCTL_UINT(_kern, OID_AUTO, hibernatemode, + CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN, + &gIOHibernateMode, 0, ""); + void IOHibernateSystemInit(IOPMrootDomain * rootDomain) { @@ -1318,27 +1661,17 @@ IOHibernateSystemInit(IOPMrootDomain * rootDomain) data->release(); } - if (PE_parse_boot_arg("hfile", gIOHibernateFilename)) + if (PE_parse_boot_argn("hfile", gIOHibernateFilename, sizeof(gIOHibernateFilename))) gIOHibernateMode = kIOHibernateModeOn; else gIOHibernateFilename[0] = 0; - static SYSCTL_STRING(_kern, OID_AUTO, hibernatefile, - CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN, - gIOHibernateFilename, sizeof(gIOHibernateFilename), ""); sysctl_register_oid(&sysctl__kern_hibernatefile); - - static SYSCTL_STRING(_kern, OID_AUTO, bootsignature, - CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN, - gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), ""); sysctl_register_oid(&sysctl__kern_bootsignature); - - static SYSCTL_UINT(_kern, OID_AUTO, hibernatemode, - CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN, - &gIOHibernateMode, 0, ""); sysctl_register_oid(&sysctl__kern_hibernatemode); } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static void @@ -1352,13 +1685,17 @@ hibernate_setup_for_wake(void) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -extern "C" boolean_t +#define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1] + +extern "C" uint32_t hibernate_write_image(void) { IOHibernateImageHeader * header = gIOHibernateCurrentHeader; IOHibernateVars * vars = &gIOHibernateVars; IOPolledFileExtent * fileExtents; + C_ASSERT(sizeof(IOHibernateImageHeader) == 512); + uint32_t pageCount, pagesDone; IOReturn err; vm_offset_t ppnum; @@ -1380,6 +1717,7 @@ hibernate_write_image(void) uint64_t nsec; uint32_t lastProgressStamp = 0; uint32_t progressStamp; + uint32_t blob, lastBlob = (uint32_t) -1L; hibernate_cryptvars_t _cryptvars; hibernate_cryptvars_t * cryptvars = 0; @@ -1389,6 +1727,7 @@ hibernate_write_image(void) restore1Sum = sum1 = sum2 = 0; +#if CRYPTO // encryption data. "iv" is the "initial vector". if (kIOHibernateModeEncrypt & gIOHibernateMode) { @@ -1416,6 +1755,7 @@ hibernate_write_image(void) bzero(&vars->cryptKey[0], sizeof(vars->cryptKey)); bzero(gIOHibernateCryptWakeVars, sizeof(hibernate_cryptwakevars_t)); } +#endif /* CRYPTO */ hibernate_setup_for_wake(); @@ -1524,7 +1864,7 @@ hibernate_write_image(void) addr64_t phys64; IOByteCount segLen; - if (vars->previewData) + if (vars->previewBuffer) { ppnum = 0; count = 0; @@ -1545,8 +1885,8 @@ hibernate_write_image(void) if (kIOReturnSuccess != err) break; - src = (uint8_t *) vars->previewData->getBytesNoCopy(); - count = vars->previewData->getLength(); + src = (uint8_t *) vars->previewBuffer->getSourceSegment(0, NULL); + count = vars->previewBuffer->getLength(); header->previewPageListSize = ppnum; header->previewSize = count + ppnum; @@ -1591,21 +1931,15 @@ hibernate_write_image(void) // mark more areas for no save, but these are not available // for trashing during restore + + hibernate_page_list_set_volatile(vars->page_list, vars->page_list_wired, &pageCount); -#if !__i386__ page = atop_32(sectHIBB); count = atop_32(round_page(sectHIBB + sectSizeHIB)) - page; -#else - // XXX - page = atop_32(sectHIBB & 0x3FFFFFFF); - count = atop_32(round_page((sectHIBB + sectSizeHIB) & 0x3FFFFFFF)) - page; -#endif hibernate_set_page_state(vars->page_list, vars->page_list_wired, page, count, kIOHibernatePageStateFree); pageCount -= count; - - if (vars->previewBuffer) for (count = 0; (phys64 = vars->previewBuffer->getPhysicalSegment64(count, &segLen)); @@ -1619,15 +1953,16 @@ hibernate_write_image(void) src = (uint8_t *) vars->srcBuffer->getBytesNoCopy(); - void * iter = 0; - pagesDone = 0; + ppnum = 0; + pagesDone = 0; + lastBlob = 0; HIBLOG("writing %d pages\n", pageCount); do { count = hibernate_page_list_iterate(pageType ? vars->page_list : vars->page_list_wired, - &iter, &ppnum); + &ppnum); // kprintf("[%d](%x : %x)\n", pageType, ppnum, count); iterDone = !count; @@ -1701,7 +2036,16 @@ hibernate_write_image(void) uncompressedSize += page_size; ppnum++; pagesDone++; - + + if (vars->consoleMapping && (0 == (1023 & pagesDone))) + { + blob = ((pagesDone * kIOHibernateProgressCount) / pageCount); + if (blob != lastBlob) + { + ProgressUpdate(gIOHibernateGraphicsInfo, vars->consoleMapping, lastBlob, blob); + lastBlob = blob; + } + } if (0 == (8191 & pagesDone)) { clock_get_uptime(&endTime); @@ -1725,7 +2069,7 @@ hibernate_write_image(void) iterDone = false; pageType = 1; - iter = 0; + ppnum = 0; image1Size = vars->fileVars->position; if (cryptvars) { @@ -1775,7 +2119,7 @@ hibernate_write_image(void) err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars); if (kIOReturnSuccess != err) break; - err = IOHibernatePollerIODone(vars->fileVars); + err = IOHibernatePollerIODone(vars->fileVars, true); if (kIOReturnSuccess != err) break; } @@ -1804,74 +2148,39 @@ hibernate_write_image(void) if (pollerOpen) IOHibernatePollerClose(vars->fileVars, kIOPolledBeforeSleepState); + if (vars->consoleMapping) + ProgressUpdate(gIOHibernateGraphicsInfo, + vars->consoleMapping, 0, kIOHibernateProgressCount); + HIBLOG("hibernate_write_image done(%x)\n", err); // should we come back via regular wake, set the state in memory. gIOHibernateState = kIOHibernateStateInactive; - if ((kIOReturnSuccess == err) && !(kIOHibernateModeSleep & gIOHibernateMode)) - return (true /* power down */ ); + if (kIOReturnSuccess == err) + { + if (kIOHibernateModeSleep & gIOHibernateMode) + { + return (kIOHibernatePostWriteSleep); + } + else if(kIOHibernateModeRestart & gIOHibernateMode) + { + return (kIOHibernatePostWriteRestart); + } + else + { + /* by default, power down */ + return (kIOHibernatePostWriteHalt); + } + } + else if (kIOReturnAborted == err) + { + return (kIOHibernatePostWriteWake); + } else - return (false /* sleep */ ); -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -DECLARE_IOHIBERNATEPROGRESSALPHA - -static void -ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select) -{ - uint32_t rowBytes, pixelShift; - uint32_t x, y; - int32_t blob, lastBlob; - uint32_t alpha, in, color, result; - uint8_t * out; - uint32_t saveindex[kIOHibernateProgressCount] = { 0 }; - - pixelShift = display->depth >> 4; - if (pixelShift < 1) - return; - - rowBytes = display->rowBytes; - - screen += ((display->width - - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1)) - + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes; - - lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1); - - screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift; - - for (y = 0; y < kIOHibernateProgressHeight; y++) { - out = screen + y * rowBytes; - for (blob = firstBlob; blob <= lastBlob; blob++) - { - color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray; - for (x = 0; x < kIOHibernateProgressWidth; x++) - { - alpha = gIOHibernateProgressAlpha[y][x]; - result = color; - if (alpha) - { - if (0xff != alpha) - { - in = display->progressSaveUnder[blob][saveindex[blob]++]; - result = ((255 - alpha) * in + alpha * result + 0xff) / 255; - } - if (1 == pixelShift) - { - result >>= 3; - *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16 - } - else - *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32 - } - out += (1 << pixelShift); - } - out += (kIOHibernateProgressSpacing << pixelShift); - } + /* on error, sleep */ + return (kIOHibernatePostWriteSleep); } } @@ -1896,10 +2205,6 @@ hibernate_machine_init(void) if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents) return; - if ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode) - hibernate_page_list_discard(vars->page_list); - - sum = gIOHibernateCurrentHeader->actualImage1Sum; pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages; @@ -1917,11 +2222,18 @@ hibernate_machine_init(void) gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1], gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]); - HIBPRINT("video %lx %ld %ld %ld\n", + HIBPRINT("video %x %d %d %d\n", gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth, gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height); - if (vars->videoMapping && gIOHibernateGraphicsInfo->physicalAddress) + if ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode) + hibernate_page_list_discard(vars->page_list); + + boot_args *args = (boot_args *) PE_state.bootArgs; + + if (vars->videoMapping + && gIOHibernateGraphicsInfo->physicalAddress + && (args->Video.v_baseAddr == gIOHibernateGraphicsInfo->physicalAddress)) { vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height * gIOHibernateGraphicsInfo->rowBytes); @@ -1930,7 +2242,19 @@ hibernate_machine_init(void) vars->videoMapSize, kIOMapInhibitCache ); } - uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();; + uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy(); + + if (gIOHibernateWakeMapSize) + { + err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(gIOHibernateWakeMap), + gIOHibernateWakeMapSize); + if (kIOReturnSuccess == err) + hibernate_newruntime_map(src, gIOHibernateWakeMapSize, + gIOHibernateCurrentHeader->systemTableOffset); + gIOHibernateWakeMap = 0; + gIOHibernateWakeMapSize = 0; + } + uint32_t decoOffset; clock_get_uptime(&allTime); @@ -1947,7 +2271,7 @@ hibernate_machine_init(void) IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size); - if (vars->videoMapping) + if (vars->videoMapSize) { lastBlob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount) / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition); @@ -1986,7 +2310,9 @@ hibernate_machine_init(void) uint32_t tag; vm_offset_t ppnum, compressedSize; - IOPolledFileRead(vars->fileVars, src, 8, cryptvars); + err = IOPolledFileRead(vars->fileVars, src, 8, cryptvars); + if (kIOReturnSuccess != err) + break; ppnum = header[0]; count = header[1]; @@ -1998,9 +2324,17 @@ hibernate_machine_init(void) for (page = 0; page < count; page++) { - IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars); + err = IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars); + if (kIOReturnSuccess != err) + break; compressedSize = kIOHibernateTagLength & tag; + if (kIOHibernateTagSignature != (tag & ~kIOHibernateTagLength)) + { + err = kIOReturnIPCError; + break; + } + if (!compressedSize) { ppnum++; @@ -2008,9 +2342,11 @@ hibernate_machine_init(void) continue; } - IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars); - - if (compressedSize != page_size) + err = IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars); + if (kIOReturnSuccess != err) + break; + + if (compressedSize < page_size) { decoOffset = page_size; WKdm_decompress((WK_word*) src, (WK_word*) (src + decoOffset), PAGE_SIZE_IN_WORDS); @@ -2022,12 +2358,15 @@ hibernate_machine_init(void) err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size); if (err) + { HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum, err); + break; + } ppnum++; pagesDone++; - if (vars->videoMapping && (0 == (255 & pagesDone))) + if (vars->videoMapSize && (0 == (1023 & pagesDone))) { blob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount) / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition); @@ -2055,14 +2394,17 @@ hibernate_machine_init(void) } while (true); + if (kIOReturnSuccess != err) + panic("Hibernate restore error %x", err); + gIOHibernateCurrentHeader->actualImage2Sum = sum; if (vars->fileVars->io) - (void) IOHibernatePollerIODone(vars->fileVars); + (void) IOHibernatePollerIODone(vars->fileVars, false); err = IOHibernatePollerClose(vars->fileVars, kIOPolledAfterSleepState); - if (vars->videoMapping) + if (vars->videoMapSize) ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);