X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/ff6e181ae92fc6f1e89841290f461d1f2f9badd9..5d5c5d0d5b79ade9a973d55186ffda2638ba2b6e:/iokit/Kernel/IOHibernateIO.cpp?ds=sidebyside diff --git a/iokit/Kernel/IOHibernateIO.cpp b/iokit/Kernel/IOHibernateIO.cpp index 09c22816d..87f1296e0 100644 --- a/iokit/Kernel/IOHibernateIO.cpp +++ b/iokit/Kernel/IOHibernateIO.cpp @@ -1,24 +1,31 @@ /* * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ * - * 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. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this + * 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. + * + * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * + * 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, 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_LICENSE_OSREFERENCE_HEADER_END@ */ @@ -152,9 +159,7 @@ to restrict I/O ops. #include #include #include // (FWRITE, ...) -extern "C" { #include -} #include #include @@ -195,6 +200,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; @@ -338,21 +346,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; + uint32_t page = *pPage; + uint32_t count; + hibernate_bitmap_t * bitmap; - idx = (uint32_t) *iterator; - - 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); } @@ -622,7 +636,15 @@ IOPolledFileOpen( const char * filename, IOBufferMemoryDescriptor * ioBuffer, do { IOPolledInterface * poller; - if ((poller = OSDynamicCast(IOPolledInterface, next->getProperty(kIOPolledInterfaceSupportKey)))) + OSObject * obj; + + obj = next->getProperty(kIOPolledInterfaceSupportKey); + if (kOSBooleanFalse == obj) + { + vars->pollers->flushCollection(); + break; + } + else if ((poller = OSDynamicCast(IOPolledInterface, obj))) vars->pollers->setObject(poller); if ((num = OSDynamicCast(OSNumber, next->getProperty(kIOMediaPreferredBlockSizeKey)))) vars->blockSize = num->unsigned32BitValue(); @@ -648,21 +670,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"); + + sprintf(str2, "%qx", vars->extentMap[0]); + + 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 + { + sprintf(str2, ",%qx", vars->extentMap[0]); + // (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); @@ -982,8 +1025,10 @@ IOHibernateSystemSleep(void) 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) { @@ -1049,8 +1094,6 @@ IOHibernateSystemSleep(void) if (gIOOptionsEntry) { const OSSymbol * sym; - size_t len; - char valueString[16]; sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey); if (sym) @@ -1060,6 +1103,10 @@ IOHibernateSystemSleep(void) } data->release(); +#ifdef __ppc__ + size_t len; + char valueString[16]; + vars->saveBootDevice = gIOOptionsEntry->copyProperty(kIOSelectedBootDeviceKey); if (gIOChosenEntry) { @@ -1075,7 +1122,6 @@ IOHibernateSystemSleep(void) if (str2) str2->release(); } - data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMemorySignatureKey)); if (data) { @@ -1095,7 +1141,57 @@ 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); + 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)); @@ -1113,7 +1209,7 @@ IOHibernateSystemSleep(void) if (sym && data) { char c; - uint8_t value; + uint8_t value = 0; for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++) { if (c >= 'a') @@ -1136,7 +1232,6 @@ IOHibernateSystemSleep(void) data->release(); } } - if (!vars->haveFastBoot) { // set boot volume to zero @@ -1150,6 +1245,7 @@ IOHibernateSystemSleep(void) &newVolume, sizeof(newVolume)); } } +#endif /* !__i386__ */ } // -- @@ -1222,6 +1318,7 @@ IOHibernateSystemWake(void) // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched +#ifdef __ppc__ OSData * data = OSData::withCapacity(4); if (gIOOptionsEntry && data) { @@ -1275,6 +1372,11 @@ 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); +#endif if (vars->srcBuffer) vars->srcBuffer->release(); @@ -1295,6 +1397,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; } @@ -1347,6 +1456,8 @@ hibernate_setup_for_wake(void) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1] + extern "C" boolean_t hibernate_write_image(void) { @@ -1354,6 +1465,8 @@ hibernate_write_image(void) IOHibernateVars * vars = &gIOHibernateVars; IOPolledFileExtent * fileExtents; + C_ASSERT(sizeof(IOHibernateImageHeader) == 512); + uint32_t pageCount, pagesDone; IOReturn err; vm_offset_t ppnum; @@ -1586,21 +1699,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)); @@ -1614,15 +1721,15 @@ hibernate_write_image(void) src = (uint8_t *) vars->srcBuffer->getBytesNoCopy(); - void * iter = 0; - pagesDone = 0; + ppnum = 0; + pagesDone = 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; @@ -1720,7 +1827,7 @@ hibernate_write_image(void) iterDone = false; pageType = 1; - iter = 0; + ppnum = 0; image1Size = vars->fileVars->position; if (cryptvars) { @@ -1891,10 +1998,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; @@ -1916,7 +2019,14 @@ hibernate_machine_init(void) 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); @@ -1925,7 +2035,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);