2 * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
35 (devices awake, normal execution context)
36 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
37 grabs its extents and searches for a polling driver willing to work with that IOMedia.
38 The BSD code makes an ioctl to the storage driver to get the partition base offset to
39 the disk, and other ioctls to get the transfer constraints
40 If successful, the file is written to make sure its initially not bootable (in case of
41 later failure) and nvram set to point to the first block of the file. (Has to be done
42 here so blocking is possible in nvram support).
43 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
44 page out any pages it wants to (currently zero, but probably some percentage of memory).
45 Its assumed just allocating pages will cause the VM system to naturally select the best
46 pages for eviction. It also copies processor flags needed for the restore path and sets
47 a flag in the boot processor proc info.
48 gIOHibernateState = kIOHibernateStateHibernating.
49 - Regular sleep progresses - some drivers may inspect the root domain property
50 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
51 as usual but leaves motherboard I/O on.
52 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
53 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
54 all ppc RC bits out of the hash table and caches into the mapping structures.
55 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
56 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
57 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
58 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
59 The image header and block list are written. The header includes the second file extent so
60 only the header block is needed to read the file, regardless of filesystem.
61 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
62 (only) is used to decompress the image during wake/boot.
63 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
64 The bitmaps are written to the image.
65 More areas are removed from the bitmaps (after they have been written to the image) - the
66 section "__HIB" pages and interrupt stack.
67 Each wired page is compressed and written and then each non-wired page. Compression and
68 disk writes are in parallel.
69 The image header is written to the start of the file and the polling driver closed.
70 The machine powers down (or sleeps).
74 - BootX sees the boot-image nvram variable containing the device and block number of the image,
75 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
76 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
77 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
78 that is in the kernel's __HIB section.
79 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
80 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
81 only code & data in that section is safe to call since all the other wired pages are still
82 compressed in the image.
83 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
84 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
85 location directly, and copies those that can't to interim free pages. When the image has been
86 completed, the copies are uncompressed, overwriting the wired image pages.
87 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
88 is used to get pages into place for 64bit.
89 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
90 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
91 are removed from the software strutures, and the hash table is reinitialized.
92 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
93 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
94 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
95 for the remaining non wired pages.
96 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
97 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
102 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
103 registry, specifying an object of calls IOPolledInterface.
105 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
106 partition) that the image is going to live, looking for polled interface properties. If it finds
107 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
108 interfaces found are kept in an ordered list.
110 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
111 few different contexts things happen in:
113 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
114 up and running) and after wake - this is safe to allocate memory and do anything. The device
115 ignores sleep requests from that point since its a waste of time if it goes to sleep and
116 immediately wakes back up for the image write.
118 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
119 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
120 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
121 used to flush and set the disk to sleep.
123 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
124 immediately after sleep. These can't block or allocate memory. This is happening after the platform
125 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
128 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
129 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
130 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
131 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
132 that is called for the hardware to check for events, and complete the I/O via the callback.
133 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
137 #include <sys/systm.h>
139 #include <IOKit/IOWorkLoop.h>
140 #include <IOKit/IOCommandGate.h>
141 #include <IOKit/IOTimerEventSource.h>
142 #include <IOKit/IOPlatformExpert.h>
143 #include <IOKit/IOKitDebug.h>
144 #include <IOKit/IOTimeStamp.h>
145 #include <IOKit/pwr_mgt/RootDomain.h>
146 #include <IOKit/pwr_mgt/IOPMPrivate.h>
147 #include <IOKit/IOMessage.h>
148 #include <IOKit/IODeviceTreeSupport.h>
149 #include <IOKit/IOBSD.h>
150 #include "RootDomainUserClient.h"
151 #include <IOKit/pwr_mgt/IOPowerConnection.h>
152 #include "IOPMPowerStateQueue.h"
153 #include <IOKit/IOBufferMemoryDescriptor.h>
154 #include <IOKit/AppleKeyStoreInterface.h>
155 #include <crypto/aes.h>
158 #include <sys/conf.h>
159 #include <sys/stat.h>
160 #include <sys/fcntl.h> // (FWRITE, ...)
161 #include <sys/sysctl.h>
162 #include <sys/kdebug.h>
164 #include <IOKit/IOHibernatePrivate.h>
165 #include <IOKit/IOPolledInterface.h>
166 #include <IOKit/IONVRAM.h>
167 #include "IOHibernateInternal.h"
168 #include <libkern/WKdm.h>
169 #include "IOKitKernelInternal.h"
170 #include <pexpert/device_tree.h>
172 #include <machine/pal_routines.h>
173 #include <machine/pal_hibernate.h>
175 extern "C" addr64_t
kvtophys(vm_offset_t va
);
177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
179 extern unsigned int save_kdebug_enable
;
180 extern uint32_t gIOHibernateState
;
181 uint32_t gIOHibernateMode
;
182 static char gIOHibernateBootSignature
[256+1];
183 static char gIOHibernateFilename
[MAXPATHLEN
+1];
184 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
185 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
187 static IODTNVRAM
* gIOOptionsEntry
;
188 static IORegistryEntry
* gIOChosenEntry
;
189 #if defined(__i386__) || defined(__x86_64__)
190 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
191 static const OSSymbol
* gIOHibernateRTCVariablesKey
;
192 static const OSSymbol
* gIOHibernateBoot0082Key
;
193 static const OSSymbol
* gIOHibernateBootNextKey
;
194 static OSData
* gIOHibernateBoot0082Data
;
195 static OSData
* gIOHibernateBootNextData
;
196 static OSObject
* gIOHibernateBootNextSave
;
199 static IOPolledFileIOVars gFileVars
;
200 static IOHibernateVars gIOHibernateVars
;
201 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
202 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
203 static hibernate_graphics_t _hibernateGraphics
;
204 static hibernate_graphics_t
* gIOHibernateGraphicsInfo
= &_hibernateGraphics
;
206 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
208 enum { kXPRamAudioVolume
= 8 };
209 enum { kDefaultIOSize
= 128 * 1024 };
210 enum { kVideoMapSize
= 32 * 1024 * 1024 };
212 #ifndef kIOMediaPreferredBlockSizeKey
213 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
216 #ifndef kIOBootPathKey
217 #define kIOBootPathKey "bootpath"
219 #ifndef kIOSelectedBootDeviceKey
220 #define kIOSelectedBootDeviceKey "boot-device"
224 enum { kIOHibernateMinPollersNeeded
= 2 };
226 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
228 // copy from phys addr to MD
231 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
232 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
234 addr64_t srcAddr
= bytes
;
235 IOByteCount remaining
;
237 remaining
= length
= min(length
, md
->getLength() - offset
);
238 while (remaining
) { // (process another target segment?)
242 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
246 // Clip segment length to remaining
247 if (dstLen
> remaining
)
251 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
253 copypv(srcAddr
, dstAddr64
, dstLen
,
254 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
263 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
266 // copy from MD to phys addr
269 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
270 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
272 addr64_t dstAddr
= bytes
;
273 IOByteCount remaining
;
275 remaining
= length
= min(length
, md
->getLength() - offset
);
276 while (remaining
) { // (process another target segment?)
280 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
284 // Clip segment length to remaining
285 if (dstLen
> remaining
)
289 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
291 copypv(srcAddr
, dstAddr64
, dstLen
,
292 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
301 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
304 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
307 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
308 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
313 case kIOHibernatePageStateUnwiredSave
:
315 for (; ppnum
< count
; ppnum
++)
317 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
318 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
321 case kIOHibernatePageStateWiredSave
:
323 for (; ppnum
< count
; ppnum
++)
325 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
326 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
329 case kIOHibernatePageStateFree
:
331 for (; ppnum
< count
; ppnum
++)
333 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
334 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
338 panic("hibernate_set_page_state");
343 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
345 uint32_t page
= *pPage
;
347 hibernate_bitmap_t
* bitmap
;
349 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
351 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
355 if (page
<= bitmap
->last_page
)
361 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
368 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
371 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
373 IOReturn err
= kIOReturnError
;
375 IOPolledInterface
* poller
;
377 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
379 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
380 err
= poller
->probe(target
);
383 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
392 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
394 IOReturn err
= kIOReturnError
;
396 IOPolledInterface
* poller
;
398 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
400 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
401 err
= poller
->open(state
, md
);
404 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
413 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
415 IOReturn err
= kIOReturnError
;
417 IOPolledInterface
* poller
;
420 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
423 err
= poller
->close(state
);
425 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
432 IOHibernatePollerIOComplete(void * target
,
435 UInt64 actualByteCount
)
437 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
439 vars
->ioStatus
= status
;
443 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
444 uint32_t operation
, uint32_t bufferOffset
,
445 uint64_t deviceOffset
, uint64_t length
)
448 IOReturn err
= kIOReturnError
;
449 IOPolledInterface
* poller
;
450 IOPolledCompletion completion
;
452 completion
.target
= 0;
453 completion
.action
= &IOHibernatePollerIOComplete
;
454 completion
.parameter
= vars
;
458 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
459 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
461 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
467 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
, bool abortable
)
469 IOReturn err
= kIOReturnSuccess
;
471 IOPolledInterface
* poller
;
473 while (-1 == vars
->ioStatus
)
476 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
480 newErr
= poller
->checkForWork();
481 if ((newErr
== kIOReturnAborted
) && !abortable
)
482 newErr
= kIOReturnSuccess
;
483 if (kIOReturnSuccess
== err
)
488 if ((kIOReturnSuccess
== err
) && abortable
&& hibernate_should_abort())
490 err
= kIOReturnAborted
;
491 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
496 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
500 err
= vars
->ioStatus
;
501 if (kIOReturnSuccess
!= err
)
502 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
509 IOPolledInterface::checkAllForWork(void)
511 IOReturn err
= kIOReturnNotReady
;
513 IOPolledInterface
* poller
;
515 IOHibernateVars
* vars
= &gIOHibernateVars
;
517 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
521 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
524 err
= poller
->checkForWork();
526 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
532 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
534 struct _OpenFileContext
541 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
543 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
544 IOPolledFileExtent extent
;
546 extent
.start
= start
;
547 extent
.length
= length
;
549 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
554 IOCopyMediaForDev(dev_t device
)
556 OSDictionary
* matching
;
559 IOService
* result
= 0;
561 matching
= IOService::serviceMatching("IOMedia");
566 num
= OSNumber::withNumber(major(device
), 32);
569 matching
->setObject(kIOBSDMajorKey
, num
);
571 num
= OSNumber::withNumber(minor(device
), 32);
574 matching
->setObject(kIOBSDMinorKey
, num
);
578 iter
= IOService::getMatchingServices(matching
);
581 result
= (IOService
*) iter
->getNextObject();
593 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
594 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
595 OSData
** imagePath
, uint8_t * volumeCryptKey
)
597 IOReturn err
= kIOReturnError
;
598 IOPolledFileIOVars
* vars
;
599 _OpenFileContext ctx
;
600 OSData
* extentsData
;
602 IOService
* part
= 0;
603 OSString
* keyUUID
= 0;
604 OSString
* keyStoreUUID
= 0;
606 dev_t hibernate_image_dev
;
612 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
613 if (sizeof(IOHibernateImageHeader
) != 512)
617 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
618 vars
->bufferHalf
= 0;
619 vars
->bufferOffset
= 0;
620 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
622 extentsData
= OSData::withCapacity(32);
624 ctx
.extents
= extentsData
;
626 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
627 &file_extent_callback
, &ctx
,
629 &hibernate_image_dev
,
633 0, (caddr_t
) gIOHibernateCurrentHeader
,
634 sizeof(IOHibernateImageHeader
));
637 err
= kIOReturnNoSpace
;
640 gIOHibernateFileRef
= vars
->fileRef
;
642 if (kIOHibernateModeSSDInvert
& gIOHibernateMode
)
643 vars
->flags
^= kIOHibernateOptionSSD
;
645 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename
, ctx
.size
,
646 vars
->block0
, maxiobytes
, kIOHibernateOptionSSD
& vars
->flags
);
647 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
649 err
= kIOReturnNoSpace
;
653 if (maxiobytes
< vars
->bufferSize
)
654 vars
->bufferSize
= maxiobytes
;
656 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
658 part
= IOCopyMediaForDev(block_dev
);
662 err
= part
->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID
, false,
663 (void *) &keyUUID
, (void *) &keyStoreUUID
, NULL
, NULL
);
664 if ((kIOReturnSuccess
== err
) && keyUUID
&& keyStoreUUID
)
666 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
667 uuid_t volumeKeyUUID
;
668 aks_volume_key_t vek
;
669 static IOService
* sKeyStore
;
670 static const OSSymbol
* sAKSGetKey
;
673 sAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
675 sKeyStore
= (IOService
*) IORegistryEntry::fromPath(AKS_SERVICE_PATH
, gIOServicePlane
);
677 err
= uuid_parse(keyStoreUUID
->getCStringNoCopy(), volumeKeyUUID
);
679 err
= kIOReturnNoResources
;
680 if (kIOReturnSuccess
== err
)
681 err
= sKeyStore
->callPlatformFunction(sAKSGetKey
, true, volumeKeyUUID
, &vek
, NULL
, NULL
);
682 if (kIOReturnSuccess
!= err
)
683 IOLog("volume key err 0x%x\n", err
);
686 size_t bytes
= (kIOHibernateAESKeySize
/ 8);
687 if (vek
.key
.keybytecount
< bytes
)
688 bytes
= vek
.key
.keybytecount
;
689 bcopy(&vek
.key
.keybytes
[0], volumeCryptKey
, bytes
);
691 bzero(&vek
, sizeof(vek
));
695 part
= IOCopyMediaForDev(hibernate_image_dev
);
699 IORegistryEntry
* next
;
700 IORegistryEntry
* child
;
703 vars
->pollers
= OSArray::withCapacity(4);
707 vars
->blockSize
= 512;
711 IOPolledInterface
* poller
;
714 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
715 if (kOSBooleanFalse
== obj
)
717 vars
->pollers
->flushCollection();
720 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
721 vars
->pollers
->setObject(poller
);
722 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
723 vars
->blockSize
= num
->unsigned32BitValue();
726 while ((next
= child
->getParentEntry(gIOServicePlane
))
727 && child
->isParent(next
, gIOServicePlane
, true));
729 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
730 major(hibernate_image_dev
), minor(hibernate_image_dev
), (long)vars
->blockSize
, vars
->pollers
->getCount());
731 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
734 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
735 if (kIOReturnSuccess
!= err
)
738 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
739 if (kIOReturnSuccess
!= err
)
743 *fileExtents
= extentsData
;
747 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
749 char str2
[24 + sizeof(uuid_string_t
) + 2];
751 #if defined(__i386__) || defined(__x86_64__)
752 if (!gIOCreateEFIDevicePathSymbol
)
753 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
756 snprintf(str2
, sizeof(str2
), "%qx:%s",
757 vars
->extentMap
[0].start
, keyUUID
->getCStringNoCopy());
759 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
761 err
= IOService::getPlatform()->callPlatformFunction(
762 gIOCreateEFIDevicePathSymbol
, false,
763 (void *) part
, (void *) str2
,
764 (void *) (uintptr_t) true, (void *) &data
);
767 int len
= sizeof(str1
);
769 if (!part
->getPath(str1
, &len
, gIODTPlane
))
770 err
= kIOReturnNotFound
;
773 snprintf(str2
, sizeof(str2
), ",%qx", vars
->extentMap
[0].start
);
774 // (strip the plane name)
775 char * tail
= strchr(str1
, ':');
778 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
779 data
->appendBytes(str2
, strlen(str2
));
782 if (kIOReturnSuccess
== err
)
785 HIBLOG("error 0x%x getting path\n", err
);
790 if (kIOReturnSuccess
!= err
)
792 HIBLOG("error 0x%x opening hibernation file\n", err
);
795 kern_close_file_for_direct_io(vars
->fileRef
, 0, 0, 0, 0, 0);
796 gIOHibernateFileRef
= vars
->fileRef
= NULL
;
807 IOPolledFileClose( IOPolledFileIOVars
* vars
)
811 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
812 vars
->pollers
->release();
815 bzero(vars
, sizeof(IOPolledFileIOVars
));
817 return (kIOReturnSuccess
);
821 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
823 IOPolledFileExtent
* extentMap
;
825 extentMap
= vars
->extentMap
;
827 vars
->position
= position
;
829 while (position
>= extentMap
->length
)
831 position
-= extentMap
->length
;
835 vars
->currentExtent
= extentMap
;
836 vars
->extentRemaining
= extentMap
->length
- position
;
837 vars
->extentPosition
= vars
->position
- position
;
839 if (vars
->bufferSize
<= vars
->extentRemaining
)
840 vars
->bufferLimit
= vars
->bufferSize
;
842 vars
->bufferLimit
= vars
->extentRemaining
;
844 return (kIOReturnSuccess
);
848 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
849 const uint8_t * bytes
, IOByteCount size
,
850 hibernate_cryptvars_t
* cryptvars
)
852 IOReturn err
= kIOReturnSuccess
;
860 // seek to end of block & flush
861 size
= vars
->position
& (vars
->blockSize
- 1);
863 size
= vars
->blockSize
- size
;
865 // use some garbage for the fill
866 bytes
= vars
->buffer
+ vars
->bufferOffset
;
869 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
877 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
881 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
884 vars
->bufferOffset
+= copy
;
885 vars
->position
+= copy
;
887 if (flush
&& vars
->bufferOffset
)
889 uint64_t offset
= (vars
->position
- vars
->bufferOffset
890 - vars
->extentPosition
+ vars
->currentExtent
->start
);
891 uint32_t length
= (vars
->bufferOffset
);
894 if (cryptvars
&& vars
->encryptStart
895 && (vars
->position
> vars
->encryptStart
)
896 && ((vars
->position
- length
) < vars
->encryptEnd
))
898 AbsoluteTime startTime
, endTime
;
900 uint64_t encryptLen
, encryptStart
;
901 encryptLen
= vars
->position
- vars
->encryptStart
;
902 if (encryptLen
> length
)
904 encryptStart
= length
- encryptLen
;
905 if (vars
->position
> vars
->encryptEnd
)
906 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
908 clock_get_uptime(&startTime
);
910 // encrypt the buffer
911 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
912 &cryptvars
->aes_iv
[0],
913 encryptLen
/ AES_BLOCK_SIZE
,
914 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
915 &cryptvars
->ctx
.encrypt
);
917 clock_get_uptime(&endTime
);
918 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
919 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
920 vars
->cryptBytes
+= encryptLen
;
922 // save initial vector for following encrypts
923 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
924 &cryptvars
->aes_iv
[0],
931 err
= IOHibernatePollerIODone(vars
, true);
932 if (kIOReturnSuccess
!= err
)
936 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
937 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
939 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
940 if (kIOReturnSuccess
!= err
)
944 vars
->extentRemaining
-= vars
->bufferOffset
;
945 if (!vars
->extentRemaining
)
947 vars
->currentExtent
++;
948 vars
->extentRemaining
= vars
->currentExtent
->length
;
949 vars
->extentPosition
= vars
->position
;
950 if (!vars
->extentRemaining
)
952 err
= kIOReturnOverrun
;
957 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
958 vars
->bufferOffset
= 0;
959 if (vars
->bufferSize
<= vars
->extentRemaining
)
960 vars
->bufferLimit
= vars
->bufferSize
;
962 vars
->bufferLimit
= vars
->extentRemaining
;
973 IOPolledFileRead(IOPolledFileIOVars
* vars
,
974 uint8_t * bytes
, IOByteCount size
,
975 hibernate_cryptvars_t
* cryptvars
)
977 IOReturn err
= kIOReturnSuccess
;
980 // bytesWritten += size;
984 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
990 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
994 vars
->bufferOffset
+= copy
;
995 // vars->position += copy;
997 if ((vars
->bufferOffset
== vars
->bufferLimit
) && (vars
->position
< vars
->readEnd
))
1001 err
= IOHibernatePollerIODone(vars
, false);
1002 if (kIOReturnSuccess
!= err
)
1008 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
1010 vars
->position
+= vars
->lastRead
;
1011 vars
->extentRemaining
-= vars
->lastRead
;
1012 vars
->bufferLimit
= vars
->lastRead
;
1014 if (!vars
->extentRemaining
)
1016 vars
->currentExtent
++;
1017 vars
->extentRemaining
= vars
->currentExtent
->length
;
1018 vars
->extentPosition
= vars
->position
;
1019 if (!vars
->extentRemaining
)
1021 err
= kIOReturnOverrun
;
1027 uint64_t lastReadLength
= vars
->lastRead
;
1028 uint64_t offset
= (vars
->position
1029 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1030 if (vars
->extentRemaining
<= vars
->bufferSize
)
1031 length
= vars
->extentRemaining
;
1033 length
= vars
->bufferSize
;
1034 if ((length
+ vars
->position
) > vars
->readEnd
)
1035 length
= vars
->readEnd
- vars
->position
;
1037 vars
->lastRead
= length
;
1040 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1041 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
1042 if (kIOReturnSuccess
!= err
)
1047 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1048 vars
->bufferOffset
= 0;
1053 uint8_t thisVector
[AES_BLOCK_SIZE
];
1054 AbsoluteTime startTime
, endTime
;
1056 // save initial vector for following decrypts
1057 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
1058 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
1059 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1061 // decrypt the buffer
1062 clock_get_uptime(&startTime
);
1064 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
1066 lastReadLength
/ AES_BLOCK_SIZE
,
1067 vars
->buffer
+ vars
->bufferHalf
,
1068 &cryptvars
->ctx
.decrypt
);
1070 clock_get_uptime(&endTime
);
1071 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1072 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1073 vars
->cryptBytes
+= lastReadLength
;
1083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1086 IOHibernateSystemSleep(void)
1094 IOHibernateVars
* vars
= &gIOHibernateVars
;
1096 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
1097 // already on the way down
1098 return (kIOReturnSuccess
);
1100 gIOHibernateState
= kIOHibernateStateInactive
;
1102 gIOHibernateDebugFlags
= 0;
1103 if (kIOLogHibernate
& gIOKitDebug
)
1104 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
1106 if (IOService::getPMRootDomain()->getHibernateSettings(
1107 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
1109 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1110 // default to discard clean for safe sleep
1111 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
1112 | kIOHibernateModeDiscardCleanActive
);
1115 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1117 if ((str
= OSDynamicCast(OSString
, obj
)))
1118 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1119 sizeof(gIOHibernateFilename
));
1123 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1124 return (kIOReturnUnsupported
);
1126 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1131 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1132 4 * page_size
, page_size
);
1133 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1134 2 * kDefaultIOSize
, page_size
);
1136 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1137 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
1139 if (!vars
->srcBuffer
|| !vars
->ioBuffer
|| !vars
->handoffBuffer
)
1141 err
= kIOReturnNoMemory
;
1145 // open & invalidate the image file
1146 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1147 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1148 &vars
->fileVars
, &vars
->fileExtents
, &data
,
1149 &vars
->volumeCryptKey
[0]);
1150 if (KERN_SUCCESS
!= err
)
1152 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1156 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1157 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1158 dsSSD
= ((0 != (kIOHibernateOptionSSD
& vars
->fileVars
->flags
))
1159 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
1162 gIOHibernateCurrentHeader
->options
|=
1163 kIOHibernateOptionSSD
1164 | kIOHibernateOptionColor
;
1166 #if defined(__i386__) || defined(__x86_64__)
1167 if (!uuid_is_null(vars
->volumeCryptKey
) &&
1168 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
)))
1170 uintptr_t smcVars
[2];
1171 smcVars
[0] = sizeof(vars
->volumeCryptKey
);
1172 smcVars
[1] = (uintptr_t)(void *) &vars
->volumeCryptKey
[0];
1174 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
1175 bzero(smcVars
, sizeof(smcVars
));
1181 gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
1184 boolean_t encryptedswap
;
1185 AbsoluteTime startTime
, endTime
;
1188 clock_get_uptime(&startTime
);
1189 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1190 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1192 &vars
->page_list
, &vars
->page_list_wired
, &vars
->page_list_pal
, &encryptedswap
);
1193 clock_get_uptime(&endTime
);
1194 SUB_ABSOLUTETIME(&endTime
, &startTime
);
1195 absolutetime_to_nanoseconds(endTime
, &nsec
);
1196 HIBLOG("hibernate_setup(%d) took %qd ms\n", err
, nsec
/ 1000000ULL);
1198 if (KERN_SUCCESS
!= err
)
1201 if (encryptedswap
|| !uuid_is_null(vars
->volumeCryptKey
))
1202 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1204 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1206 vars
->videoAllocSize
= kVideoMapSize
;
1207 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1208 vars
->videoMapping
= 0;
1211 // generate crypt keys
1212 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1213 vars
->wiredCryptKey
[i
] = random();
1214 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1215 vars
->cryptKey
[i
] = random();
1219 IORegistryEntry
* regEntry
;
1220 if (!gIOOptionsEntry
)
1222 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1223 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1224 if (regEntry
&& !gIOOptionsEntry
)
1225 regEntry
->release();
1227 if (!gIOChosenEntry
)
1228 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1230 if (gIOOptionsEntry
)
1232 const OSSymbol
* sym
;
1234 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1237 gIOOptionsEntry
->setProperty(sym
, data
);
1242 #if defined(__i386__) || defined(__x86_64__)
1243 struct AppleRTCHibernateVars
1245 uint8_t signature
[4];
1247 uint8_t booterSignature
[20];
1248 uint8_t wiredCryptKey
[16];
1250 AppleRTCHibernateVars rtcVars
;
1252 rtcVars
.signature
[0] = 'A';
1253 rtcVars
.signature
[1] = 'A';
1254 rtcVars
.signature
[2] = 'P';
1255 rtcVars
.signature
[3] = 'L';
1256 rtcVars
.revision
= 1;
1257 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1258 if (gIOHibernateBootSignature
[0])
1262 for (uint32_t i
= 0;
1263 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1274 value
= (value
<< 4) | c
;
1276 rtcVars
.booterSignature
[i
>> 1] = value
;
1279 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1282 if (!gIOHibernateRTCVariablesKey
)
1283 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1284 if (gIOHibernateRTCVariablesKey
)
1285 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
1287 if( gIOOptionsEntry
)
1289 if( gIOHibernateMode
& kIOHibernateModeSwitch
)
1291 const OSSymbol
*sym
;
1292 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey
);
1295 gIOOptionsEntry
->setProperty(sym
, data
); /* intentional insecure backup of rtc boot vars */
1305 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1307 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1311 if (!gIOHibernateBoot0082Data
)
1313 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
1316 // AppleNVRAM_EFI_LOAD_OPTION
1318 uint32_t Attributes
;
1319 uint16_t FilePathLength
;
1322 loadOptionHeader
.Attributes
= 1;
1323 loadOptionHeader
.FilePathLength
= data
->getLength();
1324 loadOptionHeader
.Desc
= 0;
1325 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
1326 if (gIOHibernateBoot0082Data
)
1328 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
1329 gIOHibernateBoot0082Data
->appendBytes(data
);
1333 if (!gIOHibernateBoot0082Key
)
1334 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1335 if (!gIOHibernateBootNextKey
)
1336 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1337 if (!gIOHibernateBootNextData
)
1339 uint16_t bits
= 0x0082;
1340 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
1342 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
1344 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
1345 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
1346 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
1350 #else /* !i386 && !x86_64 */
1351 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1353 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1354 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1356 gIOOptionsEntry
->setProperty(sym
, data
);
1361 if (false && gIOHibernateBootSignature
[0])
1363 data
= OSData::withCapacity(16);
1364 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1369 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1379 value
= (value
<< 4) | c
;
1381 data
->appendBytes(&value
, sizeof(value
));
1383 gIOOptionsEntry
->setProperty(sym
, data
);
1391 if (!vars
->haveFastBoot
)
1393 // set boot volume to zero
1394 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1395 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1396 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1399 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1400 platform
->writeXPRAM(kXPRamAudioVolume
,
1401 &newVolume
, sizeof(newVolume
));
1404 #endif /* !i386 && !x86_64 */
1408 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1409 gIOHibernateState
= kIOHibernateStateHibernating
;
1416 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1418 DECLARE_IOHIBERNATEPROGRESSALPHA
1421 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
1423 uint32_t rowBytes
, pixelShift
;
1426 uint32_t alpha
, in
, color
, result
;
1428 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1430 rowBytes
= display
->rowBytes
;
1431 pixelShift
= display
->depth
>> 4;
1432 if (pixelShift
< 1) return;
1434 screen
+= ((display
->width
1435 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1436 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1438 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1440 out
= screen
+ y
* rowBytes
;
1441 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
1443 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
1444 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1446 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1452 if (1 == pixelShift
)
1454 in
= *((uint16_t *)out
) & 0x1f; // 16
1455 in
= (in
<< 3) | (in
>> 2);
1458 in
= *((uint32_t *)out
) & 0xff; // 32
1459 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1460 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1462 if (1 == pixelShift
)
1465 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1468 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1470 out
+= (1 << pixelShift
);
1472 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1479 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1481 uint32_t rowBytes
, pixelShift
;
1483 int32_t blob
, lastBlob
;
1484 uint32_t alpha
, in
, color
, result
;
1486 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1488 pixelShift
= display
->depth
>> 4;
1492 rowBytes
= display
->rowBytes
;
1494 screen
+= ((display
->width
1495 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1496 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1498 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1500 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1502 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1504 out
= screen
+ y
* rowBytes
;
1505 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1507 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1508 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1510 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1516 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1517 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1519 if (1 == pixelShift
)
1522 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1525 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1527 out
+= (1 << pixelShift
);
1529 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1534 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1537 IOHibernateSystemHasSlept(void)
1539 IOHibernateVars
* vars
= &gIOHibernateVars
;
1543 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1544 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1545 if (obj
&& !vars
->previewBuffer
)
1548 vars
->consoleMapping
= NULL
;
1549 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1551 vars
->previewBuffer
->release();
1552 vars
->previewBuffer
= 0;
1555 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1556 && vars
->previewBuffer
1557 && (data
= OSDynamicCast(OSData
,
1558 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1560 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1561 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1563 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1565 if (kIOHibernatePreviewUpdates
& flags
)
1567 PE_Video consoleInfo
;
1568 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1570 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1572 graphicsInfo
->width
= consoleInfo
.v_width
;
1573 graphicsInfo
->height
= consoleInfo
.v_height
;
1574 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1575 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1576 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1578 HIBPRINT("video %p %d %d %d\n",
1579 vars
->consoleMapping
, graphicsInfo
->depth
,
1580 graphicsInfo
->width
, graphicsInfo
->height
);
1581 if (vars
->consoleMapping
)
1582 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1583 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1587 if (gIOOptionsEntry
)
1588 gIOOptionsEntry
->sync();
1590 return (kIOReturnSuccess
);
1593 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1595 static DeviceTreeNode
*
1596 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
1598 DeviceTreeNodeProperty
* prop
;
1599 DeviceTreeNode
* child
;
1600 IORegistryEntry
* childRegEntry
;
1601 const char * nameProp
;
1602 unsigned int propLen
, idx
;
1604 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1605 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
1607 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
1609 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1610 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1612 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1615 child
= (DeviceTreeNode
*) prop
;
1616 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
1618 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
1620 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1621 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1622 child
= MergeDeviceTree(child
, childRegEntry
);
1628 IOHibernateSystemWake(void)
1630 IOHibernateVars
* vars
= &gIOHibernateVars
;
1632 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1634 if (vars
->videoMapping
)
1636 if (vars
->videoMapSize
)
1638 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1639 if (vars
->videoAllocSize
)
1641 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1644 if (vars
->previewBuffer
)
1646 vars
->previewBuffer
->release();
1647 vars
->previewBuffer
= 0;
1650 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1652 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1653 gIOHibernateCurrentHeader
->options
, 32);
1657 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1660 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1661 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1663 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1664 &gIOHibernateGraphicsInfo
->gfxStatus
,
1665 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1669 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1675 IOPolledFileClose(vars
->fileVars
);
1678 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1680 #if defined(__i386__) || defined(__x86_64__)
1681 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1682 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1685 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1686 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1688 if (gIOOptionsEntry
) {
1690 if (gIOHibernateRTCVariablesKey
) {
1691 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1692 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1696 if (gIOHibernateBootNextKey
)
1698 if (gIOHibernateBootNextSave
)
1700 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1701 gIOHibernateBootNextSave
->release();
1702 gIOHibernateBootNextSave
= NULL
;
1705 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1707 gIOOptionsEntry
->sync();
1711 if (vars
->srcBuffer
)
1712 vars
->srcBuffer
->release();
1714 vars
->ioBuffer
->release();
1715 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1716 if (vars
->handoffBuffer
&& (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
))
1718 IOHibernateHandoff
* handoff
;
1720 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1722 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
1724 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1725 uint8_t * data
= &handoff
->data
[0];
1726 switch (handoff
->type
)
1728 case kIOHibernateHandoffTypeEnd
:
1732 case kIOHibernateHandoffTypeDeviceTree
:
1733 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
1736 case kIOHibernateHandoffTypeKeyStore
:
1737 #if defined(__i386__) || defined(__x86_64__)
1739 IOBufferMemoryDescriptor
*
1740 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1743 IOSetKeyStoreData(md
);
1750 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1754 vars
->handoffBuffer
->release();
1756 if (vars
->fileExtents
)
1757 vars
->fileExtents
->release();
1759 bzero(vars
, sizeof(*vars
));
1761 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1763 return (kIOReturnSuccess
);
1767 IOHibernateSystemPostWake(void)
1769 if (gIOHibernateFileRef
)
1771 // invalidate & close the image file
1772 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1773 kern_close_file_for_direct_io(gIOHibernateFileRef
,
1774 0, (caddr_t
) gIOHibernateCurrentHeader
,
1775 sizeof(IOHibernateImageHeader
),
1776 sizeof(IOHibernateImageHeader
),
1777 gIOHibernateCurrentHeader
->imageSize
);
1778 gIOHibernateFileRef
= 0;
1780 return (kIOReturnSuccess
);
1783 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1785 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1786 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1787 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1788 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1789 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1790 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1791 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1792 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1793 &gIOHibernateMode
, 0, "");
1796 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1798 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1801 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1805 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1806 gIOHibernateMode
= kIOHibernateModeOn
;
1808 gIOHibernateFilename
[0] = 0;
1810 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1811 sysctl_register_oid(&sysctl__kern_bootsignature
);
1812 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1816 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1819 hibernate_setup_for_wake(void)
1823 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1825 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1828 no_encrypt_page(vm_offset_t ppnum
)
1830 if (pmap_is_noencrypt((ppnum_t
)ppnum
) == TRUE
)
1837 uint32_t wired_pages_encrypted
= 0;
1838 uint32_t dirty_pages_encrypted
= 0;
1839 uint32_t wired_pages_clear
= 0;
1842 hibernate_pal_callback(void *vars_arg
, vm_offset_t addr
)
1844 IOHibernateVars
*vars
= (IOHibernateVars
*)vars_arg
;
1845 /* Make sure it's not in either of the save lists */
1846 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
, atop_64(addr
), 1, kIOHibernatePageStateFree
);
1848 /* Set it in the bitmap of pages owned by the PAL */
1849 hibernate_page_bitset(vars
->page_list_pal
, TRUE
, atop_64(addr
));
1852 static struct hibernate_cryptvars_t
*local_cryptvars
;
1855 hibernate_pal_write(void *buffer
, size_t size
)
1857 IOHibernateVars
* vars
= &gIOHibernateVars
;
1859 IOReturn err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *)buffer
, size
, local_cryptvars
);
1860 if (kIOReturnSuccess
!= err
) {
1861 kprintf("epic hibernate fail! %d\n", err
);
1870 hibernate_write_image(void)
1872 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1873 IOHibernateVars
* vars
= &gIOHibernateVars
;
1874 IOPolledFileExtent
* fileExtents
;
1876 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
1878 uint32_t pageCount
, pagesDone
;
1880 vm_offset_t ppnum
, page
;
1884 IOByteCount pageCompressedSize
;
1885 uint64_t compressedSize
, uncompressedSize
;
1886 uint64_t image1Size
= 0;
1887 uint32_t bitmap_size
;
1888 bool iterDone
, pollerOpen
, needEncrypt
;
1889 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1892 uint32_t pageAndCount
[2];
1896 AbsoluteTime startTime
, endTime
;
1897 AbsoluteTime allTime
, compTime
;
1900 uint32_t lastProgressStamp
= 0;
1901 uint32_t progressStamp
;
1902 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1904 hibernate_cryptvars_t _cryptvars
;
1905 hibernate_cryptvars_t
* cryptvars
= 0;
1907 wired_pages_encrypted
= 0;
1908 dirty_pages_encrypted
= 0;
1909 wired_pages_clear
= 0;
1911 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1912 return (false /* sleep */ );
1914 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1915 kdebug_enable
= save_kdebug_enable
;
1917 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
, 0, 0, 0, 0, 0);
1918 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
1920 restore1Sum
= sum1
= sum2
= 0;
1922 hibernate_pal_prepare();
1925 // encryption data. "iv" is the "initial vector".
1926 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1928 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1929 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1930 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1932 cryptvars
= &gIOHibernateCryptWakeContext
;
1933 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1934 aes_encrypt_key(vars
->cryptKey
,
1935 kIOHibernateAESKeySize
,
1936 &cryptvars
->ctx
.encrypt
);
1937 aes_decrypt_key(vars
->cryptKey
,
1938 kIOHibernateAESKeySize
,
1939 &cryptvars
->ctx
.decrypt
);
1941 cryptvars
= &_cryptvars
;
1942 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1943 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++)
1944 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
1945 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1946 aes_encrypt_key(vars
->wiredCryptKey
,
1947 kIOHibernateAESKeySize
,
1948 &cryptvars
->ctx
.encrypt
);
1950 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1951 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1952 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1954 local_cryptvars
= cryptvars
;
1958 hibernate_setup_for_wake();
1960 hibernate_page_list_setall(vars
->page_list
,
1961 vars
->page_list_wired
,
1962 vars
->page_list_pal
,
1965 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1967 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1970 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1971 for (page
= 0; page
< count
; page
++)
1973 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1974 fileExtents
[page
].start
, fileExtents
[page
].length
,
1975 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1979 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1980 AbsoluteTime_to_scalar(&compTime
) = 0;
1983 clock_get_uptime(&allTime
);
1984 IOService::getPMRootDomain()->pmStatsRecordEvent(
1985 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1990 uncompressedSize
= 0;
1992 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1994 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1995 ml_get_interrupts_enabled());
1996 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1997 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1998 pollerOpen
= (kIOReturnSuccess
== err
);
2002 // copy file block extent list if larger than header
2004 count
= vars
->fileExtents
->getLength();
2005 if (count
> sizeof(header
->fileExtentMap
))
2007 count
-= sizeof(header
->fileExtentMap
);
2008 err
= IOPolledFileWrite(vars
->fileVars
,
2009 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
2010 if (kIOReturnSuccess
!= err
)
2014 uintptr_t hibernateBase
;
2015 uintptr_t hibernateEnd
;
2017 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
2019 hibernateEnd
= (sectHIBB
+ sectSizeHIB
);
2021 // copy out restore1 code
2024 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2027 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
2029 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
2033 page
= atop_32(kvtophys(hibernateBase
));
2034 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
2035 header
->restore1CodePhysPage
= page
;
2036 header
->restore1CodeVirt
= hibernateBase
;
2037 header
->restore1PageCount
= count
;
2038 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
2039 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
2041 // sum __HIB sect, with zeros for the stack
2042 src
= (uint8_t *) trunc_page(hibernateBase
);
2043 for (page
= 0; page
< count
; page
++)
2045 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
2046 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
2048 restore1Sum
+= 0x00000000;
2053 // write the __HIB sect, with zeros for the stack
2055 src
= (uint8_t *) trunc_page(hibernateBase
);
2056 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
2059 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2060 if (kIOReturnSuccess
!= err
)
2063 err
= IOPolledFileWrite(vars
->fileVars
,
2065 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
2067 if (kIOReturnSuccess
!= err
)
2069 src
= &gIOHibernateRestoreStackEnd
[0];
2070 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
2073 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2074 if (kIOReturnSuccess
!= err
)
2078 // write the preview buffer
2080 if (vars
->previewBuffer
)
2086 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
2087 pageAndCount
[0] = atop_64(phys64
);
2088 pageAndCount
[1] = atop_32(segLen
);
2089 err
= IOPolledFileWrite(vars
->fileVars
,
2090 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2092 if (kIOReturnSuccess
!= err
)
2095 ppnum
+= sizeof(pageAndCount
);
2098 if (kIOReturnSuccess
!= err
)
2101 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
2102 count
= vars
->previewBuffer
->getLength();
2104 header
->previewPageListSize
= ppnum
;
2105 header
->previewSize
= count
+ ppnum
;
2107 for (page
= 0; page
< count
; page
+= page_size
)
2109 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
2110 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
2112 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2113 if (kIOReturnSuccess
!= err
)
2117 // mark areas for no save
2120 (phys64
= vars
->ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2123 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2124 atop_64(phys64
), atop_32(segLen
),
2125 kIOHibernatePageStateFree
);
2126 pageCount
-= atop_32(segLen
);
2130 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2133 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2134 atop_64(phys64
), atop_32(segLen
),
2135 kIOHibernatePageStateFree
);
2136 pageCount
-= atop_32(segLen
);
2139 // copy out bitmap of pages available for trashing during restore
2141 bitmap_size
= vars
->page_list_wired
->list_size
;
2142 src
= (uint8_t *) vars
->page_list_wired
;
2143 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
2144 if (kIOReturnSuccess
!= err
)
2147 // mark more areas for no save, but these are not available
2148 // for trashing during restore
2150 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
2153 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
2154 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
2155 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2157 kIOHibernatePageStateFree
);
2160 if (vars
->previewBuffer
) for (count
= 0;
2161 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2164 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2165 atop_64(phys64
), atop_32(segLen
),
2166 kIOHibernatePageStateFree
);
2167 pageCount
-= atop_32(segLen
);
2171 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2174 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2175 atop_64(phys64
), atop_32(segLen
),
2176 kIOHibernatePageStateFree
);
2177 pageCount
-= atop_32(segLen
);
2180 (void)hibernate_pal_callback
;
2182 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2187 HIBLOG("writing %d pages\n", pageCount
);
2194 kWiredEncrypt
= kWired
| kEncrypt
,
2195 kWiredClear
= kWired
,
2196 kUnwiredEncrypt
= kEncrypt
2199 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
2201 if (needEncrypt
&& (kEncrypt
& pageType
))
2203 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
2204 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2205 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2207 if (kUnwiredEncrypt
== pageType
)
2209 // start unwired image
2210 bcopy(&cryptvars
->aes_iv
[0],
2211 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2212 sizeof(cryptvars
->aes_iv
));
2213 cryptvars
= &gIOHibernateCryptWakeContext
;
2216 for (iterDone
= false, ppnum
= 0; !iterDone
; )
2218 count
= hibernate_page_list_iterate((kWired
& pageType
)
2219 ? vars
->page_list_wired
: vars
->page_list
,
2221 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2224 if (count
&& (kWired
& pageType
) && needEncrypt
)
2226 uint32_t checkIndex
;
2227 for (checkIndex
= 0;
2228 (checkIndex
< count
)
2229 && (((kEncrypt
& pageType
) == 0) == no_encrypt_page(ppnum
+ checkIndex
));
2242 case kWiredEncrypt
: wired_pages_encrypted
+= count
; break;
2243 case kWiredClear
: wired_pages_clear
+= count
; break;
2244 case kUnwiredEncrypt
: dirty_pages_encrypted
+= count
; break;
2247 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
2250 pageAndCount
[0] = ppnum
;
2251 pageAndCount
[1] = count
;
2252 err
= IOPolledFileWrite(vars
->fileVars
,
2253 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2255 if (kIOReturnSuccess
!= err
)
2259 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
2261 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
2264 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
2268 sum
= hibernate_sum_page(src
, page
);
2269 if (kWired
& pageType
)
2274 clock_get_uptime(&startTime
);
2276 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
2278 clock_get_uptime(&endTime
);
2279 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2280 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2281 compBytes
+= page_size
;
2283 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2284 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
2286 if (pageCompressedSize
> page_size
)
2288 // HIBLOG("------------lose: %d\n", pageCompressedSize);
2289 pageCompressedSize
= page_size
;
2292 if (pageCompressedSize
!= page_size
)
2293 data
= (src
+ page_size
);
2297 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2298 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2299 if (kIOReturnSuccess
!= err
)
2302 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2303 if (kIOReturnSuccess
!= err
)
2306 compressedSize
+= pageCompressedSize
;
2307 if (pageCompressedSize
)
2308 uncompressedSize
+= page_size
;
2311 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2313 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2314 if (blob
!= lastBlob
)
2316 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2320 if (0 == (8191 & pagesDone
))
2322 clock_get_uptime(&endTime
);
2323 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2324 absolutetime_to_nanoseconds(endTime
, &nsec
);
2325 progressStamp
= nsec
/ 750000000ULL;
2326 if (progressStamp
!= lastProgressStamp
)
2328 lastProgressStamp
= progressStamp
;
2329 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2333 if (kIOReturnSuccess
!= err
)
2338 if (kIOReturnSuccess
!= err
)
2341 if ((kEncrypt
& pageType
))
2343 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
2344 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2347 if (kWiredEncrypt
!= pageType
)
2349 // end of image1/2 - fill to next block
2350 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2351 if (kIOReturnSuccess
!= err
)
2354 if (kWiredClear
== pageType
)
2356 // enlarge wired image for test
2357 // err = IOPolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
2360 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2361 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2362 image1Size
= vars
->fileVars
->position
;
2363 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2364 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2367 if (kIOReturnSuccess
!= err
)
2372 header
->imageSize
= vars
->fileVars
->position
;
2373 header
->image1Size
= image1Size
;
2374 header
->bitmapSize
= bitmap_size
;
2375 header
->pageCount
= pageCount
;
2377 header
->restore1Sum
= restore1Sum
;
2378 header
->image1Sum
= sum1
;
2379 header
->image2Sum
= sum2
;
2381 count
= vars
->fileExtents
->getLength();
2382 if (count
> sizeof(header
->fileExtentMap
))
2384 header
->fileExtentMapSize
= count
;
2385 count
= sizeof(header
->fileExtentMap
);
2388 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2389 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2391 header
->deviceBase
= vars
->fileVars
->block0
;
2393 IOPolledFileSeek(vars
->fileVars
, 0);
2394 err
= IOPolledFileWrite(vars
->fileVars
,
2395 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2397 if (kIOReturnSuccess
!= err
)
2399 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2400 if (kIOReturnSuccess
!= err
)
2402 err
= IOHibernatePollerIODone(vars
->fileVars
, true);
2403 if (kIOReturnSuccess
!= err
)
2408 clock_get_uptime(&endTime
);
2410 IOService::getPMRootDomain()->pmStatsRecordEvent(
2411 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2413 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2414 absolutetime_to_nanoseconds(endTime
, &nsec
);
2415 HIBLOG("all time: %qd ms, ",
2418 absolutetime_to_nanoseconds(compTime
, &nsec
);
2419 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2422 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2424 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2425 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2426 vars
->fileVars
->cryptBytes
,
2428 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2430 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2432 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2433 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2436 HIBLOG("wired_pages_encrypted %d, wired_pages_clear %d, dirty_pages_encrypted %d\n",
2437 wired_pages_encrypted
, wired_pages_clear
, dirty_pages_encrypted
);
2439 if (vars
->fileVars
->io
)
2440 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2443 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
2445 if (vars
->consoleMapping
)
2446 ProgressUpdate(gIOHibernateGraphicsInfo
,
2447 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2449 HIBLOG("hibernate_write_image done(%x)\n", err
);
2451 // should we come back via regular wake, set the state in memory.
2452 gIOHibernateState
= kIOHibernateStateInactive
;
2454 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
,
2455 wired_pages_encrypted
, wired_pages_clear
, dirty_pages_encrypted
, 0, 0);
2457 if (kIOReturnSuccess
== err
)
2459 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2461 return (kIOHibernatePostWriteSleep
);
2463 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2465 return (kIOHibernatePostWriteRestart
);
2469 /* by default, power down */
2470 return (kIOHibernatePostWriteHalt
);
2473 else if (kIOReturnAborted
== err
)
2475 return (kIOHibernatePostWriteWake
);
2479 /* on error, sleep */
2480 return (kIOHibernatePostWriteSleep
);
2484 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2487 hibernate_machine_init(void)
2492 uint32_t pagesRead
= 0;
2493 AbsoluteTime startTime
, compTime
;
2494 AbsoluteTime allTime
, endTime
;
2497 uint32_t lastProgressStamp
= 0;
2498 uint32_t progressStamp
;
2499 uint64_t progressZeroPosition
= 0;
2500 uint32_t blob
, lastBlob
= (uint32_t) -1L;
2501 hibernate_cryptvars_t
* cryptvars
= 0;
2503 IOHibernateVars
* vars
= &gIOHibernateVars
;
2505 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2508 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2509 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2511 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
2512 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
2513 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2515 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2517 HIBLOG("regular wake\n");
2521 HIBPRINT("diag %x %x %x %x\n",
2522 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2523 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2525 HIBPRINT("video %x %d %d %d status %x\n",
2526 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2527 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2529 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
2530 hibernate_page_list_discard(vars
->page_list
);
2532 boot_args
*args
= (boot_args
*) PE_state
.bootArgs
;
2534 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2536 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
2537 panic("handoff overflow");
2539 IOHibernateHandoff
* handoff
;
2541 bool foundCryptData
= false;
2543 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2545 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2547 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2548 uint8_t * data
= &handoff
->data
[0];
2549 switch (handoff
->type
)
2551 case kIOHibernateHandoffTypeEnd
:
2555 case kIOHibernateHandoffTypeGraphicsInfo
:
2556 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2559 case kIOHibernateHandoffTypeCryptVars
:
2562 hibernate_cryptwakevars_t
*
2563 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
2564 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
2566 foundCryptData
= true;
2567 bzero(data
, handoff
->bytecount
);
2570 case kIOHibernateHandoffTypeMemoryMap
:
2571 hibernate_newruntime_map(data
, handoff
->bytecount
,
2572 gIOHibernateCurrentHeader
->systemTableOffset
);
2575 case kIOHibernateHandoffTypeDeviceTree
:
2577 // DTEntry chosen = NULL;
2578 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2583 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2587 if (cryptvars
&& !foundCryptData
)
2588 panic("hibernate handoff");
2590 if (vars
->videoMapping
2591 && gIOHibernateGraphicsInfo
->physicalAddress
2592 && (args
->Video
.v_baseAddr
== gIOHibernateGraphicsInfo
->physicalAddress
))
2594 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2595 * gIOHibernateGraphicsInfo
->rowBytes
);
2596 IOMapPages(kernel_map
,
2597 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2598 vars
->videoMapSize
, kIOMapInhibitCache
);
2601 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2602 uint32_t decoOffset
;
2604 clock_get_uptime(&allTime
);
2605 AbsoluteTime_to_scalar(&compTime
) = 0;
2608 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2609 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
2610 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2612 if (gIOHibernateCurrentHeader
->previewSize
)
2613 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
2614 + gIOHibernateCurrentHeader
->fileExtentMapSize
2615 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
2616 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
2618 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2620 if (vars
->videoMapSize
)
2622 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2623 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2624 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
2627 // kick off the read ahead
2628 vars
->fileVars
->io
= false;
2629 vars
->fileVars
->bufferHalf
= 0;
2630 vars
->fileVars
->bufferLimit
= 0;
2631 vars
->fileVars
->lastRead
= 0;
2632 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
2633 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2634 vars
->fileVars
->cryptBytes
= 0;
2635 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
2637 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2638 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2641 HIBLOG("hibernate_machine_init reading\n");
2643 uint32_t * header
= (uint32_t *) src
;
2646 while (kIOReturnSuccess
== err
)
2651 vm_offset_t ppnum
, compressedSize
;
2653 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2654 if (kIOReturnSuccess
!= err
)
2660 // HIBPRINT("(%x, %x)\n", ppnum, count);
2665 for (page
= 0; page
< count
; page
++)
2667 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2668 if (kIOReturnSuccess
!= err
)
2671 compressedSize
= kIOHibernateTagLength
& tag
;
2672 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2674 err
= kIOReturnIPCError
;
2678 if (!compressedSize
)
2685 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2686 if (kIOReturnSuccess
!= err
)
2689 if (compressedSize
< page_size
)
2691 decoOffset
= page_size
;
2693 clock_get_uptime(&startTime
);
2694 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2695 clock_get_uptime(&endTime
);
2696 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2697 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2699 compBytes
+= page_size
;
2704 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
2706 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2709 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2717 if (vars
->videoMapSize
&& (0 == (1023 & pagesDone
)))
2719 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2720 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2721 if (blob
!= lastBlob
)
2723 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2728 if (0 == (8191 & pagesDone
))
2730 clock_get_uptime(&endTime
);
2731 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2732 absolutetime_to_nanoseconds(endTime
, &nsec
);
2733 progressStamp
= nsec
/ 750000000ULL;
2734 if (progressStamp
!= lastProgressStamp
)
2736 lastProgressStamp
= progressStamp
;
2737 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2738 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2743 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
2744 err
= kIOReturnLockedRead
;
2746 if (kIOReturnSuccess
!= err
)
2747 panic("Hibernate restore error %x", err
);
2749 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2751 if (vars
->fileVars
->io
)
2752 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2754 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2756 if (vars
->videoMapSize
)
2757 ProgressUpdate(gIOHibernateGraphicsInfo
,
2758 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2760 clock_get_uptime(&endTime
);
2762 IOService::getPMRootDomain()->pmStatsRecordEvent(
2763 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2764 IOService::getPMRootDomain()->pmStatsRecordEvent(
2765 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2767 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2768 absolutetime_to_nanoseconds(endTime
, &nsec
);
2770 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms, ",
2771 pagesDone
, sum
, nsec
/ 1000000ULL);
2773 absolutetime_to_nanoseconds(compTime
, &nsec
);
2774 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2777 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2779 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2780 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2781 vars
->fileVars
->cryptBytes
,
2783 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2785 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 2) | DBG_FUNC_NONE
, pagesRead
, pagesDone
, 0, 0, 0);
2788 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */