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 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
684 if (gIOHibernateRTCVariablesKey
)
685 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
688 if (gIOChosenEntry
&& gIOOptionsEntry
)
690 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
691 if (data
) gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
693 if (!gIOHibernateBoot0082Data
)
695 OSData
* fileData
= 0;
696 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
697 if (data
&& data
->getLength() >= 4) fileData
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-file-path"));
700 // AppleNVRAM_EFI_LOAD_OPTION
703 uint16_t FilePathLength
;
706 loadOptionHeader
.Attributes
= 1;
707 loadOptionHeader
.FilePathLength
= data
->getLength();
708 loadOptionHeader
.Desc
= 0;
711 loadOptionHeader
.FilePathLength
-= 4;
712 loadOptionHeader
.FilePathLength
+= fileData
->getLength();
714 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
715 if (gIOHibernateBoot0082Data
)
717 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
720 gIOHibernateBoot0082Data
->appendBytes(data
->getBytesNoCopy(), data
->getLength() - 4);
721 gIOHibernateBoot0082Data
->appendBytes(fileData
);
723 else gIOHibernateBoot0082Data
->appendBytes(data
);
727 if (!gIOHibernateBootNextData
)
729 uint16_t bits
= 0x0082;
730 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
732 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
734 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
735 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
736 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
741 #endif /* !i386 && !x86_64 */
745 if (swapPinned
) hibernate_pin_swap(FALSE
);
748 if ((kIOReturnSuccess
== err
) && (kFSOpening
!= gFSState
))
750 HIBLOG("hibernate file close due timeout\n");
751 err
= kIOReturnTimeout
;
753 if (kIOReturnSuccess
== err
)
755 gFSState
= kFSOpened
;
756 gIOHibernateVars
= *vars
;
757 gFileVars
= *vars
->fileVars
;
758 gFileVars
.allocated
= false;
759 gIOHibernateVars
.fileVars
= &gFileVars
;
760 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
761 gIOHibernateState
= kIOHibernateStateHibernating
;
765 IOPolledFileIOVars
* fileVars
= vars
->fileVars
;
766 IOHibernateDone(vars
);
767 IOPolledFileClose(&fileVars
,
771 0, NULL
, 0, sizeof(IOHibernateImageHeader
), setFileSize
);
775 IOLockUnlock(gFSLock
);
777 if (vars
->fileVars
) IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
778 IODelete(vars
, IOHibernateVars
, 1);
783 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
786 IOSetBootImageNVRAM(OSData
* data
)
788 IORegistryEntry
* regEntry
;
790 if (!gIOOptionsEntry
)
792 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
793 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
794 if (regEntry
&& !gIOOptionsEntry
)
797 if (gIOOptionsEntry
&& gIOHibernateBootImageKey
)
799 if (data
) gIOOptionsEntry
->setProperty(gIOHibernateBootImageKey
, data
);
802 gIOOptionsEntry
->removeProperty(gIOHibernateBootImageKey
);
803 gIOOptionsEntry
->sync();
808 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
810 * Writes header to disk with signature, block size and file extents data.
811 * If there are more than 2 extents, then they are written on second block.
814 IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
)
816 IOHibernateImageHeader hdr
;
818 IOReturn err
= kIOReturnSuccess
;
820 IOPolledFileExtent
* fileExtents
;
822 fileExtents
= (typeof(fileExtents
)) vars
->fileExtents
->getBytesNoCopy();
824 memset(&hdr
, 0, sizeof(IOHibernateImageHeader
));
825 count
= vars
->fileExtents
->getLength();
826 if (count
> sizeof(hdr
.fileExtentMap
))
828 hdr
.fileExtentMapSize
= count
;
829 count
= sizeof(hdr
.fileExtentMap
);
832 hdr
.fileExtentMapSize
= sizeof(hdr
.fileExtentMap
);
834 bcopy(fileExtents
, &hdr
.fileExtentMap
[0], count
);
836 // copy file block extent list if larger than header
837 if (hdr
.fileExtentMapSize
> sizeof(hdr
.fileExtentMap
))
839 count
= hdr
.fileExtentMapSize
- sizeof(hdr
.fileExtentMap
);
840 rc
= kern_write_file(vars
->fileRef
, vars
->blockSize
,
841 (caddr_t
)(((uint8_t *)fileExtents
) + sizeof(hdr
.fileExtentMap
)),
842 count
, IO_SKIP_ENCRYPTION
);
844 HIBLOG("kern_write_file returned %d\n", rc
);
845 err
= kIOReturnIOError
;
849 hdr
.signature
= signature
;
850 hdr
.deviceBlockSize
= vars
->blockSize
;
852 rc
= kern_write_file(vars
->fileRef
, 0, (char *)&hdr
, sizeof(hdr
), IO_SKIP_ENCRYPTION
);
854 HIBLOG("kern_write_file returned %d\n", rc
);
855 err
= kIOReturnIOError
;
863 extern "C" boolean_t root_is_CF_drive
;
866 IOOpenDebugDataFile(const char *fname
, uint64_t size
)
869 OSData
* imagePath
= NULL
;
872 if (!gDebugImageLock
) {
873 gDebugImageLock
= IOLockAlloc();
876 if (root_is_CF_drive
) return;
878 // Try to get a lock, but don't block for getting lock
879 if (!IOLockTryLock(gDebugImageLock
)) {
880 HIBLOG("IOOpenDebugDataFile: Failed to get lock\n");
884 if (gDebugImageFileVars
|| !fname
|| !size
) {
885 HIBLOG("IOOpenDebugDataFile: conditions failed\n");
889 padding
= (PAGE_SIZE
*2); // allocate couple more pages for header and fileextents
890 err
= IOPolledFileOpen(fname
, size
+padding
, 32ULL*1024*1024*1024,
892 &gDebugImageFileVars
, &imagePath
, NULL
, 0);
894 if ((kIOReturnSuccess
== err
) && imagePath
)
896 if ((gDebugImageFileVars
->fileSize
< (size
+padding
)) ||
897 (gDebugImageFileVars
->fileExtents
->getLength() > PAGE_SIZE
)) {
898 // Can't use the file
899 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
900 HIBLOG("IOOpenDebugDataFile: too many file extents\n");
904 // write extents for debug data usage in EFI
905 IOWriteExtentsToFile(gDebugImageFileVars
, kIOHibernateHeaderOpenSignature
);
906 IOSetBootImageNVRAM(imagePath
);
910 IOLockUnlock(gDebugImageLock
);
912 if (imagePath
) imagePath
->release();
917 IOCloseDebugDataFile()
919 IOSetBootImageNVRAM(0);
921 if (gDebugImageLock
) {
922 IOLockLock(gDebugImageLock
);
923 if (gDebugImageFileVars
!= 0) {
924 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
926 IOLockUnlock(gDebugImageLock
);
932 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
934 DECLARE_IOHIBERNATEPROGRESSALPHA
937 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
939 uint32_t rowBytes
, pixelShift
;
942 uint32_t alpha
, in
, color
, result
;
944 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
946 rowBytes
= display
->rowBytes
;
947 pixelShift
= display
->depth
>> 4;
948 if (pixelShift
< 1) return;
950 screen
+= ((display
->width
951 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
952 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
954 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
956 out
= screen
+ y
* rowBytes
;
957 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
959 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
960 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
962 alpha
= gIOHibernateProgressAlpha
[y
][x
];
970 in
= *((uint16_t *)out
) & 0x1f; // 16
971 in
= (in
<< 3) | (in
>> 2);
974 in
= *((uint32_t *)out
) & 0xff; // 32
975 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
976 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
981 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
984 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
986 out
+= (1 << pixelShift
);
988 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
995 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
997 uint32_t rowBytes
, pixelShift
;
999 int32_t blob
, lastBlob
;
1000 uint32_t alpha
, in
, color
, result
;
1002 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1004 pixelShift
= display
->depth
>> 4;
1008 rowBytes
= display
->rowBytes
;
1010 screen
+= ((display
->width
1011 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1012 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1014 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1016 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1018 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1020 out
= screen
+ y
* rowBytes
;
1021 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1023 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1024 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1026 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1032 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1033 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1035 if (1 == pixelShift
)
1038 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1041 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1043 out
+= (1 << pixelShift
);
1045 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1050 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1053 IOHibernateIOKitSleep(void)
1055 IOReturn ret
= kIOReturnSuccess
;
1056 IOLockLock(gFSLock
);
1057 if (kFSOpening
== gFSState
)
1059 gFSState
= kFSTimedOut
;
1060 HIBLOG("hibernate file open timed out\n");
1061 ret
= kIOReturnTimeout
;
1063 IOLockUnlock(gFSLock
);
1067 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1070 IOHibernateSystemHasSlept(void)
1072 IOReturn ret
= kIOReturnSuccess
;
1073 IOHibernateVars
* vars
= &gIOHibernateVars
;
1077 IOLockLock(gFSLock
);
1078 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
)
1080 ret
= kIOReturnTimeout
;
1082 IOLockUnlock(gFSLock
);
1083 if (kIOReturnSuccess
!= ret
) return (ret
);
1085 if (gIOHibernateMode
) obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1086 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1087 if (obj
&& !vars
->previewBuffer
)
1090 vars
->consoleMapping
= NULL
;
1091 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1093 vars
->previewBuffer
->release();
1094 vars
->previewBuffer
= 0;
1097 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1098 && vars
->previewBuffer
1099 && (data
= OSDynamicCast(OSData
,
1100 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1102 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1103 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1105 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1107 if (kIOHibernatePreviewUpdates
& flags
)
1109 PE_Video consoleInfo
;
1110 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1112 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1114 graphicsInfo
->width
= consoleInfo
.v_width
;
1115 graphicsInfo
->height
= consoleInfo
.v_height
;
1116 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1117 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1118 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1120 HIBPRINT("video %p %d %d %d\n",
1121 vars
->consoleMapping
, graphicsInfo
->depth
,
1122 graphicsInfo
->width
, graphicsInfo
->height
);
1123 if (vars
->consoleMapping
)
1124 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1125 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1129 if (gIOOptionsEntry
)
1130 gIOOptionsEntry
->sync();
1135 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1137 static DeviceTreeNode
*
1138 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
1140 DeviceTreeNodeProperty
* prop
;
1141 DeviceTreeNode
* child
;
1142 IORegistryEntry
* childRegEntry
;
1143 const char * nameProp
;
1144 unsigned int propLen
, idx
;
1146 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1147 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
1149 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
1151 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1152 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1154 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1157 child
= (DeviceTreeNode
*) prop
;
1158 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
1160 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
1162 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1163 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1164 child
= MergeDeviceTree(child
, childRegEntry
);
1170 IOHibernateSystemWake(void)
1172 if (kFSOpened
== gFSState
)
1174 IOPolledFilePollersClose(gIOHibernateVars
.fileVars
, kIOPolledPostflightState
);
1175 IOHibernateDone(&gIOHibernateVars
);
1179 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1180 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1182 return (kIOReturnSuccess
);
1186 IOHibernateDone(IOHibernateVars
* vars
)
1191 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1193 if (vars
->videoMapping
)
1195 if (vars
->videoMapSize
)
1197 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1198 if (vars
->videoAllocSize
)
1200 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1203 if (vars
->previewBuffer
)
1205 vars
->previewBuffer
->release();
1206 vars
->previewBuffer
= 0;
1209 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1211 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1212 gIOHibernateCurrentHeader
->options
, 32);
1216 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1219 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1220 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1222 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1223 &gIOHibernateGraphicsInfo
->gfxStatus
,
1224 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1228 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1231 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1233 #if defined(__i386__) || defined(__x86_64__)
1234 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1235 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1238 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1239 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1241 if (gIOOptionsEntry
) {
1243 if (gIOHibernateRTCVariablesKey
) {
1244 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1245 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1249 if (gIOHibernateBootNextKey
)
1251 if (gIOHibernateBootNextSave
)
1253 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1254 gIOHibernateBootNextSave
->release();
1255 gIOHibernateBootNextSave
= NULL
;
1258 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1260 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) gIOOptionsEntry
->sync();
1264 if (vars
->srcBuffer
) vars
->srcBuffer
->release();
1265 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1266 if (vars
->handoffBuffer
)
1268 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1270 IOHibernateHandoff
* handoff
;
1272 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1274 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
1276 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1277 uint8_t * data
= &handoff
->data
[0];
1278 switch (handoff
->type
)
1280 case kIOHibernateHandoffTypeEnd
:
1284 case kIOHibernateHandoffTypeDeviceTree
:
1285 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
1288 case kIOHibernateHandoffTypeKeyStore
:
1289 #if defined(__i386__) || defined(__x86_64__)
1291 IOBufferMemoryDescriptor
*
1292 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1295 IOSetKeyStoreData(md
);
1302 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1306 #if defined(__i386__) || defined(__x86_64__)
1307 if (vars
->volumeCryptKeySize
)
1309 IOBufferMemoryDescriptor
*
1310 bmd
= IOBufferMemoryDescriptor::withBytes(&vars
->volumeCryptKey
[0],
1311 vars
->volumeCryptKeySize
, kIODirectionOutIn
);
1312 if (!bmd
) panic("IOBufferMemoryDescriptor");
1313 IOSetAPFSKeyStoreData(bmd
);
1314 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1319 vars
->handoffBuffer
->release();
1323 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOBridgeBootSessionUUIDKey
)))
1324 && (sizeof(gIOHibernateBridgeBootSessionUUIDString
) <= data
->getLength()))
1326 bcopy(data
->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString
[0],
1327 sizeof(gIOHibernateBridgeBootSessionUUIDString
));
1330 if (vars
->hwEncrypt
)
1332 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
, NULL
, 0);
1333 HIBLOG("IOPolledFilePollersSetEncryptionKey(0,%x)\n", err
);
1336 bzero(vars
, sizeof(*vars
));
1338 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1340 return (kIOReturnSuccess
);
1344 IOHibernateSystemPostWakeTrim(void * p1
, void * p2
)
1346 // invalidate & close the image file
1347 if (p1
) IOLockLock(gFSLock
);
1348 if (kFSTrimDelay
== gFSState
)
1350 IOPolledFileIOVars
* vars
= &gFileVars
;
1351 IOPolledFileClose(&vars
,
1355 0, (caddr_t
)gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
),
1356 sizeof(IOHibernateImageHeader
), gIOHibernateCurrentHeader
->imageSize
);
1360 if (p1
) IOLockUnlock(gFSLock
);
1364 IOHibernateSystemPostWake(bool now
)
1366 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1367 IOLockLock(gFSLock
);
1368 if (kFSTrimDelay
== gFSState
)
1370 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
1371 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1373 else if (kFSOpened
!= gFSState
) gFSState
= kFSIdle
;
1376 gFSState
= kFSTrimDelay
;
1379 thread_call_cancel(gIOHibernateTrimCalloutEntry
);
1380 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1384 AbsoluteTime deadline
;
1385 clock_interval_to_deadline(TRIM_DELAY
, kMillisecondScale
, &deadline
);
1386 thread_call_enter1_delayed(gIOHibernateTrimCalloutEntry
, NULL
, deadline
);
1389 IOLockUnlock(gFSLock
);
1391 return (kIOReturnSuccess
);
1394 uint32_t IOHibernateWasScreenLocked(void)
1397 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
)
1400 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
1403 ret
= ((uint32_t *)data
->getBytesNoCopy())[0];
1404 gIOChosenEntry
->setProperty(kIOBooterScreenLockStateKey
, data
);
1407 else gIOChosenEntry
->removeProperty(kIOBooterScreenLockStateKey
);
1412 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1414 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1415 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1416 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1417 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1418 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1419 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1420 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1421 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1422 &gIOHibernateMode
, 0, "");
1423 SYSCTL_STRUCT(_kern
, OID_AUTO
, hibernatestatistics
,
1424 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1425 &_hibernateStats
, hibernate_statistics_t
, "");
1426 SYSCTL_STRING(_kern_bridge
, OID_AUTO
, bootsessionuuid
,
1427 CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1428 gIOHibernateBridgeBootSessionUUIDString
, sizeof(gIOHibernateBridgeBootSessionUUIDString
), "");
1430 SYSCTL_UINT(_kern
, OID_AUTO
, hibernategraphicsready
,
1431 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1432 &_hibernateStats
.graphicsReadyTime
, 0, "");
1433 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatewakenotification
,
1434 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1435 &_hibernateStats
.wakeNotificationTime
, 0, "");
1436 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatelockscreenready
,
1437 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1438 &_hibernateStats
.lockScreenReadyTime
, 0, "");
1439 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatehidready
,
1440 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1441 &_hibernateStats
.hidReadyTime
, 0, "");
1444 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1446 gIOHibernateBootImageKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1447 gIOHibernateBootSignatureKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1448 gIOBridgeBootSessionUUIDKey
= OSSymbol::withCStringNoCopy(kIOBridgeBootSessionUUIDKey
);
1450 #if defined(__i386__) || defined(__x86_64__)
1451 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1452 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1453 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1454 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1455 #endif /* defined(__i386__) || defined(__x86_64__) */
1457 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1460 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1464 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1465 gIOHibernateMode
= kIOHibernateModeOn
;
1467 gIOHibernateFilename
[0] = 0;
1469 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1470 sysctl_register_oid(&sysctl__kern_bootsignature
);
1471 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1472 sysctl_register_oid(&sysctl__kern_hibernatestatistics
);
1473 sysctl_register_oid(&sysctl__kern_hibernategraphicsready
);
1474 sysctl_register_oid(&sysctl__kern_hibernatewakenotification
);
1475 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready
);
1476 sysctl_register_oid(&sysctl__kern_hibernatehidready
);
1478 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1481 && (data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(gIOBridgeBootSessionUUIDKey
)))
1482 && (sizeof(gIOHibernateBridgeBootSessionUUIDString
) <= data
->getLength()))
1484 sysctl_register_oid(&sysctl__kern_bridge_bootsessionuuid
);
1485 bcopy(data
->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString
[0], sizeof(gIOHibernateBridgeBootSessionUUIDString
));
1488 gFSLock
= IOLockAlloc();
1491 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1494 IOHibernatePolledFileWrite(IOPolledFileIOVars
* vars
,
1495 const uint8_t * bytes
, IOByteCount size
,
1496 IOPolledFileCryptVars
* cryptvars
)
1500 err
= IOPolledFileWrite(vars
, bytes
, size
, cryptvars
);
1501 if ((kIOReturnSuccess
== err
) && hibernate_should_abort()) err
= kIOReturnAborted
;
1506 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1509 hibernate_write_image(void)
1511 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1512 IOHibernateVars
* vars
= &gIOHibernateVars
;
1513 IOPolledFileExtent
* fileExtents
;
1515 _static_assert_1_arg(sizeof(IOHibernateImageHeader
) == 512);
1517 uint32_t pageCount
, pagesDone
;
1519 vm_offset_t ppnum
, page
;
1523 uint8_t * compressed
;
1525 IOByteCount pageCompressedSize
;
1526 uint64_t compressedSize
, uncompressedSize
;
1527 uint64_t image1Size
= 0;
1528 uint32_t bitmap_size
;
1529 bool iterDone
, pollerOpen
, needEncrypt
;
1530 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1534 uint32_t pageAndCount
[2];
1537 uintptr_t hibernateBase
;
1538 uintptr_t hibernateEnd
;
1540 AbsoluteTime startTime
, endTime
;
1541 AbsoluteTime allTime
, compTime
;
1544 uint32_t lastProgressStamp
= 0;
1545 uint32_t progressStamp
;
1546 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1548 uint32_t wiredPagesEncrypted
;
1549 uint32_t dirtyPagesEncrypted
;
1550 uint32_t wiredPagesClear
;
1551 uint32_t svPageCount
;
1552 uint32_t zvPageCount
;
1554 IOPolledFileCryptVars _cryptvars
;
1555 IOPolledFileCryptVars
* cryptvars
= 0;
1557 wiredPagesEncrypted
= 0;
1558 dirtyPagesEncrypted
= 0;
1559 wiredPagesClear
= 0;
1564 || !vars
->fileVars
->pollers
1565 || !(kIOHibernateModeOn
& gIOHibernateMode
)) return (kIOHibernatePostWriteSleep
);
1567 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1568 kdebug_enable
= save_kdebug_enable
;
1570 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
);
1571 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
1573 restore1Sum
= sum1
= sum2
= 0;
1576 // encryption data. "iv" is the "initial vector".
1577 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1579 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1580 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1581 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1583 cryptvars
= &gIOHibernateCryptWakeContext
;
1584 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1585 aes_encrypt_key(vars
->cryptKey
,
1586 kIOHibernateAESKeySize
,
1587 &cryptvars
->ctx
.encrypt
);
1588 aes_decrypt_key(vars
->cryptKey
,
1589 kIOHibernateAESKeySize
,
1590 &cryptvars
->ctx
.decrypt
);
1592 cryptvars
= &_cryptvars
;
1593 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1594 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++)
1595 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
1596 aes_encrypt_key(vars
->wiredCryptKey
,
1597 kIOHibernateAESKeySize
,
1598 &cryptvars
->ctx
.encrypt
);
1600 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1601 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1602 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1606 hibernate_page_list_setall(vars
->page_list
,
1607 vars
->page_list_wired
,
1608 vars
->page_list_pal
,
1609 false /* !preflight */,
1611 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
1612 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
1615 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1617 fileExtents
= (IOPolledFileExtent
*) vars
->fileVars
->fileExtents
->getBytesNoCopy();
1620 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1621 for (page
= 0; page
< count
; page
++)
1623 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1624 fileExtents
[page
].start
, fileExtents
[page
].length
,
1625 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1629 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1630 AbsoluteTime_to_scalar(&compTime
) = 0;
1633 clock_get_uptime(&allTime
);
1634 IOService::getPMRootDomain()->pmStatsRecordEvent(
1635 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1639 uncompressedSize
= 0;
1643 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
1645 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1646 ml_get_interrupts_enabled());
1647 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledBeforeSleepState
,
1648 // abortable if not low battery
1649 !IOService::getPMRootDomain()->mustHibernate());
1650 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1651 pollerOpen
= (kIOReturnSuccess
== err
);
1655 if (vars
->volumeCryptKeySize
)
1657 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
, &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
1658 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x)\n", err
);
1659 vars
->hwEncrypt
= (kIOReturnSuccess
== err
);
1660 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1661 if (vars
->hwEncrypt
) header
->options
|= kIOHibernateOptionHWEncrypt
;
1664 // copy file block extent list if larger than header
1666 count
= vars
->fileVars
->fileExtents
->getLength();
1667 if (count
> sizeof(header
->fileExtentMap
))
1669 count
-= sizeof(header
->fileExtentMap
);
1670 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1671 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1672 if (kIOReturnSuccess
!= err
)
1676 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
1677 hibernateEnd
= (segHIBB
+ segSizeHIB
);
1679 // copy out restore1 code
1682 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1685 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
1687 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
1691 page
= atop_32(kvtophys(hibernateBase
));
1692 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
1693 header
->restore1CodePhysPage
= page
;
1694 header
->restore1CodeVirt
= hibernateBase
;
1695 header
->restore1PageCount
= count
;
1696 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1697 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1699 if (uuid_parse(&gIOHibernateBridgeBootSessionUUIDString
[0], &header
->bridgeBootSessionUUID
[0]))
1701 bzero(&header
->bridgeBootSessionUUID
[0], sizeof(header
->bridgeBootSessionUUID
));
1704 // sum __HIB seg, with zeros for the stack
1705 src
= (uint8_t *) trunc_page(hibernateBase
);
1706 for (page
= 0; page
< count
; page
++)
1708 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1709 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
1711 restore1Sum
+= 0x00000000;
1716 // write the __HIB seg, with zeros for the stack
1718 src
= (uint8_t *) trunc_page(hibernateBase
);
1719 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1722 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1723 if (kIOReturnSuccess
!= err
)
1726 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1728 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1730 if (kIOReturnSuccess
!= err
)
1732 src
= &gIOHibernateRestoreStackEnd
[0];
1733 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1736 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1737 if (kIOReturnSuccess
!= err
)
1741 if (!vars
->hwEncrypt
&& (kIOHibernateModeEncrypt
& gIOHibernateMode
))
1743 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
1744 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1745 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1748 // write the preview buffer
1750 if (vars
->previewBuffer
)
1756 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1757 pageAndCount
[0] = atop_64(phys64
);
1758 pageAndCount
[1] = atop_32(segLen
);
1759 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1760 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1762 if (kIOReturnSuccess
!= err
)
1765 ppnum
+= sizeof(pageAndCount
);
1768 if (kIOReturnSuccess
!= err
)
1771 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1773 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
1775 count
= vars
->previewBuffer
->getLength();
1777 header
->previewPageListSize
= ppnum
;
1778 header
->previewSize
= count
+ ppnum
;
1780 for (page
= 0; page
< count
; page
+= page_size
)
1782 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
1783 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
1785 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1786 if (kIOReturnSuccess
!= err
)
1790 // mark areas for no save
1791 IOMemoryDescriptor
* ioBuffer
;
1792 ioBuffer
= IOPolledFileGetIOBuffer(vars
->fileVars
);
1794 (phys64
= ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1797 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1798 atop_64(phys64
), atop_32(segLen
),
1799 kIOHibernatePageStateFree
);
1800 pageCount
-= atop_32(segLen
);
1804 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1807 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1808 atop_64(phys64
), atop_32(segLen
),
1809 kIOHibernatePageStateFree
);
1810 pageCount
-= atop_32(segLen
);
1813 // copy out bitmap of pages available for trashing during restore
1815 bitmap_size
= vars
->page_list_wired
->list_size
;
1816 src
= (uint8_t *) vars
->page_list_wired
;
1817 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1818 if (kIOReturnSuccess
!= err
)
1821 // mark more areas for no save, but these are not available
1822 // for trashing during restore
1824 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1827 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
1828 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
1829 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1831 kIOHibernatePageStateFree
);
1834 if (vars
->previewBuffer
) for (count
= 0;
1835 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1838 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1839 atop_64(phys64
), atop_32(segLen
),
1840 kIOHibernatePageStateFree
);
1841 pageCount
-= atop_32(segLen
);
1845 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1848 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1849 atop_64(phys64
), atop_32(segLen
),
1850 kIOHibernatePageStateFree
);
1851 pageCount
-= atop_32(segLen
);
1855 vm_size_t shadow_pages_free
= atop_64(shadow_ptop
) - atop_64(shadow_pnext
);
1857 /* no need to save unused shadow pages */
1858 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1859 atop_64(shadow_pnext
),
1861 kIOHibernatePageStateFree
);
1864 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1865 compressed
= src
+ page_size
;
1866 scratch
= compressed
+ page_size
;
1871 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
1872 bitmap_size
, header
->previewSize
,
1873 pageCount
, vars
->fileVars
->position
);
1880 kWiredEncrypt
= kWired
| kEncrypt
,
1881 kWiredClear
= kWired
,
1882 kUnwiredEncrypt
= kEncrypt
1885 bool cpuAES
= (0 != (CPUID_FEATURE_AES
& cpuid_features()));
1886 #define _pmap_is_noencrypt(x) (cpuAES ? false : pmap_is_noencrypt((x)))
1888 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
1890 if (kUnwiredEncrypt
== pageType
)
1892 // start unwired image
1893 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1895 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
1896 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1897 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1899 bcopy(&cryptvars
->aes_iv
[0],
1900 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1901 sizeof(cryptvars
->aes_iv
));
1902 cryptvars
= &gIOHibernateCryptWakeContext
;
1904 for (iterDone
= false, ppnum
= 0; !iterDone
; )
1906 count
= hibernate_page_list_iterate((kWired
& pageType
)
1907 ? vars
->page_list_wired
: vars
->page_list
,
1909 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1912 if (count
&& (kWired
& pageType
) && needEncrypt
)
1914 uint32_t checkIndex
;
1915 for (checkIndex
= 0;
1916 (checkIndex
< count
)
1917 && (((kEncrypt
& pageType
) == 0) == _pmap_is_noencrypt(ppnum
+ checkIndex
));
1930 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
1931 case kWiredClear
: wiredPagesClear
+= count
; break;
1932 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
1935 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
1938 pageAndCount
[0] = ppnum
;
1939 pageAndCount
[1] = count
;
1940 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1941 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1943 if (kIOReturnSuccess
!= err
)
1947 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
1949 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
1952 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
1956 sum
= hibernate_sum_page(src
, page
);
1957 if (kWired
& pageType
)
1962 clock_get_uptime(&startTime
);
1963 wkresult
= WKdm_compress_new((const WK_word
*) src
,
1964 (WK_word
*) compressed
,
1968 clock_get_uptime(&endTime
);
1969 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1970 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1972 compBytes
+= page_size
;
1973 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
1975 if (pageCompressedSize
== 0)
1977 pageCompressedSize
= 4;
1980 if (*(uint32_t *)src
)
1987 if (pageCompressedSize
!= page_size
)
1993 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1994 err
= IOHibernatePolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1995 if (kIOReturnSuccess
!= err
)
1998 err
= IOHibernatePolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1999 if (kIOReturnSuccess
!= err
)
2002 compressedSize
+= pageCompressedSize
;
2003 uncompressedSize
+= page_size
;
2006 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2008 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2009 if (blob
!= lastBlob
)
2011 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2015 if (0 == (8191 & pagesDone
))
2017 clock_get_uptime(&endTime
);
2018 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2019 absolutetime_to_nanoseconds(endTime
, &nsec
);
2020 progressStamp
= nsec
/ 750000000ULL;
2021 if (progressStamp
!= lastProgressStamp
)
2023 lastProgressStamp
= progressStamp
;
2024 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2028 if (kIOReturnSuccess
!= err
)
2033 if (kIOReturnSuccess
!= err
)
2036 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
)
2038 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
2039 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2042 if (kWiredEncrypt
!= pageType
)
2044 // end of image1/2 - fill to next block
2045 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2046 if (kIOReturnSuccess
!= err
)
2049 if (kWiredClear
== pageType
)
2051 // enlarge wired image for test
2052 // err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
2055 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2056 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2057 image1Size
= vars
->fileVars
->position
;
2058 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2059 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2062 if (kIOReturnSuccess
!= err
)
2064 if (kIOReturnOverrun
== err
)
2066 // update actual compression ratio on not enough space (for retry)
2067 gIOHibernateCompression
= (compressedSize
<< 8) / uncompressedSize
;
2070 // update partial amount written (for IOPolledFileClose cleanup/unmap)
2071 header
->imageSize
= vars
->fileVars
->position
;
2077 header
->imageSize
= vars
->fileVars
->position
;
2078 header
->image1Size
= image1Size
;
2079 header
->bitmapSize
= bitmap_size
;
2080 header
->pageCount
= pageCount
;
2082 header
->restore1Sum
= restore1Sum
;
2083 header
->image1Sum
= sum1
;
2084 header
->image2Sum
= sum2
;
2085 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
2087 header
->compression
= (compressedSize
<< 8) / uncompressedSize
;
2088 gIOHibernateCompression
= header
->compression
;
2090 count
= vars
->fileVars
->fileExtents
->getLength();
2091 if (count
> sizeof(header
->fileExtentMap
))
2093 header
->fileExtentMapSize
= count
;
2094 count
= sizeof(header
->fileExtentMap
);
2097 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2098 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2100 header
->deviceBase
= vars
->fileVars
->block0
;
2101 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
2103 IOPolledFileSeek(vars
->fileVars
, 0);
2104 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
2105 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2107 if (kIOReturnSuccess
!= err
)
2109 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2113 clock_get_uptime(&endTime
);
2115 IOService::getPMRootDomain()->pmStatsRecordEvent(
2116 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2118 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2119 absolutetime_to_nanoseconds(endTime
, &nsec
);
2120 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
2122 absolutetime_to_nanoseconds(compTime
, &nsec
);
2123 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2126 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2128 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2129 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2130 vars
->fileVars
->cryptBytes
,
2132 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2134 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2135 header
->imageSize
, (header
->imageSize
* 100) / vars
->fileVars
->fileSize
,
2136 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2137 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2140 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2141 svPageCount
, zvPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
2144 IOPolledFilePollersClose(vars
->fileVars
, (kIOReturnSuccess
== err
) ? kIOPolledBeforeSleepState
: kIOPolledBeforeSleepStateAborted
);
2146 if (vars
->consoleMapping
)
2147 ProgressUpdate(gIOHibernateGraphicsInfo
,
2148 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2150 HIBLOG("hibernate_write_image done(%x)\n", err
);
2152 // should we come back via regular wake, set the state in memory.
2153 gIOHibernateState
= kIOHibernateStateInactive
;
2155 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
, wiredPagesEncrypted
,
2156 wiredPagesClear
, dirtyPagesEncrypted
);
2158 if (kIOReturnSuccess
== err
)
2160 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2162 return (kIOHibernatePostWriteSleep
);
2164 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2166 return (kIOHibernatePostWriteRestart
);
2170 /* by default, power down */
2171 return (kIOHibernatePostWriteHalt
);
2174 else if (kIOReturnAborted
== err
)
2176 return (kIOHibernatePostWriteWake
);
2180 /* on error, sleep */
2181 return (kIOHibernatePostWriteSleep
);
2185 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2188 hibernate_machine_init(void)
2193 uint32_t pagesRead
= 0;
2194 AbsoluteTime startTime
, compTime
;
2195 AbsoluteTime allTime
, endTime
;
2196 AbsoluteTime startIOTime
, endIOTime
;
2197 uint64_t nsec
, nsecIO
;
2199 uint32_t lastProgressStamp
= 0;
2200 uint32_t progressStamp
;
2201 IOPolledFileCryptVars
* cryptvars
= 0;
2203 IOHibernateVars
* vars
= &gIOHibernateVars
;
2204 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
2206 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
2209 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2210 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2212 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2214 HIBLOG("regular wake\n");
2218 HIBPRINT("diag %x %x %x %x\n",
2219 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2220 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2222 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
2223 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2224 tStat(booterStart
, booterStart
);
2225 gIOHibernateStats
->smcStart
= gIOHibernateCurrentHeader
->smcStart
;
2226 tStat(booterDuration0
, booterTime0
);
2227 tStat(booterDuration1
, booterTime1
);
2228 tStat(booterDuration2
, booterTime2
);
2229 tStat(booterDuration
, booterTime
);
2230 tStat(booterConnectDisplayDuration
, connectDisplayTime
);
2231 tStat(booterSplashDuration
, splashTime
);
2232 tStat(trampolineDuration
, trampolineTime
);
2234 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
2235 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
2236 gIOHibernateStats
->image1Pages
= pagesDone
;
2238 /* HIBERNATE_stats */
2239 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 14), gIOHibernateStats
->smcStart
,
2240 gIOHibernateStats
->booterStart
, gIOHibernateStats
->booterDuration
,
2241 gIOHibernateStats
->trampolineDuration
);
2243 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2244 gIOHibernateStats
->booterStart
,
2245 gIOHibernateStats
->smcStart
,
2246 gIOHibernateStats
->booterDuration0
,
2247 gIOHibernateStats
->booterDuration1
,
2248 gIOHibernateStats
->booterDuration2
,
2249 gIOHibernateStats
->booterDuration
,
2250 gIOHibernateStats
->booterConnectDisplayDuration
,
2251 gIOHibernateStats
->booterSplashDuration
,
2252 gIOHibernateStats
->trampolineDuration
);
2254 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2255 gIOHibernateState
, pagesDone
, sum
, gIOHibernateStats
->imageSize
, gIOHibernateStats
->image1Size
,
2256 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2258 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
2259 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)))
2261 hibernate_page_list_discard(vars
->page_list
);
2264 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2266 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
2267 panic("handoff overflow");
2269 IOHibernateHandoff
* handoff
;
2271 bool foundCryptData
= false;
2272 bool foundVolumeEncryptData
= false;
2274 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2276 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2278 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2279 uint8_t * data
= &handoff
->data
[0];
2280 switch (handoff
->type
)
2282 case kIOHibernateHandoffTypeEnd
:
2286 case kIOHibernateHandoffTypeGraphicsInfo
:
2287 if (handoff
->bytecount
== sizeof(*gIOHibernateGraphicsInfo
))
2289 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2293 case kIOHibernateHandoffTypeCryptVars
:
2296 hibernate_cryptwakevars_t
*
2297 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
2298 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
2300 foundCryptData
= true;
2301 bzero(data
, handoff
->bytecount
);
2304 case kIOHibernateHandoffTypeVolumeCryptKey
:
2305 if (handoff
->bytecount
== vars
->volumeCryptKeySize
)
2307 bcopy(data
, &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
2308 foundVolumeEncryptData
= true;
2310 else panic("kIOHibernateHandoffTypeVolumeCryptKey(%d)", handoff
->bytecount
);
2313 case kIOHibernateHandoffTypeMemoryMap
:
2315 clock_get_uptime(&allTime
);
2317 hibernate_newruntime_map(data
, handoff
->bytecount
,
2318 gIOHibernateCurrentHeader
->systemTableOffset
);
2320 clock_get_uptime(&endTime
);
2322 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2323 absolutetime_to_nanoseconds(endTime
, &nsec
);
2325 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
2329 case kIOHibernateHandoffTypeDeviceTree
:
2331 // DTEntry chosen = NULL;
2332 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2337 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2342 if (vars
->hwEncrypt
&& !foundVolumeEncryptData
)
2343 panic("no volumeCryptKey");
2344 else if (cryptvars
&& !foundCryptData
)
2345 panic("hibernate handoff");
2347 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2348 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2349 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2351 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
2353 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2354 * gIOHibernateGraphicsInfo
->rowBytes
);
2355 if (vars
->videoMapSize
> vars
->videoAllocSize
) vars
->videoMapSize
= 0;
2358 IOMapPages(kernel_map
,
2359 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2360 vars
->videoMapSize
, kIOMapInhibitCache
);
2364 if (vars
->videoMapSize
)
2365 ProgressUpdate(gIOHibernateGraphicsInfo
,
2366 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2368 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2369 uint8_t * compressed
= src
+ page_size
;
2370 uint8_t * scratch
= compressed
+ page_size
;
2371 uint32_t decoOffset
;
2373 clock_get_uptime(&allTime
);
2374 AbsoluteTime_to_scalar(&compTime
) = 0;
2377 HIBLOG("IOPolledFilePollersOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2378 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledAfterSleepState
, false);
2379 clock_get_uptime(&startIOTime
);
2380 endTime
= startIOTime
;
2381 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2382 absolutetime_to_nanoseconds(endTime
, &nsec
);
2383 HIBLOG("IOPolledFilePollersOpen(%x) %qd ms\n", err
, nsec
/ 1000000ULL);
2385 if (vars
->hwEncrypt
)
2387 err
= IOPolledFilePollersSetEncryptionKey(vars
->fileVars
,
2388 &vars
->volumeCryptKey
[0], vars
->volumeCryptKeySize
);
2389 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x)\n", err
);
2390 if (kIOReturnSuccess
!= err
) panic("IOPolledFilePollersSetEncryptionKey(0x%x)", err
);
2393 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2395 // kick off the read ahead
2396 vars
->fileVars
->bufferHalf
= 0;
2397 vars
->fileVars
->bufferLimit
= 0;
2398 vars
->fileVars
->lastRead
= 0;
2399 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
2400 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2401 vars
->fileVars
->cryptBytes
= 0;
2402 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
2404 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2405 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2408 HIBLOG("hibernate_machine_init reading\n");
2410 uint32_t * header
= (uint32_t *) src
;
2413 while (kIOReturnSuccess
== err
)
2418 vm_offset_t ppnum
, compressedSize
;
2420 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2421 if (kIOReturnSuccess
!= err
)
2427 // HIBPRINT("(%x, %x)\n", ppnum, count);
2432 for (page
= 0; page
< count
; page
++)
2434 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2435 if (kIOReturnSuccess
!= err
)
2438 compressedSize
= kIOHibernateTagLength
& tag
;
2439 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2441 err
= kIOReturnIPCError
;
2445 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2446 if (kIOReturnSuccess
!= err
) break;
2448 if (compressedSize
< page_size
)
2450 decoOffset
= page_size
;
2451 clock_get_uptime(&startTime
);
2453 if (compressedSize
== 4) {
2457 s
= (uint32_t *)src
;
2458 d
= (uint32_t *)(uintptr_t)compressed
;
2460 for (i
= 0; i
< (int)(PAGE_SIZE
/ sizeof(int32_t)); i
++)
2464 WKdm_decompress_new((WK_word
*) src
, (WK_word
*) compressed
, (WK_word
*) scratch
, compressedSize
);
2465 clock_get_uptime(&endTime
);
2466 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2467 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2468 compBytes
+= page_size
;
2470 else decoOffset
= 0;
2472 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
2473 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2476 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2484 if (0 == (8191 & pagesDone
))
2486 clock_get_uptime(&endTime
);
2487 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2488 absolutetime_to_nanoseconds(endTime
, &nsec
);
2489 progressStamp
= nsec
/ 750000000ULL;
2490 if (progressStamp
!= lastProgressStamp
)
2492 lastProgressStamp
= progressStamp
;
2493 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2494 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2499 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
2500 err
= kIOReturnLockedRead
;
2502 if (kIOReturnSuccess
!= err
)
2503 panic("Hibernate restore error %x", err
);
2505 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2506 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
2508 clock_get_uptime(&endIOTime
);
2510 err
= IOPolledFilePollersClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2512 clock_get_uptime(&endTime
);
2514 IOService::getPMRootDomain()->pmStatsRecordEvent(
2515 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2516 IOService::getPMRootDomain()->pmStatsRecordEvent(
2517 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2519 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2520 absolutetime_to_nanoseconds(endTime
, &nsec
);
2522 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
2523 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
2525 gIOHibernateStats
->kernelImageReadDuration
= nsec
/ 1000000ULL;
2526 gIOHibernateStats
->imagePages
= pagesDone
;
2528 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
2529 pagesDone
, sum
, gIOHibernateStats
->kernelImageReadDuration
, kDefaultIOSize
,
2530 nsecIO
? ((((gIOHibernateCurrentHeader
->imageSize
- gIOHibernateCurrentHeader
->image1Size
) * 1000000000ULL) / 1024 / 1024) / nsecIO
) : 0);
2532 absolutetime_to_nanoseconds(compTime
, &nsec
);
2533 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2536 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2538 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2539 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2540 vars
->fileVars
->cryptBytes
,
2542 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2544 KDBG(IOKDBG_CODE(DBG_HIBERNATE
, 2), pagesRead
, pagesDone
);
2547 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2549 void IOHibernateSetWakeCapabilities(uint32_t capability
)
2551 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2553 gIOHibernateStats
->wakeCapability
= capability
;
2555 if (kIOPMSystemCapabilityGraphics
& capability
)
2557 vm_compressor_do_warmup();
2562 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2564 void IOHibernateSystemRestart(void)
2566 static uint8_t noteStore
[32] __attribute__((aligned(32)));
2567 IORegistryEntry
* regEntry
;
2568 const OSSymbol
* sym
;
2571 uintptr_t * smcVars
;
2576 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
2579 smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
2580 smcBytes
= (typeof(smcBytes
)) smcVars
[1];
2582 if (len
> sizeof(noteStore
)) len
= sizeof(noteStore
);
2583 noteProp
= OSData::withCapacity(3 * sizeof(element
));
2584 if (!noteProp
) return;
2586 noteProp
->appendBytes(&element
, sizeof(element
));
2587 element
= crc32(0, smcBytes
, len
);
2588 noteProp
->appendBytes(&element
, sizeof(element
));
2590 bcopy(smcBytes
, noteStore
, len
);
2591 element
= (addr64_t
) ¬eStore
[0];
2592 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
2593 noteProp
->appendBytes(&element
, sizeof(element
));
2595 if (!gIOOptionsEntry
)
2597 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2598 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
2599 if (regEntry
&& !gIOOptionsEntry
)
2600 regEntry
->release();
2603 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
2604 if (gIOOptionsEntry
&& sym
) gIOOptionsEntry
->setProperty(sym
, noteProp
);
2605 if (noteProp
) noteProp
->release();
2606 if (sym
) sym
->release();