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
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
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/WKdm_new.h>
170 #include <vm/vm_protos.h>
171 #include "IOKitKernelInternal.h"
172 #include <pexpert/device_tree.h>
174 #include <machine/pal_routines.h>
175 #include <machine/pal_hibernate.h>
176 #include <i386/tsc.h>
177 #include <i386/cpuid.h>
178 #include <san/kasan.h>
180 extern "C" addr64_t
kvtophys(vm_offset_t va
);
181 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
183 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
185 #define DISABLE_TRIM 0
186 #define TRIM_DELAY 25000
188 extern unsigned int save_kdebug_enable
;
189 extern uint32_t gIOHibernateState
;
190 uint32_t gIOHibernateMode
;
191 static char gIOHibernateBootSignature
[256+1];
192 static char gIOHibernateFilename
[MAXPATHLEN
+1];
194 static uuid_string_t gIOHibernateBridgeBootSessionUUIDString
;
196 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
197 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
198 static uint64_t gIOHibernateCompression
= 0x80; // default compression 50%
199 boolean_t gIOHibernateStandbyDisabled
;
201 static IODTNVRAM
* gIOOptionsEntry
;
202 static IORegistryEntry
* gIOChosenEntry
;
204 static const OSSymbol
* gIOHibernateBootImageKey
;
205 static const OSSymbol
* gIOHibernateBootSignatureKey
;
206 static const OSSymbol
* gIOBridgeBootSessionUUIDKey
;
208 #if defined(__i386__) || defined(__x86_64__)
210 static const OSSymbol
* gIOHibernateRTCVariablesKey
;
211 static const OSSymbol
* gIOHibernateBoot0082Key
;
212 static const OSSymbol
* gIOHibernateBootNextKey
;
213 static OSData
* gIOHibernateBoot0082Data
;
214 static OSData
* gIOHibernateBootNextData
;
215 static OSObject
* gIOHibernateBootNextSave
;
217 static IOPolledFileIOVars
* gDebugImageFileVars
;
218 static IOLock
* gDebugImageLock
;
220 #endif /* defined(__i386__) || defined(__x86_64__) */
222 static IOLock
* gFSLock
;
224 static thread_call_t gIOHibernateTrimCalloutEntry
;
225 static IOPolledFileIOVars gFileVars
;
226 static IOHibernateVars gIOHibernateVars
;
227 static IOPolledFileCryptVars gIOHibernateCryptWakeContext
;
228 static hibernate_graphics_t _hibernateGraphics
;
229 static hibernate_graphics_t
* gIOHibernateGraphicsInfo
= &_hibernateGraphics
;
230 static hibernate_statistics_t _hibernateStats
;
231 static hibernate_statistics_t
* gIOHibernateStats
= &_hibernateStats
;
242 static IOReturn
IOHibernateDone(IOHibernateVars
* vars
);
243 static IOReturn
IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
);
244 static void IOSetBootImageNVRAM(OSData
* data
);
245 static void IOHibernateSystemPostWakeTrim(void * p1
, void * p2
);
247 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
249 enum { kDefaultIOSize
= 128 * 1024 };
250 enum { kVideoMapSize
= 80 * 1024 * 1024 };
252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
254 // copy from phys addr to MD
257 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
258 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
260 addr64_t srcAddr
= bytes
;
261 IOByteCount remaining
;
263 remaining
= length
= min(length
, md
->getLength() - offset
);
264 while (remaining
) { // (process another target segment?)
268 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
272 // Clip segment length to remaining
273 if (dstLen
> remaining
)
277 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
279 copypv(srcAddr
, dstAddr64
, dstLen
,
280 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
289 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
292 // copy from MD to phys addr
295 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
296 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
298 addr64_t dstAddr
= bytes
;
299 IOByteCount remaining
;
301 remaining
= length
= min(length
, md
->getLength() - offset
);
302 while (remaining
) { // (process another target segment?)
306 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
310 // Clip segment length to remaining
311 if (dstLen
> remaining
)
315 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
317 copypv(srcAddr
, dstAddr64
, dstLen
,
318 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
327 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
333 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
334 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
339 case kIOHibernatePageStateUnwiredSave
:
341 for (; ppnum
< count
; ppnum
++)
343 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
344 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
347 case kIOHibernatePageStateWiredSave
:
349 for (; ppnum
< count
; ppnum
++)
351 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
352 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
355 case kIOHibernatePageStateFree
:
357 for (; ppnum
< count
; ppnum
++)
359 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
360 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
364 panic("hibernate_set_page_state");
369 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
371 uint32_t page
= *pPage
;
373 hibernate_bitmap_t
* bitmap
;
375 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
377 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
381 if (page
<= bitmap
->last_page
)
387 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
394 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
397 IOHibernateSystemSleep(void)
404 bool dsSSD
, vmflush
, swapPinned
;
405 IOHibernateVars
* vars
;
406 uint64_t setFileSize
= 0;
408 gIOHibernateState
= kIOHibernateStateInactive
;
410 gIOHibernateDebugFlags
= 0;
411 if (kIOLogHibernate
& gIOKitDebug
)
412 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
414 if (IOService::getPMRootDomain()->getHibernateSettings(
415 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
417 if (kIOHibernateModeSleep
& gIOHibernateMode
)
418 // default to discard clean for safe sleep
419 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
420 | kIOHibernateModeDiscardCleanActive
);
423 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
425 if ((str
= OSDynamicCast(OSString
, obj
)))
426 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
427 sizeof(gIOHibernateFilename
));
431 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
432 return (kIOReturnUnsupported
);
434 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
436 vars
= IONew(IOHibernateVars
, 1);
437 if (!vars
) return (kIOReturnNoMemory
);
438 bzero(vars
, sizeof(*vars
));
441 if (!gIOHibernateTrimCalloutEntry
)
443 gIOHibernateTrimCalloutEntry
= thread_call_allocate(&IOHibernateSystemPostWakeTrim
, &gFSLock
);
445 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
446 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
447 if (kFSIdle
!= gFSState
)
449 HIBLOG("hibernate file busy\n");
450 IOLockUnlock(gFSLock
);
451 IODelete(vars
, IOHibernateVars
, 1);
452 return (kIOReturnBusy
);
454 gFSState
= kFSOpening
;
455 IOLockUnlock(gFSLock
);
460 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
461 2 * page_size
+ WKdm_SCRATCH_BUF_SIZE_INTERNAL
, page_size
);
463 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
464 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
466 if (!vars
->srcBuffer
|| !vars
->handoffBuffer
)
468 err
= kIOReturnNoMemory
;
472 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey
)))
474 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMinSize
= num
->unsigned64BitValue();
477 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey
)))
479 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMaxSize
= num
->unsigned64BitValue();
483 boolean_t encryptedswap
= true;
485 AbsoluteTime startTime
, endTime
;
488 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
489 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
490 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
492 vmflush
= ((kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
493 err
= hibernate_alloc_page_lists(&vars
->page_list
,
494 &vars
->page_list_wired
,
495 &vars
->page_list_pal
);
496 if (KERN_SUCCESS
!= err
) break;
498 err
= hibernate_pin_swap(TRUE
);
499 if (KERN_SUCCESS
!= err
) break;
502 if (vars
->fileMinSize
|| (kIOHibernateModeFileResize
& gIOHibernateMode
))
504 hibernate_page_list_setall(vars
->page_list
,
505 vars
->page_list_wired
,
507 true /* preflight */,
508 vmflush
/* discard */,
510 PE_Video consoleInfo
;
511 bzero(&consoleInfo
, sizeof(consoleInfo
));
512 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
514 // estimate: 6% increase in pages compressed
515 // screen preview 2 images compressed 0%
516 setFileSize
= ((ptoa_64((106 * pageCount
) / 100) * gIOHibernateCompression
) >> 8)
517 + vars
->page_list
->list_size
518 + (consoleInfo
.v_width
* consoleInfo
.v_height
* 8);
519 enum { setFileRound
= 1024*1024ULL };
520 setFileSize
= ((setFileSize
+ setFileRound
) & ~(setFileRound
- 1));
522 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
523 pageCount
, (100ULL * gIOHibernateCompression
) >> 8,
524 setFileSize
, vars
->fileMinSize
);
526 if (!(kIOHibernateModeFileResize
& gIOHibernateMode
)
527 && (setFileSize
< vars
->fileMinSize
))
529 setFileSize
= vars
->fileMinSize
;
533 // Invalidate the image file
534 if (gDebugImageLock
) {
535 IOLockLock(gDebugImageLock
);
536 if (gDebugImageFileVars
!= 0) {
537 IOSetBootImageNVRAM(0);
538 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
540 IOLockUnlock(gDebugImageLock
);
543 vars
->volumeCryptKeySize
= sizeof(vars
->volumeCryptKey
);
544 err
= IOPolledFileOpen(gIOHibernateFilename
, setFileSize
, 0,
545 gIOHibernateCurrentHeader
, sizeof(gIOHibernateCurrentHeader
),
546 &vars
->fileVars
, &nvramData
,
547 &vars
->volumeCryptKey
[0], &vars
->volumeCryptKeySize
);
549 if (KERN_SUCCESS
!= err
)
552 if (kFSOpening
!= gFSState
) err
= kIOReturnTimeout
;
553 IOLockUnlock(gFSLock
);
556 if (KERN_SUCCESS
!= err
)
558 HIBLOG("IOPolledFileOpen(%x)\n", err
);
562 // write extents for debug data usage in EFI
563 IOWriteExtentsToFile(vars
->fileVars
, kIOHibernateHeaderOpenSignature
);
565 err
= IOPolledFilePollersSetup(vars
->fileVars
, kIOPolledPreflightState
);
566 if (KERN_SUCCESS
!= err
) break;
568 clock_get_uptime(&startTime
);
569 err
= hibernate_setup(gIOHibernateCurrentHeader
,
571 vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
572 clock_get_uptime(&endTime
);
573 SUB_ABSOLUTETIME(&endTime
, &startTime
);
574 absolutetime_to_nanoseconds(endTime
, &nsec
);
576 boolean_t haveSwapPin
, hibFileSSD
;
577 haveSwapPin
= vm_swap_files_pinned();
579 hibFileSSD
= (kIOPolledFileSSD
& vars
->fileVars
->flags
);
581 HIBLOG("hibernate_setup(%d) took %qd ms, swapPin(%d) ssd(%d)\n",
582 err
, nsec
/ 1000000ULL,
583 haveSwapPin
, hibFileSSD
);
584 if (KERN_SUCCESS
!= err
) break;
586 gIOHibernateStandbyDisabled
= ((!haveSwapPin
|| !hibFileSSD
));
588 dsSSD
= ((0 != (kIOPolledFileSSD
& vars
->fileVars
->flags
))
589 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
591 if (dsSSD
) gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionSSD
| kIOHibernateOptionColor
;
592 else gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
595 #if defined(__i386__) || defined(__x86_64__)
596 if (vars
->volumeCryptKeySize
&&
597 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
)))
599 uintptr_t smcVars
[2];
600 smcVars
[0] = vars
->volumeCryptKeySize
;
601 smcVars
[1] = (uintptr_t)(void *) &gIOHibernateVars
.volumeCryptKey
[0];
603 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
604 bzero(smcVars
, sizeof(smcVars
));
609 if (encryptedswap
|| vars
->volumeCryptKeySize
)
610 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
612 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
614 vars
->videoAllocSize
= kVideoMapSize
;
615 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
, VM_KERN_MEMORY_IOKIT
))
616 vars
->videoMapping
= 0;
619 // generate crypt keys
620 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
621 vars
->wiredCryptKey
[i
] = random();
622 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
623 vars
->cryptKey
[i
] = random();
627 IOSetBootImageNVRAM(nvramData
);
628 nvramData
->release();
630 #if defined(__i386__) || defined(__x86_64__)
632 struct AppleRTCHibernateVars
634 uint8_t signature
[4];
636 uint8_t booterSignature
[20];
637 uint8_t wiredCryptKey
[16];
639 AppleRTCHibernateVars rtcVars
;
642 rtcVars
.signature
[0] = 'A';
643 rtcVars
.signature
[1] = 'A';
644 rtcVars
.signature
[2] = 'P';
645 rtcVars
.signature
[3] = 'L';
646 rtcVars
.revision
= 1;
647 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
650 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOHibernateBootSignatureKey
)))
651 && (sizeof(rtcVars
.booterSignature
) <= data
->getLength()))
653 bcopy(data
->getBytesNoCopy(), &rtcVars
.booterSignature
[0], sizeof(rtcVars
.booterSignature
));
655 else if (gIOHibernateBootSignature
[0])
659 uint32_t in
, out
, digits
;
660 for (in
= out
= digits
= 0;
661 (c
= gIOHibernateBootSignature
[in
]) && (in
< sizeof(gIOHibernateBootSignature
));
664 if ((c
>= 'a') && (c
<= 'f')) c
-= 'a' - 10;
665 else if ((c
>= 'A') && (c
<= 'F')) c
-= 'A' - 10;
666 else if ((c
>= '0') && (c
<= '9')) c
-= '0';
669 if (c
== '=') out
= digits
= value
= 0;
672 value
= (value
<< 4) | c
;
675 rtcVars
.booterSignature
[out
++] = value
;
676 if (out
>= sizeof(rtcVars
.booterSignature
)) break;
681 #if DEBUG || DEVELOPMENT
682 if (kIOLogHibernate
& gIOKitDebug
) IOKitKernelLogBuffer("H> rtc:",
683 &rtcVars
, sizeof(rtcVars
), &kprintf
);
684 #endif /* DEBUG || DEVELOPMENT */
686 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
689 if (gIOHibernateRTCVariablesKey
)
690 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
693 if (gIOChosenEntry
&& gIOOptionsEntry
)
695 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
696 if (data
) gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
698 if (!gIOHibernateBoot0082Data
)
700 OSData
* fileData
= 0;
701 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
702 if (data
&& data
->getLength() >= 4) fileData
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-file-path"));
705 // AppleNVRAM_EFI_LOAD_OPTION
708 uint16_t FilePathLength
;
711 loadOptionHeader
.Attributes
= 1;
712 loadOptionHeader
.FilePathLength
= data
->getLength();
713 loadOptionHeader
.Desc
= 0;
716 loadOptionHeader
.FilePathLength
-= 4;
717 loadOptionHeader
.FilePathLength
+= fileData
->getLength();
719 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
720 if (gIOHibernateBoot0082Data
)
722 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
725 gIOHibernateBoot0082Data
->appendBytes(data
->getBytesNoCopy(), data
->getLength() - 4);
726 gIOHibernateBoot0082Data
->appendBytes(fileData
);
728 else gIOHibernateBoot0082Data
->appendBytes(data
);
732 if (!gIOHibernateBootNextData
)
734 uint16_t bits
= 0x0082;
735 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
738 #if DEBUG || DEVELOPMENT
739 if (kIOLogHibernate
& gIOKitDebug
) IOKitKernelLogBuffer("H> bootnext:",
740 gIOHibernateBoot0082Data
->getBytesNoCopy(), gIOHibernateBoot0082Data
->getLength(), &kprintf
);
741 #endif /* DEBUG || DEVELOPMENT */
742 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
744 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
745 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
746 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
751 #endif /* !i386 && !x86_64 */
755 if (swapPinned
) hibernate_pin_swap(FALSE
);
758 if ((kIOReturnSuccess
== err
) && (kFSOpening
!= gFSState
))
760 HIBLOG("hibernate file close due timeout\n");
761 err
= kIOReturnTimeout
;
763 if (kIOReturnSuccess
== err
)
765 gFSState
= kFSOpened
;
766 gIOHibernateVars
= *vars
;
767 gFileVars
= *vars
->fileVars
;
768 gFileVars
.allocated
= false;
769 gIOHibernateVars
.fileVars
= &gFileVars
;
770 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
771 gIOHibernateState
= kIOHibernateStateHibernating
;
773 #if DEBUG || DEVELOPMENT
774 if (kIOLogHibernate
& gIOKitDebug
)
776 OSData
* data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
779 uintptr_t * smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
780 IOKitKernelLogBuffer("H> smc:",
781 (const void *)smcVars
[1], smcVars
[0], &kprintf
);
784 #endif /* DEBUG || DEVELOPMENT */
788 IOPolledFileIOVars
* fileVars
= vars
->fileVars
;
789 IOHibernateDone(vars
);
790 IOPolledFileClose(&fileVars
,
794 0, NULL
, 0, sizeof(IOHibernateImageHeader
), setFileSize
);
798 IOLockUnlock(gFSLock
);
800 if (vars
->fileVars
) IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
801 IODelete(vars
, IOHibernateVars
, 1);
806 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
809 IOSetBootImageNVRAM(OSData
* data
)
811 IORegistryEntry
* regEntry
;
813 if (!gIOOptionsEntry
)
815 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
816 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
817 if (regEntry
&& !gIOOptionsEntry
)
820 if (gIOOptionsEntry
&& gIOHibernateBootImageKey
)
824 gIOOptionsEntry
->setProperty(gIOHibernateBootImageKey
, data
);
825 #if DEBUG || DEVELOPMENT
826 if (kIOLogHibernate
& gIOKitDebug
) IOKitKernelLogBuffer("H> boot-image:",
827 data
->getBytesNoCopy(), data
->getLength(), &kprintf
);
828 #endif /* DEBUG || DEVELOPMENT */
832 gIOOptionsEntry
->removeProperty(gIOHibernateBootImageKey
);
833 gIOOptionsEntry
->sync();
838 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
840 * Writes header to disk with signature, block size and file extents data.
841 * If there are more than 2 extents, then they are written on second block.
844 IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
)
846 IOHibernateImageHeader hdr
;
848 IOReturn err
= kIOReturnSuccess
;
850 IOPolledFileExtent
* fileExtents
;
852 fileExtents
= (typeof(fileExtents
)) vars
->fileExtents
->getBytesNoCopy();
854 memset(&hdr
, 0, sizeof(IOHibernateImageHeader
));
855 count
= vars
->fileExtents
->getLength();
856 if (count
> sizeof(hdr
.fileExtentMap
))
858 hdr
.fileExtentMapSize
= count
;
859 count
= sizeof(hdr
.fileExtentMap
);
862 hdr
.fileExtentMapSize
= sizeof(hdr
.fileExtentMap
);
864 bcopy(fileExtents
, &hdr
.fileExtentMap
[0], count
);
866 // copy file block extent list if larger than header
867 if (hdr
.fileExtentMapSize
> sizeof(hdr
.fileExtentMap
))
869 count
= hdr
.fileExtentMapSize
- sizeof(hdr
.fileExtentMap
);
870 rc
= kern_write_file(vars
->fileRef
, vars
->blockSize
,
871 (caddr_t
)(((uint8_t *)fileExtents
) + sizeof(hdr
.fileExtentMap
)),
872 count
, IO_SKIP_ENCRYPTION
);
874 HIBLOG("kern_write_file returned %d\n", rc
);
875 err
= kIOReturnIOError
;
879 hdr
.signature
= signature
;
880 hdr
.deviceBlockSize
= vars
->blockSize
;
882 rc
= kern_write_file(vars
->fileRef
, 0, (char *)&hdr
, sizeof(hdr
), IO_SKIP_ENCRYPTION
);
884 HIBLOG("kern_write_file returned %d\n", rc
);
885 err
= kIOReturnIOError
;
893 extern "C" boolean_t root_is_CF_drive
;
896 IOOpenDebugDataFile(const char *fname
, uint64_t size
)
899 OSData
* imagePath
= NULL
;
902 if (!gDebugImageLock
) {
903 gDebugImageLock
= IOLockAlloc();
906 if (root_is_CF_drive
) return;
908 // Try to get a lock, but don't block for getting lock
909 if (!IOLockTryLock(gDebugImageLock
)) {
910 HIBLOG("IOOpenDebugDataFile: Failed to get lock\n");
914 if (gDebugImageFileVars
|| !fname
|| !size
) {
915 HIBLOG("IOOpenDebugDataFile: conditions failed\n");
919 padding
= (PAGE_SIZE
*2); // allocate couple more pages for header and fileextents
920 err
= IOPolledFileOpen(fname
, size
+padding
, 32ULL*1024*1024*1024,
922 &gDebugImageFileVars
, &imagePath
, NULL
, 0);
924 if ((kIOReturnSuccess
== err
) && imagePath
)
926 if ((gDebugImageFileVars
->fileSize
< (size
+padding
)) ||
927 (gDebugImageFileVars
->fileExtents
->getLength() > PAGE_SIZE
)) {
928 // Can't use the file
929 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
930 HIBLOG("IOOpenDebugDataFile: too many file extents\n");
934 // write extents for debug data usage in EFI
935 IOWriteExtentsToFile(gDebugImageFileVars
, kIOHibernateHeaderOpenSignature
);
936 IOSetBootImageNVRAM(imagePath
);
940 IOLockUnlock(gDebugImageLock
);
942 if (imagePath
) imagePath
->release();
947 IOCloseDebugDataFile()
949 IOSetBootImageNVRAM(0);
951 if (gDebugImageLock
) {
952 IOLockLock(gDebugImageLock
);
953 if (gDebugImageFileVars
!= 0) {
954 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
956 IOLockUnlock(gDebugImageLock
);
962 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
964 DECLARE_IOHIBERNATEPROGRESSALPHA
967 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
969 uint32_t rowBytes
, pixelShift
;
972 uint32_t alpha
, in
, color
, result
;
974 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
976 rowBytes
= display
->rowBytes
;
977 pixelShift
= display
->depth
>> 4;
978 if (pixelShift
< 1) return;
980 screen
+= ((display
->width
981 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
982 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
984 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
986 out
= screen
+ y
* rowBytes
;
987 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
989 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
990 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
992 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1000 in
= *((uint16_t *)out
) & 0x1f; // 16
1001 in
= (in
<< 3) | (in
>> 2);
1004 in
= *((uint32_t *)out
) & 0xff; // 32
1005 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1006 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1008 if (1 == pixelShift
)
1011 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1014 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1016 out
+= (1 << pixelShift
);
1018 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1025 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1027 uint32_t rowBytes
, pixelShift
;
1029 int32_t blob
, lastBlob
;
1030 uint32_t alpha
, in
, color
, result
;
1032 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1034 pixelShift
= display
->depth
>> 4;
1038 rowBytes
= display
->rowBytes
;
1040 screen
+= ((display
->width
1041 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1042 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1044 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1046 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1048 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1050 out
= screen
+ y
* rowBytes
;
1051 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1053 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1054 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1056 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1062 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1063 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1065 if (1 == pixelShift
)
1068 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1071 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1073 out
+= (1 << pixelShift
);
1075 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1080 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1083 IOHibernateIOKitSleep(void)
1085 IOReturn ret
= kIOReturnSuccess
;
1086 IOLockLock(gFSLock
);
1087 if (kFSOpening
== gFSState
)
1089 gFSState
= kFSTimedOut
;
1090 HIBLOG("hibernate file open timed out\n");
1091 ret
= kIOReturnTimeout
;
1093 IOLockUnlock(gFSLock
);
1097 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1100 IOHibernateSystemHasSlept(void)
1102 IOReturn ret
= kIOReturnSuccess
;
1103 IOHibernateVars
* vars
= &gIOHibernateVars
;
1107 IOLockLock(gFSLock
);
1108 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
)
1110 ret
= kIOReturnTimeout
;
1112 IOLockUnlock(gFSLock
);
1113 if (kIOReturnSuccess
!= ret
) return (ret
);
1115 if (gIOHibernateMode
) obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1116 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1117 if (obj
&& !vars
->previewBuffer
)
1120 vars
->consoleMapping
= NULL
;
1121 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1123 vars
->previewBuffer
->release();
1124 vars
->previewBuffer
= 0;
1127 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1128 && vars
->previewBuffer
1129 && (data
= OSDynamicCast(OSData
,
1130 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1132 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1133 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1135 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1137 if (kIOHibernatePreviewUpdates
& flags
)
1139 PE_Video consoleInfo
;
1140 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1142 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1144 graphicsInfo
->width
= consoleInfo
.v_width
;
1145 graphicsInfo
->height
= consoleInfo
.v_height
;
1146 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1147 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1148 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1150 HIBPRINT("video %p %d %d %d\n",
1151 vars
->consoleMapping
, graphicsInfo
->depth
,
1152 graphicsInfo
->width
, graphicsInfo
->height
);
1153 if (vars
->consoleMapping
)
1154 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1155 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1159 if (gIOOptionsEntry
)
1160 gIOOptionsEntry
->sync();
1165 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1167 static DeviceTreeNode
*
1168 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
1170 DeviceTreeNodeProperty
* prop
;
1171 DeviceTreeNode
* child
;
1172 IORegistryEntry
* childRegEntry
;
1173 const char * nameProp
;
1174 unsigned int propLen
, idx
;
1176 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1177 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
1179 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
1181 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1182 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1184 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1187 child
= (DeviceTreeNode
*) prop
;
1188 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
1190 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
1192 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1193 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1194 child
= MergeDeviceTree(child
, childRegEntry
);
1200 IOHibernateSystemWake(void)
1202 if (kFSOpened
== gFSState
)
1204 IOPolledFilePollersClose(gIOHibernateVars
.fileVars
, kIOPolledPostflightState
);
1205 IOHibernateDone(&gIOHibernateVars
);
1209 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1210 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1212 return (kIOReturnSuccess
);
1216 IOHibernateDone(IOHibernateVars
* vars
)
1221 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1223 if (vars
->videoMapping
)
1225 if (vars
->videoMapSize
)
1227 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1228 if (vars
->videoAllocSize
)
1230 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1233 if (vars
->previewBuffer
)
1235 vars
->previewBuffer
->release();
1236 vars
->previewBuffer
= 0;
1239 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1241 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1242 gIOHibernateCurrentHeader
->options
, 32);
1246 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1249 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1250 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1252 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1253 &gIOHibernateGraphicsInfo
->gfxStatus
,
1254 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1258 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1261 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1263 #if defined(__i386__) || defined(__x86_64__)
1264 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1265 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1268 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1269 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1271 if (gIOOptionsEntry
) {
1273 if (gIOHibernateRTCVariablesKey
) {
1274 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1275 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1279 if (gIOHibernateBootNextKey
)
1281 if (gIOHibernateBootNextSave
)
1283 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1284 gIOHibernateBootNextSave
->release();
1285 gIOHibernateBootNextSave
= NULL
;
1288 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1290 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) gIOOptionsEntry
->sync();
1294 if (vars
->srcBuffer
) vars
->srcBuffer
->release();
1295 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1296 if (vars
->handoffBuffer
)
1298 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1300 IOHibernateHandoff
* handoff
;
1302 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1304 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
1306 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1307 uint8_t * data
= &handoff
->data
[0];
1308 switch (handoff
->type
)
1310 case kIOHibernateHandoffTypeEnd
:
1314 case kIOHibernateHandoffTypeDeviceTree
:
1315 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
1318 case kIOHibernateHandoffTypeKeyStore
:
1319 #if defined(__i386__) || defined(__x86_64__)
1321 IOBufferMemoryDescriptor
*
1322 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1325 IOSetKeyStoreData(md
);
1332 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1336 #if defined(__i386__) || defined(__x86_64__)
1337 if (vars
->volumeCryptKeySize
)
1339 IOBufferMemoryDescriptor
*
1340 bmd
= IOBufferMemoryDescriptor::withBytes(&vars
->volumeCryptKey
[0],
1341 vars
->volumeCryptKeySize
, kIODirectionOutIn
);
1342 if (!bmd
) panic("IOBufferMemoryDescriptor");
1343 IOSetAPFSKeyStoreData(bmd
);
1344 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1349 vars
->handoffBuffer
->release();
1353 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOBridgeBootSessionUUIDKey
)))
1354 && (sizeof(gIOHibernateBridgeBootSessionUUIDString
) <= data
->getLength()))
1356 bcopy(data
->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString
[0],
1357 sizeof(gIOHibernateBridgeBootSessionUUIDString
));
1360 if (vars
->hwEncrypt
)
1362 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
, NULL
, 0);
1363 HIBLOG("IOPolledFilePollersSetEncryptionKey(0,%x)\n", err
);
1366 bzero(vars
, sizeof(*vars
));
1368 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1370 return (kIOReturnSuccess
);
1374 IOHibernateSystemPostWakeTrim(void * p1
, void * p2
)
1376 // invalidate & close the image file
1377 if (p1
) IOLockLock(gFSLock
);
1378 if (kFSTrimDelay
== gFSState
)
1380 IOPolledFileIOVars
* vars
= &gFileVars
;
1381 IOPolledFileClose(&vars
,
1385 0, (caddr_t
)gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
),
1386 sizeof(IOHibernateImageHeader
), gIOHibernateCurrentHeader
->imageSize
);
1390 if (p1
) IOLockUnlock(gFSLock
);
1394 IOHibernateSystemPostWake(bool now
)
1396 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1397 IOLockLock(gFSLock
);
1398 if (kFSTrimDelay
== gFSState
)
1400 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
1401 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1403 else if (kFSOpened
!= gFSState
) gFSState
= kFSIdle
;
1406 gFSState
= kFSTrimDelay
;
1409 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
1410 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1414 AbsoluteTime deadline
;
1415 clock_interval_to_deadline(TRIM_DELAY
, kMillisecondScale
, &deadline
);
1416 thread_call_enter1_delayed(gIOHibernateTrimCalloutEntry
, NULL
, deadline
);
1419 IOLockUnlock(gFSLock
);
1421 return (kIOReturnSuccess
);
1424 uint32_t IOHibernateWasScreenLocked(void)
1427 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
)
1430 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
1433 ret
= ((uint32_t *)data
->getBytesNoCopy())[0];
1434 gIOChosenEntry
->setProperty(kIOBooterScreenLockStateKey
, data
);
1437 else gIOChosenEntry
->removeProperty(kIOBooterScreenLockStateKey
);
1442 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1444 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1445 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1446 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1447 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1448 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1449 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1450 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1451 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1452 &gIOHibernateMode
, 0, "");
1453 SYSCTL_STRUCT(_kern
, OID_AUTO
, hibernatestatistics
,
1454 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1455 &_hibernateStats
, hibernate_statistics_t
, "");
1456 SYSCTL_STRING(_kern_bridge
, OID_AUTO
, bootsessionuuid
,
1457 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1458 gIOHibernateBridgeBootSessionUUIDString
, sizeof(gIOHibernateBridgeBootSessionUUIDString
), "");
1460 SYSCTL_UINT(_kern
, OID_AUTO
, hibernategraphicsready
,
1461 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1462 &_hibernateStats
.graphicsReadyTime
, 0, "");
1463 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatewakenotification
,
1464 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1465 &_hibernateStats
.wakeNotificationTime
, 0, "");
1466 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatelockscreenready
,
1467 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1468 &_hibernateStats
.lockScreenReadyTime
, 0, "");
1469 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatehidready
,
1470 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1471 &_hibernateStats
.hidReadyTime
, 0, "");
1474 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1476 gIOHibernateBootImageKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1477 gIOHibernateBootSignatureKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1478 gIOBridgeBootSessionUUIDKey
= OSSymbol::withCStringNoCopy(kIOBridgeBootSessionUUIDKey
);
1480 #if defined(__i386__) || defined(__x86_64__)
1481 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1482 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1483 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1484 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1485 #endif /* defined(__i386__) || defined(__x86_64__) */
1487 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1490 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1494 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1495 gIOHibernateMode
= kIOHibernateModeOn
;
1497 gIOHibernateFilename
[0] = 0;
1499 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1500 sysctl_register_oid(&sysctl__kern_bootsignature
);
1501 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1502 sysctl_register_oid(&sysctl__kern_hibernatestatistics
);
1503 sysctl_register_oid(&sysctl__kern_hibernategraphicsready
);
1504 sysctl_register_oid(&sysctl__kern_hibernatewakenotification
);
1505 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready
);
1506 sysctl_register_oid(&sysctl__kern_hibernatehidready
);
1508 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1511 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOBridgeBootSessionUUIDKey
)))
1512 && (sizeof(gIOHibernateBridgeBootSessionUUIDString
) <= data
->getLength()))
1514 sysctl_register_oid(&sysctl__kern_bridge_bootsessionuuid
);
1515 bcopy(data
->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString
[0], sizeof(gIOHibernateBridgeBootSessionUUIDString
));
1518 gFSLock
= IOLockAlloc();
1521 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1524 IOHibernatePolledFileWrite(IOPolledFileIOVars
* vars
,
1525 const uint8_t * bytes
, IOByteCount size
,
1526 IOPolledFileCryptVars
* cryptvars
)
1530 err
= IOPolledFileWrite(vars
, bytes
, size
, cryptvars
);
1531 if ((kIOReturnSuccess
== err
) && hibernate_should_abort()) err
= kIOReturnAborted
;
1536 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1539 hibernate_write_image(void)
1541 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1542 IOHibernateVars
* vars
= &gIOHibernateVars
;
1543 IOPolledFileExtent
* fileExtents
;
1545 _static_assert_1_arg(sizeof(IOHibernateImageHeader
) == 512);
1547 uint32_t pageCount
, pagesDone
;
1549 vm_offset_t ppnum
, page
;
1553 uint8_t * compressed
;
1555 IOByteCount pageCompressedSize
;
1556 uint64_t compressedSize
, uncompressedSize
;
1557 uint64_t image1Size
= 0;
1558 uint32_t bitmap_size
;
1559 bool iterDone
, pollerOpen
, needEncrypt
;
1560 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1564 uint32_t pageAndCount
[2];
1567 uintptr_t hibernateBase
;
1568 uintptr_t hibernateEnd
;
1570 AbsoluteTime startTime
, endTime
;
1571 AbsoluteTime allTime
, compTime
;
1574 uint32_t lastProgressStamp
= 0;
1575 uint32_t progressStamp
;
1576 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1578 uint32_t wiredPagesEncrypted
;
1579 uint32_t dirtyPagesEncrypted
;
1580 uint32_t wiredPagesClear
;
1581 uint32_t svPageCount
;
1582 uint32_t zvPageCount
;
1584 IOPolledFileCryptVars _cryptvars
;
1585 IOPolledFileCryptVars
* cryptvars
= 0;
1587 wiredPagesEncrypted
= 0;
1588 dirtyPagesEncrypted
= 0;
1589 wiredPagesClear
= 0;
1594 || !vars
->fileVars
->pollers
1595 || !(kIOHibernateModeOn
& gIOHibernateMode
)) return (kIOHibernatePostWriteSleep
);
1597 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1598 kdebug_enable
= save_kdebug_enable
;
1600 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
);
1601 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
1603 restore1Sum
= sum1
= sum2
= 0;
1606 // encryption data. "iv" is the "initial vector".
1607 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1609 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1610 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1611 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1613 cryptvars
= &gIOHibernateCryptWakeContext
;
1614 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1615 aes_encrypt_key(vars
->cryptKey
,
1616 kIOHibernateAESKeySize
,
1617 &cryptvars
->ctx
.encrypt
);
1618 aes_decrypt_key(vars
->cryptKey
,
1619 kIOHibernateAESKeySize
,
1620 &cryptvars
->ctx
.decrypt
);
1622 cryptvars
= &_cryptvars
;
1623 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1624 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++)
1625 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
1626 aes_encrypt_key(vars
->wiredCryptKey
,
1627 kIOHibernateAESKeySize
,
1628 &cryptvars
->ctx
.encrypt
);
1630 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1631 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1632 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1636 hibernate_page_list_setall(vars
->page_list
,
1637 vars
->page_list_wired
,
1638 vars
->page_list_pal
,
1639 false /* !preflight */,
1641 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
1642 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
1645 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1647 fileExtents
= (IOPolledFileExtent
*) vars
->fileVars
->fileExtents
->getBytesNoCopy();
1650 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1651 for (page
= 0; page
< count
; page
++)
1653 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1654 fileExtents
[page
].start
, fileExtents
[page
].length
,
1655 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1659 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1660 AbsoluteTime_to_scalar(&compTime
) = 0;
1663 clock_get_uptime(&allTime
);
1664 IOService::getPMRootDomain()->pmStatsRecordEvent(
1665 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1669 uncompressedSize
= 0;
1673 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
1675 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1676 ml_get_interrupts_enabled());
1677 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledBeforeSleepState
,
1678 // abortable if not low battery
1679 !IOService::getPMRootDomain()->mustHibernate());
1680 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1681 pollerOpen
= (kIOReturnSuccess
== err
);
1685 if (vars
->volumeCryptKeySize
)
1687 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
, &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
1688 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x)\n", err
);
1689 vars
->hwEncrypt
= (kIOReturnSuccess
== err
);
1690 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1691 if (vars
->hwEncrypt
) header
->options
|= kIOHibernateOptionHWEncrypt
;
1694 // copy file block extent list if larger than header
1696 count
= vars
->fileVars
->fileExtents
->getLength();
1697 if (count
> sizeof(header
->fileExtentMap
))
1699 count
-= sizeof(header
->fileExtentMap
);
1700 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1701 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1702 if (kIOReturnSuccess
!= err
)
1706 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
1707 hibernateEnd
= (segHIBB
+ segSizeHIB
);
1709 // copy out restore1 code
1712 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1715 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
1717 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
1721 page
= atop_32(kvtophys(hibernateBase
));
1722 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
1723 header
->restore1CodePhysPage
= page
;
1724 header
->restore1CodeVirt
= hibernateBase
;
1725 header
->restore1PageCount
= count
;
1726 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1727 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1729 if (uuid_parse(&gIOHibernateBridgeBootSessionUUIDString
[0], &header
->bridgeBootSessionUUID
[0]))
1731 bzero(&header
->bridgeBootSessionUUID
[0], sizeof(header
->bridgeBootSessionUUID
));
1734 // sum __HIB seg, with zeros for the stack
1735 src
= (uint8_t *) trunc_page(hibernateBase
);
1736 for (page
= 0; page
< count
; page
++)
1738 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1739 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
1741 restore1Sum
+= 0x00000000;
1746 // write the __HIB seg, with zeros for the stack
1748 src
= (uint8_t *) trunc_page(hibernateBase
);
1749 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1752 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1753 if (kIOReturnSuccess
!= err
)
1756 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1758 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1760 if (kIOReturnSuccess
!= err
)
1762 src
= &gIOHibernateRestoreStackEnd
[0];
1763 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1766 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1767 if (kIOReturnSuccess
!= err
)
1771 if (!vars
->hwEncrypt
&& (kIOHibernateModeEncrypt
& gIOHibernateMode
))
1773 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
1774 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1775 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1778 // write the preview buffer
1780 if (vars
->previewBuffer
)
1786 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1787 pageAndCount
[0] = atop_64(phys64
);
1788 pageAndCount
[1] = atop_32(segLen
);
1789 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1790 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1792 if (kIOReturnSuccess
!= err
)
1795 ppnum
+= sizeof(pageAndCount
);
1798 if (kIOReturnSuccess
!= err
)
1801 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1803 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
1805 count
= vars
->previewBuffer
->getLength();
1807 header
->previewPageListSize
= ppnum
;
1808 header
->previewSize
= count
+ ppnum
;
1810 for (page
= 0; page
< count
; page
+= page_size
)
1812 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
1813 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
1815 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1816 if (kIOReturnSuccess
!= err
)
1820 // mark areas for no save
1821 IOMemoryDescriptor
* ioBuffer
;
1822 ioBuffer
= IOPolledFileGetIOBuffer(vars
->fileVars
);
1824 (phys64
= ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1827 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1828 atop_64(phys64
), atop_32(segLen
),
1829 kIOHibernatePageStateFree
);
1830 pageCount
-= atop_32(segLen
);
1834 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1837 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1838 atop_64(phys64
), atop_32(segLen
),
1839 kIOHibernatePageStateFree
);
1840 pageCount
-= atop_32(segLen
);
1843 // copy out bitmap of pages available for trashing during restore
1845 bitmap_size
= vars
->page_list_wired
->list_size
;
1846 src
= (uint8_t *) vars
->page_list_wired
;
1847 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1848 if (kIOReturnSuccess
!= err
)
1851 // mark more areas for no save, but these are not available
1852 // for trashing during restore
1854 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1857 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
1858 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
1859 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1861 kIOHibernatePageStateFree
);
1864 if (vars
->previewBuffer
) for (count
= 0;
1865 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1868 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1869 atop_64(phys64
), atop_32(segLen
),
1870 kIOHibernatePageStateFree
);
1871 pageCount
-= atop_32(segLen
);
1875 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1878 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1879 atop_64(phys64
), atop_32(segLen
),
1880 kIOHibernatePageStateFree
);
1881 pageCount
-= atop_32(segLen
);
1885 vm_size_t shadow_pages_free
= atop_64(shadow_ptop
) - atop_64(shadow_pnext
);
1887 /* no need to save unused shadow pages */
1888 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1889 atop_64(shadow_pnext
),
1891 kIOHibernatePageStateFree
);
1894 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1895 compressed
= src
+ page_size
;
1896 scratch
= compressed
+ page_size
;
1901 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
1902 bitmap_size
, header
->previewSize
,
1903 pageCount
, vars
->fileVars
->position
);
1910 kWiredEncrypt
= kWired
| kEncrypt
,
1911 kWiredClear
= kWired
,
1912 kUnwiredEncrypt
= kEncrypt
1915 bool cpuAES
= (0 != (CPUID_FEATURE_AES
& cpuid_features()));
1916 #define _pmap_is_noencrypt(x) (cpuAES ? false : pmap_is_noencrypt((x)))
1918 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
1920 if (kUnwiredEncrypt
== pageType
)
1922 // start unwired image
1923 if (!vars
->hwEncrypt
&& (kIOHibernateModeEncrypt
& gIOHibernateMode
))
1925 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
1926 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1927 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1929 bcopy(&cryptvars
->aes_iv
[0],
1930 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1931 sizeof(cryptvars
->aes_iv
));
1932 cryptvars
= &gIOHibernateCryptWakeContext
;
1934 for (iterDone
= false, ppnum
= 0; !iterDone
; )
1936 count
= hibernate_page_list_iterate((kWired
& pageType
)
1937 ? vars
->page_list_wired
: vars
->page_list
,
1939 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1942 if (count
&& (kWired
& pageType
) && needEncrypt
)
1944 uint32_t checkIndex
;
1945 for (checkIndex
= 0;
1946 (checkIndex
< count
)
1947 && (((kEncrypt
& pageType
) == 0) == _pmap_is_noencrypt(ppnum
+ checkIndex
));
1960 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
1961 case kWiredClear
: wiredPagesClear
+= count
; break;
1962 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
1965 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
1968 pageAndCount
[0] = ppnum
;
1969 pageAndCount
[1] = count
;
1970 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1971 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1973 if (kIOReturnSuccess
!= err
)
1977 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
1979 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
1982 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
1986 sum
= hibernate_sum_page(src
, page
);
1987 if (kWired
& pageType
)
1992 clock_get_uptime(&startTime
);
1993 wkresult
= WKdm_compress_new((const WK_word
*) src
,
1994 (WK_word
*) compressed
,
1998 clock_get_uptime(&endTime
);
1999 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2000 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2002 compBytes
+= page_size
;
2003 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
2005 if (pageCompressedSize
== 0)
2007 pageCompressedSize
= 4;
2010 if (*(uint32_t *)src
)
2017 if (pageCompressedSize
!= page_size
)
2023 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2024 err
= IOHibernatePolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2025 if (kIOReturnSuccess
!= err
)
2028 err
= IOHibernatePolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2029 if (kIOReturnSuccess
!= err
)
2032 compressedSize
+= pageCompressedSize
;
2033 uncompressedSize
+= page_size
;
2036 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2038 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2039 if (blob
!= lastBlob
)
2041 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2045 if (0 == (8191 & pagesDone
))
2047 clock_get_uptime(&endTime
);
2048 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2049 absolutetime_to_nanoseconds(endTime
, &nsec
);
2050 progressStamp
= nsec
/ 750000000ULL;
2051 if (progressStamp
!= lastProgressStamp
)
2053 lastProgressStamp
= progressStamp
;
2054 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2058 if (kIOReturnSuccess
!= err
)
2063 if (kIOReturnSuccess
!= err
)
2066 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
)
2068 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
2069 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2072 if (kWiredEncrypt
!= pageType
)
2074 // end of image1/2 - fill to next block
2075 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2076 if (kIOReturnSuccess
!= err
)
2079 if (kWiredClear
== pageType
)
2081 // enlarge wired image for test
2082 // err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
2085 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2086 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2087 image1Size
= vars
->fileVars
->position
;
2088 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2089 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2092 if (kIOReturnSuccess
!= err
)
2094 if (kIOReturnOverrun
== err
)
2096 // update actual compression ratio on not enough space (for retry)
2097 gIOHibernateCompression
= (compressedSize
<< 8) / uncompressedSize
;
2100 // update partial amount written (for IOPolledFileClose cleanup/unmap)
2101 header
->imageSize
= vars
->fileVars
->position
;
2107 header
->imageSize
= vars
->fileVars
->position
;
2108 header
->image1Size
= image1Size
;
2109 header
->bitmapSize
= bitmap_size
;
2110 header
->pageCount
= pageCount
;
2112 header
->restore1Sum
= restore1Sum
;
2113 header
->image1Sum
= sum1
;
2114 header
->image2Sum
= sum2
;
2115 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
2117 header
->compression
= (compressedSize
<< 8) / uncompressedSize
;
2118 gIOHibernateCompression
= header
->compression
;
2120 count
= vars
->fileVars
->fileExtents
->getLength();
2121 if (count
> sizeof(header
->fileExtentMap
))
2123 header
->fileExtentMapSize
= count
;
2124 count
= sizeof(header
->fileExtentMap
);
2127 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2128 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2130 header
->deviceBase
= vars
->fileVars
->block0
;
2131 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
2133 IOPolledFileSeek(vars
->fileVars
, 0);
2134 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
2135 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2137 if (kIOReturnSuccess
!= err
)
2139 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2143 clock_get_uptime(&endTime
);
2145 IOService::getPMRootDomain()->pmStatsRecordEvent(
2146 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2148 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2149 absolutetime_to_nanoseconds(endTime
, &nsec
);
2150 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
2152 absolutetime_to_nanoseconds(compTime
, &nsec
);
2153 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2156 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2158 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2159 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2160 vars
->fileVars
->cryptBytes
,
2162 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2164 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2165 header
->imageSize
, (header
->imageSize
* 100) / vars
->fileVars
->fileSize
,
2166 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2167 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2170 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2171 svPageCount
, zvPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
2174 IOPolledFilePollersClose(vars
->fileVars
, (kIOReturnSuccess
== err
) ? kIOPolledBeforeSleepState
: kIOPolledBeforeSleepStateAborted
);
2176 if (vars
->consoleMapping
)
2177 ProgressUpdate(gIOHibernateGraphicsInfo
,
2178 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2180 HIBLOG("hibernate_write_image done(%x)\n", err
);
2182 // should we come back via regular wake, set the state in memory.
2183 gIOHibernateState
= kIOHibernateStateInactive
;
2185 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
, wiredPagesEncrypted
,
2186 wiredPagesClear
, dirtyPagesEncrypted
);
2188 if (kIOReturnSuccess
== err
)
2190 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2192 return (kIOHibernatePostWriteSleep
);
2194 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2196 return (kIOHibernatePostWriteRestart
);
2200 /* by default, power down */
2201 return (kIOHibernatePostWriteHalt
);
2204 else if (kIOReturnAborted
== err
)
2206 return (kIOHibernatePostWriteWake
);
2210 /* on error, sleep */
2211 return (kIOHibernatePostWriteSleep
);
2215 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2218 hibernate_machine_init(void)
2223 uint32_t pagesRead
= 0;
2224 AbsoluteTime startTime
, compTime
;
2225 AbsoluteTime allTime
, endTime
;
2226 AbsoluteTime startIOTime
, endIOTime
;
2227 uint64_t nsec
, nsecIO
;
2229 uint32_t lastProgressStamp
= 0;
2230 uint32_t progressStamp
;
2231 IOPolledFileCryptVars
* cryptvars
= 0;
2233 IOHibernateVars
* vars
= &gIOHibernateVars
;
2234 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
2236 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
2239 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2240 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2242 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2244 HIBLOG("regular wake\n");
2248 HIBPRINT("diag %x %x %x %x\n",
2249 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2250 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2252 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
2253 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2254 tStat(booterStart
, booterStart
);
2255 gIOHibernateStats
->smcStart
= gIOHibernateCurrentHeader
->smcStart
;
2256 tStat(booterDuration0
, booterTime0
);
2257 tStat(booterDuration1
, booterTime1
);
2258 tStat(booterDuration2
, booterTime2
);
2259 tStat(booterDuration
, booterTime
);
2260 tStat(booterConnectDisplayDuration
, connectDisplayTime
);
2261 tStat(booterSplashDuration
, splashTime
);
2262 tStat(trampolineDuration
, trampolineTime
);
2264 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
2265 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
2266 gIOHibernateStats
->image1Pages
= pagesDone
;
2268 /* HIBERNATE_stats */
2269 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 14), gIOHibernateStats
->smcStart
,
2270 gIOHibernateStats
->booterStart
, gIOHibernateStats
->booterDuration
,
2271 gIOHibernateStats
->trampolineDuration
);
2273 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2274 gIOHibernateStats
->booterStart
,
2275 gIOHibernateStats
->smcStart
,
2276 gIOHibernateStats
->booterDuration0
,
2277 gIOHibernateStats
->booterDuration1
,
2278 gIOHibernateStats
->booterDuration2
,
2279 gIOHibernateStats
->booterDuration
,
2280 gIOHibernateStats
->booterConnectDisplayDuration
,
2281 gIOHibernateStats
->booterSplashDuration
,
2282 gIOHibernateStats
->trampolineDuration
);
2284 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2285 gIOHibernateState
, pagesDone
, sum
, gIOHibernateStats
->imageSize
, gIOHibernateStats
->image1Size
,
2286 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2288 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
2289 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)))
2291 hibernate_page_list_discard(vars
->page_list
);
2294 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2296 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
2297 panic("handoff overflow");
2299 IOHibernateHandoff
* handoff
;
2301 bool foundCryptData
= false;
2302 bool foundVolumeEncryptData
= false;
2304 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2306 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2308 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2309 uint8_t * data
= &handoff
->data
[0];
2310 switch (handoff
->type
)
2312 case kIOHibernateHandoffTypeEnd
:
2316 case kIOHibernateHandoffTypeGraphicsInfo
:
2317 if (handoff
->bytecount
== sizeof(*gIOHibernateGraphicsInfo
))
2319 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2323 case kIOHibernateHandoffTypeCryptVars
:
2326 hibernate_cryptwakevars_t
*
2327 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
2328 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
2330 foundCryptData
= true;
2331 bzero(data
, handoff
->bytecount
);
2334 case kIOHibernateHandoffTypeVolumeCryptKey
:
2335 if (handoff
->bytecount
== vars
->volumeCryptKeySize
)
2337 bcopy(data
, &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
2338 foundVolumeEncryptData
= true;
2340 else panic("kIOHibernateHandoffTypeVolumeCryptKey(%d)", handoff
->bytecount
);
2343 case kIOHibernateHandoffTypeMemoryMap
:
2345 clock_get_uptime(&allTime
);
2347 hibernate_newruntime_map(data
, handoff
->bytecount
,
2348 gIOHibernateCurrentHeader
->systemTableOffset
);
2350 clock_get_uptime(&endTime
);
2352 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2353 absolutetime_to_nanoseconds(endTime
, &nsec
);
2355 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
2359 case kIOHibernateHandoffTypeDeviceTree
:
2361 // DTEntry chosen = NULL;
2362 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2367 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2372 if (vars
->hwEncrypt
&& !foundVolumeEncryptData
)
2373 panic("no volumeCryptKey");
2374 else if (cryptvars
&& !foundCryptData
)
2375 panic("hibernate handoff");
2377 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2378 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2379 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2381 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
2383 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2384 * gIOHibernateGraphicsInfo
->rowBytes
);
2385 if (vars
->videoMapSize
> vars
->videoAllocSize
) vars
->videoMapSize
= 0;
2388 IOMapPages(kernel_map
,
2389 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2390 vars
->videoMapSize
, kIOMapInhibitCache
);
2394 if (vars
->videoMapSize
)
2395 ProgressUpdate(gIOHibernateGraphicsInfo
,
2396 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2398 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2399 uint8_t * compressed
= src
+ page_size
;
2400 uint8_t * scratch
= compressed
+ page_size
;
2401 uint32_t decoOffset
;
2403 clock_get_uptime(&allTime
);
2404 AbsoluteTime_to_scalar(&compTime
) = 0;
2407 HIBLOG("IOPolledFilePollersOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2408 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledAfterSleepState
, false);
2409 clock_get_uptime(&startIOTime
);
2410 endTime
= startIOTime
;
2411 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2412 absolutetime_to_nanoseconds(endTime
, &nsec
);
2413 HIBLOG("IOPolledFilePollersOpen(%x) %qd ms\n", err
, nsec
/ 1000000ULL);
2415 if (vars
->hwEncrypt
)
2417 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
,
2418 &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
2419 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x) %ld\n", err
, vars
->volumeCryptKeySize
);
2420 if (kIOReturnSuccess
!= err
) panic("IOPolledFilePollersSetEncryptionKey(0x%x)", err
);
2424 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2426 // kick off the read ahead
2427 vars
->fileVars
->bufferHalf
= 0;
2428 vars
->fileVars
->bufferLimit
= 0;
2429 vars
->fileVars
->lastRead
= 0;
2430 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
2431 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2432 vars
->fileVars
->cryptBytes
= 0;
2433 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
2435 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2436 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2439 HIBLOG("hibernate_machine_init reading\n");
2441 uint32_t * header
= (uint32_t *) src
;
2444 while (kIOReturnSuccess
== err
)
2449 vm_offset_t ppnum
, compressedSize
;
2451 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2452 if (kIOReturnSuccess
!= err
)
2458 // HIBPRINT("(%x, %x)\n", ppnum, count);
2463 for (page
= 0; page
< count
; page
++)
2465 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2466 if (kIOReturnSuccess
!= err
)
2469 compressedSize
= kIOHibernateTagLength
& tag
;
2470 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2472 err
= kIOReturnIPCError
;
2476 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2477 if (kIOReturnSuccess
!= err
) break;
2479 if (compressedSize
< page_size
)
2481 decoOffset
= page_size
;
2482 clock_get_uptime(&startTime
);
2484 if (compressedSize
== 4) {
2488 s
= (uint32_t *)src
;
2489 d
= (uint32_t *)(uintptr_t)compressed
;
2491 for (i
= 0; i
< (int)(PAGE_SIZE
/ sizeof(int32_t)); i
++)
2495 WKdm_decompress_new((WK_word
*) src
, (WK_word
*) compressed
, (WK_word
*) scratch
, compressedSize
);
2496 clock_get_uptime(&endTime
);
2497 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2498 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2499 compBytes
+= page_size
;
2501 else decoOffset
= 0;
2503 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
2504 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2507 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2515 if (0 == (8191 & pagesDone
))
2517 clock_get_uptime(&endTime
);
2518 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2519 absolutetime_to_nanoseconds(endTime
, &nsec
);
2520 progressStamp
= nsec
/ 750000000ULL;
2521 if (progressStamp
!= lastProgressStamp
)
2523 lastProgressStamp
= progressStamp
;
2524 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2525 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2530 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
2531 err
= kIOReturnLockedRead
;
2533 if (kIOReturnSuccess
!= err
)
2534 panic("Hibernate restore error %x", err
);
2536 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2537 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
2539 clock_get_uptime(&endIOTime
);
2541 err
= IOPolledFilePollersClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2543 clock_get_uptime(&endTime
);
2545 IOService::getPMRootDomain()->pmStatsRecordEvent(
2546 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2547 IOService::getPMRootDomain()->pmStatsRecordEvent(
2548 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2550 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2551 absolutetime_to_nanoseconds(endTime
, &nsec
);
2553 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
2554 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
2556 gIOHibernateStats
->kernelImageReadDuration
= nsec
/ 1000000ULL;
2557 gIOHibernateStats
->imagePages
= pagesDone
;
2559 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
2560 pagesDone
, sum
, gIOHibernateStats
->kernelImageReadDuration
, kDefaultIOSize
,
2561 nsecIO
? ((((gIOHibernateCurrentHeader
->imageSize
- gIOHibernateCurrentHeader
->image1Size
) * 1000000000ULL) / 1024 / 1024) / nsecIO
) : 0);
2563 absolutetime_to_nanoseconds(compTime
, &nsec
);
2564 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2567 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2569 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2570 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2571 vars
->fileVars
->cryptBytes
,
2573 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2575 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 2), pagesRead
, pagesDone
);
2578 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2580 void IOHibernateSetWakeCapabilities(uint32_t capability
)
2582 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2584 gIOHibernateStats
->wakeCapability
= capability
;
2586 if (kIOPMSystemCapabilityGraphics
& capability
)
2588 vm_compressor_do_warmup();
2593 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2595 void IOHibernateSystemRestart(void)
2597 static uint8_t noteStore
[32] __attribute__((aligned(32)));
2598 IORegistryEntry
* regEntry
;
2599 const OSSymbol
* sym
;
2602 uintptr_t * smcVars
;
2607 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
2610 smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
2611 smcBytes
= (typeof(smcBytes
)) smcVars
[1];
2613 if (len
> sizeof(noteStore
)) len
= sizeof(noteStore
);
2614 noteProp
= OSData::withCapacity(3 * sizeof(element
));
2615 if (!noteProp
) return;
2617 noteProp
->appendBytes(&element
, sizeof(element
));
2618 element
= crc32(0, smcBytes
, len
);
2619 noteProp
->appendBytes(&element
, sizeof(element
));
2621 bcopy(smcBytes
, noteStore
, len
);
2622 element
= (addr64_t
) ¬eStore
[0];
2623 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
2624 noteProp
->appendBytes(&element
, sizeof(element
));
2626 if (!gIOOptionsEntry
)
2628 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2629 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
2630 if (regEntry
&& !gIOOptionsEntry
)
2631 regEntry
->release();
2634 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
2635 if (gIOOptionsEntry
&& sym
) gIOOptionsEntry
->setProperty(sym
, noteProp
);
2636 if (noteProp
) noteProp
->release();
2637 if (sym
) sym
->release();