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 segment "__HIB" is written uncompressed to the image. This segment 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 segment "__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 <libkern/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>
165 #include <IOKit/IOHibernatePrivate.h>
166 #include <IOKit/IOPolledInterface.h>
167 #include <IOKit/IONVRAM.h>
168 #include "IOHibernateInternal.h"
169 #include <vm/WKdm_new.h>
170 #include "IOKitKernelInternal.h"
171 #include <pexpert/device_tree.h>
173 #include <machine/pal_routines.h>
174 #include <machine/pal_hibernate.h>
175 #include <i386/tsc.h>
177 extern "C" addr64_t
kvtophys(vm_offset_t va
);
178 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
180 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
182 #define DISABLE_TRIM 0
183 #define TRIM_DELAY 5000
185 extern unsigned int save_kdebug_enable
;
186 extern uint32_t gIOHibernateState
;
187 uint32_t gIOHibernateMode
;
188 static char gIOHibernateBootSignature
[256+1];
189 static char gIOHibernateFilename
[MAXPATHLEN
+1];
190 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
191 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
192 static uint64_t gIOHibernateCompression
= 0x80; // default compression 50%
194 static IODTNVRAM
* gIOOptionsEntry
;
195 static IORegistryEntry
* gIOChosenEntry
;
196 #if defined(__i386__) || defined(__x86_64__)
197 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
198 static const OSSymbol
* gIOHibernateRTCVariablesKey
;
199 static const OSSymbol
* gIOHibernateBoot0082Key
;
200 static const OSSymbol
* gIOHibernateBootNextKey
;
201 static OSData
* gIOHibernateBoot0082Data
;
202 static OSData
* gIOHibernateBootNextData
;
203 static OSObject
* gIOHibernateBootNextSave
;
204 static struct kern_direct_file_io_ref_t
* gDebugImageFileRef
;
207 static IOLock
* gFSLock
;
208 static uint32_t gFSState
;
209 static IOPolledFileIOVars gFileVars
;
210 static IOHibernateVars gIOHibernateVars
;
211 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
212 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
213 static hibernate_graphics_t _hibernateGraphics
;
214 static hibernate_graphics_t
* gIOHibernateGraphicsInfo
= &_hibernateGraphics
;
215 static hibernate_statistics_t _hibernateStats
;
216 static hibernate_statistics_t
* gIOHibernateStats
= &_hibernateStats
;
226 static IOReturn
IOHibernateDone(IOHibernateVars
* vars
);
228 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
230 enum { kXPRamAudioVolume
= 8 };
231 enum { kDefaultIOSize
= 128 * 1024 };
232 enum { kVideoMapSize
= 80 * 1024 * 1024 };
234 #ifndef kIOMediaPreferredBlockSizeKey
235 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
238 #ifndef kIOBootPathKey
239 #define kIOBootPathKey "bootpath"
241 #ifndef kIOSelectedBootDeviceKey
242 #define kIOSelectedBootDeviceKey "boot-device"
245 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
247 // copy from phys addr to MD
250 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
251 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
253 addr64_t srcAddr
= bytes
;
254 IOByteCount remaining
;
256 remaining
= length
= min(length
, md
->getLength() - offset
);
257 while (remaining
) { // (process another target segment?)
261 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
265 // Clip segment length to remaining
266 if (dstLen
> remaining
)
270 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
272 copypv(srcAddr
, dstAddr64
, dstLen
,
273 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
282 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
285 // copy from MD to phys addr
288 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
289 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
291 addr64_t dstAddr
= bytes
;
292 IOByteCount remaining
;
294 remaining
= length
= min(length
, md
->getLength() - offset
);
295 while (remaining
) { // (process another target segment?)
299 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
303 // Clip segment length to remaining
304 if (dstLen
> remaining
)
308 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
310 copypv(srcAddr
, dstAddr64
, dstLen
,
311 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
320 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
323 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
326 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
327 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
332 case kIOHibernatePageStateUnwiredSave
:
334 for (; ppnum
< count
; ppnum
++)
336 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
337 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
340 case kIOHibernatePageStateWiredSave
:
342 for (; ppnum
< count
; ppnum
++)
344 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
345 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
348 case kIOHibernatePageStateFree
:
350 for (; ppnum
< count
; ppnum
++)
352 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
353 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
357 panic("hibernate_set_page_state");
362 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
364 uint32_t page
= *pPage
;
366 hibernate_bitmap_t
* bitmap
;
368 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
370 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
374 if (page
<= bitmap
->last_page
)
380 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
387 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
390 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
392 IOReturn err
= kIOReturnError
;
394 IOPolledInterface
* poller
;
396 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
398 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
399 err
= poller
->probe(target
);
402 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
411 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
413 IOReturn err
= kIOReturnError
;
415 IOPolledInterface
* poller
;
417 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
419 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
420 err
= poller
->open(state
, md
);
423 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
432 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
434 IOReturn err
= kIOReturnError
;
436 IOPolledInterface
* poller
;
439 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
442 err
= poller
->close(state
);
444 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
451 IOHibernatePollerIOComplete(void * target
,
454 UInt64 actualByteCount
)
456 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
458 vars
->ioStatus
= status
;
462 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
463 uint32_t operation
, uint32_t bufferOffset
,
464 uint64_t deviceOffset
, uint64_t length
)
467 IOReturn err
= kIOReturnError
;
468 IOPolledInterface
* poller
;
469 IOPolledCompletion completion
;
471 completion
.target
= 0;
472 completion
.action
= &IOHibernatePollerIOComplete
;
473 completion
.parameter
= vars
;
477 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
478 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
480 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
486 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
, bool abortable
)
488 IOReturn err
= kIOReturnSuccess
;
490 IOPolledInterface
* poller
;
492 while (-1 == vars
->ioStatus
)
495 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
499 newErr
= poller
->checkForWork();
500 if ((newErr
== kIOReturnAborted
) && !abortable
)
501 newErr
= kIOReturnSuccess
;
502 if (kIOReturnSuccess
== err
)
507 if ((kIOReturnSuccess
== err
) && abortable
&& hibernate_should_abort())
509 err
= kIOReturnAborted
;
510 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
515 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
519 err
= vars
->ioStatus
;
520 if (kIOReturnSuccess
!= err
)
521 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
528 IOPolledInterface::checkAllForWork(void)
530 IOReturn err
= kIOReturnNotReady
;
532 IOPolledInterface
* poller
;
534 IOHibernateVars
* vars
= &gIOHibernateVars
;
536 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
540 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
543 err
= poller
->checkForWork();
545 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
551 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
553 struct _OpenFileContext
560 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
562 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
563 IOPolledFileExtent extent
;
565 extent
.start
= start
;
566 extent
.length
= length
;
568 HIBLOG("[0x%qx, 0x%qx]\n", start
, length
);
570 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
575 IOCopyMediaForDev(dev_t device
)
577 OSDictionary
* matching
;
580 IOService
* result
= 0;
582 matching
= IOService::serviceMatching("IOMedia");
587 num
= OSNumber::withNumber(major(device
), 32);
590 matching
->setObject(kIOBSDMajorKey
, num
);
592 num
= OSNumber::withNumber(minor(device
), 32);
595 matching
->setObject(kIOBSDMinorKey
, num
);
599 iter
= IOService::getMatchingServices(matching
);
602 result
= (IOService
*) iter
->getNextObject();
614 * Writes header to disk with signature, block size and file extents data.
615 * If there are more than 2 extents, then they are written on second block.
618 WriteExtentsToFile(struct kern_direct_file_io_ref_t
* fileRef
,
619 uint32_t signature
, uint32_t blockSize
,
620 IOPolledFileExtent
*fileExtents
,
623 IOHibernateImageHeader hdr
;
625 IOReturn err
= kIOReturnSuccess
;
628 memset(&hdr
, 0, sizeof(IOHibernateImageHeader
));
630 if (count
> sizeof(hdr
.fileExtentMap
))
632 hdr
.fileExtentMapSize
= count
;
633 count
= sizeof(hdr
.fileExtentMap
);
636 hdr
.fileExtentMapSize
= sizeof(hdr
.fileExtentMap
);
638 bcopy(fileExtents
, &hdr
.fileExtentMap
[0], count
);
640 // copy file block extent list if larger than header
641 if (hdr
.fileExtentMapSize
> sizeof(hdr
.fileExtentMap
))
643 count
= hdr
.fileExtentMapSize
- sizeof(hdr
.fileExtentMap
);
644 rc
= kern_write_file(fileRef
, blockSize
,
645 (caddr_t
)(((uint8_t *)fileExtents
) + sizeof(hdr
.fileExtentMap
)),
646 count
, IO_SKIP_ENCRYPTION
);
648 HIBLOG("kern_write_file returned %d\n", rc
);
649 err
= kIOReturnIOError
;
653 hdr
.signature
= signature
;
654 hdr
.deviceBlockSize
= blockSize
;
656 rc
= kern_write_file(fileRef
, 0, (char *)&hdr
, sizeof(hdr
), IO_SKIP_ENCRYPTION
);
658 HIBLOG("kern_write_file returned %d\n", rc
);
659 err
= kIOReturnIOError
;
668 GetImageBlockSize(IOService
*part
, OSArray
*pollers
, IOByteCount
*blockSize
)
671 IORegistryEntry
* next
;
672 IORegistryEntry
* child
;
674 IOReturn err
= kIOReturnSuccess
;
680 IOPolledInterface
* poller
;
684 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
685 if (kOSBooleanFalse
== obj
)
687 pollers
->flushCollection();
690 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
691 pollers
->setObject(poller
);
693 if ((service
= OSDynamicCast(IOService
, next
))
694 && service
->getDeviceMemory()
695 && !pollers
->getCount()) break;
697 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
698 *blockSize
= num
->unsigned32BitValue();
701 while ((next
= child
->getParentEntry(gIOServicePlane
))
702 && child
->isParent(next
, gIOServicePlane
, true));
704 if (*blockSize
< 4096) *blockSize
= 4096;
706 if (!pollers
->getCount())
707 err
= kIOReturnUnsupported
;
713 IOPolledFileOpen( const char * filename
, uint64_t setFileSize
,
714 IOBufferMemoryDescriptor
* ioBuffer
,
715 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
716 OSData
** imagePath
, uint8_t * volumeCryptKey
)
718 IOReturn err
= kIOReturnSuccess
;
719 IOPolledFileIOVars
* vars
;
720 _OpenFileContext ctx
;
721 OSData
* extentsData
;
722 IOService
* part
= 0;
723 OSString
* keyUUID
= 0;
724 OSString
* keyStoreUUID
= 0;
726 dev_t hibernate_image_dev
;
728 AbsoluteTime startTime
, endTime
;
730 caddr_t write_file_addr
= NULL
;
731 vm_size_t write_file_len
= 0;
733 vars
= IONew(IOPolledFileIOVars
, 1);
734 if (!vars
) return (kIOReturnNoMemory
);
735 bzero(vars
, sizeof(*vars
));
740 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
741 vars
->bufferHalf
= 0;
742 vars
->bufferOffset
= 0;
743 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
745 extentsData
= OSData::withCapacity(32);
746 ctx
.extents
= extentsData
;
748 clock_get_uptime(&startTime
);
749 if (!gDebugImageFileRef
)
751 // Avoid writing the header if it is written when file is prep'd for debug data
752 // Image is locked during prep for debug data. So, write may fail.
753 write_file_addr
= (caddr_t
)gIOHibernateCurrentHeader
;
754 write_file_len
= sizeof(IOHibernateImageHeader
);
756 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
758 &file_extent_callback
, &ctx
,
765 &hibernate_image_dev
,
770 uint32_t msDelay
= (131071 & random());
771 HIBLOG("sleep %d\n", msDelay
);
774 clock_get_uptime(&endTime
);
775 SUB_ABSOLUTETIME(&endTime
, &startTime
);
776 absolutetime_to_nanoseconds(endTime
, &nsec
);
778 if (!vars
->fileRef
) err
= kIOReturnNoSpace
;
781 if (kFSOpening
!= gFSState
) err
= kIOReturnTimeout
;
782 IOLockUnlock(gFSLock
);
784 HIBLOG("kern_open_file_for_direct_io(%d) took %qd ms\n", err
, nsec
/ 1000000ULL);
785 if (kIOReturnSuccess
!= err
) break;
787 if (kIOHibernateModeSSDInvert
& gIOHibernateMode
)
788 vars
->flags
^= kIOHibernateOptionSSD
;
790 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename
, ctx
.size
,
791 vars
->block0
, maxiobytes
, kIOHibernateOptionSSD
& vars
->flags
);
792 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
794 err
= kIOReturnNoSpace
;
798 vars
->fileSize
= ctx
.size
;
799 if (maxiobytes
< vars
->bufferSize
) vars
->bufferSize
= maxiobytes
;
801 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
803 part
= IOCopyMediaForDev(block_dev
);
806 err
= kIOReturnNotFound
;
809 err
= part
->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID
, false,
810 (void *) &keyUUID
, (void *) &keyStoreUUID
, NULL
, NULL
);
811 if ((kIOReturnSuccess
== err
) && keyUUID
&& keyStoreUUID
)
813 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
814 uuid_t volumeKeyUUID
;
815 aks_volume_key_t vek
;
816 static IOService
* sKeyStore
;
817 static const OSSymbol
* sAKSGetKey
;
820 sAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
822 sKeyStore
= (IOService
*) IORegistryEntry::fromPath(AKS_SERVICE_PATH
, gIOServicePlane
);
824 err
= uuid_parse(keyStoreUUID
->getCStringNoCopy(), volumeKeyUUID
);
826 err
= kIOReturnNoResources
;
827 if (kIOReturnSuccess
== err
)
828 err
= sKeyStore
->callPlatformFunction(sAKSGetKey
, true, volumeKeyUUID
, &vek
, NULL
, NULL
);
829 if (kIOReturnSuccess
!= err
)
830 IOLog("volume key err 0x%x\n", err
);
833 size_t bytes
= (kIOHibernateAESKeySize
/ 8);
834 if (vek
.key
.keybytecount
< bytes
)
835 bytes
= vek
.key
.keybytecount
;
836 bcopy(&vek
.key
.keybytes
[0], volumeCryptKey
, bytes
);
838 bzero(&vek
, sizeof(vek
));
842 part
= IOCopyMediaForDev(hibernate_image_dev
);
845 err
= kIOReturnNotFound
;
849 vars
->pollers
= OSArray::withCapacity(4);
852 err
= kIOReturnNoMemory
;
856 err
= GetImageBlockSize(part
, vars
->pollers
, &vars
->blockSize
);
858 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
859 major(hibernate_image_dev
), minor(hibernate_image_dev
), (long)vars
->blockSize
,
860 vars
->pollers
->getCount());
862 if (err
!= kIOReturnSuccess
)
865 IORegistryEntry
* next
;
867 if (vars
->blockSize
< sizeof(IOHibernateImageHeader
))
869 err
= kIOReturnError
;
873 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
874 if (kIOReturnSuccess
!= err
) break;
876 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
877 if (kIOReturnSuccess
!= err
) break;
883 next
->setProperty(kIOPolledInterfaceActiveKey
, kOSBooleanTrue
);
884 next
= next
->getParentEntry(gIOServicePlane
);
888 *fileExtents
= extentsData
;
892 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
894 char str2
[24 + sizeof(uuid_string_t
) + 2];
896 #if defined(__i386__) || defined(__x86_64__)
897 if (!gIOCreateEFIDevicePathSymbol
)
898 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
901 snprintf(str2
, sizeof(str2
), "%qx:%s",
902 vars
->extentMap
[0].start
, keyUUID
->getCStringNoCopy());
904 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
906 err
= IOService::getPlatform()->callPlatformFunction(
907 gIOCreateEFIDevicePathSymbol
, false,
908 (void *) part
, (void *) str2
,
909 (void *) (uintptr_t) true, (void *) &data
);
912 int len
= sizeof(str1
);
914 if (!part
->getPath(str1
, &len
, gIODTPlane
))
915 err
= kIOReturnNotFound
;
918 snprintf(str2
, sizeof(str2
), ",%qx", vars
->extentMap
[0].start
);
919 // (strip the plane name)
920 char * tail
= strchr(str1
, ':');
923 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
924 data
->appendBytes(str2
, strlen(str2
));
927 if (kIOReturnSuccess
== err
)
930 HIBLOG("error 0x%x getting path\n", err
);
935 if (kIOReturnSuccess
!= err
)
937 HIBLOG("error 0x%x opening hibernation file\n", err
);
940 kern_close_file_for_direct_io(vars
->fileRef
, 0, 0, 0, 0, 0);
941 vars
->fileRef
= NULL
;
946 WriteExtentsToFile(vars
->fileRef
, kIOHibernateHeaderOpenSignature
, vars
->blockSize
,
947 (IOPolledFileExtent
*)extentsData
->getBytesNoCopy(),
948 extentsData
->getLength());
958 IOPolledFileClose( IOPolledFileIOVars
* vars
)
962 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
963 vars
->pollers
->release();
966 bzero(vars
, sizeof(IOPolledFileIOVars
));
968 return (kIOReturnSuccess
);
972 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
974 IOPolledFileExtent
* extentMap
;
976 extentMap
= vars
->extentMap
;
978 vars
->position
= position
;
980 while (position
>= extentMap
->length
)
982 position
-= extentMap
->length
;
986 vars
->currentExtent
= extentMap
;
987 vars
->extentRemaining
= extentMap
->length
- position
;
988 vars
->extentPosition
= vars
->position
- position
;
990 if (vars
->bufferSize
<= vars
->extentRemaining
)
991 vars
->bufferLimit
= vars
->bufferSize
;
993 vars
->bufferLimit
= vars
->extentRemaining
;
995 return (kIOReturnSuccess
);
999 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
1000 const uint8_t * bytes
, IOByteCount size
,
1001 hibernate_cryptvars_t
* cryptvars
)
1003 IOReturn err
= kIOReturnSuccess
;
1009 if (!bytes
&& !size
)
1011 // seek to end of block & flush
1012 size
= vars
->position
& (vars
->blockSize
- 1);
1014 size
= vars
->blockSize
- size
;
1016 // use some garbage for the fill
1017 bytes
= vars
->buffer
+ vars
->bufferOffset
;
1020 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
1028 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
1032 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
1035 vars
->bufferOffset
+= copy
;
1036 vars
->position
+= copy
;
1038 if (flush
&& vars
->bufferOffset
)
1040 uint64_t offset
= (vars
->position
- vars
->bufferOffset
1041 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1042 uint32_t length
= (vars
->bufferOffset
);
1045 if (cryptvars
&& vars
->encryptStart
1046 && (vars
->position
> vars
->encryptStart
)
1047 && ((vars
->position
- length
) < vars
->encryptEnd
))
1049 AbsoluteTime startTime
, endTime
;
1051 uint64_t encryptLen
, encryptStart
;
1052 encryptLen
= vars
->position
- vars
->encryptStart
;
1053 if (encryptLen
> length
)
1054 encryptLen
= length
;
1055 encryptStart
= length
- encryptLen
;
1056 if (vars
->position
> vars
->encryptEnd
)
1057 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
1059 clock_get_uptime(&startTime
);
1061 // encrypt the buffer
1062 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
1063 &cryptvars
->aes_iv
[0],
1064 encryptLen
/ AES_BLOCK_SIZE
,
1065 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
1066 &cryptvars
->ctx
.encrypt
);
1068 clock_get_uptime(&endTime
);
1069 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1070 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1071 vars
->cryptBytes
+= encryptLen
;
1073 // save initial vector for following encrypts
1074 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
1075 &cryptvars
->aes_iv
[0],
1082 err
= IOHibernatePollerIODone(vars
, true);
1083 if (kIOReturnSuccess
!= err
)
1087 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
1088 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
1090 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
1091 if (kIOReturnSuccess
!= err
)
1095 vars
->extentRemaining
-= vars
->bufferOffset
;
1096 if (!vars
->extentRemaining
)
1098 vars
->currentExtent
++;
1099 vars
->extentRemaining
= vars
->currentExtent
->length
;
1100 vars
->extentPosition
= vars
->position
;
1101 if (!vars
->extentRemaining
)
1103 err
= kIOReturnOverrun
;
1108 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1109 vars
->bufferOffset
= 0;
1110 if (vars
->bufferSize
<= vars
->extentRemaining
)
1111 vars
->bufferLimit
= vars
->bufferSize
;
1113 vars
->bufferLimit
= vars
->extentRemaining
;
1124 IOPolledFileRead(IOPolledFileIOVars
* vars
,
1125 uint8_t * bytes
, IOByteCount size
,
1126 hibernate_cryptvars_t
* cryptvars
)
1128 IOReturn err
= kIOReturnSuccess
;
1131 // bytesWritten += size;
1135 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
1141 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1145 vars
->bufferOffset
+= copy
;
1146 // vars->position += copy;
1148 if ((vars
->bufferOffset
== vars
->bufferLimit
) && (vars
->position
< vars
->readEnd
))
1152 err
= IOHibernatePollerIODone(vars
, false);
1153 if (kIOReturnSuccess
!= err
)
1159 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
1161 vars
->position
+= vars
->lastRead
;
1162 vars
->extentRemaining
-= vars
->lastRead
;
1163 vars
->bufferLimit
= vars
->lastRead
;
1165 if (!vars
->extentRemaining
)
1167 vars
->currentExtent
++;
1168 vars
->extentRemaining
= vars
->currentExtent
->length
;
1169 vars
->extentPosition
= vars
->position
;
1170 if (!vars
->extentRemaining
)
1172 err
= kIOReturnOverrun
;
1178 uint64_t lastReadLength
= vars
->lastRead
;
1179 uint64_t offset
= (vars
->position
1180 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1181 if (vars
->extentRemaining
<= vars
->bufferSize
)
1182 length
= vars
->extentRemaining
;
1184 length
= vars
->bufferSize
;
1185 if ((length
+ vars
->position
) > vars
->readEnd
)
1186 length
= vars
->readEnd
- vars
->position
;
1188 vars
->lastRead
= length
;
1191 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1192 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
1193 if (kIOReturnSuccess
!= err
)
1198 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1199 vars
->bufferOffset
= 0;
1204 uint8_t thisVector
[AES_BLOCK_SIZE
];
1205 AbsoluteTime startTime
, endTime
;
1207 // save initial vector for following decrypts
1208 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
1209 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
1210 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1212 // decrypt the buffer
1213 clock_get_uptime(&startTime
);
1215 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
1217 lastReadLength
/ AES_BLOCK_SIZE
,
1218 vars
->buffer
+ vars
->bufferHalf
,
1219 &cryptvars
->ctx
.decrypt
);
1221 clock_get_uptime(&endTime
);
1222 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1223 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1224 vars
->cryptBytes
+= lastReadLength
;
1234 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1238 IOHibernateOpenForDebugData( )
1241 OSData
*extentsData
= NULL
;
1244 IOByteCount blockSize
= 0;
1246 IOService
* part
= 0;
1247 OSData
* data
= NULL
;
1249 IOPolledFileExtent
* fileExtents
;
1250 IOReturn err
= kIOReturnSuccess
;
1251 IORegistryEntry
* regEntry
;
1252 OSArray
* pollers
= NULL
;
1254 _OpenFileContext ctx
;
1256 if (gDebugImageFileRef
!= NULL
)
1257 return kIOReturnError
;
1259 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1261 if ((str
= OSDynamicCast(OSString
, obj
)))
1262 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1263 sizeof(gIOHibernateFilename
));
1267 if (!gIOHibernateFilename
[0]) {
1268 HIBLOG("Failed to get hibernate image filename\n");
1269 return (kIOReturnUnsupported
);
1272 extentsData
= OSData::withCapacity(32);
1273 ctx
.extents
= extentsData
;
1276 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1277 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1278 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1280 gDebugImageFileRef
= kern_open_file_for_direct_io(gIOHibernateFilename
,
1282 &file_extent_callback
, &ctx
,
1284 (caddr_t
)gIOHibernateCurrentHeader
,
1285 sizeof(IOHibernateImageHeader
),
1286 NULL
, &image_dev
, NULL
, NULL
, NULL
);
1288 if (gDebugImageFileRef
== NULL
)
1290 HIBLOG("Failed to open the file \n");
1291 err
= kIOReturnError
;
1294 fileExtents
= (IOPolledFileExtent
*)extentsData
->getBytesNoCopy();
1295 size
= extentsData
->getLength();
1297 part
= IOCopyMediaForDev(image_dev
);
1300 HIBLOG("Failed to get the media device\n");
1301 err
= kIOReturnNotFound
;
1306 pollers
= OSArray::withCapacity(4);
1309 err
= kIOReturnNoMemory
;
1313 err
= GetImageBlockSize(part
, pollers
, &blockSize
);
1314 if (err
!= kIOReturnSuccess
)
1316 HIBLOG("Failed to get block size\n");
1319 if (blockSize
< sizeof(IOHibernateImageHeader
))
1321 HIBLOG("block size %llu is less than the size of the header\n", blockSize
);
1322 err
= kIOReturnError
;
1326 WriteExtentsToFile(gDebugImageFileRef
, kIOHibernateHeaderOpenSignature
,
1327 blockSize
, fileExtents
, size
);
1329 char str2
[24 + sizeof(uuid_string_t
) + 2];
1331 if (!gIOCreateEFIDevicePathSymbol
)
1332 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
1334 snprintf(str2
, sizeof(str2
), "%qx", fileExtents
[0].start
);
1336 err
= IOService::getPlatform()->callPlatformFunction(
1337 gIOCreateEFIDevicePathSymbol
, false,
1338 (void *) part
, (void *) str2
,
1339 (void *) (uintptr_t) true, (void *) &data
);
1341 if (!gIOOptionsEntry
)
1343 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1344 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1345 if (regEntry
&& !gIOOptionsEntry
)
1346 regEntry
->release();
1348 if (gIOOptionsEntry
)
1350 const OSSymbol
* sym
;
1352 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1355 gIOOptionsEntry
->setProperty(sym
, data
);
1363 if ( (err
!= kIOReturnSuccess
) && gDebugImageFileRef
) {
1364 kern_close_file_for_direct_io(gDebugImageFileRef
, 0, 0, 0, 0, 0);
1365 gDebugImageFileRef
= NULL
;
1367 if (extentsData
) extentsData
->release();
1368 if (part
) part
->release();
1369 if (pollers
) pollers
->release();
1370 if (data
) data
->release();
1376 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1379 IOHibernateSystemSleep(void)
1386 bool dsSSD
, vmflush
;
1387 IOHibernateVars
* vars
;
1389 gIOHibernateState
= kIOHibernateStateInactive
;
1391 if (!gIOChosenEntry
)
1392 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1394 gIOHibernateDebugFlags
= 0;
1395 if (kIOLogHibernate
& gIOKitDebug
)
1396 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
1398 if (IOService::getPMRootDomain()->getHibernateSettings(
1399 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
1401 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1402 // default to discard clean for safe sleep
1403 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
1404 | kIOHibernateModeDiscardCleanActive
);
1407 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1409 if ((str
= OSDynamicCast(OSString
, obj
)))
1410 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1411 sizeof(gIOHibernateFilename
));
1415 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1416 return (kIOReturnUnsupported
);
1418 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1420 vars
= IONew(IOHibernateVars
, 1);
1421 if (!vars
) return (kIOReturnNoMemory
);
1422 bzero(vars
, sizeof(*vars
));
1424 IOLockLock(gFSLock
);
1425 if (kFSIdle
!= gFSState
)
1427 HIBLOG("hibernate file busy\n");
1428 IOLockUnlock(gFSLock
);
1429 IODelete(vars
, IOHibernateVars
, 1);
1430 return (kIOReturnBusy
);
1432 gFSState
= kFSOpening
;
1433 IOLockUnlock(gFSLock
);
1437 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1438 2 * page_size
+ WKdm_SCRATCH_BUF_SIZE
, page_size
);
1439 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1440 2 * kDefaultIOSize
, page_size
);
1442 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1443 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
1445 if (!vars
->srcBuffer
|| !vars
->ioBuffer
|| !vars
->handoffBuffer
)
1447 err
= kIOReturnNoMemory
;
1451 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey
)))
1453 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMinSize
= num
->unsigned64BitValue();
1456 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey
)))
1458 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMaxSize
= num
->unsigned64BitValue();
1462 boolean_t encryptedswap
= true;
1464 AbsoluteTime startTime
, endTime
;
1467 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1468 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1469 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1471 vmflush
= (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
));
1472 uint64_t setFileSize
= 0;
1473 err
= hibernate_alloc_page_lists(&vars
->page_list
,
1474 &vars
->page_list_wired
,
1475 &vars
->page_list_pal
);
1476 if (KERN_SUCCESS
!= err
)
1479 if (vars
->fileMinSize
|| (kIOHibernateModeFileResize
& gIOHibernateMode
))
1481 hibernate_page_list_setall(vars
->page_list
,
1482 vars
->page_list_wired
,
1483 vars
->page_list_pal
,
1484 true /* preflight */,
1485 vmflush
/* discard */,
1487 PE_Video consoleInfo
;
1488 bzero(&consoleInfo
, sizeof(consoleInfo
));
1489 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1491 // estimate: 6% increase in pages compressed
1492 // screen preview 2 images compressed 0%
1493 setFileSize
= ((ptoa_64((106 * pageCount
) / 100) * gIOHibernateCompression
) >> 8)
1494 + vars
->page_list
->list_size
1495 + (consoleInfo
.v_width
* consoleInfo
.v_height
* 8);
1496 enum { setFileRound
= 1024*1024ULL };
1497 setFileSize
= ((setFileSize
+ setFileRound
) & ~(setFileRound
- 1));
1499 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
1500 pageCount
, (100ULL * gIOHibernateCompression
) >> 8,
1501 setFileSize
, vars
->fileMinSize
);
1503 if (!(kIOHibernateModeFileResize
& gIOHibernateMode
)
1504 && (setFileSize
< vars
->fileMinSize
))
1506 setFileSize
= vars
->fileMinSize
;
1510 // open & invalidate the image file
1512 if (gDebugImageFileRef
) {
1513 kern_close_file_for_direct_io(gDebugImageFileRef
, 0, 0, 0, 0, 0);
1514 gDebugImageFileRef
= NULL
;
1517 err
= IOPolledFileOpen(gIOHibernateFilename
, setFileSize
, vars
->ioBuffer
,
1518 &vars
->fileVars
, &vars
->fileExtents
, &data
,
1519 &vars
->volumeCryptKey
[0]);
1521 if (KERN_SUCCESS
!= err
)
1523 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1527 clock_get_uptime(&startTime
);
1528 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1529 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1531 vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1532 clock_get_uptime(&endTime
);
1533 SUB_ABSOLUTETIME(&endTime
, &startTime
);
1534 absolutetime_to_nanoseconds(endTime
, &nsec
);
1535 HIBLOG("hibernate_setup(%d) took %qd ms\n", err
, nsec
/ 1000000ULL);
1537 dsSSD
= ((0 != (kIOHibernateOptionSSD
& vars
->fileVars
->flags
))
1538 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
1541 gIOHibernateCurrentHeader
->options
|=
1542 kIOHibernateOptionSSD
1543 | kIOHibernateOptionColor
;
1545 #if defined(__i386__) || defined(__x86_64__)
1546 if (!uuid_is_null(vars
->volumeCryptKey
) &&
1547 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
)))
1549 uintptr_t smcVars
[2];
1550 smcVars
[0] = sizeof(vars
->volumeCryptKey
);
1551 smcVars
[1] = (uintptr_t)(void *) &gIOHibernateVars
.volumeCryptKey
[0];
1553 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
1554 bzero(smcVars
, sizeof(smcVars
));
1560 gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
1564 if (KERN_SUCCESS
!= err
)
1567 if (encryptedswap
|| !uuid_is_null(vars
->volumeCryptKey
))
1568 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1570 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1572 vars
->videoAllocSize
= kVideoMapSize
;
1573 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1574 vars
->videoMapping
= 0;
1577 // generate crypt keys
1578 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1579 vars
->wiredCryptKey
[i
] = random();
1580 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1581 vars
->cryptKey
[i
] = random();
1585 IORegistryEntry
* regEntry
;
1586 if (!gIOOptionsEntry
)
1588 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1589 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1590 if (regEntry
&& !gIOOptionsEntry
)
1591 regEntry
->release();
1594 if (gIOOptionsEntry
)
1596 const OSSymbol
* sym
;
1598 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1601 gIOOptionsEntry
->setProperty(sym
, data
);
1606 #if defined(__i386__) || defined(__x86_64__)
1607 struct AppleRTCHibernateVars
1609 uint8_t signature
[4];
1611 uint8_t booterSignature
[20];
1612 uint8_t wiredCryptKey
[16];
1614 AppleRTCHibernateVars rtcVars
;
1616 rtcVars
.signature
[0] = 'A';
1617 rtcVars
.signature
[1] = 'A';
1618 rtcVars
.signature
[2] = 'P';
1619 rtcVars
.signature
[3] = 'L';
1620 rtcVars
.revision
= 1;
1621 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1622 if (gIOHibernateBootSignature
[0])
1626 for (uint32_t i
= 0;
1627 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1638 value
= (value
<< 4) | c
;
1640 rtcVars
.booterSignature
[i
>> 1] = value
;
1643 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1646 if (!gIOHibernateRTCVariablesKey
)
1647 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1648 if (gIOHibernateRTCVariablesKey
)
1649 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
1651 if( gIOOptionsEntry
)
1653 if( gIOHibernateMode
& kIOHibernateModeSwitch
)
1655 const OSSymbol
*sym
;
1656 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey
);
1659 gIOOptionsEntry
->setProperty(sym
, data
); /* intentional insecure backup of rtc boot vars */
1669 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1671 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1675 if (!gIOHibernateBoot0082Data
)
1677 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
1680 // AppleNVRAM_EFI_LOAD_OPTION
1682 uint32_t Attributes
;
1683 uint16_t FilePathLength
;
1686 loadOptionHeader
.Attributes
= 1;
1687 loadOptionHeader
.FilePathLength
= data
->getLength();
1688 loadOptionHeader
.Desc
= 0;
1689 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
1690 if (gIOHibernateBoot0082Data
)
1692 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
1693 gIOHibernateBoot0082Data
->appendBytes(data
);
1697 if (!gIOHibernateBoot0082Key
)
1698 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1699 if (!gIOHibernateBootNextKey
)
1700 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1701 if (!gIOHibernateBootNextData
)
1703 uint16_t bits
= 0x0082;
1704 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
1706 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
1708 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
1709 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
1710 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
1714 #else /* !i386 && !x86_64 */
1715 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1717 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1718 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1720 gIOOptionsEntry
->setProperty(sym
, data
);
1725 if (false && gIOHibernateBootSignature
[0])
1727 data
= OSData::withCapacity(16);
1728 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1733 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1743 value
= (value
<< 4) | c
;
1745 data
->appendBytes(&value
, sizeof(value
));
1747 gIOOptionsEntry
->setProperty(sym
, data
);
1755 if (!vars
->haveFastBoot
)
1757 // set boot volume to zero
1758 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1759 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1760 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1763 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1764 platform
->writeXPRAM(kXPRamAudioVolume
,
1765 &newVolume
, sizeof(newVolume
));
1768 #endif /* !i386 && !x86_64 */
1775 IOLockLock(gFSLock
);
1776 if ((kIOReturnSuccess
== err
) && (kFSOpening
== gFSState
))
1778 gFSState
= kFSOpened
;
1779 gIOHibernateVars
= *vars
;
1780 gFileVars
= *vars
->fileVars
;
1781 gIOHibernateVars
.fileVars
= &gFileVars
;
1782 gIOHibernateFileRef
= gFileVars
.fileRef
;
1783 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1784 gIOHibernateState
= kIOHibernateStateHibernating
;
1788 HIBLOG("hibernate file close due timeout\n");
1789 if (vars
->fileVars
&& vars
->fileVars
->fileRef
) kern_close_file_for_direct_io(vars
->fileVars
->fileRef
, 0, 0, 0, 0, 0);
1790 IOHibernateDone(vars
);
1793 IOLockUnlock(gFSLock
);
1795 if (vars
->fileVars
) IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
1796 IODelete(vars
, IOHibernateVars
, 1);
1801 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1803 DECLARE_IOHIBERNATEPROGRESSALPHA
1806 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
1808 uint32_t rowBytes
, pixelShift
;
1811 uint32_t alpha
, in
, color
, result
;
1813 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1815 rowBytes
= display
->rowBytes
;
1816 pixelShift
= display
->depth
>> 4;
1817 if (pixelShift
< 1) return;
1819 screen
+= ((display
->width
1820 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1821 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1823 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1825 out
= screen
+ y
* rowBytes
;
1826 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
1828 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
1829 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1831 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1837 if (1 == pixelShift
)
1839 in
= *((uint16_t *)out
) & 0x1f; // 16
1840 in
= (in
<< 3) | (in
>> 2);
1843 in
= *((uint32_t *)out
) & 0xff; // 32
1844 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1845 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1847 if (1 == pixelShift
)
1850 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1853 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1855 out
+= (1 << pixelShift
);
1857 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1864 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1866 uint32_t rowBytes
, pixelShift
;
1868 int32_t blob
, lastBlob
;
1869 uint32_t alpha
, in
, color
, result
;
1871 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1873 pixelShift
= display
->depth
>> 4;
1877 rowBytes
= display
->rowBytes
;
1879 screen
+= ((display
->width
1880 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1881 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1883 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1885 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1887 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1889 out
= screen
+ y
* rowBytes
;
1890 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1892 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1893 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1895 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1901 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1902 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1904 if (1 == pixelShift
)
1907 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1910 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1912 out
+= (1 << pixelShift
);
1914 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1919 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1922 IOHibernateIOKitSleep(void)
1924 IOReturn ret
= kIOReturnSuccess
;
1925 IOLockLock(gFSLock
);
1926 if (kFSOpening
== gFSState
)
1928 gFSState
= kFSTimedOut
;
1929 HIBLOG("hibernate file open timed out\n");
1930 ret
= kIOReturnTimeout
;
1932 IOLockUnlock(gFSLock
);
1936 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1939 IOHibernateSystemHasSlept(void)
1941 IOReturn ret
= kIOReturnSuccess
;
1942 IOHibernateVars
* vars
= &gIOHibernateVars
;
1946 IOLockLock(gFSLock
);
1947 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
)
1949 ret
= kIOReturnTimeout
;
1951 IOLockUnlock(gFSLock
);
1952 if (kIOReturnSuccess
!= ret
) return (ret
);
1954 if (gIOHibernateMode
) obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1955 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1956 if (obj
&& !vars
->previewBuffer
)
1959 vars
->consoleMapping
= NULL
;
1960 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1962 vars
->previewBuffer
->release();
1963 vars
->previewBuffer
= 0;
1966 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1967 && vars
->previewBuffer
1968 && (data
= OSDynamicCast(OSData
,
1969 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1971 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1972 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1974 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1976 if (kIOHibernatePreviewUpdates
& flags
)
1978 PE_Video consoleInfo
;
1979 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1981 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1983 graphicsInfo
->width
= consoleInfo
.v_width
;
1984 graphicsInfo
->height
= consoleInfo
.v_height
;
1985 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1986 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1987 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1989 HIBPRINT("video %p %d %d %d\n",
1990 vars
->consoleMapping
, graphicsInfo
->depth
,
1991 graphicsInfo
->width
, graphicsInfo
->height
);
1992 if (vars
->consoleMapping
)
1993 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1994 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1998 if (gIOOptionsEntry
)
1999 gIOOptionsEntry
->sync();
2004 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006 static DeviceTreeNode
*
2007 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
2009 DeviceTreeNodeProperty
* prop
;
2010 DeviceTreeNode
* child
;
2011 IORegistryEntry
* childRegEntry
;
2012 const char * nameProp
;
2013 unsigned int propLen
, idx
;
2015 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
2016 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
2018 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
2020 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
2021 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
2023 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
2026 child
= (DeviceTreeNode
*) prop
;
2027 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
2029 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
2031 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
2032 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
2033 child
= MergeDeviceTree(child
, childRegEntry
);
2039 IOHibernateSystemWake(void)
2041 if (kFSOpened
== gFSState
)
2043 IOHibernateDone(&gIOHibernateVars
);
2047 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
2048 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
2050 return (kIOReturnSuccess
);
2054 IOHibernateDone(IOHibernateVars
* vars
)
2056 IORegistryEntry
* next
;
2058 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
2060 if (vars
->videoMapping
)
2062 if (vars
->videoMapSize
)
2064 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
2065 if (vars
->videoAllocSize
)
2067 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
2070 if (vars
->previewBuffer
)
2072 vars
->previewBuffer
->release();
2073 vars
->previewBuffer
= 0;
2076 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2078 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
2079 gIOHibernateCurrentHeader
->options
, 32);
2083 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
2086 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2087 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
2089 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
2090 &gIOHibernateGraphicsInfo
->gfxStatus
,
2091 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
2095 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
2100 if ((next
= vars
->fileVars
->media
)) do
2102 next
->removeProperty(kIOPolledInterfaceActiveKey
);
2103 next
= next
->getParentEntry(gIOServicePlane
);
2106 IOPolledFileClose(vars
->fileVars
);
2109 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
2111 #if defined(__i386__) || defined(__x86_64__)
2112 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
2113 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
2116 * Hibernate variable is written to NVRAM on platforms in which RtcRam
2117 * is not backed by coin cell. Remove Hibernate data from NVRAM.
2119 if (gIOOptionsEntry
) {
2121 if (gIOHibernateRTCVariablesKey
) {
2122 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
2123 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
2127 if (gIOHibernateBootNextKey
)
2129 if (gIOHibernateBootNextSave
)
2131 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
2132 gIOHibernateBootNextSave
->release();
2133 gIOHibernateBootNextSave
= NULL
;
2136 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
2138 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) gIOOptionsEntry
->sync();
2142 if (vars
->srcBuffer
)
2143 vars
->srcBuffer
->release();
2145 vars
->ioBuffer
->release();
2146 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
2147 if (vars
->handoffBuffer
)
2149 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2151 IOHibernateHandoff
* handoff
;
2153 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2155 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2157 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
2158 uint8_t * data
= &handoff
->data
[0];
2159 switch (handoff
->type
)
2161 case kIOHibernateHandoffTypeEnd
:
2165 case kIOHibernateHandoffTypeDeviceTree
:
2166 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
2169 case kIOHibernateHandoffTypeKeyStore
:
2170 #if defined(__i386__) || defined(__x86_64__)
2172 IOBufferMemoryDescriptor
*
2173 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
2176 IOSetKeyStoreData(md
);
2183 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2188 vars
->handoffBuffer
->release();
2190 if (vars
->fileExtents
)
2191 vars
->fileExtents
->release();
2193 bzero(vars
, sizeof(*vars
));
2195 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
2197 return (kIOReturnSuccess
);
2201 IOHibernateSystemPostWake(void)
2203 struct kern_direct_file_io_ref_t
* fileRef
;
2205 if (kFSOpened
== gFSState
)
2207 // invalidate & close the image file
2208 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
2209 if ((fileRef
= gIOHibernateFileRef
))
2211 gIOHibernateFileRef
= 0;
2212 IOSleep(TRIM_DELAY
);
2213 kern_close_file_for_direct_io(fileRef
,
2217 0, (caddr_t
) gIOHibernateCurrentHeader
,
2218 sizeof(IOHibernateImageHeader
),
2220 gIOHibernateCurrentHeader
->imageSize
);
2226 if (gDebugImageFileRef
) {
2227 kern_close_file_for_direct_io(gDebugImageFileRef
, 0, 0, 0, 0, 0);
2228 gDebugImageFileRef
= NULL
;
2231 if (!gIOOptionsEntry
)
2233 IORegistryEntry
* regEntry
;
2234 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2235 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
2236 if (regEntry
&& !gIOOptionsEntry
)
2237 regEntry
->release();
2239 if (gIOOptionsEntry
)
2241 const OSSymbol
* sym
;
2243 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
2246 gIOOptionsEntry
->removeProperty(sym
);
2247 gIOOptionsEntry
->sync();
2252 return (kIOReturnSuccess
);
2255 bool IOHibernateWasScreenLocked(void)
2258 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
)
2261 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
2262 if (data
) switch (*((uint32_t *)data
->getBytesNoCopy()))
2264 case kIOScreenLockLocked
:
2265 case kIOScreenLockFileVaultDialog
:
2268 case kIOScreenLockNoLock
:
2269 case kIOScreenLockUnlocked
:
2278 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2280 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
2281 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2282 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
2283 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
2284 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2285 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
2286 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
2287 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2288 &gIOHibernateMode
, 0, "");
2289 SYSCTL_STRUCT(_kern
, OID_AUTO
, hibernatestatistics
,
2290 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2291 gIOHibernateStats
, hibernate_statistics_t
, "");
2293 SYSCTL_UINT(_kern
, OID_AUTO
, hibernategraphicsready
,
2294 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2295 &gIOHibernateStats
->graphicsReadyTime
, 0, "");
2296 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatewakenotification
,
2297 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2298 &gIOHibernateStats
->wakeNotificationTime
, 0, "");
2299 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatelockscreenready
,
2300 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2301 &gIOHibernateStats
->lockScreenReadyTime
, 0, "");
2302 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatehidready
,
2303 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2304 &gIOHibernateStats
->hidReadyTime
, 0, "");
2308 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
2310 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
2313 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
2317 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
2318 gIOHibernateMode
= kIOHibernateModeOn
;
2320 gIOHibernateFilename
[0] = 0;
2322 sysctl_register_oid(&sysctl__kern_hibernatefile
);
2323 sysctl_register_oid(&sysctl__kern_bootsignature
);
2324 sysctl_register_oid(&sysctl__kern_hibernatemode
);
2325 sysctl_register_oid(&sysctl__kern_hibernatestatistics
);
2326 sysctl_register_oid(&sysctl__kern_hibernategraphicsready
);
2327 sysctl_register_oid(&sysctl__kern_hibernatewakenotification
);
2328 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready
);
2329 sysctl_register_oid(&sysctl__kern_hibernatehidready
);
2331 gFSLock
= IOLockAlloc();
2335 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2338 hibernate_setup_for_wake(void)
2342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2344 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
2347 no_encrypt_page(vm_offset_t ppnum
)
2349 if (pmap_is_noencrypt((ppnum_t
)ppnum
) == TRUE
)
2357 hibernate_pal_callback(void *vars_arg
, vm_offset_t addr
)
2359 IOHibernateVars
*vars
= (IOHibernateVars
*)vars_arg
;
2360 /* Make sure it's not in either of the save lists */
2361 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
, atop_64(addr
), 1, kIOHibernatePageStateFree
);
2363 /* Set it in the bitmap of pages owned by the PAL */
2364 hibernate_page_bitset(vars
->page_list_pal
, TRUE
, atop_64(addr
));
2367 static struct hibernate_cryptvars_t
*local_cryptvars
;
2370 hibernate_pal_write(void *buffer
, size_t size
)
2372 IOHibernateVars
* vars
= &gIOHibernateVars
;
2374 IOReturn err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *)buffer
, size
, local_cryptvars
);
2375 if (kIOReturnSuccess
!= err
) {
2376 kprintf("epic hibernate fail! %d\n", err
);
2385 hibernate_write_image(void)
2387 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
2388 IOHibernateVars
* vars
= &gIOHibernateVars
;
2389 IOPolledFileExtent
* fileExtents
;
2391 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
2393 uint32_t pageCount
, pagesDone
;
2395 vm_offset_t ppnum
, page
;
2399 uint8_t * compressed
;
2401 void * zerosCompressed
;
2402 IOByteCount pageCompressedSize
, zerosCompressedLen
;
2403 uint64_t compressedSize
, uncompressedSize
;
2404 uint64_t image1Size
= 0;
2405 uint32_t bitmap_size
;
2406 bool iterDone
, pollerOpen
, needEncrypt
;
2407 uint32_t restore1Sum
, sum
, sum1
, sum2
;
2411 uint32_t pageAndCount
[2];
2415 AbsoluteTime startTime
, endTime
;
2416 AbsoluteTime allTime
, compTime
;
2419 uint32_t lastProgressStamp
= 0;
2420 uint32_t progressStamp
;
2421 uint32_t blob
, lastBlob
= (uint32_t) -1L;
2423 uint32_t wiredPagesEncrypted
;
2424 uint32_t dirtyPagesEncrypted
;
2425 uint32_t wiredPagesClear
;
2426 uint32_t zeroPageCount
;
2428 hibernate_cryptvars_t _cryptvars
;
2429 hibernate_cryptvars_t
* cryptvars
= 0;
2431 wiredPagesEncrypted
= 0;
2432 dirtyPagesEncrypted
= 0;
2433 wiredPagesClear
= 0;
2436 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2437 return (false /* sleep */ );
2439 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2440 kdebug_enable
= save_kdebug_enable
;
2442 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
, 0, 0, 0, 0, 0);
2443 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
2445 restore1Sum
= sum1
= sum2
= 0;
2447 hibernate_pal_prepare();
2450 // encryption data. "iv" is the "initial vector".
2451 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2453 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
2454 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
2455 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
2457 cryptvars
= &gIOHibernateCryptWakeContext
;
2458 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
2459 aes_encrypt_key(vars
->cryptKey
,
2460 kIOHibernateAESKeySize
,
2461 &cryptvars
->ctx
.encrypt
);
2462 aes_decrypt_key(vars
->cryptKey
,
2463 kIOHibernateAESKeySize
,
2464 &cryptvars
->ctx
.decrypt
);
2466 cryptvars
= &_cryptvars
;
2467 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
2468 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++)
2469 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
2470 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
2471 aes_encrypt_key(vars
->wiredCryptKey
,
2472 kIOHibernateAESKeySize
,
2473 &cryptvars
->ctx
.encrypt
);
2475 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
2476 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
2477 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
2479 local_cryptvars
= cryptvars
;
2483 hibernate_setup_for_wake();
2485 hibernate_page_list_setall(vars
->page_list
,
2486 vars
->page_list_wired
,
2487 vars
->page_list_pal
,
2488 false /* !preflight */,
2490 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
2491 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
2494 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
2496 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
2499 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
2500 for (page
= 0; page
< count
; page
++)
2502 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
2503 fileExtents
[page
].start
, fileExtents
[page
].length
,
2504 fileExtents
[page
].start
+ fileExtents
[page
].length
);
2508 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
2509 AbsoluteTime_to_scalar(&compTime
) = 0;
2512 clock_get_uptime(&allTime
);
2513 IOService::getPMRootDomain()->pmStatsRecordEvent(
2514 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
2518 uncompressedSize
= 0;
2521 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
2523 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
2524 ml_get_interrupts_enabled());
2525 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
2526 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2527 pollerOpen
= (kIOReturnSuccess
== err
);
2531 // copy file block extent list if larger than header
2533 count
= vars
->fileExtents
->getLength();
2534 if (count
> sizeof(header
->fileExtentMap
))
2536 count
-= sizeof(header
->fileExtentMap
);
2537 err
= IOPolledFileWrite(vars
->fileVars
,
2538 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
2539 if (kIOReturnSuccess
!= err
)
2543 uintptr_t hibernateBase
;
2544 uintptr_t hibernateEnd
;
2546 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
2548 hibernateEnd
= (segHIBB
+ segSizeHIB
);
2550 // copy out restore1 code
2553 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2556 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
2558 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
2562 page
= atop_32(kvtophys(hibernateBase
));
2563 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
2564 header
->restore1CodePhysPage
= page
;
2565 header
->restore1CodeVirt
= hibernateBase
;
2566 header
->restore1PageCount
= count
;
2567 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
2568 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
2570 // sum __HIB seg, with zeros for the stack
2571 src
= (uint8_t *) trunc_page(hibernateBase
);
2572 for (page
= 0; page
< count
; page
++)
2574 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
2575 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
2577 restore1Sum
+= 0x00000000;
2582 // write the __HIB seg, with zeros for the stack
2584 src
= (uint8_t *) trunc_page(hibernateBase
);
2585 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
2588 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2589 if (kIOReturnSuccess
!= err
)
2592 err
= IOPolledFileWrite(vars
->fileVars
,
2594 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
2596 if (kIOReturnSuccess
!= err
)
2598 src
= &gIOHibernateRestoreStackEnd
[0];
2599 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
2602 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2603 if (kIOReturnSuccess
!= err
)
2607 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2609 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
2610 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2611 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2614 // write the preview buffer
2616 if (vars
->previewBuffer
)
2622 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
2623 pageAndCount
[0] = atop_64(phys64
);
2624 pageAndCount
[1] = atop_32(segLen
);
2625 err
= IOPolledFileWrite(vars
->fileVars
,
2626 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2628 if (kIOReturnSuccess
!= err
)
2631 ppnum
+= sizeof(pageAndCount
);
2634 if (kIOReturnSuccess
!= err
)
2637 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
2639 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
2641 count
= vars
->previewBuffer
->getLength();
2643 header
->previewPageListSize
= ppnum
;
2644 header
->previewSize
= count
+ ppnum
;
2646 for (page
= 0; page
< count
; page
+= page_size
)
2648 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
2649 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
2651 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2652 if (kIOReturnSuccess
!= err
)
2656 // mark areas for no save
2659 (phys64
= vars
->ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2662 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2663 atop_64(phys64
), atop_32(segLen
),
2664 kIOHibernatePageStateFree
);
2665 pageCount
-= atop_32(segLen
);
2669 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2672 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2673 atop_64(phys64
), atop_32(segLen
),
2674 kIOHibernatePageStateFree
);
2675 pageCount
-= atop_32(segLen
);
2678 // copy out bitmap of pages available for trashing during restore
2680 bitmap_size
= vars
->page_list_wired
->list_size
;
2681 src
= (uint8_t *) vars
->page_list_wired
;
2682 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
2683 if (kIOReturnSuccess
!= err
)
2686 // mark more areas for no save, but these are not available
2687 // for trashing during restore
2689 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
2692 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
2693 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
2694 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2696 kIOHibernatePageStateFree
);
2699 if (vars
->previewBuffer
) for (count
= 0;
2700 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2703 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2704 atop_64(phys64
), atop_32(segLen
),
2705 kIOHibernatePageStateFree
);
2706 pageCount
-= atop_32(segLen
);
2710 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2713 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2714 atop_64(phys64
), atop_32(segLen
),
2715 kIOHibernatePageStateFree
);
2716 pageCount
-= atop_32(segLen
);
2719 (void)hibernate_pal_callback
;
2721 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2722 compressed
= src
+ page_size
;
2723 scratch
= compressed
+ page_size
;
2725 // compress a zero page
2726 bzero(src
, page_size
);
2727 zerosCompressed
= vars
->handoffBuffer
->getBytesNoCopy();
2728 zerosCompressedLen
= WKdm_compress_new((WK_word
*) src
,
2729 (WK_word
*) zerosCompressed
,
2736 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
2737 bitmap_size
, header
->previewSize
,
2738 pageCount
, vars
->fileVars
->position
);
2745 kWiredEncrypt
= kWired
| kEncrypt
,
2746 kWiredClear
= kWired
,
2747 kUnwiredEncrypt
= kEncrypt
2750 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
2752 if (kUnwiredEncrypt
== pageType
)
2754 // start unwired image
2755 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2757 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
2758 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2759 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2761 bcopy(&cryptvars
->aes_iv
[0],
2762 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2763 sizeof(cryptvars
->aes_iv
));
2764 cryptvars
= &gIOHibernateCryptWakeContext
;
2766 for (iterDone
= false, ppnum
= 0; !iterDone
; )
2768 count
= hibernate_page_list_iterate((kWired
& pageType
)
2769 ? vars
->page_list_wired
: vars
->page_list
,
2771 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2774 if (count
&& (kWired
& pageType
) && needEncrypt
)
2776 uint32_t checkIndex
;
2777 for (checkIndex
= 0;
2778 (checkIndex
< count
)
2779 && (((kEncrypt
& pageType
) == 0) == no_encrypt_page(ppnum
+ checkIndex
));
2792 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
2793 case kWiredClear
: wiredPagesClear
+= count
; break;
2794 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
2797 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
2800 pageAndCount
[0] = ppnum
;
2801 pageAndCount
[1] = count
;
2802 err
= IOPolledFileWrite(vars
->fileVars
,
2803 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2805 if (kIOReturnSuccess
!= err
)
2809 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
2811 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
2814 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
2818 sum
= hibernate_sum_page(src
, page
);
2819 if (kWired
& pageType
)
2824 clock_get_uptime(&startTime
);
2825 wkresult
= WKdm_compress_new((WK_word
*) src
,
2826 (WK_word
*) compressed
,
2830 clock_get_uptime(&endTime
);
2831 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2832 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2834 compBytes
+= page_size
;
2835 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
2837 if ((pageCompressedSize
== zerosCompressedLen
)
2838 && !bcmp(compressed
, zerosCompressed
, zerosCompressedLen
))
2840 pageCompressedSize
= 0;
2844 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2845 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
2847 if (pageCompressedSize
!= page_size
)
2852 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2853 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2854 if (kIOReturnSuccess
!= err
)
2857 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2858 if (kIOReturnSuccess
!= err
)
2861 compressedSize
+= pageCompressedSize
;
2862 uncompressedSize
+= page_size
;
2865 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2867 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2868 if (blob
!= lastBlob
)
2870 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2874 if (0 == (8191 & pagesDone
))
2876 clock_get_uptime(&endTime
);
2877 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2878 absolutetime_to_nanoseconds(endTime
, &nsec
);
2879 progressStamp
= nsec
/ 750000000ULL;
2880 if (progressStamp
!= lastProgressStamp
)
2882 lastProgressStamp
= progressStamp
;
2883 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2887 if (kIOReturnSuccess
!= err
)
2892 if (kIOReturnSuccess
!= err
)
2895 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
)
2897 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
2898 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2901 if (kWiredEncrypt
!= pageType
)
2903 // end of image1/2 - fill to next block
2904 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2905 if (kIOReturnSuccess
!= err
)
2908 if (kWiredClear
== pageType
)
2910 // enlarge wired image for test
2911 // err = IOPolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
2914 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2915 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2916 image1Size
= vars
->fileVars
->position
;
2917 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2918 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2921 if (kIOReturnSuccess
!= err
)
2923 if (kIOReturnOverrun
== err
)
2925 // update actual compression ratio on not enough space
2926 gIOHibernateCompression
= (compressedSize
<< 8) / uncompressedSize
;
2933 header
->imageSize
= vars
->fileVars
->position
;
2934 header
->image1Size
= image1Size
;
2935 header
->bitmapSize
= bitmap_size
;
2936 header
->pageCount
= pageCount
;
2938 header
->restore1Sum
= restore1Sum
;
2939 header
->image1Sum
= sum1
;
2940 header
->image2Sum
= sum2
;
2941 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
2943 header
->compression
= (compressedSize
<< 8) / uncompressedSize
;
2944 gIOHibernateCompression
= header
->compression
;
2946 count
= vars
->fileExtents
->getLength();
2947 if (count
> sizeof(header
->fileExtentMap
))
2949 header
->fileExtentMapSize
= count
;
2950 count
= sizeof(header
->fileExtentMap
);
2953 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2954 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2956 header
->deviceBase
= vars
->fileVars
->block0
;
2957 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
2959 IOPolledFileSeek(vars
->fileVars
, 0);
2960 err
= IOPolledFileWrite(vars
->fileVars
,
2961 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2963 if (kIOReturnSuccess
!= err
)
2965 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2966 if (kIOReturnSuccess
!= err
)
2968 err
= IOHibernatePollerIODone(vars
->fileVars
, true);
2969 if (kIOReturnSuccess
!= err
)
2974 clock_get_uptime(&endTime
);
2976 IOService::getPMRootDomain()->pmStatsRecordEvent(
2977 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2979 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2980 absolutetime_to_nanoseconds(endTime
, &nsec
);
2981 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
2983 absolutetime_to_nanoseconds(compTime
, &nsec
);
2984 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2987 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2989 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2990 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2991 vars
->fileVars
->cryptBytes
,
2993 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2995 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2996 header
->imageSize
, (header
->imageSize
* 100) / vars
->fileVars
->fileSize
,
2997 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2998 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
3001 HIBLOG("zeroPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
3002 zeroPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
3004 if (vars
->fileVars
->io
)
3005 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
3008 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
3010 if (vars
->consoleMapping
)
3011 ProgressUpdate(gIOHibernateGraphicsInfo
,
3012 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
3014 HIBLOG("hibernate_write_image done(%x)\n", err
);
3016 // should we come back via regular wake, set the state in memory.
3017 gIOHibernateState
= kIOHibernateStateInactive
;
3019 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
,
3020 wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
, 0, 0);
3022 if (kIOReturnSuccess
== err
)
3024 if (kIOHibernateModeSleep
& gIOHibernateMode
)
3026 return (kIOHibernatePostWriteSleep
);
3028 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
3030 return (kIOHibernatePostWriteRestart
);
3034 /* by default, power down */
3035 return (kIOHibernatePostWriteHalt
);
3038 else if (kIOReturnAborted
== err
)
3040 return (kIOHibernatePostWriteWake
);
3044 /* on error, sleep */
3045 return (kIOHibernatePostWriteSleep
);
3049 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3052 hibernate_machine_init(void)
3057 uint32_t pagesRead
= 0;
3058 AbsoluteTime startTime
, compTime
;
3059 AbsoluteTime allTime
, endTime
;
3060 AbsoluteTime startIOTime
, endIOTime
;
3061 uint64_t nsec
, nsecIO
;
3063 uint32_t lastProgressStamp
= 0;
3064 uint32_t progressStamp
;
3065 hibernate_cryptvars_t
* cryptvars
= 0;
3067 IOHibernateVars
* vars
= &gIOHibernateVars
;
3068 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
3070 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
3073 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
3074 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
3076 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
3078 HIBLOG("regular wake\n");
3082 HIBPRINT("diag %x %x %x %x\n",
3083 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
3084 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
3086 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
3087 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
3088 tStat(booterStart
, booterStart
);
3089 gIOHibernateStats
->smcStart
= gIOHibernateCurrentHeader
->smcStart
,
3090 tStat(booterDuration0
, booterTime0
);
3091 tStat(booterDuration1
, booterTime1
);
3092 tStat(booterDuration2
, booterTime2
);
3093 tStat(booterDuration
, booterTime
);
3094 tStat(booterConnectDisplayDuration
, connectDisplayTime
);
3095 tStat(booterSplashDuration
, splashTime
);
3096 tStat(trampolineDuration
, trampolineTime
);
3098 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
3099 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
3100 gIOHibernateStats
->image1Pages
= pagesDone
;
3102 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
3103 gIOHibernateStats
->booterStart
,
3104 gIOHibernateStats
->smcStart
,
3105 gIOHibernateStats
->booterDuration0
,
3106 gIOHibernateStats
->booterDuration1
,
3107 gIOHibernateStats
->booterDuration2
,
3108 gIOHibernateStats
->booterDuration
,
3109 gIOHibernateStats
->booterConnectDisplayDuration
,
3110 gIOHibernateStats
->booterSplashDuration
,
3111 gIOHibernateStats
->trampolineDuration
);
3113 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
3114 gIOHibernateState
, pagesDone
, sum
, gIOHibernateStats
->imageSize
, gIOHibernateStats
->image1Size
,
3115 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
3117 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
3118 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)))
3120 hibernate_page_list_discard(vars
->page_list
);
3123 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
3125 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
3126 panic("handoff overflow");
3128 IOHibernateHandoff
* handoff
;
3130 bool foundCryptData
= false;
3132 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
3134 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
3136 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
3137 uint8_t * data
= &handoff
->data
[0];
3138 switch (handoff
->type
)
3140 case kIOHibernateHandoffTypeEnd
:
3144 case kIOHibernateHandoffTypeGraphicsInfo
:
3145 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
3148 case kIOHibernateHandoffTypeCryptVars
:
3151 hibernate_cryptwakevars_t
*
3152 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
3153 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
3155 foundCryptData
= true;
3156 bzero(data
, handoff
->bytecount
);
3159 case kIOHibernateHandoffTypeMemoryMap
:
3161 clock_get_uptime(&allTime
);
3163 hibernate_newruntime_map(data
, handoff
->bytecount
,
3164 gIOHibernateCurrentHeader
->systemTableOffset
);
3166 clock_get_uptime(&endTime
);
3168 SUB_ABSOLUTETIME(&endTime
, &allTime
);
3169 absolutetime_to_nanoseconds(endTime
, &nsec
);
3171 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
3175 case kIOHibernateHandoffTypeDeviceTree
:
3177 // DTEntry chosen = NULL;
3178 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
3183 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
3187 if (cryptvars
&& !foundCryptData
)
3188 panic("hibernate handoff");
3190 HIBPRINT("video %x %d %d %d status %x\n",
3191 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
3192 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
3194 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
3196 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
3197 * gIOHibernateGraphicsInfo
->rowBytes
);
3198 if (vars
->videoMapSize
> vars
->videoAllocSize
) vars
->videoMapSize
= 0;
3201 IOMapPages(kernel_map
,
3202 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
3203 vars
->videoMapSize
, kIOMapInhibitCache
);
3207 if (vars
->videoMapSize
)
3208 ProgressUpdate(gIOHibernateGraphicsInfo
,
3209 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
3211 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
3212 uint8_t * compressed
= src
+ page_size
;
3213 uint8_t * scratch
= compressed
+ page_size
;
3214 uint32_t decoOffset
;
3216 clock_get_uptime(&allTime
);
3217 AbsoluteTime_to_scalar(&compTime
) = 0;
3220 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
3221 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
3222 clock_get_uptime(&startIOTime
);
3223 endTime
= startIOTime
;
3224 SUB_ABSOLUTETIME(&endTime
, &allTime
);
3225 absolutetime_to_nanoseconds(endTime
, &nsec
);
3226 HIBLOG("IOHibernatePollerOpen(%x) %qd ms\n", err
, nsec
/ 1000000ULL);
3228 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
3230 // kick off the read ahead
3231 vars
->fileVars
->io
= false;
3232 vars
->fileVars
->bufferHalf
= 0;
3233 vars
->fileVars
->bufferLimit
= 0;
3234 vars
->fileVars
->lastRead
= 0;
3235 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
3236 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
3237 vars
->fileVars
->cryptBytes
= 0;
3238 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
3240 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
3241 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
3244 HIBLOG("hibernate_machine_init reading\n");
3246 uint32_t * header
= (uint32_t *) src
;
3249 while (kIOReturnSuccess
== err
)
3254 vm_offset_t ppnum
, compressedSize
;
3256 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
3257 if (kIOReturnSuccess
!= err
)
3263 // HIBPRINT("(%x, %x)\n", ppnum, count);
3268 for (page
= 0; page
< count
; page
++)
3270 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
3271 if (kIOReturnSuccess
!= err
)
3274 compressedSize
= kIOHibernateTagLength
& tag
;
3275 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
3277 err
= kIOReturnIPCError
;
3281 if (!compressedSize
) bzero_phys(ptoa_64(ppnum
), page_size
);
3284 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
3285 if (kIOReturnSuccess
!= err
) break;
3286 if (compressedSize
< page_size
)
3288 decoOffset
= page_size
;
3289 clock_get_uptime(&startTime
);
3290 WKdm_decompress_new((WK_word
*) src
, (WK_word
*) compressed
, (WK_word
*) scratch
, page_size
);
3291 clock_get_uptime(&endTime
);
3292 ADD_ABSOLUTETIME(&compTime
, &endTime
);
3293 SUB_ABSOLUTETIME(&compTime
, &startTime
);
3294 compBytes
+= page_size
;
3296 else decoOffset
= 0;
3298 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
3299 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
3302 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
3311 if (0 == (8191 & pagesDone
))
3313 clock_get_uptime(&endTime
);
3314 SUB_ABSOLUTETIME(&endTime
, &allTime
);
3315 absolutetime_to_nanoseconds(endTime
, &nsec
);
3316 progressStamp
= nsec
/ 750000000ULL;
3317 if (progressStamp
!= lastProgressStamp
)
3319 lastProgressStamp
= progressStamp
;
3320 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
3321 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
3326 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
3327 err
= kIOReturnLockedRead
;
3329 if (kIOReturnSuccess
!= err
)
3330 panic("Hibernate restore error %x", err
);
3332 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
3333 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
3335 if (vars
->fileVars
->io
)
3336 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
3338 clock_get_uptime(&endIOTime
);
3340 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
3342 clock_get_uptime(&endTime
);
3344 IOService::getPMRootDomain()->pmStatsRecordEvent(
3345 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
3346 IOService::getPMRootDomain()->pmStatsRecordEvent(
3347 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
3349 SUB_ABSOLUTETIME(&endTime
, &allTime
);
3350 absolutetime_to_nanoseconds(endTime
, &nsec
);
3352 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
3353 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
3355 gIOHibernateStats
->kernelImageReadDuration
= nsec
/ 1000000ULL;
3356 gIOHibernateStats
->imagePages
= pagesDone
;
3358 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
3359 pagesDone
, sum
, gIOHibernateStats
->kernelImageReadDuration
, kDefaultIOSize
,
3360 nsecIO
? ((((gIOHibernateCurrentHeader
->imageSize
- gIOHibernateCurrentHeader
->image1Size
) * 1000000000ULL) / 1024 / 1024) / nsecIO
) : 0);
3362 absolutetime_to_nanoseconds(compTime
, &nsec
);
3363 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
3366 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
3368 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
3369 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
3370 vars
->fileVars
->cryptBytes
,
3372 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
3374 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 2) | DBG_FUNC_NONE
, pagesRead
, pagesDone
, 0, 0, 0);
3377 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3379 void IOHibernateSetWakeCapabilities(uint32_t capability
)
3381 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
3383 gIOHibernateStats
->wakeCapability
= capability
;
3385 if (kIOPMSystemCapabilityGraphics
& capability
)
3387 vm_compressor_do_warmup();
3392 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3394 void IOHibernateSystemRestart(void)
3396 static uint8_t noteStore
[32] __attribute__((aligned(32)));
3397 IORegistryEntry
* regEntry
;
3398 const OSSymbol
* sym
;
3401 uintptr_t * smcVars
;
3406 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
3409 smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
3410 smcBytes
= (typeof(smcBytes
)) smcVars
[1];
3412 if (len
> sizeof(noteStore
)) len
= sizeof(noteStore
);
3413 noteProp
= OSData::withCapacity(3 * sizeof(element
));
3414 if (!noteProp
) return;
3416 noteProp
->appendBytes(&element
, sizeof(element
));
3417 element
= crc32(0, smcBytes
, len
);
3418 noteProp
->appendBytes(&element
, sizeof(element
));
3420 bcopy(smcBytes
, noteStore
, len
);
3421 element
= (addr64_t
) ¬eStore
[0];
3422 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
3423 noteProp
->appendBytes(&element
, sizeof(element
));
3425 if (!gIOOptionsEntry
)
3427 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
3428 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
3429 if (regEntry
&& !gIOOptionsEntry
)
3430 regEntry
->release();
3433 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
3434 if (gIOOptionsEntry
&& sym
) gIOOptionsEntry
->setProperty(sym
, noteProp
);
3435 if (noteProp
) noteProp
->release();
3436 if (sym
) sym
->release();