2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
36 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
37 (devices awake, normal execution context)
38 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
39 grabs its extents and searches for a polling driver willing to work with that IOMedia.
40 The BSD code makes an ioctl to the storage driver to get the partition base offset to
41 the disk, and other ioctls to get the transfer constraints
42 If successful, the file is written to make sure its initially not bootable (in case of
43 later failure) and nvram set to point to the first block of the file. (Has to be done
44 here so blocking is possible in nvram support).
45 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
46 page out any pages it wants to (currently zero, but probably some percentage of memory).
47 Its assumed just allocating pages will cause the VM system to naturally select the best
48 pages for eviction. It also copies processor flags needed for the restore path and sets
49 a flag in the boot processor proc info.
50 gIOHibernateState = kIOHibernateStateHibernating.
51 - Regular sleep progresses - some drivers may inspect the root domain property
52 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
53 as usual but leaves motherboard I/O on.
54 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
55 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
56 all ppc RC bits out of the hash table and caches into the mapping structures.
57 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
58 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
59 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
60 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
61 The image header and block list are written. The header includes the second file extent so
62 only the header block is needed to read the file, regardless of filesystem.
63 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
64 (only) is used to decompress the image during wake/boot.
65 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
66 The bitmaps are written to the image.
67 More areas are removed from the bitmaps (after they have been written to the image) - the
68 section "__HIB" pages and interrupt stack.
69 Each wired page is compressed and written and then each non-wired page. Compression and
70 disk writes are in parallel.
71 The image header is written to the start of the file and the polling driver closed.
72 The machine powers down (or sleeps).
76 - BootX sees the boot-image nvram variable containing the device and block number of the image,
77 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
78 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
79 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
80 that is in the kernel's __HIB section.
81 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
82 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
83 only code & data in that section is safe to call since all the other wired pages are still
84 compressed in the image.
85 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
86 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
87 location directly, and copies those that can't to interim free pages. When the image has been
88 completed, the copies are uncompressed, overwriting the wired image pages.
89 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
90 is used to get pages into place for 64bit.
91 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
92 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
93 are removed from the software strutures, and the hash table is reinitialized.
94 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
95 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
96 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
97 for the remaining non wired pages.
98 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
99 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
104 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
105 registry, specifying an object of calls IOPolledInterface.
107 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
108 partition) that the image is going to live, looking for polled interface properties. If it finds
109 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
110 interfaces found are kept in an ordered list.
112 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
113 few different contexts things happen in:
115 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
116 up and running) and after wake - this is safe to allocate memory and do anything. The device
117 ignores sleep requests from that point since its a waste of time if it goes to sleep and
118 immediately wakes back up for the image write.
120 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
121 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
122 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
123 used to flush and set the disk to sleep.
125 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
126 immediately after sleep. These can't block or allocate memory. This is happening after the platform
127 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
130 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
131 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
132 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
133 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
134 that is called for the hardware to check for events, and complete the I/O via the callback.
135 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
139 #include <sys/systm.h>
141 #include <IOKit/IOWorkLoop.h>
142 #include <IOKit/IOCommandGate.h>
143 #include <IOKit/IOTimerEventSource.h>
144 #include <IOKit/IOPlatformExpert.h>
145 #include <IOKit/IOKitDebug.h>
146 #include <IOKit/IOTimeStamp.h>
147 #include <IOKit/pwr_mgt/RootDomain.h>
148 #include <IOKit/pwr_mgt/IOPMPrivate.h>
149 #include <IOKit/IOMessage.h>
150 #include <IOKit/IODeviceTreeSupport.h>
151 #include <IOKit/IOBSD.h>
152 #include "RootDomainUserClient.h"
153 #include <IOKit/pwr_mgt/IOPowerConnection.h>
154 #include "IOPMPowerStateQueue.h"
155 #include <IOKit/IOBufferMemoryDescriptor.h>
156 #include <crypto/aes.h>
159 #include <sys/conf.h>
160 #include <sys/stat.h>
161 #include <sys/fcntl.h> // (FWRITE, ...)
162 #include <sys/sysctl.h>
164 #include <IOKit/IOHibernatePrivate.h>
165 #include <IOKit/IOPolledInterface.h>
166 #include <IOKit/IONVRAM.h>
167 #include "IOHibernateInternal.h"
169 #include "IOKitKernelInternal.h"
171 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
173 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
175 OSMetaClassDefineReservedUnused(IOPolledInterface
, 0);
176 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
177 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
178 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
179 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
180 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
181 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
182 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
183 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
184 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
185 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
186 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
187 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
188 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
189 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
190 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
192 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
194 extern uint32_t gIOHibernateState
;
195 uint32_t gIOHibernateMode
;
196 static char gIOHibernateBootSignature
[256+1];
197 static char gIOHibernateFilename
[MAXPATHLEN
+1];
198 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
199 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
201 static IODTNVRAM
* gIOOptionsEntry
;
202 static IORegistryEntry
* gIOChosenEntry
;
204 static IOPolledFileIOVars gFileVars
;
205 static IOHibernateVars gIOHibernateVars
;
206 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
207 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
209 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211 enum { kXPRamAudioVolume
= 8 };
212 enum { kDefaultIOSize
= 128 * 1024 };
213 enum { kVideoMapSize
= 32 * 1024 * 1024 };
215 #ifndef kIOMediaPreferredBlockSizeKey
216 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
219 #ifndef kIOBootPathKey
220 #define kIOBootPathKey "bootpath"
222 #ifndef kIOSelectedBootDeviceKey
223 #define kIOSelectedBootDeviceKey "boot-device"
227 enum { kIOHibernateMinPollersNeeded
= 2 };
229 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
231 // copy from phys addr to MD
234 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
235 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
237 addr64_t srcAddr
= bytes
;
238 IOByteCount remaining
;
240 remaining
= length
= min(length
, md
->getLength() - offset
);
241 while (remaining
) { // (process another target segment?)
245 dstAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
249 // Clip segment length to remaining
250 if (dstLen
> remaining
)
254 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
256 copypv(srcAddr
, dstAddr64
, dstLen
,
257 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
266 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
269 // copy from MD to phys addr
272 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
273 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
275 addr64_t dstAddr
= bytes
;
276 IOByteCount remaining
;
278 remaining
= length
= min(length
, md
->getLength() - offset
);
279 while (remaining
) { // (process another target segment?)
283 srcAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
287 // Clip segment length to remaining
288 if (dstLen
> remaining
)
292 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
294 copypv(srcAddr
, dstAddr64
, dstLen
,
295 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
304 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
307 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
310 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
311 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
316 case kIOHibernatePageStateUnwiredSave
:
318 for (; ppnum
< count
; ppnum
++)
320 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
321 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
324 case kIOHibernatePageStateWiredSave
:
326 for (; ppnum
< count
; ppnum
++)
328 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
329 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
332 case kIOHibernatePageStateFree
:
334 for (; ppnum
< count
; ppnum
++)
336 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
337 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
341 panic("hibernate_set_page_state");
346 hibernate_page_list_iterate(hibernate_page_list_t
* list
,
347 void ** iterator
, vm_offset_t
* ppnum
)
351 idx
= (uint32_t) *iterator
;
354 idx
= hibernate_page_list_count(list
, TRUE
, idx
);
357 count
= hibernate_page_list_count(list
, FALSE
, idx
);
359 idx
+= hibernate_page_list_count(list
, TRUE
, idx
);
360 *iterator
= (void *) idx
;
365 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
368 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
370 IOReturn err
= kIOReturnError
;
372 IOPolledInterface
* poller
;
374 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
376 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
377 err
= poller
->probe(target
);
380 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
389 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
391 IOReturn err
= kIOReturnError
;
393 IOPolledInterface
* poller
;
395 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
397 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
398 err
= poller
->open(state
, md
);
401 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
410 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
412 IOReturn err
= kIOReturnError
;
414 IOPolledInterface
* poller
;
417 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
420 err
= poller
->close(state
);
422 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
429 IOHibernatePollerIOComplete(void * target
,
432 UInt64 actualByteCount
)
434 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
436 vars
->ioStatus
= status
;
440 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
441 uint32_t operation
, uint32_t bufferOffset
,
442 uint64_t deviceOffset
, uint64_t length
)
445 IOReturn err
= kIOReturnError
;
446 IOPolledInterface
* poller
;
447 IOPolledCompletion completion
;
449 completion
.target
= 0;
450 completion
.action
= &IOHibernatePollerIOComplete
;
451 completion
.parameter
= vars
;
455 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
456 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
458 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
464 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
)
466 IOReturn err
= kIOReturnError
;
468 IOPolledInterface
* poller
;
470 while (-1 == vars
->ioStatus
)
473 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
476 err
= poller
->checkForWork();
478 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
482 if (kIOReturnSuccess
!= vars
->ioStatus
)
483 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars
->ioStatus
);
485 return (vars
->ioStatus
);
489 IOPolledInterface::checkAllForWork(void)
491 IOReturn err
= kIOReturnNotReady
;
493 IOPolledInterface
* poller
;
495 IOHibernateVars
* vars
= &gIOHibernateVars
;
497 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
501 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
504 err
= poller
->checkForWork();
506 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
512 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
514 struct _OpenFileContext
521 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
523 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
524 IOPolledFileExtent extent
;
526 extent
.start
= start
;
527 extent
.length
= length
;
529 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
534 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
535 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
538 IOReturn err
= kIOReturnError
;
539 IOPolledFileIOVars
* vars
;
540 _OpenFileContext ctx
;
541 OSData
* extentsData
;
543 IORegistryEntry
* part
= 0;
544 OSDictionary
* matching
;
546 dev_t hibernate_image_dev
;
552 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
553 if (sizeof(IOHibernateImageHeader
) != 512)
557 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
558 vars
->bufferHalf
= 0;
559 vars
->bufferOffset
= 0;
560 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
562 extentsData
= OSData::withCapacity(32);
564 ctx
.extents
= extentsData
;
566 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
567 &file_extent_callback
, &ctx
,
568 &hibernate_image_dev
,
573 err
= kIOReturnNoSpace
;
576 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
577 vars
->block0
, maxiobytes
);
578 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
580 err
= kIOReturnNoSpace
;
584 if (maxiobytes
< vars
->bufferSize
)
585 vars
->bufferSize
= maxiobytes
;
587 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
589 matching
= IOService::serviceMatching("IOMedia");
590 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
591 matching
->setObject(kIOBSDMajorKey
, num
);
593 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
594 matching
->setObject(kIOBSDMinorKey
, num
);
596 iter
= IOService::getMatchingServices(matching
);
600 part
= (IORegistryEntry
*) iter
->getNextObject();
606 IORegistryEntry
* next
;
607 IORegistryEntry
* child
;
610 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
613 major
= num
->unsigned32BitValue();
614 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
617 minor
= num
->unsigned32BitValue();
619 hibernate_image_dev
= makedev(major
, minor
);
621 vars
->pollers
= OSArray::withCapacity(4);
625 vars
->blockSize
= 512;
629 IOPolledInterface
* poller
;
632 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
633 if (kOSBooleanFalse
== obj
)
635 vars
->pollers
->flushCollection();
638 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
639 vars
->pollers
->setObject(poller
);
640 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
641 vars
->blockSize
= num
->unsigned32BitValue();
644 while ((next
= child
->getParentEntry(gIOServicePlane
))
645 && child
->isParent(next
, gIOServicePlane
, true));
647 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
648 major
, minor
, vars
->blockSize
, vars
->pollers
->getCount());
649 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
652 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
653 if (kIOReturnSuccess
!= err
)
656 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
657 if (kIOReturnSuccess
!= err
)
661 *fileExtents
= extentsData
;
666 int len
= sizeof(str1
);
668 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
))
669 && part
->getPath(str1
, &len
, gIODTPlane
))
671 // (strip the plane name)
672 char * tail
= strchr(str1
, ':');
675 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
676 sprintf(str2
, ",%qx", vars
->extentMap
[0]);
677 data
->appendBytes(str2
, strlen(str2
));
683 if (kIOReturnSuccess
!= err
)
685 HIBLOG("error 0x%x opening hibernation file\n", err
);
687 kern_close_file_for_direct_io(vars
->fileRef
);
697 IOPolledFileClose( IOPolledFileIOVars
* vars
)
701 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
702 vars
->pollers
->release();
705 gIOHibernateFileRef
= vars
->fileRef
;
707 bzero(vars
, sizeof(IOPolledFileIOVars
));
709 return (kIOReturnSuccess
);
713 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
715 IOPolledFileExtent
* extentMap
;
717 extentMap
= vars
->extentMap
;
719 vars
->position
= position
;
721 while (position
>= extentMap
->length
)
723 position
-= extentMap
->length
;
727 vars
->currentExtent
= extentMap
;
728 vars
->extentRemaining
= extentMap
->length
- position
;
729 vars
->extentPosition
= vars
->position
- position
;
731 if (vars
->bufferSize
<= vars
->extentRemaining
)
732 vars
->bufferLimit
= vars
->bufferSize
;
734 vars
->bufferLimit
= vars
->extentRemaining
;
736 return (kIOReturnSuccess
);
740 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
741 const uint8_t * bytes
, IOByteCount size
,
742 hibernate_cryptvars_t
* cryptvars
)
744 IOReturn err
= kIOReturnSuccess
;
752 // seek to end of block & flush
753 size
= vars
->position
& (vars
->blockSize
- 1);
755 size
= vars
->blockSize
- size
;
757 // use some garbage for the fill
758 bytes
= vars
->buffer
+ vars
->bufferOffset
;
761 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
769 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
773 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
776 vars
->bufferOffset
+= copy
;
777 vars
->position
+= copy
;
779 if (flush
&& vars
->bufferOffset
)
781 uint64_t offset
= (vars
->position
- vars
->bufferOffset
782 - vars
->extentPosition
+ vars
->currentExtent
->start
);
783 uint32_t length
= (vars
->bufferOffset
);
785 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
787 uint32_t encryptLen
, encryptStart
;
788 encryptLen
= vars
->position
- vars
->encryptStart
;
789 if (encryptLen
> length
)
791 encryptStart
= length
- encryptLen
;
793 // encrypt the buffer
794 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
795 &cryptvars
->aes_iv
[0],
796 encryptLen
/ AES_BLOCK_SIZE
,
797 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
798 &cryptvars
->ctx
.encrypt
);
799 // save initial vector for following encrypts
800 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
801 &cryptvars
->aes_iv
[0],
807 err
= IOHibernatePollerIODone(vars
);
808 if (kIOReturnSuccess
!= err
)
812 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
813 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
815 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
816 if (kIOReturnSuccess
!= err
)
820 vars
->extentRemaining
-= vars
->bufferOffset
;
821 if (!vars
->extentRemaining
)
823 vars
->currentExtent
++;
824 vars
->extentRemaining
= vars
->currentExtent
->length
;
825 vars
->extentPosition
= vars
->position
;
826 if (!vars
->extentRemaining
)
828 err
= kIOReturnOverrun
;
833 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
834 vars
->bufferOffset
= 0;
835 if (vars
->bufferSize
<= vars
->extentRemaining
)
836 vars
->bufferLimit
= vars
->bufferSize
;
838 vars
->bufferLimit
= vars
->extentRemaining
;
849 IOPolledFileRead(IOPolledFileIOVars
* vars
,
850 uint8_t * bytes
, IOByteCount size
,
851 hibernate_cryptvars_t
* cryptvars
)
853 IOReturn err
= kIOReturnSuccess
;
856 // bytesWritten += size;
860 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
866 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
870 vars
->bufferOffset
+= copy
;
871 // vars->position += copy;
873 if (vars
->bufferOffset
== vars
->bufferLimit
)
877 err
= IOHibernatePollerIODone(vars
);
878 if (kIOReturnSuccess
!= err
)
884 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
886 vars
->position
+= vars
->lastRead
;
887 vars
->extentRemaining
-= vars
->lastRead
;
888 vars
->bufferLimit
= vars
->lastRead
;
890 if (!vars
->extentRemaining
)
892 vars
->currentExtent
++;
893 vars
->extentRemaining
= vars
->currentExtent
->length
;
894 vars
->extentPosition
= vars
->position
;
895 if (!vars
->extentRemaining
)
897 err
= kIOReturnOverrun
;
902 if (vars
->extentRemaining
<= vars
->bufferSize
)
903 vars
->lastRead
= vars
->extentRemaining
;
905 vars
->lastRead
= vars
->bufferSize
;
907 uint64_t offset
= (vars
->position
908 - vars
->extentPosition
+ vars
->currentExtent
->start
);
909 uint64_t length
= (vars
->lastRead
);
911 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
913 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
914 if (kIOReturnSuccess
!= err
)
918 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
919 vars
->bufferOffset
= 0;
923 uint8_t thisVector
[AES_BLOCK_SIZE
];
924 // save initial vector for following decrypts
925 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
926 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->lastRead
- AES_BLOCK_SIZE
,
927 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
928 // decrypt the buffer
929 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
931 vars
->lastRead
/ AES_BLOCK_SIZE
,
932 vars
->buffer
+ vars
->bufferHalf
,
933 &cryptvars
->ctx
.decrypt
);
942 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
945 IOHibernateSystemSleep(void)
953 IOHibernateVars
* vars
= &gIOHibernateVars
;
955 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
956 // already on the way down
957 return (kIOReturnSuccess
);
959 gIOHibernateState
= kIOHibernateStateInactive
;
961 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
)))
963 if ((num
= OSDynamicCast(OSNumber
, obj
)))
964 gIOHibernateMode
= num
->unsigned32BitValue();
965 if (kIOHibernateModeSleep
& gIOHibernateMode
)
966 // default to discard clean for safe sleep
967 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
968 | kIOHibernateModeDiscardCleanActive
);
972 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
)))
974 if ((num
= OSDynamicCast(OSNumber
, obj
)))
975 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
978 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
980 if ((num
= OSDynamicCast(OSNumber
, obj
)))
981 gIOHibernateFreeTime
= num
->unsigned32BitValue();
984 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
986 if ((str
= OSDynamicCast(OSString
, obj
)))
987 strcpy(gIOHibernateFilename
, str
->getCStringNoCopy());
991 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
992 return (kIOReturnUnsupported
);
994 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
998 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(0, 4 * page_size
, page_size
);
999 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize
, page_size
);
1001 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
1003 err
= kIOReturnNoMemory
;
1007 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1008 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1009 if (KERN_SUCCESS
!= err
)
1011 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1014 if (vars
->fileVars
->fileRef
)
1016 // invalidate the image file
1017 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1018 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1019 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1020 if (KERN_SUCCESS
!= err
)
1021 HIBLOG("kern_write_file(%d)\n", err
);
1024 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1026 boolean_t encryptedswap
;
1027 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1028 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1029 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1030 if (KERN_SUCCESS
!= err
)
1032 HIBLOG("hibernate_setup(%d)\n", err
);
1037 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1039 vars
->videoAllocSize
= kVideoMapSize
;
1040 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1041 vars
->videoMapping
= 0;
1043 // generate crypt keys
1044 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1045 vars
->wiredCryptKey
[i
] = random();
1046 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1047 vars
->cryptKey
[i
] = random();
1051 IORegistryEntry
* regEntry
;
1052 if (!gIOOptionsEntry
)
1054 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1055 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1056 if (regEntry
&& !gIOOptionsEntry
)
1057 regEntry
->release();
1059 if (!gIOChosenEntry
)
1060 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1062 if (gIOOptionsEntry
)
1064 const OSSymbol
* sym
;
1066 char valueString
[16];
1068 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1071 gIOOptionsEntry
->setProperty(sym
, data
);
1076 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1079 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1082 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1083 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1085 gIOOptionsEntry
->setProperty(sym
, str2
);
1092 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1095 vars
->haveFastBoot
= true;
1097 len
= sprintf(valueString
, "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1098 data
= OSData::withBytes(valueString
, len
+ 1);
1099 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1101 gIOOptionsEntry
->setProperty(sym
, data
);
1107 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1109 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1112 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1114 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1115 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1117 gIOOptionsEntry
->setProperty(sym
, data
);
1122 if (gIOHibernateBootSignature
[0])
1124 data
= OSData::withCapacity(16);
1125 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1130 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1140 value
= (value
<< 4) | c
;
1142 data
->appendBytes(&value
, sizeof(value
));
1144 gIOOptionsEntry
->setProperty(sym
, data
);
1153 if (!vars
->haveFastBoot
)
1155 // set boot volume to zero
1156 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1157 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1158 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1161 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1162 platform
->writeXPRAM(kXPRamAudioVolume
,
1163 &newVolume
, sizeof(newVolume
));
1169 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1170 gIOHibernateState
= kIOHibernateStateHibernating
;
1177 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1180 IOHibernateSystemHasSlept(void)
1182 IOHibernateVars
* vars
= &gIOHibernateVars
;
1184 if ((vars
->previewData
= OSDynamicCast(OSData
,
1185 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey
))))
1187 vars
->previewBuffer
= IOMemoryDescriptor::withAddress(
1188 (void *) vars
->previewData
->getBytesNoCopy(),
1189 vars
->previewData
->getLength(),
1192 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1194 vars
->previewBuffer
->release();
1195 vars
->previewBuffer
= 0;
1197 if (!vars
->previewBuffer
)
1198 vars
->previewData
= 0;
1200 if (gIOOptionsEntry
)
1201 gIOOptionsEntry
->sync();
1203 return (kIOReturnSuccess
);
1206 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1209 IOHibernateSystemWake(void)
1211 IOHibernateVars
* vars
= &gIOHibernateVars
;
1213 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1215 if (vars
->videoMapping
)
1217 if (vars
->videoMapSize
)
1219 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1220 if (vars
->videoAllocSize
)
1222 kmem_free(kernel_map
, trunc_page_32(vars
->videoMapping
), vars
->videoAllocSize
);
1225 if (vars
->previewBuffer
)
1227 vars
->previewBuffer
->release();
1228 vars
->previewBuffer
= 0;
1233 IOPolledFileClose(vars
->fileVars
);
1236 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1238 OSData
* data
= OSData::withCapacity(4);
1239 if (gIOOptionsEntry
&& data
)
1241 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1244 gIOOptionsEntry
->setProperty(sym
, data
);
1247 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1250 if (vars
->saveBootDevice
)
1252 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1253 vars
->saveBootDevice
->release();
1257 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1260 gIOOptionsEntry
->setProperty(sym
, data
);
1263 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1266 gIOOptionsEntry
->removeProperty(sym
);
1273 if (gIOOptionsEntry
)
1275 if (!vars
->haveFastBoot
)
1277 // reset boot audio volume
1278 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1280 platform
->writeXPRAM(kXPRamAudioVolume
,
1281 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1284 // sync now to hardware if the booter has not
1285 if (kIOHibernateStateInactive
== gIOHibernateState
)
1286 gIOOptionsEntry
->sync();
1288 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1289 gIOOptionsEntry
->syncOFVariables();
1292 if (vars
->srcBuffer
)
1293 vars
->srcBuffer
->release();
1295 vars
->ioBuffer
->release();
1296 if (vars
->fileExtents
)
1297 vars
->fileExtents
->release();
1299 bzero(vars
, sizeof(*vars
));
1301 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1303 return (kIOReturnSuccess
);
1307 IOHibernateSystemPostWake(void)
1309 if (gIOHibernateFileRef
)
1311 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1312 gIOHibernateFileRef
= 0;
1314 return (kIOReturnSuccess
);
1317 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1320 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1322 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1325 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1329 if (PE_parse_boot_arg("hfile", gIOHibernateFilename
))
1330 gIOHibernateMode
= kIOHibernateModeOn
;
1332 gIOHibernateFilename
[0] = 0;
1334 static SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1335 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1336 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1337 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1339 static SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1340 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1341 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1342 sysctl_register_oid(&sysctl__kern_bootsignature
);
1344 static SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1345 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1346 &gIOHibernateMode
, 0, "");
1347 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1350 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1353 hibernate_setup_for_wake(void)
1356 // go slow (state needed for wake)
1357 ml_set_processor_speed(1);
1361 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1363 extern "C" boolean_t
1364 hibernate_write_image(void)
1366 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1367 IOHibernateVars
* vars
= &gIOHibernateVars
;
1368 IOPolledFileExtent
* fileExtents
;
1370 uint32_t pageCount
, pagesDone
;
1373 IOItemCount page
, count
;
1376 IOByteCount pageCompressedSize
;
1377 uint64_t compressedSize
, uncompressedSize
;
1378 uint64_t image1Size
= 0;
1379 uint32_t bitmap_size
;
1380 bool iterDone
, pollerOpen
, needEncryptStart
;
1381 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1384 uint32_t pageAndCount
[2];
1386 AbsoluteTime startTime
, endTime
;
1387 AbsoluteTime allTime
, compTime
, decoTime
;
1389 uint32_t lastProgressStamp
= 0;
1390 uint32_t progressStamp
;
1392 hibernate_cryptvars_t _cryptvars
;
1393 hibernate_cryptvars_t
* cryptvars
= 0;
1395 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1396 return (false /* sleep */ );
1398 restore1Sum
= sum1
= sum2
= 0;
1400 // encryption data. "iv" is the "initial vector".
1401 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1403 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1404 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1405 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1407 cryptvars
= &gIOHibernateCryptWakeContext
;
1408 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1409 aes_encrypt_key(vars
->cryptKey
,
1410 kIOHibernateAESKeySize
,
1411 &cryptvars
->ctx
.encrypt
);
1412 aes_decrypt_key(vars
->cryptKey
,
1413 kIOHibernateAESKeySize
,
1414 &cryptvars
->ctx
.decrypt
);
1416 cryptvars
= &_cryptvars
;
1417 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1418 aes_encrypt_key(vars
->wiredCryptKey
,
1419 kIOHibernateAESKeySize
,
1420 &cryptvars
->ctx
.encrypt
);
1422 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1423 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1424 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1425 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1428 hibernate_setup_for_wake();
1430 hibernate_page_list_setall(vars
->page_list
,
1431 vars
->page_list_wired
,
1434 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1436 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1439 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1440 for (page
= 0; page
< count
; page
++)
1442 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1443 fileExtents
[page
].start
, fileExtents
[page
].length
,
1444 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1448 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1450 AbsoluteTime_to_scalar(&compTime
) = 0;
1451 AbsoluteTime_to_scalar(&decoTime
) = 0;
1453 clock_get_uptime(&allTime
);
1458 uncompressedSize
= 0;
1460 pageType
= 0; // wired pages first
1462 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1464 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1465 ml_get_interrupts_enabled());
1466 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1467 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1468 pollerOpen
= (kIOReturnSuccess
== err
);
1472 // copy file block extent list if larger than header
1474 count
= vars
->fileExtents
->getLength();
1475 if (count
> sizeof(header
->fileExtentMap
))
1477 count
-= sizeof(header
->fileExtentMap
);
1478 err
= IOPolledFileWrite(vars
->fileVars
,
1479 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1480 if (kIOReturnSuccess
!= err
)
1484 // copy out restore1 code
1486 page
= atop_32(sectHIBB
);
1487 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1488 header
->restore1CodePage
= page
;
1489 header
->restore1PageCount
= count
;
1490 header
->restore1CodeOffset
= ((uint32_t) &hibernate_machine_entrypoint
) - sectHIBB
;
1491 header
->restore1StackOffset
= ((uint32_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - sectHIBB
;
1493 // sum __HIB sect, with zeros for the stack
1494 src
= (uint8_t *) trunc_page(sectHIBB
);
1495 for (page
= 0; page
< count
; page
++)
1497 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1498 restore1Sum
+= hibernate_sum(src
, page_size
);
1500 restore1Sum
+= 0x10000001;
1505 // write the __HIB sect, with zeros for the stack
1507 src
= (uint8_t *) trunc_page(sectHIBB
);
1508 count
= ((uint32_t) &gIOHibernateRestoreStack
[0]) - trunc_page(sectHIBB
);
1511 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1512 if (kIOReturnSuccess
!= err
)
1515 err
= IOPolledFileWrite(vars
->fileVars
,
1517 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1519 if (kIOReturnSuccess
!= err
)
1521 src
= &gIOHibernateRestoreStackEnd
[0];
1522 count
= round_page(sectHIBB
+ sectSizeHIB
) - ((uint32_t) src
);
1525 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1526 if (kIOReturnSuccess
!= err
)
1530 // write the preview buffer
1535 if (vars
->previewData
)
1541 phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
);
1542 pageAndCount
[0] = atop_64(phys64
);
1543 pageAndCount
[1] = atop_32(segLen
);
1544 err
= IOPolledFileWrite(vars
->fileVars
,
1545 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1547 if (kIOReturnSuccess
!= err
)
1550 ppnum
+= sizeof(pageAndCount
);
1553 if (kIOReturnSuccess
!= err
)
1556 src
= (uint8_t *) vars
->previewData
->getBytesNoCopy();
1557 count
= vars
->previewData
->getLength();
1559 header
->previewPageListSize
= ppnum
;
1560 header
->previewSize
= count
+ ppnum
;
1562 for (page
= 0; page
< count
; page
+= page_size
)
1563 sum1
+= hibernate_sum(src
+ page
, page_size
);
1565 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1566 if (kIOReturnSuccess
!= err
)
1570 // mark areas for no save
1573 (phys64
= vars
->ioBuffer
->getPhysicalSegment64(count
, &segLen
));
1576 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1577 atop_64(phys64
), atop_32(segLen
),
1578 kIOHibernatePageStateFree
);
1579 pageCount
-= atop_32(segLen
);
1583 (phys64
= vars
->srcBuffer
->getPhysicalSegment64(count
, &segLen
));
1586 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1587 atop_64(phys64
), atop_32(segLen
),
1588 kIOHibernatePageStateFree
);
1589 pageCount
-= atop_32(segLen
);
1592 // copy out bitmap of pages available for trashing during restore
1594 bitmap_size
= vars
->page_list_wired
->list_size
;
1595 src
= (uint8_t *) vars
->page_list_wired
;
1596 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1597 if (kIOReturnSuccess
!= err
)
1600 // mark more areas for no save, but these are not available
1601 // for trashing during restore
1604 page
= atop_32(sectHIBB
);
1605 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1608 page
= atop_32(sectHIBB
& 0x3FFFFFFF);
1609 count
= atop_32(round_page((sectHIBB
+ sectSizeHIB
) & 0x3FFFFFFF)) - page
;
1611 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1613 kIOHibernatePageStateFree
);
1618 if (vars
->previewBuffer
) for (count
= 0;
1619 (phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
));
1622 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1623 atop_64(phys64
), atop_32(segLen
),
1624 kIOHibernatePageStateFree
);
1625 pageCount
-= atop_32(segLen
);
1628 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1633 HIBLOG("writing %d pages\n", pageCount
);
1637 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1639 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1643 pageAndCount
[0] = ppnum
;
1644 pageAndCount
[1] = count
;
1645 err
= IOPolledFileWrite(vars
->fileVars
,
1646 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1648 if (kIOReturnSuccess
!= err
)
1651 for (page
= 0; page
< count
; page
++)
1653 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1656 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__
, ppnum
, err
);
1660 sum
= hibernate_sum(src
, page_size
);
1662 clock_get_uptime(&startTime
);
1664 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1666 clock_get_uptime(&endTime
);
1667 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1668 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1670 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1671 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1673 if (pageCompressedSize
> page_size
)
1675 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1676 pageCompressedSize
= page_size
;
1679 if (pageCompressedSize
!= page_size
)
1680 data
= (src
+ page_size
);
1684 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1691 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
1693 // start encrypting partway into the data about to be written
1694 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
1695 & ~(AES_BLOCK_SIZE
- 1);
1696 needEncryptStart
= false;
1699 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1700 if (kIOReturnSuccess
!= err
)
1703 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1704 if (kIOReturnSuccess
!= err
)
1707 compressedSize
+= pageCompressedSize
;
1708 if (pageCompressedSize
)
1709 uncompressedSize
+= page_size
;
1713 if (0 == (8191 & pagesDone
))
1715 clock_get_uptime(&endTime
);
1716 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1717 absolutetime_to_nanoseconds(endTime
, &nsec
);
1718 progressStamp
= nsec
/ 750000000ULL;
1719 if (progressStamp
!= lastProgressStamp
)
1721 lastProgressStamp
= progressStamp
;
1722 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1726 if (kIOReturnSuccess
!= err
)
1728 if (iterDone
&& !pageType
)
1730 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1731 if (kIOReturnSuccess
!= err
)
1737 image1Size
= vars
->fileVars
->position
;
1740 bcopy(&cryptvars
->aes_iv
[0],
1741 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1742 sizeof(cryptvars
->aes_iv
));
1743 cryptvars
= &gIOHibernateCryptWakeContext
;
1745 HIBLOG("image1Size %qd\n", image1Size
);
1749 if (kIOReturnSuccess
!= err
)
1751 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1752 if (kIOReturnSuccess
!= err
)
1757 header
->imageSize
= vars
->fileVars
->position
;
1758 header
->image1Size
= image1Size
;
1759 header
->bitmapSize
= bitmap_size
;
1760 header
->pageCount
= pageCount
;
1761 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1763 header
->restore1Sum
= restore1Sum
;
1764 header
->image1Sum
= sum1
;
1765 header
->image2Sum
= sum2
;
1767 count
= vars
->fileExtents
->getLength();
1768 if (count
> sizeof(header
->fileExtentMap
))
1770 header
->fileExtentMapSize
= count
;
1771 count
= sizeof(header
->fileExtentMap
);
1774 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1775 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1777 IOPolledFileSeek(vars
->fileVars
, 0);
1778 err
= IOPolledFileWrite(vars
->fileVars
,
1779 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1781 if (kIOReturnSuccess
!= err
)
1783 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1784 if (kIOReturnSuccess
!= err
)
1786 err
= IOHibernatePollerIODone(vars
->fileVars
);
1787 if (kIOReturnSuccess
!= err
)
1792 clock_get_uptime(&endTime
);
1793 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1794 absolutetime_to_nanoseconds(endTime
, &nsec
);
1795 HIBLOG("all time: %qd ms, ",
1798 absolutetime_to_nanoseconds(compTime
, &nsec
);
1799 HIBLOG("comp time: %qd ms, ",
1802 absolutetime_to_nanoseconds(decoTime
, &nsec
);
1803 HIBLOG("deco time: %qd ms, ",
1806 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1808 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
1809 (int) ((compressedSize
* 100ULL) / uncompressedSize
),
1813 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
1815 HIBLOG("hibernate_write_image done(%x)\n", err
);
1817 // should we come back via regular wake, set the state in memory.
1818 gIOHibernateState
= kIOHibernateStateInactive
;
1820 if ((kIOReturnSuccess
== err
) && !(kIOHibernateModeSleep
& gIOHibernateMode
))
1821 return (true /* power down */ );
1823 return (false /* sleep */ );
1826 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1828 DECLARE_IOHIBERNATEPROGRESSALPHA
1831 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1833 uint32_t rowBytes
, pixelShift
;
1835 int32_t blob
, lastBlob
;
1836 uint32_t alpha
, in
, color
, result
;
1838 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1840 pixelShift
= display
->depth
>> 4;
1844 rowBytes
= display
->rowBytes
;
1846 screen
+= ((display
->width
1847 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1848 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1850 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1852 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1854 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1856 out
= screen
+ y
* rowBytes
;
1857 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1859 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1860 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1862 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1868 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1869 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1871 if (1 == pixelShift
)
1874 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1877 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1879 out
+= (1 << pixelShift
);
1881 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1886 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1889 hibernate_machine_init(void)
1894 AbsoluteTime allTime
, endTime
;
1896 uint32_t lastProgressStamp
= 0;
1897 uint32_t progressStamp
;
1898 uint64_t progressZeroPosition
= 0;
1899 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1900 hibernate_cryptvars_t
* cryptvars
= 0;
1902 IOHibernateVars
* vars
= &gIOHibernateVars
;
1904 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1907 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
1908 hibernate_page_list_discard(vars
->page_list
);
1911 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
1912 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
1914 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1915 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
1916 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
1918 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
1920 HIBLOG("regular wake\n");
1924 HIBPRINT("diag %x %x %x %x\n",
1925 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
1926 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
1928 HIBPRINT("video %x %d %d %d\n",
1929 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
1930 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1932 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
1934 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
1935 * gIOHibernateGraphicsInfo
->rowBytes
);
1936 IOMapPages(kernel_map
,
1937 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
1938 vars
->videoMapSize
, kIOMapInhibitCache
);
1941 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();;
1942 uint32_t decoOffset
;
1944 clock_get_uptime(&allTime
);
1946 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
1947 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
1948 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1950 if (gIOHibernateCurrentHeader
->previewSize
)
1951 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
1952 + gIOHibernateCurrentHeader
->fileExtentMapSize
1953 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
1954 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
1956 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
1958 if (vars
->videoMapping
)
1960 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
1961 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
1962 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
1965 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
1966 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1968 cryptvars
= &gIOHibernateCryptWakeContext
;
1969 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
1970 &cryptvars
->aes_iv
[0],
1971 sizeof(cryptvars
->aes_iv
));
1974 // kick off the read ahead
1975 vars
->fileVars
->io
= false;
1976 vars
->fileVars
->bufferHalf
= 0;
1977 vars
->fileVars
->bufferLimit
= 0;
1978 vars
->fileVars
->lastRead
= 0;
1979 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1981 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
1982 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1985 HIBLOG("hibernate_machine_init reading\n");
1987 uint32_t * header
= (uint32_t *) src
;
1995 vm_offset_t ppnum
, compressedSize
;
1997 IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2002 // HIBPRINT("(%x, %x)\n", ppnum, count);
2007 for (page
= 0; page
< count
; page
++)
2009 IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2011 compressedSize
= kIOHibernateTagLength
& tag
;
2012 if (!compressedSize
)
2019 IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2021 if (compressedSize
!= page_size
)
2023 decoOffset
= page_size
;
2024 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2029 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2031 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2033 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum
, err
);
2038 if (vars
->videoMapping
&& (0 == (255 & pagesDone
)))
2040 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2041 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2042 if (blob
!= lastBlob
)
2044 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2049 if (0 == (8191 & pagesDone
))
2051 clock_get_uptime(&endTime
);
2052 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2053 absolutetime_to_nanoseconds(endTime
, &nsec
);
2054 progressStamp
= nsec
/ 750000000ULL;
2055 if (progressStamp
!= lastProgressStamp
)
2057 lastProgressStamp
= progressStamp
;
2058 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2059 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2066 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2068 if (vars
->fileVars
->io
)
2069 (void) IOHibernatePollerIODone(vars
->fileVars
);
2071 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2073 if (vars
->videoMapping
)
2074 ProgressUpdate(gIOHibernateGraphicsInfo
,
2075 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2077 clock_get_uptime(&endTime
);
2078 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2079 absolutetime_to_nanoseconds(endTime
, &nsec
);
2081 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2082 pagesDone
, sum
, nsec
/ 1000000ULL);
2085 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */