2 * Copyright (c) 2004-2016 Apple 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@
33 * - PMRootDomain calls IOHibernateSystemSleep() before system sleep
34 * (devices awake, normal execution context)
35 * - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
36 * grabs its extents and searches for a polling driver willing to work with that IOMedia.
37 * The BSD code makes an ioctl to the storage driver to get the partition base offset to
38 * the disk, and other ioctls to get the transfer constraints
39 * If successful, the file is written to make sure its initially not bootable (in case of
40 * later failure) and nvram set to point to the first block of the file. (Has to be done
41 * here so blocking is possible in nvram support).
42 * hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
43 * page out any pages it wants to (currently zero, but probably some percentage of memory).
44 * Its assumed just allocating pages will cause the VM system to naturally select the best
45 * pages for eviction. It also copies processor flags needed for the restore path and sets
46 * a flag in the boot processor proc info.
47 * gIOHibernateState = kIOHibernateStateHibernating.
48 * - Regular sleep progresses - some drivers may inspect the root domain property
49 * kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
50 * as usual but leaves motherboard I/O on.
51 * - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
52 * at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
53 * all ppc RC bits out of the hash table and caches into the mapping structures.
54 * - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
55 * hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
56 * All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
57 * by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
58 * The image header and block list are written. The header includes the second file extent so
59 * only the header block is needed to read the file, regardless of filesystem.
60 * The kernel segment "__HIB" is written uncompressed to the image. This segment of code and data
61 * (only) is used to decompress the image during wake/boot.
62 * Some additional pages are removed from the bitmaps - the buffers used for hibernation.
63 * The bitmaps are written to the image.
64 * More areas are removed from the bitmaps (after they have been written to the image) - the
65 * segment "__HIB" pages and interrupt stack.
66 * Each wired page is compressed and written and then each non-wired page. Compression and
67 * disk writes are in parallel.
68 * The image header is written to the start of the file and the polling driver closed.
69 * The machine powers down (or sleeps).
73 * - BootX sees the boot-image nvram variable containing the device and block number of the image,
74 * reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
75 * - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
76 * in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
77 * that is in the kernel's __HIB section.
78 * - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
79 * hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
80 * only code & data in that section is safe to call since all the other wired pages are still
81 * compressed in the image.
82 * - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
83 * It uses the bitmaps to work out which pages can be uncompressed from the image to their final
84 * location directly, and copies those that can't to interim free pages. When the image has been
85 * completed, the copies are uncompressed, overwriting the wired image pages.
86 * hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
87 * is used to get pages into place for 64bit.
88 * - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
89 * changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
90 * are removed from the software strutures, and the hash table is reinitialized.
91 * - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
92 * of memory, using the polled mode driver, before other threads can run or any devices are turned on.
93 * This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
94 * for the remaining non wired pages.
95 * - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
96 * (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
101 * IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
102 * registry, specifying an object of calls IOPolledInterface.
104 * Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
105 * partition) that the image is going to live, looking for polled interface properties. If it finds
106 * one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
107 * interfaces found are kept in an ordered list.
109 * There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
110 * few different contexts things happen in:
112 * - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
113 * up and running) and after wake - this is safe to allocate memory and do anything. The device
114 * ignores sleep requests from that point since its a waste of time if it goes to sleep and
115 * immediately wakes back up for the image write.
117 * - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
118 * immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
119 * from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
120 * used to flush and set the disk to sleep.
122 * - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
123 * immediately after sleep. These can't block or allocate memory. This is happening after the platform
124 * expert has woken the low level bits of the system, but most of the I/O system has not. There is only
125 * one thread running.
127 * For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
128 * (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
129 * the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
130 * Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
131 * that is called for the hardware to check for events, and complete the I/O via the callback.
132 * The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
133 * to restrict I/O ops.
136 #include <sys/systm.h>
138 #include <IOKit/IOWorkLoop.h>
139 #include <IOKit/IOCommandGate.h>
140 #include <IOKit/IOTimerEventSource.h>
141 #include <IOKit/IOPlatformExpert.h>
142 #include <IOKit/IOKitDebug.h>
143 #include <IOKit/IOTimeStamp.h>
144 #include <IOKit/pwr_mgt/RootDomain.h>
145 #include <IOKit/pwr_mgt/IOPMPrivate.h>
146 #include <IOKit/IOMessage.h>
147 #include <IOKit/IODeviceTreeSupport.h>
148 #include <IOKit/IOBSD.h>
149 #include <IOKit/IOKitKeysPrivate.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/vm_protos.h>
170 #include "IOKitKernelInternal.h"
171 #include <pexpert/device_tree.h>
173 #include <machine/pal_routines.h>
174 #include <machine/pal_hibernate.h>
175 #if defined(__i386__) || defined(__x86_64__)
176 #include <i386/tsc.h>
177 #include <i386/cpuid.h>
178 #include <vm/WKdm_new.h>
179 #elif defined(__arm64__)
180 #include <arm64/amcc_rorgn.h>
181 #endif /* defined(__i386__) || defined(__x86_64__) */
182 #include <san/kasan.h>
184 #if HIBERNATE_HMAC_IMAGE
185 #include <arm64/hibernate_ppl_hmac.h>
186 #endif /* HIBERNATE_HMAC_IMAGE */
188 extern "C" addr64_t
kvtophys(vm_offset_t va
);
189 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
191 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
193 #define DISABLE_TRIM 0
194 #define TRIM_DELAY 25000
196 extern unsigned int save_kdebug_enable
;
197 extern uint32_t gIOHibernateState
;
198 uint32_t gIOHibernateMode
;
199 static char gIOHibernateBootSignature
[256 + 1];
200 static char gIOHibernateFilename
[MAXPATHLEN
+ 1];
201 uint32_t gIOHibernateCount
;
203 static uuid_string_t gIOHibernateBridgeBootSessionUUIDString
;
205 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
206 uint32_t gIOHibernateFreeTime
= 0 * 1000; // max time to spend freeing pages (ms)
207 static uint64_t gIOHibernateCompression
= 0x80; // default compression 50%
208 boolean_t gIOHibernateStandbyDisabled
;
210 static IODTNVRAM
* gIOOptionsEntry
;
211 static IORegistryEntry
* gIOChosenEntry
;
213 static const OSSymbol
* gIOHibernateBootImageKey
;
214 static const OSSymbol
* gIOHibernateBootSignatureKey
;
215 static const OSSymbol
* gIOBridgeBootSessionUUIDKey
;
217 #if defined(__i386__) || defined(__x86_64__)
219 static const OSSymbol
* gIOHibernateRTCVariablesKey
;
220 static const OSSymbol
* gIOHibernateBoot0082Key
;
221 static const OSSymbol
* gIOHibernateBootNextKey
;
222 static OSData
* gIOHibernateBoot0082Data
;
223 static OSData
* gIOHibernateBootNextData
;
224 static OSObject
* gIOHibernateBootNextSave
;
226 #endif /* defined(__i386__) || defined(__x86_64__) */
228 static IOLock
* gFSLock
;
230 static thread_call_t gIOHibernateTrimCalloutEntry
;
231 static IOPolledFileIOVars gFileVars
;
232 static IOHibernateVars gIOHibernateVars
;
233 static IOPolledFileCryptVars gIOHibernateCryptWakeContext
;
234 static hibernate_graphics_t _hibernateGraphics
;
235 static hibernate_graphics_t
* gIOHibernateGraphicsInfo
= &_hibernateGraphics
;
236 static hibernate_statistics_t _hibernateStats
;
237 static hibernate_statistics_t
* gIOHibernateStats
= &_hibernateStats
;
247 static IOReturn
IOHibernateDone(IOHibernateVars
* vars
);
248 static IOReturn
IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
);
249 static void IOSetBootImageNVRAM(OSData
* data
);
250 static void IOHibernateSystemPostWakeTrim(void * p1
, void * p2
);
252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
254 enum { kDefaultIOSize
= 128 * 1024 };
255 enum { kVideoMapSize
= 80 * 1024 * 1024 };
257 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
259 // copy from phys addr to MD
261 #if !HIBERNATE_HMAC_IMAGE
263 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
264 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
266 addr64_t srcAddr
= bytes
;
267 IOByteCount remaining
;
269 remaining
= length
= min(length
, md
->getLength() - offset
);
270 while (remaining
) { // (process another target segment?)
274 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
279 // Clip segment length to remaining
280 if (dstLen
> remaining
) {
285 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
287 copypv(srcAddr
, dstAddr64
, dstLen
,
288 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
297 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
299 #endif /* !HIBERNATE_HMAC_IMAGE */
301 // copy from MD to phys addr
304 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
305 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
307 addr64_t dstAddr
= bytes
;
308 IOByteCount remaining
;
310 remaining
= length
= min(length
, md
->getLength() - offset
);
311 while (remaining
) { // (process another target segment?)
315 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
320 // Clip segment length to remaining
321 if (dstLen
> remaining
) {
326 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
328 copypv(srcAddr
, dstAddr64
, dstLen
,
329 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
338 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
341 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
344 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
345 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
349 if (count
> UINT_MAX
) {
350 panic("hibernate_set_page_state ppnum");
354 case kIOHibernatePageStateUnwiredSave
:
356 for (; ppnum
< count
; ppnum
++) {
357 hibernate_page_bitset(page_list
, FALSE
, (uint32_t) ppnum
);
358 hibernate_page_bitset(page_list_wired
, TRUE
, (uint32_t) ppnum
);
361 case kIOHibernatePageStateWiredSave
:
363 for (; ppnum
< count
; ppnum
++) {
364 hibernate_page_bitset(page_list
, FALSE
, (uint32_t) ppnum
);
365 hibernate_page_bitset(page_list_wired
, FALSE
, (uint32_t) ppnum
);
368 case kIOHibernatePageStateFree
:
370 for (; ppnum
< count
; ppnum
++) {
371 hibernate_page_bitset(page_list
, TRUE
, (uint32_t) ppnum
);
372 hibernate_page_bitset(page_list_wired
, TRUE
, (uint32_t) ppnum
);
376 panic("hibernate_set_page_state");
381 hibernate_set_descriptor_page_state(IOHibernateVars
*vars
,
382 IOMemoryDescriptor
*descriptor
,
391 (phys64
= descriptor
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
393 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
394 atop_64(phys64
), atop_32(segLen
),
396 *pageCount
-= atop_32(segLen
);
402 hibernate_page_list_iterate(hibernate_page_list_t
* list
, ppnum_t
* pPage
)
404 uint32_t page
= ((typeof(page
)) * pPage
);
406 hibernate_bitmap_t
* bitmap
;
408 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
))) {
409 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
414 if (page
<= bitmap
->last_page
) {
421 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
429 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
432 IOHibernateSystemSleep(void)
439 bool dsSSD
, vmflush
, swapPinned
;
440 IOHibernateVars
* vars
;
441 uint64_t setFileSize
= 0;
443 gIOHibernateState
= kIOHibernateStateInactive
;
445 gIOHibernateDebugFlags
= 0;
446 if (kIOLogHibernate
& gIOKitDebug
) {
447 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
450 if (IOService::getPMRootDomain()->getHibernateSettings(
451 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
)) {
452 if (kIOHibernateModeSleep
& gIOHibernateMode
) {
453 // default to discard clean for safe sleep
454 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
455 | kIOHibernateModeDiscardCleanActive
);
459 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
))) {
460 if ((str
= OSDynamicCast(OSString
, obj
))) {
461 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
462 sizeof(gIOHibernateFilename
));
467 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0]) {
468 return kIOReturnUnsupported
;
471 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
473 vars
= IONew(IOHibernateVars
, 1);
475 return kIOReturnNoMemory
;
477 bzero(vars
, sizeof(*vars
));
480 if (!gIOHibernateTrimCalloutEntry
) {
481 gIOHibernateTrimCalloutEntry
= thread_call_allocate(&IOHibernateSystemPostWakeTrim
, &gFSLock
);
483 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
484 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
485 if (kFSIdle
!= gFSState
) {
486 HIBLOG("hibernate file busy\n");
487 IOLockUnlock(gFSLock
);
488 IODelete(vars
, IOHibernateVars
, 1);
489 return kIOReturnBusy
;
491 gFSState
= kFSOpening
;
492 IOLockUnlock(gFSLock
);
496 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
497 HIBERNATION_SRC_BUFFER_SIZE
, page_size
);
499 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
500 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
502 if (!vars
->srcBuffer
|| !vars
->handoffBuffer
) {
503 err
= kIOReturnNoMemory
;
507 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey
))) {
508 if ((num
= OSDynamicCast(OSNumber
, obj
))) {
509 vars
->fileMinSize
= num
->unsigned64BitValue();
513 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey
))) {
514 if ((num
= OSDynamicCast(OSNumber
, obj
))) {
515 vars
->fileMaxSize
= num
->unsigned64BitValue();
520 boolean_t encryptedswap
= true;
522 AbsoluteTime startTime
, endTime
;
525 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
526 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
527 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
529 vmflush
= ((kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
530 err
= hibernate_alloc_page_lists(&vars
->page_list
,
531 &vars
->page_list_wired
,
532 &vars
->page_list_pal
);
533 if (KERN_SUCCESS
!= err
) {
534 HIBLOG("%s err, hibernate_alloc_page_lists return 0x%x\n", __FUNCTION__
, err
);
538 err
= hibernate_pin_swap(TRUE
);
539 if (KERN_SUCCESS
!= err
) {
540 HIBLOG("%s error, hibernate_pin_swap return 0x%x\n", __FUNCTION__
, err
);
545 if (vars
->fileMinSize
|| (kIOHibernateModeFileResize
& gIOHibernateMode
)) {
546 hibernate_page_list_setall(vars
->page_list
,
547 vars
->page_list_wired
,
549 true /* preflight */,
550 vmflush
/* discard */,
552 PE_Video consoleInfo
;
553 bzero(&consoleInfo
, sizeof(consoleInfo
));
554 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
556 // estimate: 6% increase in pages compressed
557 // screen preview 2 images compressed 0%
558 setFileSize
= ((ptoa_64((106 * pageCount
) / 100) * gIOHibernateCompression
) >> 8)
559 + vars
->page_list
->list_size
560 + (consoleInfo
.v_width
* consoleInfo
.v_height
* 8);
561 enum { setFileRound
= 1024 * 1024ULL };
562 setFileSize
= ((setFileSize
+ setFileRound
) & ~(setFileRound
- 1));
564 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
565 pageCount
, (100ULL * gIOHibernateCompression
) >> 8,
566 setFileSize
, vars
->fileMinSize
);
568 if (!(kIOHibernateModeFileResize
& gIOHibernateMode
)
569 && (setFileSize
< vars
->fileMinSize
)) {
570 setFileSize
= vars
->fileMinSize
;
574 vars
->volumeCryptKeySize
= sizeof(vars
->volumeCryptKey
);
575 err
= IOPolledFileOpen(gIOHibernateFilename
,
576 (kIOPolledFileCreate
| kIOPolledFileHibernate
),
578 gIOHibernateCurrentHeader
, sizeof(gIOHibernateCurrentHeader
),
579 &vars
->fileVars
, &nvramData
,
580 &vars
->volumeCryptKey
[0], &vars
->volumeCryptKeySize
);
582 if (KERN_SUCCESS
!= err
) {
584 if (kFSOpening
!= gFSState
) {
585 err
= kIOReturnTimeout
;
587 IOLockUnlock(gFSLock
);
590 if (KERN_SUCCESS
!= err
) {
591 HIBLOG("IOPolledFileOpen(%x)\n", err
);
595 // write extents for debug data usage in EFI
596 IOWriteExtentsToFile(vars
->fileVars
, kIOHibernateHeaderOpenSignature
);
598 err
= IOPolledFilePollersSetup(vars
->fileVars
, kIOPolledPreflightState
);
599 if (KERN_SUCCESS
!= err
) {
603 clock_get_uptime(&startTime
);
604 err
= hibernate_setup(gIOHibernateCurrentHeader
,
606 vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
607 clock_get_uptime(&endTime
);
608 SUB_ABSOLUTETIME(&endTime
, &startTime
);
609 absolutetime_to_nanoseconds(endTime
, &nsec
);
611 boolean_t haveSwapPin
, hibFileSSD
;
612 haveSwapPin
= vm_swap_files_pinned();
614 hibFileSSD
= (kIOPolledFileSSD
& vars
->fileVars
->flags
);
616 HIBLOG("hibernate_setup(%d) took %qd ms, swapPin(%d) ssd(%d)\n",
617 err
, nsec
/ 1000000ULL,
618 haveSwapPin
, hibFileSSD
);
619 if (KERN_SUCCESS
!= err
) {
623 gIOHibernateStandbyDisabled
= ((!haveSwapPin
|| !hibFileSSD
));
625 dsSSD
= ((0 != (kIOPolledFileSSD
& vars
->fileVars
->flags
))
626 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
629 gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionSSD
| kIOHibernateOptionColor
;
631 gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
634 #if HIBERNATE_HMAC_IMAGE
635 // inform HMAC driver that we're going to hibernate
636 ppl_hmac_hibernate_begin();
637 #endif /* HIBERNATE_HMAC_IMAGE */
639 #if defined(__i386__) || defined(__x86_64__)
640 if (vars
->volumeCryptKeySize
&&
641 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
))) {
642 uintptr_t smcVars
[2];
643 smcVars
[0] = vars
->volumeCryptKeySize
;
644 smcVars
[1] = (uintptr_t)(void *) &gIOHibernateVars
.volumeCryptKey
[0];
646 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
647 bzero(smcVars
, sizeof(smcVars
));
652 if (encryptedswap
|| vars
->volumeCryptKeySize
) {
653 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
656 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
) {
657 vars
->videoAllocSize
= kVideoMapSize
;
658 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
, VM_KERN_MEMORY_IOKIT
)) {
659 vars
->videoMapping
= 0;
663 // generate crypt keys
664 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++) {
665 vars
->wiredCryptKey
[i
] = ((uint8_t) random());
667 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++) {
668 vars
->cryptKey
[i
] = ((uint8_t) random());
673 IOSetBootImageNVRAM(nvramData
);
674 nvramData
->release();
676 #if defined(__i386__) || defined(__x86_64__)
678 struct AppleRTCHibernateVars
{
679 uint8_t signature
[4];
681 uint8_t booterSignature
[20];
682 uint8_t wiredCryptKey
[16];
684 AppleRTCHibernateVars rtcVars
;
687 rtcVars
.signature
[0] = 'A';
688 rtcVars
.signature
[1] = 'A';
689 rtcVars
.signature
[2] = 'P';
690 rtcVars
.signature
[3] = 'L';
691 rtcVars
.revision
= 1;
692 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
695 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOHibernateBootSignatureKey
)))
696 && (sizeof(rtcVars
.booterSignature
) <= data
->getLength())) {
697 bcopy(data
->getBytesNoCopy(), &rtcVars
.booterSignature
[0], sizeof(rtcVars
.booterSignature
));
698 } else if (gIOHibernateBootSignature
[0]) {
701 uint32_t in
, out
, digits
;
702 for (in
= out
= digits
= 0;
703 (c
= gIOHibernateBootSignature
[in
]) && (in
< sizeof(gIOHibernateBootSignature
));
705 if ((c
>= 'a') && (c
<= 'f')) {
707 } else if ((c
>= 'A') && (c
<= 'F')) {
709 } else if ((c
>= '0') && (c
<= '9')) {
713 out
= digits
= value
= 0;
717 value
= ((uint8_t) ((value
<< 4) | c
));
719 rtcVars
.booterSignature
[out
++] = value
;
720 if (out
>= sizeof(rtcVars
.booterSignature
)) {
727 #if DEBUG || DEVELOPMENT
728 if (kIOLogHibernate
& gIOKitDebug
) {
729 IOKitKernelLogBuffer("H> rtc:",
730 &rtcVars
, sizeof(rtcVars
), &kprintf
);
732 #endif /* DEBUG || DEVELOPMENT */
734 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
736 if (gIOHibernateRTCVariablesKey
) {
737 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
741 if (gIOChosenEntry
&& gIOOptionsEntry
) {
742 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
744 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
747 if (!gIOHibernateBoot0082Data
) {
748 OSData
* fileData
= NULL
;
749 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
750 if (data
&& data
->getLength() >= 4) {
751 fileData
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-file-path"));
753 if (data
&& (data
->getLength() <= UINT16_MAX
)) {
754 // AppleNVRAM_EFI_LOAD_OPTION
757 uint16_t FilePathLength
;
760 loadOptionHeader
.Attributes
= 1;
761 loadOptionHeader
.FilePathLength
= ((uint16_t) data
->getLength());
762 loadOptionHeader
.Desc
= 0;
764 loadOptionHeader
.FilePathLength
-= 4;
765 loadOptionHeader
.FilePathLength
+= fileData
->getLength();
767 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
768 if (gIOHibernateBoot0082Data
) {
769 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
771 gIOHibernateBoot0082Data
->appendBytes(data
->getBytesNoCopy(), data
->getLength() - 4);
772 gIOHibernateBoot0082Data
->appendBytes(fileData
);
774 gIOHibernateBoot0082Data
->appendBytes(data
);
779 if (!gIOHibernateBootNextData
) {
780 uint16_t bits
= 0x0082;
781 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
784 #if DEBUG || DEVELOPMENT
785 if (kIOLogHibernate
& gIOKitDebug
) {
786 IOKitKernelLogBuffer("H> bootnext:",
787 gIOHibernateBoot0082Data
->getBytesNoCopy(), gIOHibernateBoot0082Data
->getLength(), &kprintf
);
789 #endif /* DEBUG || DEVELOPMENT */
790 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
) {
791 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
792 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
793 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
798 #endif /* !i386 && !x86_64 */
802 hibernate_pin_swap(FALSE
);
806 if ((kIOReturnSuccess
== err
) && (kFSOpening
!= gFSState
)) {
807 HIBLOG("hibernate file close due timeout\n");
808 err
= kIOReturnTimeout
;
810 if (kIOReturnSuccess
== err
) {
811 gFSState
= kFSOpened
;
812 gIOHibernateVars
= *vars
;
813 gFileVars
= *vars
->fileVars
;
814 gFileVars
.allocated
= false;
815 gIOHibernateVars
.fileVars
= &gFileVars
;
816 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
817 gIOHibernateCurrentHeader
->kernVirtSlide
= vm_kernel_slide
;
818 gIOHibernateState
= kIOHibernateStateHibernating
;
820 #if DEBUG || DEVELOPMENT
821 if (kIOLogHibernate
& gIOKitDebug
) {
822 OSData
* data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
824 uintptr_t * smcVars
= (typeof(smcVars
))data
->getBytesNoCopy();
825 IOKitKernelLogBuffer("H> smc:",
826 (const void *)smcVars
[1], smcVars
[0], &kprintf
);
829 #endif /* DEBUG || DEVELOPMENT */
831 IOPolledFileIOVars
* fileVars
= vars
->fileVars
;
832 IOHibernateDone(vars
);
833 IOPolledFileClose(&fileVars
,
837 0, NULL
, 0, sizeof(IOHibernateImageHeader
), setFileSize
);
841 IOLockUnlock(gFSLock
);
843 if (vars
->fileVars
) {
844 IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
846 IODelete(vars
, IOHibernateVars
, 1);
851 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
854 IOSetBootImageNVRAM(OSData
* data
)
856 IORegistryEntry
* regEntry
;
858 if (!gIOOptionsEntry
) {
859 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
860 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
861 if (regEntry
&& !gIOOptionsEntry
) {
865 if (gIOOptionsEntry
&& gIOHibernateBootImageKey
) {
867 gIOOptionsEntry
->setProperty(gIOHibernateBootImageKey
, data
);
868 #if DEBUG || DEVELOPMENT
869 if (kIOLogHibernate
& gIOKitDebug
) {
870 IOKitKernelLogBuffer("H> boot-image:",
871 data
->getBytesNoCopy(), data
->getLength(), &kprintf
);
873 #endif /* DEBUG || DEVELOPMENT */
875 gIOOptionsEntry
->removeProperty(gIOHibernateBootImageKey
);
877 gIOOptionsEntry
->sync();
879 if (gIOHibernateState
== kIOHibernateStateWakingFromHibernate
) {
880 // if we woke from hibernation, the booter may have changed the state of NVRAM, so force a sync
881 gIOOptionsEntry
->sync();
888 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
890 * Writes header to disk with signature, block size and file extents data.
891 * If there are more than 2 extents, then they are written on second block.
894 IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
)
896 IOHibernateImageHeader hdr
;
898 IOReturn err
= kIOReturnSuccess
;
900 IOPolledFileExtent
* fileExtents
;
902 fileExtents
= (typeof(fileExtents
))vars
->fileExtents
->getBytesNoCopy();
904 memset(&hdr
, 0, sizeof(IOHibernateImageHeader
));
905 count
= vars
->fileExtents
->getLength();
906 if (count
> sizeof(hdr
.fileExtentMap
)) {
907 hdr
.fileExtentMapSize
= count
;
908 count
= sizeof(hdr
.fileExtentMap
);
910 hdr
.fileExtentMapSize
= sizeof(hdr
.fileExtentMap
);
913 bcopy(fileExtents
, &hdr
.fileExtentMap
[0], count
);
915 // copy file block extent list if larger than header
916 if (hdr
.fileExtentMapSize
> sizeof(hdr
.fileExtentMap
)) {
917 count
= hdr
.fileExtentMapSize
- sizeof(hdr
.fileExtentMap
);
918 rc
= kern_write_file(vars
->fileRef
, vars
->blockSize
,
919 (caddr_t
)(((uint8_t *)fileExtents
) + sizeof(hdr
.fileExtentMap
)),
920 count
, IO_SKIP_ENCRYPTION
);
922 HIBLOG("kern_write_file returned %d\n", rc
);
923 err
= kIOReturnIOError
;
927 hdr
.signature
= signature
;
928 hdr
.deviceBlockSize
= vars
->blockSize
;
930 rc
= kern_write_file(vars
->fileRef
, 0, (char *)&hdr
, sizeof(hdr
), IO_SKIP_ENCRYPTION
);
932 HIBLOG("kern_write_file returned %d\n", rc
);
933 err
= kIOReturnIOError
;
941 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
943 DECLARE_IOHIBERNATEPROGRESSALPHA
946 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
948 uint32_t rowBytes
, pixelShift
;
951 uint32_t alpha
, color
, result
;
953 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
955 rowBytes
= display
->rowBytes
;
956 pixelShift
= display
->depth
>> 4;
957 if (pixelShift
< 1) {
961 screen
+= ((display
->width
962 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
963 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
965 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++) {
966 out
= screen
+ y
* rowBytes
;
967 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++) {
968 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
969 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++) {
970 alpha
= gIOHibernateProgressAlpha
[y
][x
];
974 if (1 == pixelShift
) {
975 in
= *((uint16_t *)out
) & 0x1f; // 16
976 in
= ((uint8_t)(in
<< 3)) | ((uint8_t)(in
>> 2));
978 in
= *((uint32_t *)out
) & 0xff; // 32
980 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
981 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
983 if (1 == pixelShift
) {
985 *((uint16_t *)out
) = ((uint16_t)((result
<< 10) | (result
<< 5) | result
)); // 16
987 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
990 out
+= (1 << pixelShift
);
992 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
999 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1001 uint32_t rowBytes
, pixelShift
;
1003 int32_t blob
, lastBlob
;
1004 uint32_t alpha
, in
, color
, result
;
1006 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1008 pixelShift
= display
->depth
>> 4;
1009 if (pixelShift
< 1) {
1013 rowBytes
= display
->rowBytes
;
1015 screen
+= ((display
->width
1016 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1017 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1019 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1021 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1023 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++) {
1024 out
= screen
+ y
* rowBytes
;
1025 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++) {
1026 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1027 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++) {
1028 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1031 if (0xff != alpha
) {
1032 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1033 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1035 if (1 == pixelShift
) {
1037 *((uint16_t *)out
) = ((uint16_t)((result
<< 10) | (result
<< 5) | result
)); // 16
1039 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1042 out
+= (1 << pixelShift
);
1044 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1049 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1052 IOHibernateIOKitSleep(void)
1054 IOReturn ret
= kIOReturnSuccess
;
1055 IOLockLock(gFSLock
);
1056 if (kFSOpening
== gFSState
) {
1057 gFSState
= kFSTimedOut
;
1058 HIBLOG("hibernate file open timed out\n");
1059 ret
= kIOReturnTimeout
;
1061 IOLockUnlock(gFSLock
);
1065 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1068 IOHibernateSystemHasSlept(void)
1070 IOReturn ret
= kIOReturnSuccess
;
1071 IOHibernateVars
* vars
= &gIOHibernateVars
;
1072 OSObject
* obj
= NULL
;
1075 IOLockLock(gFSLock
);
1076 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
) {
1077 ret
= kIOReturnTimeout
;
1079 IOLockUnlock(gFSLock
);
1080 if (kIOReturnSuccess
!= ret
) {
1084 if (gIOHibernateMode
) {
1085 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1087 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1088 if (obj
&& !vars
->previewBuffer
) {
1091 if (vars
->previewBuffer
&& (vars
->previewBuffer
->getLength() > UINT_MAX
)) {
1092 OSSafeReleaseNULL(vars
->previewBuffer
);
1095 vars
->consoleMapping
= NULL
;
1096 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare())) {
1097 vars
->previewBuffer
->release();
1098 vars
->previewBuffer
= NULL
;
1101 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1102 && vars
->previewBuffer
1103 && (data
= OSDynamicCast(OSData
,
1104 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
)))) {
1105 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1106 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1108 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1110 if (kIOHibernatePreviewUpdates
& flags
) {
1111 PE_Video consoleInfo
;
1112 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1114 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1116 graphicsInfo
->width
= (uint32_t) consoleInfo
.v_width
;
1117 graphicsInfo
->height
= (uint32_t) consoleInfo
.v_height
;
1118 graphicsInfo
->rowBytes
= (uint32_t) consoleInfo
.v_rowBytes
;
1119 graphicsInfo
->depth
= (uint32_t) consoleInfo
.v_depth
;
1120 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1122 HIBPRINT("video %p %d %d %d\n",
1123 vars
->consoleMapping
, graphicsInfo
->depth
,
1124 graphicsInfo
->width
, graphicsInfo
->height
);
1125 if (vars
->consoleMapping
) {
1126 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1127 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1132 if (gIOOptionsEntry
) {
1134 gIOOptionsEntry
->sync();
1136 if (gIOHibernateMode
) {
1137 gIOOptionsEntry
->sync();
1145 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1147 #if defined(__i386__) || defined(__x86_64__)
1148 static DeviceTreeNode
*
1149 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
, vm_offset_t region_start
, vm_size_t region_size
)
1151 DeviceTreeNodeProperty
* prop
;
1152 DeviceTreeNode
* child
;
1153 IORegistryEntry
* childRegEntry
;
1154 const char * nameProp
;
1155 unsigned int propLen
, idx
;
1157 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1158 for (idx
= 0; idx
< entry
->nProperties
; idx
++) {
1159 if (regEntry
&& (0 != strcmp("name", prop
->name
))) {
1160 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1161 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1163 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1166 child
= (DeviceTreeNode
*) prop
;
1167 for (idx
= 0; idx
< entry
->nChildren
; idx
++) {
1168 if (kSuccess
!= SecureDTGetPropertyRegion(child
, "name", (void const **) &nameProp
, &propLen
,
1169 region_start
, region_size
)) {
1172 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1173 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1174 child
= MergeDeviceTree(child
, childRegEntry
, region_start
, region_size
);
1182 IOHibernateSystemWake(void)
1184 if (kFSOpened
== gFSState
) {
1185 IOPolledFilePollersClose(gIOHibernateVars
.fileVars
, kIOPolledPostflightState
);
1186 IOHibernateDone(&gIOHibernateVars
);
1188 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1189 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1192 if (gIOOptionsEntry
&& gIOHibernateBootImageKey
) {
1193 // if we got this far, clear boot-image
1194 // we don't need to sync immediately; the booter should have already removed this entry
1195 // we just want to make sure that if anyone syncs nvram after this point, we don't re-write
1196 // a stale boot-image value
1197 gIOOptionsEntry
->removeProperty(gIOHibernateBootImageKey
);
1200 return kIOReturnSuccess
;
1204 IOHibernateDone(IOHibernateVars
* vars
)
1209 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1211 if (vars
->videoMapping
) {
1212 if (vars
->videoMapSize
) {
1214 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1216 if (vars
->videoAllocSize
) {
1218 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1222 if (vars
->previewBuffer
) {
1223 vars
->previewBuffer
->release();
1224 vars
->previewBuffer
= NULL
;
1227 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
1228 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1229 gIOHibernateCurrentHeader
->options
, 32);
1231 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1234 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1235 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
)) {
1236 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1237 &gIOHibernateGraphicsInfo
->gfxStatus
,
1238 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1240 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1243 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1245 #if defined(__i386__) || defined(__x86_64__)
1246 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1247 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1250 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1251 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1253 if (gIOOptionsEntry
) {
1254 if (gIOHibernateRTCVariablesKey
) {
1255 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1256 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1260 if (gIOHibernateBootNextKey
) {
1261 if (gIOHibernateBootNextSave
) {
1262 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1263 gIOHibernateBootNextSave
->release();
1264 gIOHibernateBootNextSave
= NULL
;
1266 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1269 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) {
1270 gIOOptionsEntry
->sync();
1275 if (vars
->srcBuffer
) {
1276 vars
->srcBuffer
->release();
1279 #if HIBERNATE_HMAC_IMAGE
1280 // inform HMAC driver that we're done hibernating
1281 ppl_hmac_hibernate_end();
1282 #endif /* HIBERNATE_HMAC_IMAGE */
1284 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1285 if (vars
->handoffBuffer
) {
1286 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
1287 IOHibernateHandoff
* handoff
;
1289 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1291 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
]) {
1292 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1293 uint8_t * __unused data
= &handoff
->data
[0];
1294 switch (handoff
->type
) {
1295 case kIOHibernateHandoffTypeEnd
:
1299 case kIOHibernateHandoffTypeDeviceTree
:
1300 #if defined(__i386__) || defined(__x86_64__)
1301 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot(),
1302 (vm_offset_t
)data
, (vm_size_t
)handoff
->bytecount
);
1304 // On ARM, the device tree is confined to its region covered by CTRR, so effectively immutable.
1305 panic("kIOHibernateHandoffTypeDeviceTree not supported on this platform.");
1309 case kIOHibernateHandoffTypeKeyStore
:
1310 #if defined(__i386__) || defined(__x86_64__)
1312 IOBufferMemoryDescriptor
*
1313 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1315 IOSetKeyStoreData(md
);
1322 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1326 #if defined(__i386__) || defined(__x86_64__)
1327 if (vars
->volumeCryptKeySize
) {
1328 IOBufferMemoryDescriptor
*
1329 bmd
= IOBufferMemoryDescriptor::withBytes(&vars
->volumeCryptKey
[0],
1330 vars
->volumeCryptKeySize
, kIODirectionOutIn
);
1332 panic("IOBufferMemoryDescriptor");
1334 IOSetAPFSKeyStoreData(bmd
);
1335 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1339 vars
->handoffBuffer
->release();
1343 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOBridgeBootSessionUUIDKey
)))
1344 && (sizeof(gIOHibernateBridgeBootSessionUUIDString
) <= data
->getLength())) {
1345 bcopy(data
->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString
[0],
1346 sizeof(gIOHibernateBridgeBootSessionUUIDString
));
1349 if (vars
->hwEncrypt
) {
1350 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
, NULL
, 0);
1351 HIBLOG("IOPolledFilePollersSetEncryptionKey(0,%x)\n", err
);
1354 bzero(vars
, sizeof(*vars
));
1356 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1357 gIOHibernateCount
++;
1359 return kIOReturnSuccess
;
1363 IOHibernateSystemPostWakeTrim(void * p1
, void * p2
)
1365 // invalidate & close the image file
1367 IOLockLock(gFSLock
);
1369 if (kFSTrimDelay
== gFSState
) {
1370 IOPolledFileIOVars
* vars
= &gFileVars
;
1371 IOPolledFileClose(&vars
,
1375 0, (caddr_t
)gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
),
1376 sizeof(IOHibernateImageHeader
), gIOHibernateCurrentHeader
->imageSize
);
1381 IOLockUnlock(gFSLock
);
1386 IOHibernateSystemPostWake(bool now
)
1388 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1389 IOSetBootImageNVRAM(NULL
);
1391 IOLockLock(gFSLock
);
1392 if (kFSTrimDelay
== gFSState
) {
1393 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
1394 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1395 } else if (kFSOpened
!= gFSState
) {
1398 gFSState
= kFSTrimDelay
;
1400 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
1401 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1403 AbsoluteTime deadline
;
1404 clock_interval_to_deadline(TRIM_DELAY
, kMillisecondScale
, &deadline
);
1405 thread_call_enter1_delayed(gIOHibernateTrimCalloutEntry
, NULL
, deadline
);
1408 IOLockUnlock(gFSLock
);
1410 return kIOReturnSuccess
;
1414 IOHibernateWasScreenLocked(void)
1417 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
) {
1419 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
1421 ret
= ((uint32_t *)data
->getBytesNoCopy())[0];
1422 gIOChosenEntry
->setProperty(kIOBooterScreenLockStateKey
, data
);
1425 gIOChosenEntry
->removeProperty(kIOBooterScreenLockStateKey
);
1431 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1433 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1434 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1435 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1436 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1437 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1438 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1439 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1440 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1441 &gIOHibernateMode
, 0, "");
1442 SYSCTL_STRUCT(_kern
, OID_AUTO
, hibernatestatistics
,
1443 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1444 &_hibernateStats
, hibernate_statistics_t
, "");
1445 SYSCTL_STRING(_kern_bridge
, OID_AUTO
, bootsessionuuid
,
1446 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1447 gIOHibernateBridgeBootSessionUUIDString
, sizeof(gIOHibernateBridgeBootSessionUUIDString
), "");
1449 SYSCTL_UINT(_kern
, OID_AUTO
, hibernategraphicsready
,
1450 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1451 &_hibernateStats
.graphicsReadyTime
, 0, "");
1452 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatewakenotification
,
1453 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1454 &_hibernateStats
.wakeNotificationTime
, 0, "");
1455 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatelockscreenready
,
1456 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1457 &_hibernateStats
.lockScreenReadyTime
, 0, "");
1458 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatehidready
,
1459 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1460 &_hibernateStats
.hidReadyTime
, 0, "");
1462 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatecount
,
1463 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1464 &gIOHibernateCount
, 0, "");
1466 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1469 hibernate_set_preview SYSCTL_HANDLER_ARGS
1471 #pragma unused(oidp, arg1, arg2)
1473 if (!IOTaskHasEntitlement(current_task(), kIOHibernateSetPreviewEntitlementKey
)) {
1477 if ((req
->newptr
== USER_ADDR_NULL
) || (!req
->newlen
)) {
1478 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewBufferKey
);
1482 size_t rounded_size
= round_page(req
->newlen
);
1483 IOBufferMemoryDescriptor
*md
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
, rounded_size
, page_size
);
1488 uint8_t *bytes
= (uint8_t *)md
->getBytesNoCopy();
1489 int error
= SYSCTL_IN(req
, bytes
, req
->newlen
);
1495 IOService::getPMRootDomain()->setProperty(kIOHibernatePreviewBufferKey
, md
);
1501 SYSCTL_PROC(_kern
, OID_AUTO
, hibernatepreview
,
1502 CTLTYPE_OPAQUE
| CTLFLAG_WR
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
, NULL
, 0,
1503 hibernate_set_preview
, "S", "");
1505 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1508 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1510 gIOHibernateBootImageKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1511 gIOHibernateBootSignatureKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1512 gIOBridgeBootSessionUUIDKey
= OSSymbol::withCStringNoCopy(kIOBridgeBootSessionUUIDKey
);
1514 #if defined(__i386__) || defined(__x86_64__)
1515 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1516 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1517 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1518 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1519 #endif /* defined(__i386__) || defined(__x86_64__) */
1521 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1523 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1527 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
))) {
1528 gIOHibernateMode
= kIOHibernateModeOn
;
1530 gIOHibernateFilename
[0] = 0;
1533 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1534 sysctl_register_oid(&sysctl__kern_bootsignature
);
1535 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1536 sysctl_register_oid(&sysctl__kern_hibernatestatistics
);
1537 sysctl_register_oid(&sysctl__kern_hibernategraphicsready
);
1538 sysctl_register_oid(&sysctl__kern_hibernatewakenotification
);
1539 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready
);
1540 sysctl_register_oid(&sysctl__kern_hibernatehidready
);
1541 sysctl_register_oid(&sysctl__kern_hibernatecount
);
1543 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1546 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOBridgeBootSessionUUIDKey
)))
1547 && (sizeof(gIOHibernateBridgeBootSessionUUIDString
) <= data
->getLength())) {
1548 sysctl_register_oid(&sysctl__kern_bridge_bootsessionuuid
);
1549 bcopy(data
->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString
[0], sizeof(gIOHibernateBridgeBootSessionUUIDString
));
1552 gFSLock
= IOLockAlloc();
1553 gIOHibernateCount
= 0;
1556 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1559 IOHibernatePolledFileWrite(IOHibernateVars
* vars
,
1560 const uint8_t * bytes
, IOByteCount size
,
1561 IOPolledFileCryptVars
* cryptvars
)
1565 #if HIBERNATE_HMAC_IMAGE
1566 uint64_t originalPosition
= 0;
1567 if (!bytes
&& !size
) {
1568 originalPosition
= vars
->fileVars
->position
;
1570 #endif /* HIBERNATE_HMAC_IMAGE */
1572 err
= IOPolledFileWrite(vars
->fileVars
, bytes
, size
, cryptvars
);
1573 if ((kIOReturnSuccess
== err
) && hibernate_should_abort()) {
1574 err
= kIOReturnAborted
;
1577 #if HIBERNATE_HMAC_IMAGE
1578 if ((kIOReturnSuccess
== err
) && (vars
->imageShaCtx
)) {
1579 if (!bytes
&& !size
) {
1580 // determine how many bytes were written
1581 size
= vars
->fileVars
->position
- originalPosition
;
1584 SHA256_Update(vars
->imageShaCtx
, bytes
, size
);
1586 // update with zeroes
1587 uint8_t zeroes
[512] = {};
1590 IOByteCount toHash
= min(len
, sizeof(zeroes
));
1591 SHA256_Update(vars
->imageShaCtx
, zeroes
, toHash
);
1596 #endif /* HIBERNATE_HMAC_IMAGE */
1601 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1604 hibernate_write_image(void)
1606 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1607 IOHibernateVars
* vars
= &gIOHibernateVars
;
1608 IOPolledFileExtent
* fileExtents
;
1610 #if !defined(__arm64__)
1611 _static_assert_1_arg(sizeof(IOHibernateImageHeader
) == 512);
1612 #endif /* !defined(__arm64__) */
1614 uint32_t pageCount
, pagesDone
;
1616 ppnum_t ppnum
, page
;
1620 uint8_t * compressed
;
1622 IOByteCount pageCompressedSize
;
1623 uint64_t compressedSize
, uncompressedSize
;
1624 uint64_t image1Size
= 0;
1625 uint32_t bitmap_size
;
1626 bool iterDone
, pollerOpen
, needEncrypt
;
1630 uint32_t pageAndCount
[2];
1633 #if !HIBERNATE_HMAC_IMAGE
1634 uint32_t restore1Sum
= 0, sum
= 0, sum1
= 0, sum2
= 0;
1635 uintptr_t hibernateBase
;
1636 uintptr_t hibernateEnd
;
1637 #endif /* HIBERNATE_HMAC_IMAGE */
1639 AbsoluteTime startTime
, endTime
;
1640 AbsoluteTime allTime
, compTime
;
1643 uint64_t lastProgressStamp
= 0;
1644 uint64_t progressStamp
;
1645 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1647 uint32_t wiredPagesEncrypted
;
1648 uint32_t dirtyPagesEncrypted
;
1649 uint32_t wiredPagesClear
;
1650 uint32_t svPageCount
;
1651 uint32_t zvPageCount
;
1653 IOPolledFileCryptVars _cryptvars
;
1654 IOPolledFileCryptVars
* cryptvars
= NULL
;
1656 wiredPagesEncrypted
= 0;
1657 dirtyPagesEncrypted
= 0;
1658 wiredPagesClear
= 0;
1663 || !vars
->fileVars
->pollers
1664 || !(kIOHibernateModeOn
& gIOHibernateMode
)) {
1665 return kIOHibernatePostWriteSleep
;
1668 #if HIBERNATE_HMAC_IMAGE
1669 // set up SHA and HMAC context to hash image1 (wired pages)
1670 SHA256_CTX imageShaCtx
;
1671 vars
->imageShaCtx
= &imageShaCtx
;
1672 SHA256_Init(vars
->imageShaCtx
);
1673 ppl_hmac_reset(true);
1674 #endif /* HIBERNATE_HMAC_IMAGE */
1676 #if !defined(__arm64__)
1677 if (kIOHibernateModeSleep
& gIOHibernateMode
) {
1678 kdebug_enable
= save_kdebug_enable
;
1680 #endif /* !defined(__arm64__) */
1682 pal_hib_write_hook();
1684 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
);
1685 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
1688 // encryption data. "iv" is the "initial vector".
1689 if (kIOHibernateModeEncrypt
& gIOHibernateMode
) {
1690 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1691 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1692 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1694 cryptvars
= &gIOHibernateCryptWakeContext
;
1695 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1696 aes_encrypt_key(vars
->cryptKey
,
1697 kIOHibernateAESKeySize
,
1698 &cryptvars
->ctx
.encrypt
);
1699 aes_decrypt_key(vars
->cryptKey
,
1700 kIOHibernateAESKeySize
,
1701 &cryptvars
->ctx
.decrypt
);
1703 cryptvars
= &_cryptvars
;
1704 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1705 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++) {
1706 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
1708 aes_encrypt_key(vars
->wiredCryptKey
,
1709 kIOHibernateAESKeySize
,
1710 &cryptvars
->ctx
.encrypt
);
1712 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1713 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1714 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1718 hibernate_page_list_setall(vars
->page_list
,
1719 vars
->page_list_wired
,
1720 vars
->page_list_pal
,
1721 false /* !preflight */,
1723 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
1724 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
1727 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1729 fileExtents
= (IOPolledFileExtent
*) vars
->fileVars
->fileExtents
->getBytesNoCopy();
1732 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1733 for (page
= 0; page
< count
; page
++) {
1734 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1735 fileExtents
[page
].start
, fileExtents
[page
].length
,
1736 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1740 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1741 AbsoluteTime_to_scalar(&compTime
) = 0;
1744 clock_get_uptime(&allTime
);
1745 IOService::getPMRootDomain()->pmStatsRecordEvent(
1746 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1749 uncompressedSize
= 0;
1753 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
1755 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1756 ml_get_interrupts_enabled());
1757 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledBeforeSleepState
,
1758 // abortable if not low battery
1759 !IOService::getPMRootDomain()->mustHibernate());
1760 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1761 pollerOpen
= (kIOReturnSuccess
== err
);
1766 if (vars
->volumeCryptKeySize
) {
1767 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
, &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
1768 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x)\n", err
);
1769 vars
->hwEncrypt
= (kIOReturnSuccess
== err
);
1770 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1771 if (vars
->hwEncrypt
) {
1772 header
->options
|= kIOHibernateOptionHWEncrypt
;
1776 // copy file block extent list if larger than header
1778 count
= vars
->fileVars
->fileExtents
->getLength();
1779 if (count
> sizeof(header
->fileExtentMap
)) {
1780 count
-= sizeof(header
->fileExtentMap
);
1781 err
= IOHibernatePolledFileWrite(vars
,
1782 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1783 if (kIOReturnSuccess
!= err
) {
1788 // copy out restore1 code
1791 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1793 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++) {
1794 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64_ppnum(phys64
) + pagesDone
;
1798 #if HIBERNATE_HMAC_IMAGE
1799 if (vars
->fileVars
->position
> UINT32_MAX
) {
1800 err
= kIOReturnNoSpace
;
1803 header
->segmentsFileOffset
= (uint32_t)vars
->fileVars
->position
;
1805 // fetch the IOHibernateHibSegInfo and the actual pages to write
1806 // we use srcBuffer as scratch space
1807 IOHibernateHibSegInfo
*segInfo
= &header
->hibSegInfo
;
1808 void *segInfoScratch
= vars
->srcBuffer
->getBytesNoCopy();
1810 // This call also enables PMAP hibernation asserts which will prevent modification
1811 // of PMAP data structures. This needs to occur before pages start getting written
1813 ppl_hmac_fetch_hibseg_and_info(segInfoScratch
, vars
->srcBuffer
->getCapacity(), segInfo
);
1815 // write each segment to the file
1816 size_t segInfoScratchPos
= 0;
1817 int hibSectIdx
= -1;
1818 uint32_t hibSegPageCount
= 0;
1819 for (int i
= 0; i
< NUM_HIBSEGINFO_SEGMENTS
; i
++) {
1820 hibSegPageCount
+= segInfo
->segments
[i
].pageCount
;
1821 size_t size
= ptoa_64(segInfo
->segments
[i
].pageCount
);
1823 err
= IOHibernatePolledFileWrite(vars
,
1824 (uint8_t*)segInfoScratch
+ segInfoScratchPos
, size
, cryptvars
);
1825 if (kIOReturnSuccess
!= err
) {
1828 segInfoScratchPos
+= size
;
1830 // is this sectHIBTEXTB?
1831 if (ptoa_64(segInfo
->segments
[i
].physPage
) == trunc_page(kvtophys(sectHIBTEXTB
))) {
1832 // remember which segment is sectHIBTEXTB because we'll need it later
1838 if (hibSectIdx
== -1) {
1839 panic("couldn't find sectHIBTEXTB in segInfo");
1842 // set the header fields corresponding to the HIB segments
1843 header
->restore1CodePhysPage
= segInfo
->segments
[hibSectIdx
].physPage
;
1844 header
->restore1CodeVirt
= trunc_page(sectHIBTEXTB
);
1845 header
->restore1PageCount
= hibSegPageCount
;
1846 header
->restore1CodeOffset
= (uint32_t)(((uintptr_t) &hibernate_machine_entrypoint
) - header
->restore1CodeVirt
);
1848 // set restore1StackOffset to the physical page of the top of the stack to simplify the restore code
1849 vm_offset_t stackFirstPage
, stackPageSize
;
1850 pal_hib_get_stack_pages(&stackFirstPage
, &stackPageSize
);
1851 header
->restore1StackOffset
= (uint32_t)(stackFirstPage
+ stackPageSize
);
1852 #else /* !HIBERNATE_HMAC_IMAGE */
1853 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
1854 hibernateEnd
= (segHIBB
+ segSizeHIB
);
1856 page
= atop_32(kvtophys(hibernateBase
));
1857 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
1858 uintptr_t entrypoint
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1859 uintptr_t stack
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1860 if ((count
> UINT_MAX
) || (entrypoint
> UINT_MAX
) || (stack
> UINT_MAX
)) {
1861 panic("malformed kernel layout");
1863 header
->restore1CodePhysPage
= (ppnum_t
) page
;
1864 header
->restore1CodeVirt
= hibernateBase
;
1865 header
->restore1PageCount
= (uint32_t) count
;
1866 header
->restore1CodeOffset
= (uint32_t) entrypoint
;
1867 header
->restore1StackOffset
= (uint32_t) stack
;
1869 if (uuid_parse(&gIOHibernateBridgeBootSessionUUIDString
[0], &header
->bridgeBootSessionUUID
[0])) {
1870 bzero(&header
->bridgeBootSessionUUID
[0], sizeof(header
->bridgeBootSessionUUID
));
1873 // sum __HIB seg, with zeros for the stack
1874 src
= (uint8_t *) trunc_page(hibernateBase
);
1875 for (page
= 0; page
< count
; page
++) {
1876 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0])) {
1877 restore1Sum
+= hibernate_sum_page(src
, (uint32_t) (header
->restore1CodeVirt
+ page
));
1879 restore1Sum
+= 0x00000000;
1885 // write the __HIB seg, with zeros for the stack
1887 src
= (uint8_t *) trunc_page(hibernateBase
);
1888 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1890 err
= IOHibernatePolledFileWrite(vars
, src
, count
, cryptvars
);
1891 if (kIOReturnSuccess
!= err
) {
1895 err
= IOHibernatePolledFileWrite(vars
,
1897 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1899 if (kIOReturnSuccess
!= err
) {
1902 src
= &gIOHibernateRestoreStackEnd
[0];
1903 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1905 err
= IOHibernatePolledFileWrite(vars
, src
, count
, cryptvars
);
1906 if (kIOReturnSuccess
!= err
) {
1910 #endif /* !HIBERNATE_HMAC_IMAGE */
1912 if (!vars
->hwEncrypt
&& (kIOHibernateModeEncrypt
& gIOHibernateMode
)) {
1913 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
1914 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1915 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1918 // write the preview buffer
1920 if (vars
->previewBuffer
) {
1924 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1925 pageAndCount
[0] = atop_64_ppnum(phys64
);
1926 pageAndCount
[1] = atop_64_ppnum(segLen
);
1927 err
= IOHibernatePolledFileWrite(vars
,
1928 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1930 if (kIOReturnSuccess
!= err
) {
1934 ppnum
+= sizeof(pageAndCount
);
1936 if (kIOReturnSuccess
!= err
) {
1940 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1942 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
1944 count
= (uint32_t) vars
->previewBuffer
->getLength();
1946 header
->previewPageListSize
= ((uint32_t) ppnum
);
1947 header
->previewSize
= ((uint32_t) (count
+ ppnum
));
1949 for (page
= 0; page
< count
; page
+= page_size
) {
1950 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
1951 #if HIBERNATE_HMAC_IMAGE
1952 err
= ppl_hmac_update_and_compress_page(atop_64_ppnum(phys64
), NULL
, NULL
);
1953 if (kIOReturnSuccess
!= err
) {
1956 #else /* !HIBERNATE_HMAC_IMAGE */
1957 sum1
+= hibernate_sum_page(src
+ page
, atop_64_ppnum(phys64
));
1958 #endif /* !HIBERNATE_HMAC_IMAGE */
1960 if (kIOReturnSuccess
!= err
) {
1963 err
= IOHibernatePolledFileWrite(vars
, src
, count
, cryptvars
);
1964 if (kIOReturnSuccess
!= err
) {
1969 // mark areas for no save
1970 hibernate_set_descriptor_page_state(vars
, IOPolledFileGetIOBuffer(vars
->fileVars
),
1971 kIOHibernatePageStateFree
, &pageCount
);
1972 hibernate_set_descriptor_page_state(vars
, vars
->srcBuffer
,
1973 kIOHibernatePageStateFree
, &pageCount
);
1975 // copy out bitmap of pages available for trashing during restore
1977 bitmap_size
= vars
->page_list_wired
->list_size
;
1978 src
= (uint8_t *) vars
->page_list_wired
;
1979 err
= IOHibernatePolledFileWrite(vars
, src
, bitmap_size
, cryptvars
);
1980 if (kIOReturnSuccess
!= err
) {
1984 // mark more areas for no save, but these are not available
1985 // for trashing during restore
1987 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1989 #if defined(__i386__) || defined(__x86_64__)
1990 // __HIB is explicitly saved above so we don't have to save it again
1991 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
1992 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
1993 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1995 kIOHibernatePageStateFree
);
1997 #elif defined(__arm64__)
1998 // the segments described in IOHibernateHibSegInfo are stored directly in the
1999 // hibernation file, so they don't need to be saved again
2000 extern unsigned long gPhysBase
, gPhysSize
;
2001 for (size_t i
= 0; i
< NUM_HIBSEGINFO_SEGMENTS
; i
++) {
2002 page
= segInfo
->segments
[i
].physPage
;
2003 count
= segInfo
->segments
[i
].pageCount
;
2004 uint64_t physAddr
= ptoa_64(page
);
2005 uint64_t size
= ptoa_64(count
);
2007 (physAddr
>= gPhysBase
) &&
2008 (physAddr
+ size
<= gPhysBase
+ gPhysSize
)) {
2009 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2011 kIOHibernatePageStateFree
);
2016 #error unimplemented
2019 hibernate_set_descriptor_page_state(vars
, vars
->previewBuffer
,
2020 kIOHibernatePageStateFree
, &pageCount
);
2021 hibernate_set_descriptor_page_state(vars
, vars
->handoffBuffer
,
2022 kIOHibernatePageStateFree
, &pageCount
);
2025 vm_size_t shadow_pages_free
= atop_64(shadow_ptop
) - atop_64(shadow_pnext
);
2027 /* no need to save unused shadow pages */
2028 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2029 atop_64(shadow_pnext
),
2031 kIOHibernatePageStateFree
);
2034 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2035 compressed
= src
+ page_size
;
2036 scratch
= compressed
+ page_size
;
2041 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
2042 bitmap_size
, header
->previewSize
,
2043 pageCount
, vars
->fileVars
->position
);
2045 #if HIBERNATE_HMAC_IMAGE
2046 // we don't need to sign the page data into imageHeaderHMAC because it's
2047 // already signed into image1PagesHMAC/image2PagesHMAC
2048 vars
->imageShaCtx
= NULL
;
2049 header
->imageHeaderHMACSize
= (uint32_t)vars
->fileVars
->position
;
2050 #endif /* HIBERNATE_HMAC_IMAGE */
2057 kWiredEncrypt
= kWired
| kEncrypt
,
2058 kWiredClear
= kWired
,
2059 kUnwiredEncrypt
= kEncrypt
2062 #if defined(__i386__) || defined(__x86_64__)
2063 bool cpuAES
= (0 != (CPUID_FEATURE_AES
& cpuid_features()));
2064 #else /* defined(__i386__) || defined(__x86_64__) */
2065 static const bool cpuAES
= true;
2066 #endif /* defined(__i386__) || defined(__x86_64__) */
2068 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--) {
2069 if (kUnwiredEncrypt
== pageType
) {
2070 // start unwired image
2071 if (!vars
->hwEncrypt
&& (kIOHibernateModeEncrypt
& gIOHibernateMode
)) {
2072 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
2073 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2074 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2076 bcopy(&cryptvars
->aes_iv
[0],
2077 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2078 sizeof(cryptvars
->aes_iv
));
2079 cryptvars
= &gIOHibernateCryptWakeContext
;
2081 for (iterDone
= false, ppnum
= 0; !iterDone
;) {
2082 if (cpuAES
&& (pageType
== kWiredClear
)) {
2085 count
= hibernate_page_list_iterate((kWired
& pageType
) ? vars
->page_list_wired
: vars
->page_list
,
2087 if (count
> UINT_MAX
) {
2091 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2095 if (count
&& (kWired
& pageType
) && needEncrypt
) {
2096 uint32_t checkIndex
;
2097 for (checkIndex
= 0;
2098 (checkIndex
< count
)
2099 && (((kEncrypt
& pageType
) == 0) == pmap_is_noencrypt(((ppnum_t
)(ppnum
+ checkIndex
))));
2111 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
2112 case kWiredClear
: wiredPagesClear
+= count
; break;
2113 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
2116 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */
2118 pageAndCount
[0] = (uint32_t) ppnum
;
2119 pageAndCount
[1] = (uint32_t) count
;
2120 err
= IOHibernatePolledFileWrite(vars
,
2121 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2123 if (kIOReturnSuccess
!= err
) {
2128 for (page
= ppnum
; page
< (ppnum
+ count
); page
++) {
2129 #if HIBERNATE_HMAC_IMAGE
2130 wkresult
= ppl_hmac_update_and_compress_page(page
, (void **)&src
, compressed
);
2131 #else /* !HIBERNATE_HMAC_IMAGE */
2132 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
2134 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
2138 sum
= hibernate_sum_page(src
, (uint32_t) page
);
2139 if (kWired
& pageType
) {
2145 clock_get_uptime(&startTime
);
2146 wkresult
= WKdm_compress_new((const WK_word
*) src
,
2147 (WK_word
*) compressed
,
2149 (uint32_t) (page_size
- 4));
2150 #endif /* !HIBERNATE_HMAC_IMAGE */
2152 clock_get_uptime(&endTime
);
2153 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2154 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2156 compBytes
+= page_size
;
2157 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
2159 if (pageCompressedSize
== 0) {
2160 pageCompressedSize
= 4;
2163 if (*(uint32_t *)src
) {
2169 if (pageCompressedSize
!= page_size
) {
2176 assert(pageCompressedSize
<= page_size
);
2177 tag
= ((uint32_t) pageCompressedSize
) | kIOHibernateTagSignature
;
2178 err
= IOHibernatePolledFileWrite(vars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2179 if (kIOReturnSuccess
!= err
) {
2183 err
= IOHibernatePolledFileWrite(vars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2184 if (kIOReturnSuccess
!= err
) {
2188 compressedSize
+= pageCompressedSize
;
2189 uncompressedSize
+= page_size
;
2192 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
))) {
2193 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2194 if (blob
!= lastBlob
) {
2195 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2199 if (0 == (8191 & pagesDone
)) {
2200 clock_get_uptime(&endTime
);
2201 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2202 absolutetime_to_nanoseconds(endTime
, &nsec
);
2203 progressStamp
= nsec
/ 750000000ULL;
2204 if (progressStamp
!= lastProgressStamp
) {
2205 lastProgressStamp
= progressStamp
;
2206 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2210 if (kIOReturnSuccess
!= err
) {
2216 if (kIOReturnSuccess
!= err
) {
2220 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
) {
2221 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
2222 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2225 if (kWiredEncrypt
!= pageType
) {
2226 // end of image1/2 - fill to next block
2227 err
= IOHibernatePolledFileWrite(vars
, NULL
, 0, cryptvars
);
2228 if (kIOReturnSuccess
!= err
) {
2232 if (kWiredClear
== pageType
) {
2233 // enlarge wired image for test
2234 // err = IOHibernatePolledFileWrite(vars, 0, 0x60000000, cryptvars);
2237 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2238 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2239 image1Size
= vars
->fileVars
->position
;
2240 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2241 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2242 #if HIBERNATE_HMAC_IMAGE
2243 // compute the image1 HMAC
2244 ppl_hmac_final(header
->image1PagesHMAC
, sizeof(header
->image1PagesHMAC
));
2245 // reset the PPL context so we can compute the image2 (non-wired pages) HMAC
2246 ppl_hmac_reset(false);
2247 #endif /* HIBERNATE_HMAC_IMAGE */
2250 if (kIOReturnSuccess
!= err
) {
2251 if (kIOReturnOverrun
== err
) {
2252 // update actual compression ratio on not enough space (for retry)
2253 gIOHibernateCompression
= (compressedSize
<< 8) / uncompressedSize
;
2256 // update partial amount written (for IOPolledFileClose cleanup/unmap)
2257 header
->imageSize
= vars
->fileVars
->position
;
2261 #if HIBERNATE_HMAC_IMAGE
2262 // compute the image2 HMAC
2263 ppl_hmac_final(header
->image2PagesHMAC
, sizeof(header
->image2PagesHMAC
));
2264 #endif /* HIBERNATE_HMAC_IMAGE */
2268 header
->imageSize
= vars
->fileVars
->position
;
2269 header
->image1Size
= image1Size
;
2270 header
->bitmapSize
= bitmap_size
;
2271 header
->pageCount
= pageCount
;
2273 #if !HIBERNATE_HMAC_IMAGE
2274 header
->restore1Sum
= restore1Sum
;
2275 header
->image1Sum
= sum1
;
2276 header
->image2Sum
= sum2
;
2277 #endif /* !HIBERNATE_HMAC_IMAGE */
2278 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
2280 header
->compression
= ((uint32_t)((compressedSize
<< 8) / uncompressedSize
));
2281 gIOHibernateCompression
= header
->compression
;
2283 count
= vars
->fileVars
->fileExtents
->getLength();
2284 if (count
> sizeof(header
->fileExtentMap
)) {
2285 header
->fileExtentMapSize
= ((uint32_t) count
);
2286 count
= sizeof(header
->fileExtentMap
);
2288 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2290 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2292 header
->deviceBase
= vars
->fileVars
->block0
;
2293 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
2294 header
->lastHibAbsTime
= mach_absolute_time();
2295 header
->lastHibContTime
= mach_continuous_time();
2297 #if HIBERNATE_HMAC_IMAGE
2298 // include the headers in the SHA calculation
2299 SHA256_Update(&imageShaCtx
, header
, sizeof(*header
));
2301 // finalize the image header SHA
2302 uint8_t imageHash
[CCSHA256_OUTPUT_SIZE
];
2303 SHA256_Final(imageHash
, &imageShaCtx
);
2305 // compute the header HMAC
2306 ppl_hmac_finalize_image(imageHash
, sizeof(imageHash
), header
->imageHeaderHMAC
, sizeof(header
->imageHeaderHMAC
));
2307 #endif /* HIBERNATE_HMAC_IMAGE */
2309 IOPolledFileSeek(vars
->fileVars
, 0);
2310 err
= IOHibernatePolledFileWrite(vars
,
2311 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2313 if (kIOReturnSuccess
!= err
) {
2317 err
= IOHibernatePolledFileWrite(vars
, NULL
, 0, cryptvars
);
2320 clock_get_uptime(&endTime
);
2322 IOService::getPMRootDomain()->pmStatsRecordEvent(
2323 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2325 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2326 absolutetime_to_nanoseconds(endTime
, &nsec
);
2327 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
2329 absolutetime_to_nanoseconds(compTime
, &nsec
);
2330 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2333 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2335 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2336 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2337 vars
->fileVars
->cryptBytes
,
2339 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2341 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%)\n",
2342 header
->imageSize
, (header
->imageSize
* 100) / vars
->fileVars
->fileSize
,
2343 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2344 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0);
2346 #if !HIBERNATE_HMAC_IMAGE
2347 HIBLOG("\nsum1 %x, sum2 %x\n", sum1
, sum2
);
2348 #endif /* !HIBERNATE_HMAC_IMAGE */
2350 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2351 svPageCount
, zvPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
2354 IOPolledFilePollersClose(vars
->fileVars
, (kIOReturnSuccess
== err
) ? kIOPolledBeforeSleepState
: kIOPolledBeforeSleepStateAborted
);
2357 if (vars
->consoleMapping
) {
2358 ProgressUpdate(gIOHibernateGraphicsInfo
,
2359 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2362 HIBLOG("hibernate_write_image done(%x)\n", err
);
2364 // should we come back via regular wake, set the state in memory.
2365 gIOHibernateState
= kIOHibernateStateInactive
;
2367 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
, wiredPagesEncrypted
,
2368 wiredPagesClear
, dirtyPagesEncrypted
);
2370 #if defined(__arm64__)
2371 if (kIOReturnSuccess
== err
) {
2372 return kIOHibernatePostWriteHalt
;
2374 // on ARM, once ApplePMGR decides we're hibernating, we can't turn back
2375 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
2376 panic("hibernate_write_image encountered error 0x%x", err
);
2379 if (kIOReturnSuccess
== err
) {
2380 if (kIOHibernateModeSleep
& gIOHibernateMode
) {
2381 return kIOHibernatePostWriteSleep
;
2382 } else if (kIOHibernateModeRestart
& gIOHibernateMode
) {
2383 return kIOHibernatePostWriteRestart
;
2385 /* by default, power down */
2386 return kIOHibernatePostWriteHalt
;
2388 } else if (kIOReturnAborted
== err
) {
2389 return kIOHibernatePostWriteWake
;
2391 /* on error, sleep */
2392 return kIOHibernatePostWriteSleep
;
2397 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2400 hibernate_machine_init(void)
2405 uint32_t pagesRead
= 0;
2406 AbsoluteTime startTime
, compTime
;
2407 AbsoluteTime allTime
, endTime
;
2408 AbsoluteTime startIOTime
, endIOTime
;
2409 uint64_t nsec
, nsecIO
;
2411 uint64_t lastProgressStamp
= 0;
2412 uint64_t progressStamp
;
2413 IOPolledFileCryptVars
* cryptvars
= NULL
;
2415 IOHibernateVars
* vars
= &gIOHibernateVars
;
2416 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
2418 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
) {
2422 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2423 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2425 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) {
2426 HIBLOG("regular wake\n");
2430 HIBPRINT("diag %x %x %x %x\n",
2431 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2432 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2434 #if defined(__i386__) || defined(__x86_64__)
2435 #define t40ms(x) ((uint32_t)((tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)))
2436 #else /* defined(__i386__) || defined(__x86_64__) */
2438 #endif /* defined(__i386__) || defined(__x86_64__) */
2439 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2440 tStat(booterStart
, booterStart
);
2441 gIOHibernateStats
->smcStart
= gIOHibernateCurrentHeader
->smcStart
;
2442 tStat(booterDuration0
, booterTime0
);
2443 tStat(booterDuration1
, booterTime1
);
2444 tStat(booterDuration2
, booterTime2
);
2445 tStat(booterDuration
, booterTime
);
2446 tStat(booterConnectDisplayDuration
, connectDisplayTime
);
2447 tStat(booterSplashDuration
, splashTime
);
2448 tStat(trampolineDuration
, trampolineTime
);
2450 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
2451 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
2452 gIOHibernateStats
->image1Pages
= pagesDone
;
2454 /* HIBERNATE_stats */
2455 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 14), gIOHibernateStats
->smcStart
,
2456 gIOHibernateStats
->booterStart
, gIOHibernateStats
->booterDuration
,
2457 gIOHibernateStats
->trampolineDuration
);
2459 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2460 gIOHibernateStats
->booterStart
,
2461 gIOHibernateStats
->smcStart
,
2462 gIOHibernateStats
->booterDuration0
,
2463 gIOHibernateStats
->booterDuration1
,
2464 gIOHibernateStats
->booterDuration2
,
2465 gIOHibernateStats
->booterDuration
,
2466 gIOHibernateStats
->booterConnectDisplayDuration
,
2467 gIOHibernateStats
->booterSplashDuration
,
2468 gIOHibernateStats
->trampolineDuration
);
2470 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2471 gIOHibernateState
, pagesDone
, sum
, gIOHibernateStats
->imageSize
, gIOHibernateStats
->image1Size
,
2472 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2474 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
2475 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))) {
2476 hibernate_page_list_discard(vars
->page_list
);
2479 if (vars
->hwEncrypt
) {
2480 // if vars->hwEncrypt is true, we don't need cryptvars since we supply the
2481 // decryption key via IOPolledFilePollersSetEncryptionKey
2484 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: NULL
;
2487 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
) {
2488 panic("handoff overflow");
2491 IOHibernateHandoff
* handoff
;
2493 bool foundCryptData
= false;
2494 bool foundVolumeEncryptData
= false;
2495 const uint8_t * handoffStart
= (const uint8_t*)vars
->handoffBuffer
->getBytesNoCopy();
2496 const uint8_t * handoffEnd
= handoffStart
+ vars
->handoffBuffer
->getLength();
2498 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2500 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
]) {
2501 if (((uint8_t*)handoff
< handoffStart
) ||
2502 (&handoff
->data
[handoff
->bytecount
] > handoffEnd
)) {
2503 panic("handoff out of range");
2505 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2506 uint8_t * data
= &handoff
->data
[0];
2507 switch (handoff
->type
) {
2508 case kIOHibernateHandoffTypeEnd
:
2512 case kIOHibernateHandoffTypeGraphicsInfo
:
2513 if (handoff
->bytecount
== sizeof(*gIOHibernateGraphicsInfo
)) {
2514 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2518 case kIOHibernateHandoffTypeCryptVars
:
2520 hibernate_cryptwakevars_t
*
2521 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
2522 if (handoff
->bytecount
== sizeof(*wakevars
)) {
2523 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
2525 panic("kIOHibernateHandoffTypeCryptVars(%d)", handoff
->bytecount
);
2528 foundCryptData
= true;
2529 bzero(data
, handoff
->bytecount
);
2532 case kIOHibernateHandoffTypeVolumeCryptKey
:
2533 if (handoff
->bytecount
== vars
->volumeCryptKeySize
) {
2534 bcopy(data
, &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
2535 foundVolumeEncryptData
= true;
2537 panic("kIOHibernateHandoffTypeVolumeCryptKey(%d)", handoff
->bytecount
);
2541 #if defined(__i386__) || defined(__x86_64__)
2542 case kIOHibernateHandoffTypeMemoryMap
:
2544 clock_get_uptime(&allTime
);
2546 hibernate_newruntime_map(data
, handoff
->bytecount
,
2547 gIOHibernateCurrentHeader
->systemTableOffset
);
2549 clock_get_uptime(&endTime
);
2551 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2552 absolutetime_to_nanoseconds(endTime
, &nsec
);
2554 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
2558 case kIOHibernateHandoffTypeDeviceTree
:
2560 // DTEntry chosen = NULL;
2561 // HIBPRINT("SecureDTLookupEntry %d\n", SecureDTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2564 #endif /* defined(__i386__) || defined(__x86_64__) */
2567 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2572 if (vars
->hwEncrypt
&& !foundVolumeEncryptData
) {
2573 panic("no volumeCryptKey");
2574 } else if (cryptvars
&& !foundCryptData
) {
2575 panic("hibernate handoff");
2578 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2579 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2580 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2582 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
) {
2583 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2584 * gIOHibernateGraphicsInfo
->rowBytes
);
2585 if (vars
->videoMapSize
> vars
->videoAllocSize
) {
2586 vars
->videoMapSize
= 0;
2588 IOMapPages(kernel_map
,
2589 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2590 vars
->videoMapSize
, kIOMapInhibitCache
);
2594 if (vars
->videoMapSize
) {
2595 ProgressUpdate(gIOHibernateGraphicsInfo
,
2596 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2599 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2600 uint8_t * compressed
= src
+ page_size
;
2601 uint8_t * scratch
= compressed
+ page_size
;
2602 uint32_t decoOffset
;
2604 clock_get_uptime(&allTime
);
2605 AbsoluteTime_to_scalar(&compTime
) = 0;
2608 HIBLOG("IOPolledFilePollersOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2609 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledAfterSleepState
, false);
2610 clock_get_uptime(&startIOTime
);
2611 endTime
= startIOTime
;
2612 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2613 absolutetime_to_nanoseconds(endTime
, &nsec
);
2614 HIBLOG("IOPolledFilePollersOpen(%x) %qd ms\n", err
, nsec
/ 1000000ULL);
2616 if (vars
->hwEncrypt
) {
2617 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
,
2618 &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
2619 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x) %ld\n", err
, vars
->volumeCryptKeySize
);
2620 if (kIOReturnSuccess
!= err
) {
2621 panic("IOPolledFilePollersSetEncryptionKey(0x%x)", err
);
2626 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2628 // kick off the read ahead
2629 vars
->fileVars
->bufferHalf
= 0;
2630 vars
->fileVars
->bufferLimit
= 0;
2631 vars
->fileVars
->lastRead
= 0;
2632 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
2633 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2634 vars
->fileVars
->cryptBytes
= 0;
2635 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
2637 err
= IOPolledFileRead(vars
->fileVars
, NULL
, 0, cryptvars
);
2638 if (kIOReturnSuccess
!= err
) {
2639 panic("Hibernate restore error %x", err
);
2641 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2644 HIBLOG("hibernate_machine_init reading\n");
2646 #if HIBERNATE_HMAC_IMAGE
2647 // Reset SHA context to verify image2 hash (non-wired pages).
2648 ppl_hmac_reset(false);
2649 #endif /* HIBERNATE_HMAC_IMAGE */
2651 uint32_t * header
= (uint32_t *) src
;
2654 while (kIOReturnSuccess
== err
) {
2658 vm_offset_t compressedSize
;
2661 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2662 if (kIOReturnSuccess
!= err
) {
2663 panic("Hibernate restore error %x", err
);
2669 // HIBPRINT("(%x, %x)\n", ppnum, count);
2675 for (page
= 0; page
< count
; page
++) {
2676 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2677 if (kIOReturnSuccess
!= err
) {
2678 panic("Hibernate restore error %x", err
);
2681 compressedSize
= kIOHibernateTagLength
& tag
;
2682 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
)) {
2683 err
= kIOReturnIPCError
;
2684 panic("Hibernate restore error %x", err
);
2687 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2688 if (kIOReturnSuccess
!= err
) {
2689 panic("Hibernate restore error %x", err
);
2692 if (compressedSize
< page_size
) {
2693 decoOffset
= ((uint32_t) page_size
);
2694 clock_get_uptime(&startTime
);
2696 if (compressedSize
== 4) {
2700 s
= (uint32_t *)src
;
2701 d
= (uint32_t *)(uintptr_t)compressed
;
2703 for (i
= 0; i
< (int)(PAGE_SIZE
/ sizeof(int32_t)); i
++) {
2707 pal_hib_decompress_page(src
, compressed
, scratch
, ((unsigned int) compressedSize
));
2709 clock_get_uptime(&endTime
);
2710 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2711 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2712 compBytes
+= page_size
;
2717 sum
+= hibernate_sum_page((src
+ decoOffset
), ((uint32_t) ppnum
));
2718 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2720 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2721 panic("Hibernate restore error %x", err
);
2724 #if HIBERNATE_HMAC_IMAGE
2725 err
= ppl_hmac_update_and_compress_page(ppnum
, NULL
, NULL
);
2727 panic("Hibernate restore error %x", err
);
2729 #endif /* HIBERNATE_HMAC_IMAGE */
2735 if (0 == (8191 & pagesDone
)) {
2736 clock_get_uptime(&endTime
);
2737 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2738 absolutetime_to_nanoseconds(endTime
, &nsec
);
2739 progressStamp
= nsec
/ 750000000ULL;
2740 if (progressStamp
!= lastProgressStamp
) {
2741 lastProgressStamp
= progressStamp
;
2742 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2743 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2748 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
)) {
2749 err
= kIOReturnLockedRead
;
2752 if (kIOReturnSuccess
!= err
) {
2753 panic("Hibernate restore error %x", err
);
2756 #if HIBERNATE_HMAC_IMAGE
2757 uint8_t image2PagesHMAC
[HIBERNATE_HMAC_SIZE
];
2758 ppl_hmac_final(image2PagesHMAC
, sizeof(image2PagesHMAC
));
2759 if (memcmp(image2PagesHMAC
, gIOHibernateCurrentHeader
->image2PagesHMAC
, sizeof(image2PagesHMAC
)) != 0) {
2760 panic("image2 pages corrupted");
2762 #endif /* HIBERNATE_HMAC_IMAGE */
2764 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2765 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
2767 clock_get_uptime(&endIOTime
);
2769 err
= IOPolledFilePollersClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2771 clock_get_uptime(&endTime
);
2773 IOService::getPMRootDomain()->pmStatsRecordEvent(
2774 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2775 IOService::getPMRootDomain()->pmStatsRecordEvent(
2776 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2778 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2779 absolutetime_to_nanoseconds(endTime
, &nsec
);
2781 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
2782 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
2784 gIOHibernateStats
->kernelImageReadDuration
= ((uint32_t) (nsec
/ 1000000ULL));
2785 gIOHibernateStats
->imagePages
= pagesDone
;
2787 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
2788 pagesDone
, sum
, gIOHibernateStats
->kernelImageReadDuration
, kDefaultIOSize
,
2789 nsecIO
? ((((gIOHibernateCurrentHeader
->imageSize
- gIOHibernateCurrentHeader
->image1Size
) * 1000000000ULL) / 1024 / 1024) / nsecIO
) : 0);
2791 absolutetime_to_nanoseconds(compTime
, &nsec
);
2792 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2795 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2797 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2798 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2799 vars
->fileVars
->cryptBytes
,
2801 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2803 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 2), pagesRead
, pagesDone
);
2806 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2809 IOHibernateSetWakeCapabilities(uint32_t capability
)
2811 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2812 gIOHibernateStats
->wakeCapability
= capability
;
2814 if (kIOPMSystemCapabilityGraphics
& capability
) {
2815 vm_compressor_do_warmup();
2820 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2823 IOHibernateSystemRestart(void)
2825 static uint8_t noteStore
[32] __attribute__((aligned(32)));
2826 IORegistryEntry
* regEntry
;
2827 const OSSymbol
* sym
;
2830 uintptr_t * smcVars
;
2835 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
2840 smcVars
= (typeof(smcVars
))data
->getBytesNoCopy();
2841 smcBytes
= (typeof(smcBytes
))smcVars
[1];
2843 if (len
> sizeof(noteStore
)) {
2844 len
= sizeof(noteStore
);
2846 noteProp
= OSData::withCapacity(3 * sizeof(element
));
2851 noteProp
->appendBytes(&element
, sizeof(element
));
2852 element
= crc32(0, smcBytes
, len
);
2853 noteProp
->appendBytes(&element
, sizeof(element
));
2855 bcopy(smcBytes
, noteStore
, len
);
2856 element
= (addr64_t
) ¬eStore
[0];
2857 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
2858 noteProp
->appendBytes(&element
, sizeof(element
));
2860 if (!gIOOptionsEntry
) {
2861 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2862 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
2863 if (regEntry
&& !gIOOptionsEntry
) {
2864 regEntry
->release();
2868 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
2869 if (gIOOptionsEntry
&& sym
) {
2870 gIOOptionsEntry
->setProperty(sym
, noteProp
);
2873 noteProp
->release();