2 * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
35 (devices awake, normal execution context)
36 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
37 grabs its extents and searches for a polling driver willing to work with that IOMedia.
38 The BSD code makes an ioctl to the storage driver to get the partition base offset to
39 the disk, and other ioctls to get the transfer constraints
40 If successful, the file is written to make sure its initially not bootable (in case of
41 later failure) and nvram set to point to the first block of the file. (Has to be done
42 here so blocking is possible in nvram support).
43 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
44 page out any pages it wants to (currently zero, but probably some percentage of memory).
45 Its assumed just allocating pages will cause the VM system to naturally select the best
46 pages for eviction. It also copies processor flags needed for the restore path and sets
47 a flag in the boot processor proc info.
48 gIOHibernateState = kIOHibernateStateHibernating.
49 - Regular sleep progresses - some drivers may inspect the root domain property
50 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
51 as usual but leaves motherboard I/O on.
52 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
53 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
54 all ppc RC bits out of the hash table and caches into the mapping structures.
55 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
56 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
57 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
58 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
59 The image header and block list are written. The header includes the second file extent so
60 only the header block is needed to read the file, regardless of filesystem.
61 The kernel segment "__HIB" is written uncompressed to the image. This segment of code and data
62 (only) is used to decompress the image during wake/boot.
63 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
64 The bitmaps are written to the image.
65 More areas are removed from the bitmaps (after they have been written to the image) - the
66 segment "__HIB" pages and interrupt stack.
67 Each wired page is compressed and written and then each non-wired page. Compression and
68 disk writes are in parallel.
69 The image header is written to the start of the file and the polling driver closed.
70 The machine powers down (or sleeps).
74 - BootX sees the boot-image nvram variable containing the device and block number of the image,
75 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
76 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
77 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
78 that is in the kernel's __HIB section.
79 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
80 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
81 only code & data in that section is safe to call since all the other wired pages are still
82 compressed in the image.
83 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
84 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
85 location directly, and copies those that can't to interim free pages. When the image has been
86 completed, the copies are uncompressed, overwriting the wired image pages.
87 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
88 is used to get pages into place for 64bit.
89 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
90 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
91 are removed from the software strutures, and the hash table is reinitialized.
92 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
93 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
94 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
95 for the remaining non wired pages.
96 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
97 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
102 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
103 registry, specifying an object of calls IOPolledInterface.
105 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
106 partition) that the image is going to live, looking for polled interface properties. If it finds
107 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
108 interfaces found are kept in an ordered list.
110 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
111 few different contexts things happen in:
113 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
114 up and running) and after wake - this is safe to allocate memory and do anything. The device
115 ignores sleep requests from that point since its a waste of time if it goes to sleep and
116 immediately wakes back up for the image write.
118 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
119 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
120 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
121 used to flush and set the disk to sleep.
123 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
124 immediately after sleep. These can't block or allocate memory. This is happening after the platform
125 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
128 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
129 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
130 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
131 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
132 that is called for the hardware to check for events, and complete the I/O via the callback.
133 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
137 #include <sys/systm.h>
139 #include <IOKit/IOWorkLoop.h>
140 #include <IOKit/IOCommandGate.h>
141 #include <IOKit/IOTimerEventSource.h>
142 #include <IOKit/IOPlatformExpert.h>
143 #include <IOKit/IOKitDebug.h>
144 #include <IOKit/IOTimeStamp.h>
145 #include <IOKit/pwr_mgt/RootDomain.h>
146 #include <IOKit/pwr_mgt/IOPMPrivate.h>
147 #include <IOKit/IOMessage.h>
148 #include <IOKit/IODeviceTreeSupport.h>
149 #include <IOKit/IOBSD.h>
150 #include "RootDomainUserClient.h"
151 #include <IOKit/pwr_mgt/IOPowerConnection.h>
152 #include "IOPMPowerStateQueue.h"
153 #include <IOKit/IOBufferMemoryDescriptor.h>
154 #include <IOKit/AppleKeyStoreInterface.h>
155 #include <libkern/crypto/aes.h>
158 #include <sys/conf.h>
159 #include <sys/stat.h>
160 #include <sys/fcntl.h> // (FWRITE, ...)
161 #include <sys/sysctl.h>
162 #include <sys/kdebug.h>
164 #include <IOKit/IOHibernatePrivate.h>
165 #include <IOKit/IOPolledInterface.h>
166 #include <IOKit/IONVRAM.h>
167 #include "IOHibernateInternal.h"
168 #include <vm/WKdm_new.h>
169 #include "IOKitKernelInternal.h"
170 #include <pexpert/device_tree.h>
172 #include <machine/pal_routines.h>
173 #include <machine/pal_hibernate.h>
174 #include <i386/tsc.h>
176 extern "C" addr64_t
kvtophys(vm_offset_t va
);
177 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
179 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
181 #define DISABLE_TRIM 0
182 #define TRIM_DELAY 5000
184 extern unsigned int save_kdebug_enable
;
185 extern uint32_t gIOHibernateState
;
186 uint32_t gIOHibernateMode
;
187 static char gIOHibernateBootSignature
[256+1];
188 static char gIOHibernateFilename
[MAXPATHLEN
+1];
189 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
190 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
191 static uint64_t gIOHibernateCompression
= 0x80; // default compression 50%
193 static IODTNVRAM
* gIOOptionsEntry
;
194 static IORegistryEntry
* gIOChosenEntry
;
195 #if defined(__i386__) || defined(__x86_64__)
196 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
197 static const OSSymbol
* gIOHibernateRTCVariablesKey
;
198 static const OSSymbol
* gIOHibernateBoot0082Key
;
199 static const OSSymbol
* gIOHibernateBootNextKey
;
200 static OSData
* gIOHibernateBoot0082Data
;
201 static OSData
* gIOHibernateBootNextData
;
202 static OSObject
* gIOHibernateBootNextSave
;
205 static IOLock
* gFSLock
;
206 static uint32_t gFSState
;
207 static IOPolledFileIOVars gFileVars
;
208 static IOHibernateVars gIOHibernateVars
;
209 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
210 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
211 static hibernate_graphics_t _hibernateGraphics
;
212 static hibernate_graphics_t
* gIOHibernateGraphicsInfo
= &_hibernateGraphics
;
213 static hibernate_statistics_t _hibernateStats
;
214 static hibernate_statistics_t
* gIOHibernateStats
= &_hibernateStats
;
224 static IOReturn
IOHibernateDone(IOHibernateVars
* vars
);
226 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
228 enum { kXPRamAudioVolume
= 8 };
229 enum { kDefaultIOSize
= 128 * 1024 };
230 enum { kVideoMapSize
= 32 * 1024 * 1024 };
232 #ifndef kIOMediaPreferredBlockSizeKey
233 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
236 #ifndef kIOBootPathKey
237 #define kIOBootPathKey "bootpath"
239 #ifndef kIOSelectedBootDeviceKey
240 #define kIOSelectedBootDeviceKey "boot-device"
244 enum { kIOHibernateMinPollersNeeded
= 2 };
246 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
248 // copy from phys addr to MD
251 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
252 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
254 addr64_t srcAddr
= bytes
;
255 IOByteCount remaining
;
257 remaining
= length
= min(length
, md
->getLength() - offset
);
258 while (remaining
) { // (process another target segment?)
262 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
266 // Clip segment length to remaining
267 if (dstLen
> remaining
)
271 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
273 copypv(srcAddr
, dstAddr64
, dstLen
,
274 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
283 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
286 // copy from MD to phys addr
289 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
290 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
292 addr64_t dstAddr
= bytes
;
293 IOByteCount remaining
;
295 remaining
= length
= min(length
, md
->getLength() - offset
);
296 while (remaining
) { // (process another target segment?)
300 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
304 // Clip segment length to remaining
305 if (dstLen
> remaining
)
309 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
311 copypv(srcAddr
, dstAddr64
, dstLen
,
312 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
321 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
324 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
328 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
333 case kIOHibernatePageStateUnwiredSave
:
335 for (; ppnum
< count
; ppnum
++)
337 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
338 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
341 case kIOHibernatePageStateWiredSave
:
343 for (; ppnum
< count
; ppnum
++)
345 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
346 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
349 case kIOHibernatePageStateFree
:
351 for (; ppnum
< count
; ppnum
++)
353 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
354 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
358 panic("hibernate_set_page_state");
363 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
365 uint32_t page
= *pPage
;
367 hibernate_bitmap_t
* bitmap
;
369 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
371 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
375 if (page
<= bitmap
->last_page
)
381 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
388 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
391 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
393 IOReturn err
= kIOReturnError
;
395 IOPolledInterface
* poller
;
397 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
399 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
400 err
= poller
->probe(target
);
403 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
412 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
414 IOReturn err
= kIOReturnError
;
416 IOPolledInterface
* poller
;
418 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
420 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
421 err
= poller
->open(state
, md
);
424 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
433 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
435 IOReturn err
= kIOReturnError
;
437 IOPolledInterface
* poller
;
440 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
443 err
= poller
->close(state
);
445 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
452 IOHibernatePollerIOComplete(void * target
,
455 UInt64 actualByteCount
)
457 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
459 vars
->ioStatus
= status
;
463 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
464 uint32_t operation
, uint32_t bufferOffset
,
465 uint64_t deviceOffset
, uint64_t length
)
468 IOReturn err
= kIOReturnError
;
469 IOPolledInterface
* poller
;
470 IOPolledCompletion completion
;
472 completion
.target
= 0;
473 completion
.action
= &IOHibernatePollerIOComplete
;
474 completion
.parameter
= vars
;
478 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
479 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
481 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
487 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
, bool abortable
)
489 IOReturn err
= kIOReturnSuccess
;
491 IOPolledInterface
* poller
;
493 while (-1 == vars
->ioStatus
)
496 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
500 newErr
= poller
->checkForWork();
501 if ((newErr
== kIOReturnAborted
) && !abortable
)
502 newErr
= kIOReturnSuccess
;
503 if (kIOReturnSuccess
== err
)
508 if ((kIOReturnSuccess
== err
) && abortable
&& hibernate_should_abort())
510 err
= kIOReturnAborted
;
511 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
516 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
520 err
= vars
->ioStatus
;
521 if (kIOReturnSuccess
!= err
)
522 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
529 IOPolledInterface::checkAllForWork(void)
531 IOReturn err
= kIOReturnNotReady
;
533 IOPolledInterface
* poller
;
535 IOHibernateVars
* vars
= &gIOHibernateVars
;
537 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
541 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
544 err
= poller
->checkForWork();
546 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
552 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
554 struct _OpenFileContext
561 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
563 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
564 IOPolledFileExtent extent
;
566 extent
.start
= start
;
567 extent
.length
= length
;
569 HIBLOG("[0x%qx, 0x%qx]\n", start
, length
);
571 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
576 IOCopyMediaForDev(dev_t device
)
578 OSDictionary
* matching
;
581 IOService
* result
= 0;
583 matching
= IOService::serviceMatching("IOMedia");
588 num
= OSNumber::withNumber(major(device
), 32);
591 matching
->setObject(kIOBSDMajorKey
, num
);
593 num
= OSNumber::withNumber(minor(device
), 32);
596 matching
->setObject(kIOBSDMinorKey
, num
);
600 iter
= IOService::getMatchingServices(matching
);
603 result
= (IOService
*) iter
->getNextObject();
615 IOPolledFileOpen( const char * filename
, uint64_t setFileSize
,
616 IOBufferMemoryDescriptor
* ioBuffer
,
617 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
618 OSData
** imagePath
, uint8_t * volumeCryptKey
)
620 IOReturn err
= kIOReturnSuccess
;
621 IOPolledFileIOVars
* vars
;
622 _OpenFileContext ctx
;
623 OSData
* extentsData
;
625 IOService
* part
= 0;
626 OSString
* keyUUID
= 0;
627 OSString
* keyStoreUUID
= 0;
629 dev_t hibernate_image_dev
;
631 AbsoluteTime startTime
, endTime
;
634 vars
= IONew(IOPolledFileIOVars
, 1);
635 if (!vars
) return (kIOReturnNoMemory
);
636 bzero(vars
, sizeof(*vars
));
641 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
642 vars
->bufferHalf
= 0;
643 vars
->bufferOffset
= 0;
644 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
646 extentsData
= OSData::withCapacity(32);
647 ctx
.extents
= extentsData
;
649 clock_get_uptime(&startTime
);
650 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
651 &file_extent_callback
, &ctx
,
654 0, (caddr_t
) gIOHibernateCurrentHeader
,
655 sizeof(IOHibernateImageHeader
),
658 &hibernate_image_dev
,
663 uint32_t msDelay
= (131071 & random());
664 HIBLOG("sleep %d\n", msDelay
);
667 clock_get_uptime(&endTime
);
668 SUB_ABSOLUTETIME(&endTime
, &startTime
);
669 absolutetime_to_nanoseconds(endTime
, &nsec
);
671 if (!vars
->fileRef
) err
= kIOReturnNoSpace
;
674 if (kFSOpening
!= gFSState
) err
= kIOReturnTimeout
;
675 IOLockUnlock(gFSLock
);
677 HIBLOG("kern_open_file_for_direct_io(%d) took %qd ms\n", err
, nsec
/ 1000000ULL);
678 if (kIOReturnSuccess
!= err
) break;
680 if (kIOHibernateModeSSDInvert
& gIOHibernateMode
)
681 vars
->flags
^= kIOHibernateOptionSSD
;
683 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename
, ctx
.size
,
684 vars
->block0
, maxiobytes
, kIOHibernateOptionSSD
& vars
->flags
);
685 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
687 err
= kIOReturnNoSpace
;
691 vars
->fileSize
= ctx
.size
;
692 if (maxiobytes
< vars
->bufferSize
) vars
->bufferSize
= maxiobytes
;
694 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
696 part
= IOCopyMediaForDev(block_dev
);
699 err
= kIOReturnNotFound
;
702 err
= part
->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID
, false,
703 (void *) &keyUUID
, (void *) &keyStoreUUID
, NULL
, NULL
);
704 if ((kIOReturnSuccess
== err
) && keyUUID
&& keyStoreUUID
)
706 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
707 uuid_t volumeKeyUUID
;
708 aks_volume_key_t vek
;
709 static IOService
* sKeyStore
;
710 static const OSSymbol
* sAKSGetKey
;
713 sAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
715 sKeyStore
= (IOService
*) IORegistryEntry::fromPath(AKS_SERVICE_PATH
, gIOServicePlane
);
717 err
= uuid_parse(keyStoreUUID
->getCStringNoCopy(), volumeKeyUUID
);
719 err
= kIOReturnNoResources
;
720 if (kIOReturnSuccess
== err
)
721 err
= sKeyStore
->callPlatformFunction(sAKSGetKey
, true, volumeKeyUUID
, &vek
, NULL
, NULL
);
722 if (kIOReturnSuccess
!= err
)
723 IOLog("volume key err 0x%x\n", err
);
726 size_t bytes
= (kIOHibernateAESKeySize
/ 8);
727 if (vek
.key
.keybytecount
< bytes
)
728 bytes
= vek
.key
.keybytecount
;
729 bcopy(&vek
.key
.keybytes
[0], volumeCryptKey
, bytes
);
731 bzero(&vek
, sizeof(vek
));
735 part
= IOCopyMediaForDev(hibernate_image_dev
);
738 err
= kIOReturnNotFound
;
742 IORegistryEntry
* next
;
743 IORegistryEntry
* child
;
746 vars
->pollers
= OSArray::withCapacity(4);
749 err
= kIOReturnNoMemory
;
753 vars
->blockSize
= 512;
757 IOPolledInterface
* poller
;
760 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
761 if (kOSBooleanFalse
== obj
)
763 vars
->pollers
->flushCollection();
766 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
767 vars
->pollers
->setObject(poller
);
768 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
769 vars
->blockSize
= num
->unsigned32BitValue();
772 while ((next
= child
->getParentEntry(gIOServicePlane
))
773 && child
->isParent(next
, gIOServicePlane
, true));
775 if (vars
->blockSize
< 4096) vars
->blockSize
= 4096;
777 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
778 major(hibernate_image_dev
), minor(hibernate_image_dev
), (long)vars
->blockSize
, vars
->pollers
->getCount());
780 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
782 err
= kIOReturnUnsupported
;
785 if (vars
->blockSize
< sizeof(IOHibernateImageHeader
))
787 err
= kIOReturnError
;
791 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
792 if (kIOReturnSuccess
!= err
) break;
794 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
795 if (kIOReturnSuccess
!= err
) break;
801 next
->setProperty(kIOPolledInterfaceActiveKey
, kOSBooleanTrue
);
802 next
= next
->getParentEntry(gIOServicePlane
);
806 *fileExtents
= extentsData
;
810 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
812 char str2
[24 + sizeof(uuid_string_t
) + 2];
814 #if defined(__i386__) || defined(__x86_64__)
815 if (!gIOCreateEFIDevicePathSymbol
)
816 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
819 snprintf(str2
, sizeof(str2
), "%qx:%s",
820 vars
->extentMap
[0].start
, keyUUID
->getCStringNoCopy());
822 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
824 err
= IOService::getPlatform()->callPlatformFunction(
825 gIOCreateEFIDevicePathSymbol
, false,
826 (void *) part
, (void *) str2
,
827 (void *) (uintptr_t) true, (void *) &data
);
830 int len
= sizeof(str1
);
832 if (!part
->getPath(str1
, &len
, gIODTPlane
))
833 err
= kIOReturnNotFound
;
836 snprintf(str2
, sizeof(str2
), ",%qx", vars
->extentMap
[0].start
);
837 // (strip the plane name)
838 char * tail
= strchr(str1
, ':');
841 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
842 data
->appendBytes(str2
, strlen(str2
));
845 if (kIOReturnSuccess
== err
)
848 HIBLOG("error 0x%x getting path\n", err
);
853 if (kIOReturnSuccess
!= err
)
855 HIBLOG("error 0x%x opening hibernation file\n", err
);
858 kern_close_file_for_direct_io(vars
->fileRef
, 0, 0, 0, 0, 0);
859 vars
->fileRef
= NULL
;
870 IOPolledFileClose( IOPolledFileIOVars
* vars
)
874 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
875 vars
->pollers
->release();
878 bzero(vars
, sizeof(IOPolledFileIOVars
));
880 return (kIOReturnSuccess
);
884 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
886 IOPolledFileExtent
* extentMap
;
888 extentMap
= vars
->extentMap
;
890 vars
->position
= position
;
892 while (position
>= extentMap
->length
)
894 position
-= extentMap
->length
;
898 vars
->currentExtent
= extentMap
;
899 vars
->extentRemaining
= extentMap
->length
- position
;
900 vars
->extentPosition
= vars
->position
- position
;
902 if (vars
->bufferSize
<= vars
->extentRemaining
)
903 vars
->bufferLimit
= vars
->bufferSize
;
905 vars
->bufferLimit
= vars
->extentRemaining
;
907 return (kIOReturnSuccess
);
911 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
912 const uint8_t * bytes
, IOByteCount size
,
913 hibernate_cryptvars_t
* cryptvars
)
915 IOReturn err
= kIOReturnSuccess
;
923 // seek to end of block & flush
924 size
= vars
->position
& (vars
->blockSize
- 1);
926 size
= vars
->blockSize
- size
;
928 // use some garbage for the fill
929 bytes
= vars
->buffer
+ vars
->bufferOffset
;
932 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
940 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
944 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
947 vars
->bufferOffset
+= copy
;
948 vars
->position
+= copy
;
950 if (flush
&& vars
->bufferOffset
)
952 uint64_t offset
= (vars
->position
- vars
->bufferOffset
953 - vars
->extentPosition
+ vars
->currentExtent
->start
);
954 uint32_t length
= (vars
->bufferOffset
);
957 if (cryptvars
&& vars
->encryptStart
958 && (vars
->position
> vars
->encryptStart
)
959 && ((vars
->position
- length
) < vars
->encryptEnd
))
961 AbsoluteTime startTime
, endTime
;
963 uint64_t encryptLen
, encryptStart
;
964 encryptLen
= vars
->position
- vars
->encryptStart
;
965 if (encryptLen
> length
)
967 encryptStart
= length
- encryptLen
;
968 if (vars
->position
> vars
->encryptEnd
)
969 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
971 clock_get_uptime(&startTime
);
973 // encrypt the buffer
974 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
975 &cryptvars
->aes_iv
[0],
976 encryptLen
/ AES_BLOCK_SIZE
,
977 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
978 &cryptvars
->ctx
.encrypt
);
980 clock_get_uptime(&endTime
);
981 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
982 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
983 vars
->cryptBytes
+= encryptLen
;
985 // save initial vector for following encrypts
986 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
987 &cryptvars
->aes_iv
[0],
994 err
= IOHibernatePollerIODone(vars
, true);
995 if (kIOReturnSuccess
!= err
)
999 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
1000 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
1002 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
1003 if (kIOReturnSuccess
!= err
)
1007 vars
->extentRemaining
-= vars
->bufferOffset
;
1008 if (!vars
->extentRemaining
)
1010 vars
->currentExtent
++;
1011 vars
->extentRemaining
= vars
->currentExtent
->length
;
1012 vars
->extentPosition
= vars
->position
;
1013 if (!vars
->extentRemaining
)
1015 err
= kIOReturnOverrun
;
1020 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1021 vars
->bufferOffset
= 0;
1022 if (vars
->bufferSize
<= vars
->extentRemaining
)
1023 vars
->bufferLimit
= vars
->bufferSize
;
1025 vars
->bufferLimit
= vars
->extentRemaining
;
1036 IOPolledFileRead(IOPolledFileIOVars
* vars
,
1037 uint8_t * bytes
, IOByteCount size
,
1038 hibernate_cryptvars_t
* cryptvars
)
1040 IOReturn err
= kIOReturnSuccess
;
1043 // bytesWritten += size;
1047 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
1053 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1057 vars
->bufferOffset
+= copy
;
1058 // vars->position += copy;
1060 if ((vars
->bufferOffset
== vars
->bufferLimit
) && (vars
->position
< vars
->readEnd
))
1064 err
= IOHibernatePollerIODone(vars
, false);
1065 if (kIOReturnSuccess
!= err
)
1071 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
1073 vars
->position
+= vars
->lastRead
;
1074 vars
->extentRemaining
-= vars
->lastRead
;
1075 vars
->bufferLimit
= vars
->lastRead
;
1077 if (!vars
->extentRemaining
)
1079 vars
->currentExtent
++;
1080 vars
->extentRemaining
= vars
->currentExtent
->length
;
1081 vars
->extentPosition
= vars
->position
;
1082 if (!vars
->extentRemaining
)
1084 err
= kIOReturnOverrun
;
1090 uint64_t lastReadLength
= vars
->lastRead
;
1091 uint64_t offset
= (vars
->position
1092 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1093 if (vars
->extentRemaining
<= vars
->bufferSize
)
1094 length
= vars
->extentRemaining
;
1096 length
= vars
->bufferSize
;
1097 if ((length
+ vars
->position
) > vars
->readEnd
)
1098 length
= vars
->readEnd
- vars
->position
;
1100 vars
->lastRead
= length
;
1103 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1104 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
1105 if (kIOReturnSuccess
!= err
)
1110 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1111 vars
->bufferOffset
= 0;
1116 uint8_t thisVector
[AES_BLOCK_SIZE
];
1117 AbsoluteTime startTime
, endTime
;
1119 // save initial vector for following decrypts
1120 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
1121 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
1122 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1124 // decrypt the buffer
1125 clock_get_uptime(&startTime
);
1127 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
1129 lastReadLength
/ AES_BLOCK_SIZE
,
1130 vars
->buffer
+ vars
->bufferHalf
,
1131 &cryptvars
->ctx
.decrypt
);
1133 clock_get_uptime(&endTime
);
1134 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1135 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1136 vars
->cryptBytes
+= lastReadLength
;
1146 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1149 IOHibernateSystemSleep(void)
1156 bool dsSSD
, vmflush
;
1157 IOHibernateVars
* vars
;
1159 gIOHibernateState
= kIOHibernateStateInactive
;
1161 if (!gIOChosenEntry
)
1162 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1164 gIOHibernateDebugFlags
= 0;
1165 if (kIOLogHibernate
& gIOKitDebug
)
1166 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
1168 if (IOService::getPMRootDomain()->getHibernateSettings(
1169 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
1171 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1172 // default to discard clean for safe sleep
1173 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
1174 | kIOHibernateModeDiscardCleanActive
);
1177 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1179 if ((str
= OSDynamicCast(OSString
, obj
)))
1180 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1181 sizeof(gIOHibernateFilename
));
1185 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1186 return (kIOReturnUnsupported
);
1188 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1190 vars
= IONew(IOHibernateVars
, 1);
1191 if (!vars
) return (kIOReturnNoMemory
);
1192 bzero(vars
, sizeof(*vars
));
1194 IOLockLock(gFSLock
);
1195 if (kFSIdle
!= gFSState
)
1197 HIBLOG("hibernate file busy\n");
1198 IOLockUnlock(gFSLock
);
1199 IODelete(vars
, IOHibernateVars
, 1);
1200 return (kIOReturnBusy
);
1202 gFSState
= kFSOpening
;
1203 IOLockUnlock(gFSLock
);
1207 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1208 2 * page_size
+ WKdm_SCRATCH_BUF_SIZE
, page_size
);
1209 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1210 2 * kDefaultIOSize
, page_size
);
1212 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1213 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
1215 if (!vars
->srcBuffer
|| !vars
->ioBuffer
|| !vars
->handoffBuffer
)
1217 err
= kIOReturnNoMemory
;
1221 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey
)))
1223 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMinSize
= num
->unsigned64BitValue();
1226 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey
)))
1228 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMaxSize
= num
->unsigned64BitValue();
1232 boolean_t encryptedswap
= true;
1234 AbsoluteTime startTime
, endTime
;
1237 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1238 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1239 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1241 vmflush
= (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
));
1242 uint64_t setFileSize
= 0;
1243 err
= hibernate_alloc_page_lists(&vars
->page_list
,
1244 &vars
->page_list_wired
,
1245 &vars
->page_list_pal
);
1246 if (KERN_SUCCESS
!= err
)
1249 if (vars
->fileMinSize
|| (kIOHibernateModeFileResize
& gIOHibernateMode
))
1251 hibernate_page_list_setall(vars
->page_list
,
1252 vars
->page_list_wired
,
1253 vars
->page_list_pal
,
1254 true /* preflight */,
1255 vmflush
/* discard */,
1257 PE_Video consoleInfo
;
1258 bzero(&consoleInfo
, sizeof(consoleInfo
));
1259 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1261 // estimate: 5% increase in pages compressed
1262 // screen preview 2 images compressed 50%
1263 setFileSize
= ((ptoa_64((105 * pageCount
) / 100) * gIOHibernateCompression
) >> 8)
1264 + vars
->page_list
->list_size
1265 + (consoleInfo
.v_width
* consoleInfo
.v_height
* 4);
1267 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
1268 pageCount
, (100ULL * gIOHibernateCompression
) >> 8,
1269 setFileSize
, vars
->fileMinSize
);
1271 if (!(kIOHibernateModeFileResize
& gIOHibernateMode
)
1272 && (setFileSize
< vars
->fileMinSize
))
1274 setFileSize
= vars
->fileMinSize
;
1278 // open & invalidate the image file
1280 err
= IOPolledFileOpen(gIOHibernateFilename
, setFileSize
, vars
->ioBuffer
,
1281 &vars
->fileVars
, &vars
->fileExtents
, &data
,
1282 &vars
->volumeCryptKey
[0]);
1283 if (KERN_SUCCESS
!= err
)
1285 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1289 clock_get_uptime(&startTime
);
1290 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1291 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1293 vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1294 clock_get_uptime(&endTime
);
1295 SUB_ABSOLUTETIME(&endTime
, &startTime
);
1296 absolutetime_to_nanoseconds(endTime
, &nsec
);
1297 HIBLOG("hibernate_setup(%d) took %qd ms\n", err
, nsec
/ 1000000ULL);
1299 dsSSD
= ((0 != (kIOHibernateOptionSSD
& vars
->fileVars
->flags
))
1300 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
1303 gIOHibernateCurrentHeader
->options
|=
1304 kIOHibernateOptionSSD
1305 | kIOHibernateOptionColor
;
1307 #if defined(__i386__) || defined(__x86_64__)
1308 if (!uuid_is_null(vars
->volumeCryptKey
) &&
1309 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
)))
1311 uintptr_t smcVars
[2];
1312 smcVars
[0] = sizeof(vars
->volumeCryptKey
);
1313 smcVars
[1] = (uintptr_t)(void *) &gIOHibernateVars
.volumeCryptKey
[0];
1315 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
1316 bzero(smcVars
, sizeof(smcVars
));
1322 gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
1326 if (KERN_SUCCESS
!= err
)
1329 if (encryptedswap
|| !uuid_is_null(vars
->volumeCryptKey
))
1330 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1332 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1334 vars
->videoAllocSize
= kVideoMapSize
;
1335 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1336 vars
->videoMapping
= 0;
1339 // generate crypt keys
1340 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1341 vars
->wiredCryptKey
[i
] = random();
1342 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1343 vars
->cryptKey
[i
] = random();
1347 IORegistryEntry
* regEntry
;
1348 if (!gIOOptionsEntry
)
1350 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1351 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1352 if (regEntry
&& !gIOOptionsEntry
)
1353 regEntry
->release();
1356 if (gIOOptionsEntry
)
1358 const OSSymbol
* sym
;
1360 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1363 gIOOptionsEntry
->setProperty(sym
, data
);
1368 #if defined(__i386__) || defined(__x86_64__)
1369 struct AppleRTCHibernateVars
1371 uint8_t signature
[4];
1373 uint8_t booterSignature
[20];
1374 uint8_t wiredCryptKey
[16];
1376 AppleRTCHibernateVars rtcVars
;
1378 rtcVars
.signature
[0] = 'A';
1379 rtcVars
.signature
[1] = 'A';
1380 rtcVars
.signature
[2] = 'P';
1381 rtcVars
.signature
[3] = 'L';
1382 rtcVars
.revision
= 1;
1383 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1384 if (gIOHibernateBootSignature
[0])
1388 for (uint32_t i
= 0;
1389 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1400 value
= (value
<< 4) | c
;
1402 rtcVars
.booterSignature
[i
>> 1] = value
;
1405 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1408 if (!gIOHibernateRTCVariablesKey
)
1409 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1410 if (gIOHibernateRTCVariablesKey
)
1411 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
1413 if( gIOOptionsEntry
)
1415 if( gIOHibernateMode
& kIOHibernateModeSwitch
)
1417 const OSSymbol
*sym
;
1418 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey
);
1421 gIOOptionsEntry
->setProperty(sym
, data
); /* intentional insecure backup of rtc boot vars */
1431 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1433 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1437 if (!gIOHibernateBoot0082Data
)
1439 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
1442 // AppleNVRAM_EFI_LOAD_OPTION
1444 uint32_t Attributes
;
1445 uint16_t FilePathLength
;
1448 loadOptionHeader
.Attributes
= 1;
1449 loadOptionHeader
.FilePathLength
= data
->getLength();
1450 loadOptionHeader
.Desc
= 0;
1451 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
1452 if (gIOHibernateBoot0082Data
)
1454 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
1455 gIOHibernateBoot0082Data
->appendBytes(data
);
1459 if (!gIOHibernateBoot0082Key
)
1460 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1461 if (!gIOHibernateBootNextKey
)
1462 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1463 if (!gIOHibernateBootNextData
)
1465 uint16_t bits
= 0x0082;
1466 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
1468 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
1470 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
1471 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
1472 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
1476 #else /* !i386 && !x86_64 */
1477 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1479 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1480 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1482 gIOOptionsEntry
->setProperty(sym
, data
);
1487 if (false && gIOHibernateBootSignature
[0])
1489 data
= OSData::withCapacity(16);
1490 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1495 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1505 value
= (value
<< 4) | c
;
1507 data
->appendBytes(&value
, sizeof(value
));
1509 gIOOptionsEntry
->setProperty(sym
, data
);
1517 if (!vars
->haveFastBoot
)
1519 // set boot volume to zero
1520 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1521 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1522 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1525 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1526 platform
->writeXPRAM(kXPRamAudioVolume
,
1527 &newVolume
, sizeof(newVolume
));
1530 #endif /* !i386 && !x86_64 */
1537 IOLockLock(gFSLock
);
1538 if ((kIOReturnSuccess
== err
) && (kFSOpening
== gFSState
))
1540 gFSState
= kFSOpened
;
1541 gIOHibernateVars
= *vars
;
1542 gFileVars
= *vars
->fileVars
;
1543 gIOHibernateVars
.fileVars
= &gFileVars
;
1544 gIOHibernateFileRef
= gFileVars
.fileRef
;
1545 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1546 gIOHibernateState
= kIOHibernateStateHibernating
;
1550 HIBLOG("hibernate file close due timeout\n");
1551 if (vars
->fileVars
&& vars
->fileVars
->fileRef
) kern_close_file_for_direct_io(vars
->fileVars
->fileRef
, 0, 0, 0, 0, 0);
1552 IOHibernateDone(vars
);
1555 IOLockUnlock(gFSLock
);
1557 if (vars
->fileVars
) IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
1558 IODelete(vars
, IOHibernateVars
, 1);
1563 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1565 DECLARE_IOHIBERNATEPROGRESSALPHA
1568 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
1570 uint32_t rowBytes
, pixelShift
;
1573 uint32_t alpha
, in
, color
, result
;
1575 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1577 rowBytes
= display
->rowBytes
;
1578 pixelShift
= display
->depth
>> 4;
1579 if (pixelShift
< 1) return;
1581 screen
+= ((display
->width
1582 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1583 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1585 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1587 out
= screen
+ y
* rowBytes
;
1588 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
1590 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
1591 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1593 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1599 if (1 == pixelShift
)
1601 in
= *((uint16_t *)out
) & 0x1f; // 16
1602 in
= (in
<< 3) | (in
>> 2);
1605 in
= *((uint32_t *)out
) & 0xff; // 32
1606 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1607 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1609 if (1 == pixelShift
)
1612 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1615 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1617 out
+= (1 << pixelShift
);
1619 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1626 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1628 uint32_t rowBytes
, pixelShift
;
1630 int32_t blob
, lastBlob
;
1631 uint32_t alpha
, in
, color
, result
;
1633 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1635 pixelShift
= display
->depth
>> 4;
1639 rowBytes
= display
->rowBytes
;
1641 screen
+= ((display
->width
1642 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1643 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1645 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1647 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1649 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1651 out
= screen
+ y
* rowBytes
;
1652 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1654 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1655 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1657 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1663 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1664 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1666 if (1 == pixelShift
)
1669 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1672 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1674 out
+= (1 << pixelShift
);
1676 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1681 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1684 IOHibernateIOKitSleep(void)
1686 IOReturn ret
= kIOReturnSuccess
;
1687 IOLockLock(gFSLock
);
1688 if (kFSOpening
== gFSState
)
1690 gFSState
= kFSTimedOut
;
1691 HIBLOG("hibernate file open timed out\n");
1692 ret
= kIOReturnTimeout
;
1694 IOLockUnlock(gFSLock
);
1698 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1701 IOHibernateSystemHasSlept(void)
1703 IOReturn ret
= kIOReturnSuccess
;
1704 IOHibernateVars
* vars
= &gIOHibernateVars
;
1708 IOLockLock(gFSLock
);
1709 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
)
1711 ret
= kIOReturnTimeout
;
1713 IOLockUnlock(gFSLock
);
1714 if (kIOReturnSuccess
!= ret
) return (ret
);
1716 if (gIOHibernateMode
) obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1717 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1718 if (obj
&& !vars
->previewBuffer
)
1721 vars
->consoleMapping
= NULL
;
1722 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1724 vars
->previewBuffer
->release();
1725 vars
->previewBuffer
= 0;
1728 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1729 && vars
->previewBuffer
1730 && (data
= OSDynamicCast(OSData
,
1731 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1733 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1734 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1736 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1738 if (kIOHibernatePreviewUpdates
& flags
)
1740 PE_Video consoleInfo
;
1741 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1743 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1745 graphicsInfo
->width
= consoleInfo
.v_width
;
1746 graphicsInfo
->height
= consoleInfo
.v_height
;
1747 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1748 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1749 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1751 HIBPRINT("video %p %d %d %d\n",
1752 vars
->consoleMapping
, graphicsInfo
->depth
,
1753 graphicsInfo
->width
, graphicsInfo
->height
);
1754 if (vars
->consoleMapping
)
1755 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1756 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1760 if (gIOOptionsEntry
)
1761 gIOOptionsEntry
->sync();
1766 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1768 static DeviceTreeNode
*
1769 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
1771 DeviceTreeNodeProperty
* prop
;
1772 DeviceTreeNode
* child
;
1773 IORegistryEntry
* childRegEntry
;
1774 const char * nameProp
;
1775 unsigned int propLen
, idx
;
1777 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1778 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
1780 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
1782 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1783 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1785 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1788 child
= (DeviceTreeNode
*) prop
;
1789 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
1791 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
1793 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1794 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1795 child
= MergeDeviceTree(child
, childRegEntry
);
1801 IOHibernateSystemWake(void)
1803 if (kFSOpened
== gFSState
)
1805 IOHibernateDone(&gIOHibernateVars
);
1809 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1810 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1812 return (kIOReturnSuccess
);
1816 IOHibernateDone(IOHibernateVars
* vars
)
1818 IORegistryEntry
* next
;
1820 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1822 if (vars
->videoMapping
)
1824 if (vars
->videoMapSize
)
1826 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1827 if (vars
->videoAllocSize
)
1829 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1832 if (vars
->previewBuffer
)
1834 vars
->previewBuffer
->release();
1835 vars
->previewBuffer
= 0;
1838 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1840 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1841 gIOHibernateCurrentHeader
->options
, 32);
1845 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1848 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1849 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1851 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1852 &gIOHibernateGraphicsInfo
->gfxStatus
,
1853 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1857 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1862 if ((next
= vars
->fileVars
->media
)) do
1864 next
->removeProperty(kIOPolledInterfaceActiveKey
);
1865 next
= next
->getParentEntry(gIOServicePlane
);
1868 IOPolledFileClose(vars
->fileVars
);
1871 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1873 #if defined(__i386__) || defined(__x86_64__)
1874 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1875 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1878 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1879 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1881 if (gIOOptionsEntry
) {
1883 if (gIOHibernateRTCVariablesKey
) {
1884 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1885 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1889 if (gIOHibernateBootNextKey
)
1891 if (gIOHibernateBootNextSave
)
1893 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1894 gIOHibernateBootNextSave
->release();
1895 gIOHibernateBootNextSave
= NULL
;
1898 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1900 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) gIOOptionsEntry
->sync();
1904 if (vars
->srcBuffer
)
1905 vars
->srcBuffer
->release();
1907 vars
->ioBuffer
->release();
1908 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1909 if (vars
->handoffBuffer
)
1911 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1913 IOHibernateHandoff
* handoff
;
1915 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1917 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
1919 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1920 uint8_t * data
= &handoff
->data
[0];
1921 switch (handoff
->type
)
1923 case kIOHibernateHandoffTypeEnd
:
1927 case kIOHibernateHandoffTypeDeviceTree
:
1928 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
1931 case kIOHibernateHandoffTypeKeyStore
:
1932 #if defined(__i386__) || defined(__x86_64__)
1934 IOBufferMemoryDescriptor
*
1935 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1938 IOSetKeyStoreData(md
);
1945 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1950 vars
->handoffBuffer
->release();
1952 if (vars
->fileExtents
)
1953 vars
->fileExtents
->release();
1955 bzero(vars
, sizeof(*vars
));
1957 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1959 return (kIOReturnSuccess
);
1963 IOHibernateSystemPostWake(void)
1965 struct kern_direct_file_io_ref_t
* fileRef
;
1967 if (kFSOpened
== gFSState
)
1969 // invalidate & close the image file
1970 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1971 if ((fileRef
= gIOHibernateFileRef
))
1973 gIOHibernateFileRef
= 0;
1974 IOSleep(TRIM_DELAY
);
1975 kern_close_file_for_direct_io(fileRef
,
1979 0, (caddr_t
) gIOHibernateCurrentHeader
,
1980 sizeof(IOHibernateImageHeader
),
1982 gIOHibernateCurrentHeader
->imageSize
);
1987 return (kIOReturnSuccess
);
1990 bool IOHibernateWasScreenLocked(void)
1993 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
)
1996 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
1997 if (data
) switch (*((uint32_t *)data
->getBytesNoCopy()))
1999 case kIOScreenLockLocked
:
2000 case kIOScreenLockFileVaultDialog
:
2003 case kIOScreenLockNoLock
:
2004 case kIOScreenLockUnlocked
:
2013 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
2016 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2017 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
2018 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
2019 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2020 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
2021 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
2022 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2023 &gIOHibernateMode
, 0, "");
2024 SYSCTL_STRUCT(_kern
, OID_AUTO
, hibernatestatistics
,
2025 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
2026 gIOHibernateStats
, hibernate_statistics_t
, "");
2028 SYSCTL_UINT(_kern
, OID_AUTO
, hibernategraphicsready
,
2029 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2030 &gIOHibernateStats
->graphicsReadyTime
, 0, "");
2031 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatewakenotification
,
2032 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2033 &gIOHibernateStats
->wakeNotificationTime
, 0, "");
2034 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatelockscreenready
,
2035 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2036 &gIOHibernateStats
->lockScreenReadyTime
, 0, "");
2037 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatehidready
,
2038 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
2039 &gIOHibernateStats
->hidReadyTime
, 0, "");
2043 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
2045 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
2048 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
2052 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
2053 gIOHibernateMode
= kIOHibernateModeOn
;
2055 gIOHibernateFilename
[0] = 0;
2057 sysctl_register_oid(&sysctl__kern_hibernatefile
);
2058 sysctl_register_oid(&sysctl__kern_bootsignature
);
2059 sysctl_register_oid(&sysctl__kern_hibernatemode
);
2060 sysctl_register_oid(&sysctl__kern_hibernatestatistics
);
2061 sysctl_register_oid(&sysctl__kern_hibernategraphicsready
);
2062 sysctl_register_oid(&sysctl__kern_hibernatewakenotification
);
2063 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready
);
2064 sysctl_register_oid(&sysctl__kern_hibernatehidready
);
2066 gFSLock
= IOLockAlloc();
2070 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2073 hibernate_setup_for_wake(void)
2077 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2079 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
2082 no_encrypt_page(vm_offset_t ppnum
)
2084 if (pmap_is_noencrypt((ppnum_t
)ppnum
) == TRUE
)
2092 hibernate_pal_callback(void *vars_arg
, vm_offset_t addr
)
2094 IOHibernateVars
*vars
= (IOHibernateVars
*)vars_arg
;
2095 /* Make sure it's not in either of the save lists */
2096 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
, atop_64(addr
), 1, kIOHibernatePageStateFree
);
2098 /* Set it in the bitmap of pages owned by the PAL */
2099 hibernate_page_bitset(vars
->page_list_pal
, TRUE
, atop_64(addr
));
2102 static struct hibernate_cryptvars_t
*local_cryptvars
;
2105 hibernate_pal_write(void *buffer
, size_t size
)
2107 IOHibernateVars
* vars
= &gIOHibernateVars
;
2109 IOReturn err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *)buffer
, size
, local_cryptvars
);
2110 if (kIOReturnSuccess
!= err
) {
2111 kprintf("epic hibernate fail! %d\n", err
);
2120 hibernate_write_image(void)
2122 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
2123 IOHibernateVars
* vars
= &gIOHibernateVars
;
2124 IOPolledFileExtent
* fileExtents
;
2126 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
2128 uint32_t pageCount
, pagesDone
;
2130 vm_offset_t ppnum
, page
;
2134 uint8_t * compressed
;
2136 void * zerosCompressed
;
2137 IOByteCount pageCompressedSize
, zerosCompressedLen
;
2138 uint64_t compressedSize
, uncompressedSize
;
2139 uint64_t image1Size
= 0;
2140 uint32_t bitmap_size
;
2141 bool iterDone
, pollerOpen
, needEncrypt
;
2142 uint32_t restore1Sum
, sum
, sum1
, sum2
;
2146 uint32_t pageAndCount
[2];
2150 AbsoluteTime startTime
, endTime
;
2151 AbsoluteTime allTime
, compTime
;
2154 uint32_t lastProgressStamp
= 0;
2155 uint32_t progressStamp
;
2156 uint32_t blob
, lastBlob
= (uint32_t) -1L;
2158 uint32_t wiredPagesEncrypted
;
2159 uint32_t dirtyPagesEncrypted
;
2160 uint32_t wiredPagesClear
;
2161 uint32_t zeroPageCount
;
2163 hibernate_cryptvars_t _cryptvars
;
2164 hibernate_cryptvars_t
* cryptvars
= 0;
2166 wiredPagesEncrypted
= 0;
2167 dirtyPagesEncrypted
= 0;
2168 wiredPagesClear
= 0;
2171 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2172 return (false /* sleep */ );
2174 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2175 kdebug_enable
= save_kdebug_enable
;
2177 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
, 0, 0, 0, 0, 0);
2178 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
2180 restore1Sum
= sum1
= sum2
= 0;
2182 hibernate_pal_prepare();
2185 // encryption data. "iv" is the "initial vector".
2186 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2188 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
2189 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
2190 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
2192 cryptvars
= &gIOHibernateCryptWakeContext
;
2193 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
2194 aes_encrypt_key(vars
->cryptKey
,
2195 kIOHibernateAESKeySize
,
2196 &cryptvars
->ctx
.encrypt
);
2197 aes_decrypt_key(vars
->cryptKey
,
2198 kIOHibernateAESKeySize
,
2199 &cryptvars
->ctx
.decrypt
);
2201 cryptvars
= &_cryptvars
;
2202 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
2203 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++)
2204 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
2205 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
2206 aes_encrypt_key(vars
->wiredCryptKey
,
2207 kIOHibernateAESKeySize
,
2208 &cryptvars
->ctx
.encrypt
);
2210 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
2211 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
2212 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
2214 local_cryptvars
= cryptvars
;
2218 hibernate_setup_for_wake();
2220 hibernate_page_list_setall(vars
->page_list
,
2221 vars
->page_list_wired
,
2222 vars
->page_list_pal
,
2223 false /* !preflight */,
2225 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
2226 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
2229 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
2231 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
2234 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
2235 for (page
= 0; page
< count
; page
++)
2237 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
2238 fileExtents
[page
].start
, fileExtents
[page
].length
,
2239 fileExtents
[page
].start
+ fileExtents
[page
].length
);
2243 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
2244 AbsoluteTime_to_scalar(&compTime
) = 0;
2247 clock_get_uptime(&allTime
);
2248 IOService::getPMRootDomain()->pmStatsRecordEvent(
2249 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
2253 uncompressedSize
= 0;
2256 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
2258 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
2259 ml_get_interrupts_enabled());
2260 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
2261 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2262 pollerOpen
= (kIOReturnSuccess
== err
);
2266 // copy file block extent list if larger than header
2268 count
= vars
->fileExtents
->getLength();
2269 if (count
> sizeof(header
->fileExtentMap
))
2271 count
-= sizeof(header
->fileExtentMap
);
2272 err
= IOPolledFileWrite(vars
->fileVars
,
2273 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
2274 if (kIOReturnSuccess
!= err
)
2278 uintptr_t hibernateBase
;
2279 uintptr_t hibernateEnd
;
2281 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
2283 hibernateEnd
= (segHIBB
+ segSizeHIB
);
2285 // copy out restore1 code
2288 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2291 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
2293 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
2297 page
= atop_32(kvtophys(hibernateBase
));
2298 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
2299 header
->restore1CodePhysPage
= page
;
2300 header
->restore1CodeVirt
= hibernateBase
;
2301 header
->restore1PageCount
= count
;
2302 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
2303 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
2305 // sum __HIB seg, with zeros for the stack
2306 src
= (uint8_t *) trunc_page(hibernateBase
);
2307 for (page
= 0; page
< count
; page
++)
2309 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
2310 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
2312 restore1Sum
+= 0x00000000;
2317 // write the __HIB seg, with zeros for the stack
2319 src
= (uint8_t *) trunc_page(hibernateBase
);
2320 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
2323 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2324 if (kIOReturnSuccess
!= err
)
2327 err
= IOPolledFileWrite(vars
->fileVars
,
2329 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
2331 if (kIOReturnSuccess
!= err
)
2333 src
= &gIOHibernateRestoreStackEnd
[0];
2334 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
2337 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2338 if (kIOReturnSuccess
!= err
)
2342 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2344 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
2345 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2346 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2349 // write the preview buffer
2351 if (vars
->previewBuffer
)
2357 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
2358 pageAndCount
[0] = atop_64(phys64
);
2359 pageAndCount
[1] = atop_32(segLen
);
2360 err
= IOPolledFileWrite(vars
->fileVars
,
2361 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2363 if (kIOReturnSuccess
!= err
)
2366 ppnum
+= sizeof(pageAndCount
);
2369 if (kIOReturnSuccess
!= err
)
2372 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
2374 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
2376 count
= vars
->previewBuffer
->getLength();
2378 header
->previewPageListSize
= ppnum
;
2379 header
->previewSize
= count
+ ppnum
;
2381 for (page
= 0; page
< count
; page
+= page_size
)
2383 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
2384 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
2386 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
2387 if (kIOReturnSuccess
!= err
)
2391 // mark areas for no save
2394 (phys64
= vars
->ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2397 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2398 atop_64(phys64
), atop_32(segLen
),
2399 kIOHibernatePageStateFree
);
2400 pageCount
-= atop_32(segLen
);
2404 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2407 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2408 atop_64(phys64
), atop_32(segLen
),
2409 kIOHibernatePageStateFree
);
2410 pageCount
-= atop_32(segLen
);
2413 // copy out bitmap of pages available for trashing during restore
2415 bitmap_size
= vars
->page_list_wired
->list_size
;
2416 src
= (uint8_t *) vars
->page_list_wired
;
2417 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
2418 if (kIOReturnSuccess
!= err
)
2421 // mark more areas for no save, but these are not available
2422 // for trashing during restore
2424 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
2427 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
2428 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
2429 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2431 kIOHibernatePageStateFree
);
2434 if (vars
->previewBuffer
) for (count
= 0;
2435 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2438 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2439 atop_64(phys64
), atop_32(segLen
),
2440 kIOHibernatePageStateFree
);
2441 pageCount
-= atop_32(segLen
);
2445 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2448 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2449 atop_64(phys64
), atop_32(segLen
),
2450 kIOHibernatePageStateFree
);
2451 pageCount
-= atop_32(segLen
);
2454 (void)hibernate_pal_callback
;
2456 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2457 compressed
= src
+ page_size
;
2458 scratch
= compressed
+ page_size
;
2460 // compress a zero page
2461 bzero(src
, page_size
);
2462 zerosCompressed
= vars
->handoffBuffer
->getBytesNoCopy();
2463 zerosCompressedLen
= WKdm_compress_new((WK_word
*) src
,
2464 (WK_word
*) zerosCompressed
,
2471 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
2472 bitmap_size
, header
->previewSize
,
2473 pageCount
, vars
->fileVars
->position
);
2480 kWiredEncrypt
= kWired
| kEncrypt
,
2481 kWiredClear
= kWired
,
2482 kUnwiredEncrypt
= kEncrypt
2485 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
2487 if (kUnwiredEncrypt
== pageType
)
2489 // start unwired image
2490 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2492 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
2493 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2494 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2496 bcopy(&cryptvars
->aes_iv
[0],
2497 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2498 sizeof(cryptvars
->aes_iv
));
2499 cryptvars
= &gIOHibernateCryptWakeContext
;
2501 for (iterDone
= false, ppnum
= 0; !iterDone
; )
2503 count
= hibernate_page_list_iterate((kWired
& pageType
)
2504 ? vars
->page_list_wired
: vars
->page_list
,
2506 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2509 if (count
&& (kWired
& pageType
) && needEncrypt
)
2511 uint32_t checkIndex
;
2512 for (checkIndex
= 0;
2513 (checkIndex
< count
)
2514 && (((kEncrypt
& pageType
) == 0) == no_encrypt_page(ppnum
+ checkIndex
));
2527 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
2528 case kWiredClear
: wiredPagesClear
+= count
; break;
2529 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
2532 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
2535 pageAndCount
[0] = ppnum
;
2536 pageAndCount
[1] = count
;
2537 err
= IOPolledFileWrite(vars
->fileVars
,
2538 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2540 if (kIOReturnSuccess
!= err
)
2544 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
2546 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
2549 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
2553 sum
= hibernate_sum_page(src
, page
);
2554 if (kWired
& pageType
)
2559 clock_get_uptime(&startTime
);
2560 wkresult
= WKdm_compress_new((WK_word
*) src
,
2561 (WK_word
*) compressed
,
2565 clock_get_uptime(&endTime
);
2566 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2567 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2569 compBytes
+= page_size
;
2570 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
2572 if ((pageCompressedSize
== zerosCompressedLen
)
2573 && !bcmp(compressed
, zerosCompressed
, zerosCompressedLen
))
2575 pageCompressedSize
= 0;
2579 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2580 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
2582 if (pageCompressedSize
!= page_size
)
2587 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2588 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2589 if (kIOReturnSuccess
!= err
)
2592 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2593 if (kIOReturnSuccess
!= err
)
2596 compressedSize
+= pageCompressedSize
;
2597 uncompressedSize
+= page_size
;
2600 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2602 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2603 if (blob
!= lastBlob
)
2605 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2609 if (0 == (8191 & pagesDone
))
2611 clock_get_uptime(&endTime
);
2612 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2613 absolutetime_to_nanoseconds(endTime
, &nsec
);
2614 progressStamp
= nsec
/ 750000000ULL;
2615 if (progressStamp
!= lastProgressStamp
)
2617 lastProgressStamp
= progressStamp
;
2618 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2622 if (kIOReturnSuccess
!= err
)
2627 if (kIOReturnSuccess
!= err
)
2630 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
)
2632 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
2633 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2636 if (kWiredEncrypt
!= pageType
)
2638 // end of image1/2 - fill to next block
2639 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2640 if (kIOReturnSuccess
!= err
)
2643 if (kWiredClear
== pageType
)
2645 // enlarge wired image for test
2646 // err = IOPolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
2649 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2650 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2651 image1Size
= vars
->fileVars
->position
;
2652 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2653 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2656 if (kIOReturnSuccess
!= err
)
2661 header
->imageSize
= vars
->fileVars
->position
;
2662 header
->image1Size
= image1Size
;
2663 header
->bitmapSize
= bitmap_size
;
2664 header
->pageCount
= pageCount
;
2666 header
->restore1Sum
= restore1Sum
;
2667 header
->image1Sum
= sum1
;
2668 header
->image2Sum
= sum2
;
2669 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
2671 header
->compression
= (compressedSize
<< 8) / uncompressedSize
;
2672 gIOHibernateCompression
= header
->compression
;
2674 count
= vars
->fileExtents
->getLength();
2675 if (count
> sizeof(header
->fileExtentMap
))
2677 header
->fileExtentMapSize
= count
;
2678 count
= sizeof(header
->fileExtentMap
);
2681 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2682 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2684 header
->deviceBase
= vars
->fileVars
->block0
;
2685 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
2687 IOPolledFileSeek(vars
->fileVars
, 0);
2688 err
= IOPolledFileWrite(vars
->fileVars
,
2689 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2691 if (kIOReturnSuccess
!= err
)
2693 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2694 if (kIOReturnSuccess
!= err
)
2696 err
= IOHibernatePollerIODone(vars
->fileVars
, true);
2697 if (kIOReturnSuccess
!= err
)
2702 clock_get_uptime(&endTime
);
2704 IOService::getPMRootDomain()->pmStatsRecordEvent(
2705 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2707 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2708 absolutetime_to_nanoseconds(endTime
, &nsec
);
2709 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
2711 absolutetime_to_nanoseconds(compTime
, &nsec
);
2712 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2715 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2717 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2718 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2719 vars
->fileVars
->cryptBytes
,
2721 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2723 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2724 header
->imageSize
, (header
->imageSize
* 100) / vars
->fileVars
->fileSize
,
2725 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2726 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2729 HIBLOG("zeroPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2730 zeroPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
2732 if (vars
->fileVars
->io
)
2733 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2736 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
2738 if (vars
->consoleMapping
)
2739 ProgressUpdate(gIOHibernateGraphicsInfo
,
2740 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2742 HIBLOG("hibernate_write_image done(%x)\n", err
);
2744 // should we come back via regular wake, set the state in memory.
2745 gIOHibernateState
= kIOHibernateStateInactive
;
2747 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
,
2748 wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
, 0, 0);
2750 if (kIOReturnSuccess
== err
)
2752 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2754 return (kIOHibernatePostWriteSleep
);
2756 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2758 return (kIOHibernatePostWriteRestart
);
2762 /* by default, power down */
2763 return (kIOHibernatePostWriteHalt
);
2766 else if (kIOReturnAborted
== err
)
2768 return (kIOHibernatePostWriteWake
);
2772 /* on error, sleep */
2773 return (kIOHibernatePostWriteSleep
);
2777 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2780 hibernate_machine_init(void)
2785 uint32_t pagesRead
= 0;
2786 AbsoluteTime startTime
, compTime
;
2787 AbsoluteTime allTime
, endTime
;
2788 AbsoluteTime startIOTime
, endIOTime
;
2789 uint64_t nsec
, nsecIO
;
2791 uint32_t lastProgressStamp
= 0;
2792 uint32_t progressStamp
;
2793 hibernate_cryptvars_t
* cryptvars
= 0;
2795 IOHibernateVars
* vars
= &gIOHibernateVars
;
2796 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
2798 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2801 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2802 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2804 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2806 HIBLOG("regular wake\n");
2810 HIBPRINT("diag %x %x %x %x\n",
2811 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2812 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2814 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
2815 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2816 tStat(booterStart
, booterStart
);
2817 gIOHibernateStats
->smcStart
= gIOHibernateCurrentHeader
->smcStart
,
2818 tStat(booterDuration0
, booterTime0
);
2819 tStat(booterDuration1
, booterTime1
);
2820 tStat(booterDuration2
, booterTime2
);
2821 tStat(booterDuration
, booterTime
);
2822 tStat(booterConnectDisplayDuration
, connectDisplayTime
);
2823 tStat(booterSplashDuration
, splashTime
);
2824 tStat(trampolineDuration
, trampolineTime
);
2826 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
2827 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
2828 gIOHibernateStats
->image1Pages
= pagesDone
;
2830 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2831 gIOHibernateStats
->booterStart
,
2832 gIOHibernateStats
->smcStart
,
2833 gIOHibernateStats
->booterDuration0
,
2834 gIOHibernateStats
->booterDuration1
,
2835 gIOHibernateStats
->booterDuration2
,
2836 gIOHibernateStats
->booterDuration
,
2837 gIOHibernateStats
->booterConnectDisplayDuration
,
2838 gIOHibernateStats
->booterSplashDuration
,
2839 gIOHibernateStats
->trampolineDuration
);
2841 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2842 gIOHibernateState
, pagesDone
, sum
, gIOHibernateStats
->imageSize
, gIOHibernateStats
->image1Size
,
2843 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2845 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
2846 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)))
2848 hibernate_page_list_discard(vars
->page_list
);
2851 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2853 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
2854 panic("handoff overflow");
2856 IOHibernateHandoff
* handoff
;
2858 bool foundCryptData
= false;
2860 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2862 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2864 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2865 uint8_t * data
= &handoff
->data
[0];
2866 switch (handoff
->type
)
2868 case kIOHibernateHandoffTypeEnd
:
2872 case kIOHibernateHandoffTypeGraphicsInfo
:
2873 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2876 case kIOHibernateHandoffTypeCryptVars
:
2879 hibernate_cryptwakevars_t
*
2880 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
2881 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
2883 foundCryptData
= true;
2884 bzero(data
, handoff
->bytecount
);
2887 case kIOHibernateHandoffTypeMemoryMap
:
2889 clock_get_uptime(&allTime
);
2891 hibernate_newruntime_map(data
, handoff
->bytecount
,
2892 gIOHibernateCurrentHeader
->systemTableOffset
);
2894 clock_get_uptime(&endTime
);
2896 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2897 absolutetime_to_nanoseconds(endTime
, &nsec
);
2899 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
2903 case kIOHibernateHandoffTypeDeviceTree
:
2905 // DTEntry chosen = NULL;
2906 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2911 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2915 if (cryptvars
&& !foundCryptData
)
2916 panic("hibernate handoff");
2918 HIBPRINT("video %x %d %d %d status %x\n",
2919 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2920 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2922 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
2924 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2925 * gIOHibernateGraphicsInfo
->rowBytes
);
2926 IOMapPages(kernel_map
,
2927 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2928 vars
->videoMapSize
, kIOMapInhibitCache
);
2931 if (vars
->videoMapSize
)
2932 ProgressUpdate(gIOHibernateGraphicsInfo
,
2933 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2935 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2936 uint8_t * compressed
= src
+ page_size
;
2937 uint8_t * scratch
= compressed
+ page_size
;
2938 uint32_t decoOffset
;
2940 clock_get_uptime(&allTime
);
2941 AbsoluteTime_to_scalar(&compTime
) = 0;
2944 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2945 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
2946 clock_get_uptime(&startIOTime
);
2947 endTime
= startIOTime
;
2948 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2949 absolutetime_to_nanoseconds(endTime
, &nsec
);
2950 HIBLOG("IOHibernatePollerOpen(%x) %qd ms\n", err
, nsec
/ 1000000ULL);
2952 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2954 // kick off the read ahead
2955 vars
->fileVars
->io
= false;
2956 vars
->fileVars
->bufferHalf
= 0;
2957 vars
->fileVars
->bufferLimit
= 0;
2958 vars
->fileVars
->lastRead
= 0;
2959 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
2960 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2961 vars
->fileVars
->cryptBytes
= 0;
2962 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
2964 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2965 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2968 HIBLOG("hibernate_machine_init reading\n");
2970 uint32_t * header
= (uint32_t *) src
;
2973 while (kIOReturnSuccess
== err
)
2978 vm_offset_t ppnum
, compressedSize
;
2980 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2981 if (kIOReturnSuccess
!= err
)
2987 // HIBPRINT("(%x, %x)\n", ppnum, count);
2992 for (page
= 0; page
< count
; page
++)
2994 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2995 if (kIOReturnSuccess
!= err
)
2998 compressedSize
= kIOHibernateTagLength
& tag
;
2999 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
3001 err
= kIOReturnIPCError
;
3005 if (!compressedSize
) bzero_phys(ptoa_64(ppnum
), page_size
);
3008 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
3009 if (kIOReturnSuccess
!= err
) break;
3010 if (compressedSize
< page_size
)
3012 decoOffset
= page_size
;
3013 clock_get_uptime(&startTime
);
3014 WKdm_decompress_new((WK_word
*) src
, (WK_word
*) compressed
, (WK_word
*) scratch
, page_size
);
3015 clock_get_uptime(&endTime
);
3016 ADD_ABSOLUTETIME(&compTime
, &endTime
);
3017 SUB_ABSOLUTETIME(&compTime
, &startTime
);
3018 compBytes
+= page_size
;
3020 else decoOffset
= 0;
3022 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
3023 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
3026 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
3035 if (0 == (8191 & pagesDone
))
3037 clock_get_uptime(&endTime
);
3038 SUB_ABSOLUTETIME(&endTime
, &allTime
);
3039 absolutetime_to_nanoseconds(endTime
, &nsec
);
3040 progressStamp
= nsec
/ 750000000ULL;
3041 if (progressStamp
!= lastProgressStamp
)
3043 lastProgressStamp
= progressStamp
;
3044 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
3045 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
3050 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
3051 err
= kIOReturnLockedRead
;
3053 if (kIOReturnSuccess
!= err
)
3054 panic("Hibernate restore error %x", err
);
3056 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
3057 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
3059 if (vars
->fileVars
->io
)
3060 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
3062 clock_get_uptime(&endIOTime
);
3064 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
3066 clock_get_uptime(&endTime
);
3068 IOService::getPMRootDomain()->pmStatsRecordEvent(
3069 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
3070 IOService::getPMRootDomain()->pmStatsRecordEvent(
3071 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
3073 SUB_ABSOLUTETIME(&endTime
, &allTime
);
3074 absolutetime_to_nanoseconds(endTime
, &nsec
);
3076 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
3077 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
3079 gIOHibernateStats
->kernelImageReadDuration
= nsec
/ 1000000ULL;
3080 gIOHibernateStats
->imagePages
= pagesDone
;
3082 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
3083 pagesDone
, sum
, gIOHibernateStats
->kernelImageReadDuration
, kDefaultIOSize
,
3084 nsecIO
? ((((gIOHibernateCurrentHeader
->imageSize
- gIOHibernateCurrentHeader
->image1Size
) * 1000000000ULL) / 1024 / 1024) / nsecIO
) : 0);
3086 absolutetime_to_nanoseconds(compTime
, &nsec
);
3087 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
3090 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
3092 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
3093 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
3094 vars
->fileVars
->cryptBytes
,
3096 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
3098 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 2) | DBG_FUNC_NONE
, pagesRead
, pagesDone
, 0, 0, 0);
3101 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3103 void IOHibernateSetWakeCapabilities(uint32_t capability
)
3105 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
3107 gIOHibernateStats
->wakeCapability
= capability
;
3111 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3113 void IOHibernateSystemRestart(void)
3115 static uint8_t noteStore
[32] __attribute__((aligned(32)));
3116 IORegistryEntry
* regEntry
;
3117 const OSSymbol
* sym
;
3120 uintptr_t * smcVars
;
3125 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
3128 smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
3129 smcBytes
= (typeof(smcBytes
)) smcVars
[1];
3131 if (len
> sizeof(noteStore
)) len
= sizeof(noteStore
);
3132 noteProp
= OSData::withCapacity(3 * sizeof(element
));
3133 if (!noteProp
) return;
3135 noteProp
->appendBytes(&element
, sizeof(element
));
3136 element
= crc32(0, smcBytes
, len
);
3137 noteProp
->appendBytes(&element
, sizeof(element
));
3139 bcopy(smcBytes
, noteStore
, len
);
3140 element
= (addr64_t
) ¬eStore
[0];
3141 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
3142 noteProp
->appendBytes(&element
, sizeof(element
));
3144 if (!gIOOptionsEntry
)
3146 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
3147 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
3148 if (regEntry
&& !gIOOptionsEntry
)
3149 regEntry
->release();
3152 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
3153 if (gIOOptionsEntry
&& sym
) gIOOptionsEntry
->setProperty(sym
, noteProp
);
3154 if (noteProp
) noteProp
->release();
3155 if (sym
) sym
->release();