2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
29 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
30 (devices awake, normal execution context)
31 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
32 grabs its extents and searches for a polling driver willing to work with that IOMedia.
33 The BSD code makes an ioctl to the storage driver to get the partition base offset to
34 the disk, and other ioctls to get the transfer constraints
35 If successful, the file is written to make sure its initially not bootable (in case of
36 later failure) and nvram set to point to the first block of the file. (Has to be done
37 here so blocking is possible in nvram support).
38 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
39 page out any pages it wants to (currently zero, but probably some percentage of memory).
40 Its assumed just allocating pages will cause the VM system to naturally select the best
41 pages for eviction. It also copies processor flags needed for the restore path and sets
42 a flag in the boot processor proc info.
43 gIOHibernateState = kIOHibernateStateHibernating.
44 - Regular sleep progresses - some drivers may inspect the root domain property
45 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
46 as usual but leaves motherboard I/O on.
47 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
48 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
49 all ppc RC bits out of the hash table and caches into the mapping structures.
50 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
51 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
52 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
53 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
54 The image header and block list are written. The header includes the second file extent so
55 only the header block is needed to read the file, regardless of filesystem.
56 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
57 (only) is used to decompress the image during wake/boot.
58 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
59 The bitmaps are written to the image.
60 More areas are removed from the bitmaps (after they have been written to the image) - the
61 section "__HIB" pages and interrupt stack.
62 Each wired page is compressed and written and then each non-wired page. Compression and
63 disk writes are in parallel.
64 The image header is written to the start of the file and the polling driver closed.
65 The machine powers down (or sleeps).
69 - BootX sees the boot-image nvram variable containing the device and block number of the image,
70 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
71 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
72 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
73 that is in the kernel's __HIB section.
74 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
75 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
76 only code & data in that section is safe to call since all the other wired pages are still
77 compressed in the image.
78 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
79 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
80 location directly, and copies those that can't to interim free pages. When the image has been
81 completed, the copies are uncompressed, overwriting the wired image pages.
82 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
83 is used to get pages into place for 64bit.
84 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
85 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
86 are removed from the software strutures, and the hash table is reinitialized.
87 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
88 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
89 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
90 for the remaining non wired pages.
91 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
92 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
97 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
98 registry, specifying an object of calls IOPolledInterface.
100 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
101 partition) that the image is going to live, looking for polled interface properties. If it finds
102 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
103 interfaces found are kept in an ordered list.
105 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
106 few different contexts things happen in:
108 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
109 up and running) and after wake - this is safe to allocate memory and do anything. The device
110 ignores sleep requests from that point since its a waste of time if it goes to sleep and
111 immediately wakes back up for the image write.
113 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
114 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
115 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
116 used to flush and set the disk to sleep.
118 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
119 immediately after sleep. These can't block or allocate memory. This is happening after the platform
120 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
123 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
124 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
125 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
126 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
127 that is called for the hardware to check for events, and complete the I/O via the callback.
128 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
132 #include <sys/systm.h>
134 #include <IOKit/IOWorkLoop.h>
135 #include <IOKit/IOCommandGate.h>
136 #include <IOKit/IOTimerEventSource.h>
137 #include <IOKit/IOPlatformExpert.h>
138 #include <IOKit/IOKitDebug.h>
139 #include <IOKit/IOTimeStamp.h>
140 #include <IOKit/pwr_mgt/RootDomain.h>
141 #include <IOKit/pwr_mgt/IOPMPrivate.h>
142 #include <IOKit/IOMessage.h>
143 #include <IOKit/IODeviceTreeSupport.h>
144 #include <IOKit/IOBSD.h>
145 #include "RootDomainUserClient.h"
146 #include <IOKit/pwr_mgt/IOPowerConnection.h>
147 #include "IOPMPowerStateQueue.h"
148 #include <IOKit/IOBufferMemoryDescriptor.h>
149 #include <crypto/aes.h>
152 #include <sys/conf.h>
153 #include <sys/stat.h>
154 #include <sys/fcntl.h> // (FWRITE, ...)
156 #include <sys/sysctl.h>
159 #include <IOKit/IOHibernatePrivate.h>
160 #include <IOKit/IOPolledInterface.h>
161 #include <IOKit/IONVRAM.h>
162 #include "IOHibernateInternal.h"
164 #include "IOKitKernelInternal.h"
166 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
168 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
170 OSMetaClassDefineReservedUnused(IOPolledInterface
, 0);
171 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
172 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
173 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
174 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
175 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
176 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
177 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
178 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
179 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
180 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
181 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
182 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
183 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
184 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
185 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
187 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
189 extern uint32_t gIOHibernateState
;
190 uint32_t gIOHibernateMode
;
191 static char gIOHibernateBootSignature
[256+1];
192 static char gIOHibernateFilename
[MAXPATHLEN
+1];
193 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
194 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
196 static IODTNVRAM
* gIOOptionsEntry
;
197 static IORegistryEntry
* gIOChosenEntry
;
199 static IOPolledFileIOVars gFileVars
;
200 static IOHibernateVars gIOHibernateVars
;
201 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
202 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
204 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
206 enum { kXPRamAudioVolume
= 8 };
207 enum { kDefaultIOSize
= 128 * 1024 };
208 enum { kVideoMapSize
= 32 * 1024 * 1024 };
210 #ifndef kIOMediaPreferredBlockSizeKey
211 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
214 #ifndef kIOBootPathKey
215 #define kIOBootPathKey "bootpath"
217 #ifndef kIOSelectedBootDeviceKey
218 #define kIOSelectedBootDeviceKey "boot-device"
222 enum { kIOHibernateMinPollersNeeded
= 2 };
224 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
226 // copy from phys addr to MD
229 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
230 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
232 addr64_t srcAddr
= bytes
;
233 IOByteCount remaining
;
235 remaining
= length
= min(length
, md
->getLength() - offset
);
236 while (remaining
) { // (process another target segment?)
240 dstAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
244 // Clip segment length to remaining
245 if (dstLen
> remaining
)
249 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
251 copypv(srcAddr
, dstAddr64
, dstLen
,
252 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
261 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
264 // copy from MD to phys addr
267 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
268 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
270 addr64_t dstAddr
= bytes
;
271 IOByteCount remaining
;
273 remaining
= length
= min(length
, md
->getLength() - offset
);
274 while (remaining
) { // (process another target segment?)
278 srcAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
282 // Clip segment length to remaining
283 if (dstLen
> remaining
)
287 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
289 copypv(srcAddr
, dstAddr64
, dstLen
,
290 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
299 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
302 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
306 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
311 case kIOHibernatePageStateUnwiredSave
:
313 for (; ppnum
< count
; ppnum
++)
315 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
316 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
319 case kIOHibernatePageStateWiredSave
:
321 for (; ppnum
< count
; ppnum
++)
323 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
324 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
327 case kIOHibernatePageStateFree
:
329 for (; ppnum
< count
; ppnum
++)
331 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
332 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
336 panic("hibernate_set_page_state");
341 hibernate_page_list_iterate(hibernate_page_list_t
* list
,
342 void ** iterator
, vm_offset_t
* ppnum
)
346 idx
= (uint32_t) *iterator
;
349 idx
= hibernate_page_list_count(list
, TRUE
, idx
);
352 count
= hibernate_page_list_count(list
, FALSE
, idx
);
354 idx
+= hibernate_page_list_count(list
, TRUE
, idx
);
355 *iterator
= (void *) idx
;
360 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
363 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
365 IOReturn err
= kIOReturnError
;
367 IOPolledInterface
* poller
;
369 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
371 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
372 err
= poller
->probe(target
);
375 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
384 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
386 IOReturn err
= kIOReturnError
;
388 IOPolledInterface
* poller
;
390 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
392 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
393 err
= poller
->open(state
, md
);
396 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
405 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
407 IOReturn err
= kIOReturnError
;
409 IOPolledInterface
* poller
;
412 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
415 err
= poller
->close(state
);
417 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
424 IOHibernatePollerIOComplete(void * target
,
427 UInt64 actualByteCount
)
429 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
431 vars
->ioStatus
= status
;
435 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
436 uint32_t operation
, uint32_t bufferOffset
,
437 uint64_t deviceOffset
, uint64_t length
)
440 IOReturn err
= kIOReturnError
;
441 IOPolledInterface
* poller
;
442 IOPolledCompletion completion
;
444 completion
.target
= 0;
445 completion
.action
= &IOHibernatePollerIOComplete
;
446 completion
.parameter
= vars
;
450 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
451 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
453 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
459 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
)
461 IOReturn err
= kIOReturnError
;
463 IOPolledInterface
* poller
;
465 while (-1 == vars
->ioStatus
)
468 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
471 err
= poller
->checkForWork();
473 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
477 if (kIOReturnSuccess
!= vars
->ioStatus
)
478 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars
->ioStatus
);
480 return (vars
->ioStatus
);
484 IOPolledInterface::checkAllForWork(void)
486 IOReturn err
= kIOReturnNotReady
;
488 IOPolledInterface
* poller
;
490 IOHibernateVars
* vars
= &gIOHibernateVars
;
492 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
496 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
499 err
= poller
->checkForWork();
501 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
507 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
509 struct _OpenFileContext
516 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
518 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
519 IOPolledFileExtent extent
;
521 extent
.start
= start
;
522 extent
.length
= length
;
524 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
529 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
530 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
533 IOReturn err
= kIOReturnError
;
534 IOPolledFileIOVars
* vars
;
535 _OpenFileContext ctx
;
536 OSData
* extentsData
;
538 IORegistryEntry
* part
= 0;
539 OSDictionary
* matching
;
541 dev_t hibernate_image_dev
;
547 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
548 if (sizeof(IOHibernateImageHeader
) != 512)
552 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
553 vars
->bufferHalf
= 0;
554 vars
->bufferOffset
= 0;
555 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
557 extentsData
= OSData::withCapacity(32);
559 ctx
.extents
= extentsData
;
561 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
562 &file_extent_callback
, &ctx
,
563 &hibernate_image_dev
,
568 err
= kIOReturnNoSpace
;
571 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
572 vars
->block0
, maxiobytes
);
573 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
575 err
= kIOReturnNoSpace
;
579 if (maxiobytes
< vars
->bufferSize
)
580 vars
->bufferSize
= maxiobytes
;
582 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
584 matching
= IOService::serviceMatching("IOMedia");
585 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
586 matching
->setObject(kIOBSDMajorKey
, num
);
588 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
589 matching
->setObject(kIOBSDMinorKey
, num
);
591 iter
= IOService::getMatchingServices(matching
);
595 part
= (IORegistryEntry
*) iter
->getNextObject();
601 IORegistryEntry
* next
;
602 IORegistryEntry
* child
;
605 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
608 major
= num
->unsigned32BitValue();
609 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
612 minor
= num
->unsigned32BitValue();
614 hibernate_image_dev
= makedev(major
, minor
);
616 vars
->pollers
= OSArray::withCapacity(4);
620 vars
->blockSize
= 512;
624 IOPolledInterface
* poller
;
625 if ((poller
= OSDynamicCast(IOPolledInterface
, next
->getProperty(kIOPolledInterfaceSupportKey
))))
626 vars
->pollers
->setObject(poller
);
627 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
628 vars
->blockSize
= num
->unsigned32BitValue();
631 while ((next
= child
->getParentEntry(gIOServicePlane
))
632 && child
->isParent(next
, gIOServicePlane
, true));
634 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
635 major
, minor
, vars
->blockSize
, vars
->pollers
->getCount());
636 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
639 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
640 if (kIOReturnSuccess
!= err
)
643 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
644 if (kIOReturnSuccess
!= err
)
648 *fileExtents
= extentsData
;
653 int len
= sizeof(str1
);
655 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
))
656 && part
->getPath(str1
, &len
, gIODTPlane
))
658 // (strip the plane name)
659 char * tail
= strchr(str1
, ':');
662 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
663 sprintf(str2
, ",%qx", vars
->extentMap
[0]);
664 data
->appendBytes(str2
, strlen(str2
));
670 if (kIOReturnSuccess
!= err
)
672 HIBLOG("error 0x%x opening hibernation file\n", err
);
674 kern_close_file_for_direct_io(vars
->fileRef
);
684 IOPolledFileClose( IOPolledFileIOVars
* vars
)
688 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
689 vars
->pollers
->release();
692 gIOHibernateFileRef
= vars
->fileRef
;
694 bzero(vars
, sizeof(IOPolledFileIOVars
));
696 return (kIOReturnSuccess
);
700 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
702 IOPolledFileExtent
* extentMap
;
704 extentMap
= vars
->extentMap
;
706 vars
->position
= position
;
708 while (position
>= extentMap
->length
)
710 position
-= extentMap
->length
;
714 vars
->currentExtent
= extentMap
;
715 vars
->extentRemaining
= extentMap
->length
- position
;
716 vars
->extentPosition
= vars
->position
- position
;
718 if (vars
->bufferSize
<= vars
->extentRemaining
)
719 vars
->bufferLimit
= vars
->bufferSize
;
721 vars
->bufferLimit
= vars
->extentRemaining
;
723 return (kIOReturnSuccess
);
727 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
728 const uint8_t * bytes
, IOByteCount size
,
729 hibernate_cryptvars_t
* cryptvars
)
731 IOReturn err
= kIOReturnSuccess
;
739 // seek to end of block & flush
740 size
= vars
->position
& (vars
->blockSize
- 1);
742 size
= vars
->blockSize
- size
;
744 // use some garbage for the fill
745 bytes
= vars
->buffer
+ vars
->bufferOffset
;
748 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
756 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
760 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
763 vars
->bufferOffset
+= copy
;
764 vars
->position
+= copy
;
766 if (flush
&& vars
->bufferOffset
)
768 uint64_t offset
= (vars
->position
- vars
->bufferOffset
769 - vars
->extentPosition
+ vars
->currentExtent
->start
);
770 uint32_t length
= (vars
->bufferOffset
);
772 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
774 uint32_t encryptLen
, encryptStart
;
775 encryptLen
= vars
->position
- vars
->encryptStart
;
776 if (encryptLen
> length
)
778 encryptStart
= length
- encryptLen
;
780 // encrypt the buffer
781 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
782 &cryptvars
->aes_iv
[0],
783 encryptLen
/ AES_BLOCK_SIZE
,
784 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
785 &cryptvars
->ctx
.encrypt
);
786 // save initial vector for following encrypts
787 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
788 &cryptvars
->aes_iv
[0],
794 err
= IOHibernatePollerIODone(vars
);
795 if (kIOReturnSuccess
!= err
)
799 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
800 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
802 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
803 if (kIOReturnSuccess
!= err
)
807 vars
->extentRemaining
-= vars
->bufferOffset
;
808 if (!vars
->extentRemaining
)
810 vars
->currentExtent
++;
811 vars
->extentRemaining
= vars
->currentExtent
->length
;
812 vars
->extentPosition
= vars
->position
;
813 if (!vars
->extentRemaining
)
815 err
= kIOReturnOverrun
;
820 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
821 vars
->bufferOffset
= 0;
822 if (vars
->bufferSize
<= vars
->extentRemaining
)
823 vars
->bufferLimit
= vars
->bufferSize
;
825 vars
->bufferLimit
= vars
->extentRemaining
;
836 IOPolledFileRead(IOPolledFileIOVars
* vars
,
837 uint8_t * bytes
, IOByteCount size
,
838 hibernate_cryptvars_t
* cryptvars
)
840 IOReturn err
= kIOReturnSuccess
;
843 // bytesWritten += size;
847 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
853 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
857 vars
->bufferOffset
+= copy
;
858 // vars->position += copy;
860 if (vars
->bufferOffset
== vars
->bufferLimit
)
864 err
= IOHibernatePollerIODone(vars
);
865 if (kIOReturnSuccess
!= err
)
871 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
873 vars
->position
+= vars
->lastRead
;
874 vars
->extentRemaining
-= vars
->lastRead
;
875 vars
->bufferLimit
= vars
->lastRead
;
877 if (!vars
->extentRemaining
)
879 vars
->currentExtent
++;
880 vars
->extentRemaining
= vars
->currentExtent
->length
;
881 vars
->extentPosition
= vars
->position
;
882 if (!vars
->extentRemaining
)
884 err
= kIOReturnOverrun
;
889 if (vars
->extentRemaining
<= vars
->bufferSize
)
890 vars
->lastRead
= vars
->extentRemaining
;
892 vars
->lastRead
= vars
->bufferSize
;
894 uint64_t offset
= (vars
->position
895 - vars
->extentPosition
+ vars
->currentExtent
->start
);
896 uint64_t length
= (vars
->lastRead
);
898 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
900 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
901 if (kIOReturnSuccess
!= err
)
905 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
906 vars
->bufferOffset
= 0;
910 uint8_t thisVector
[AES_BLOCK_SIZE
];
911 // save initial vector for following decrypts
912 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
913 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->lastRead
- AES_BLOCK_SIZE
,
914 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
915 // decrypt the buffer
916 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
918 vars
->lastRead
/ AES_BLOCK_SIZE
,
919 vars
->buffer
+ vars
->bufferHalf
,
920 &cryptvars
->ctx
.decrypt
);
929 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
932 IOHibernateSystemSleep(void)
940 IOHibernateVars
* vars
= &gIOHibernateVars
;
942 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
943 // already on the way down
944 return (kIOReturnSuccess
);
946 gIOHibernateState
= kIOHibernateStateInactive
;
948 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
)))
950 if ((num
= OSDynamicCast(OSNumber
, obj
)))
951 gIOHibernateMode
= num
->unsigned32BitValue();
952 if (kIOHibernateModeSleep
& gIOHibernateMode
)
953 // default to discard clean for safe sleep
954 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
955 | kIOHibernateModeDiscardCleanActive
);
959 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
)))
961 if ((num
= OSDynamicCast(OSNumber
, obj
)))
962 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
965 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
967 if ((num
= OSDynamicCast(OSNumber
, obj
)))
968 gIOHibernateFreeTime
= num
->unsigned32BitValue();
971 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
973 if ((str
= OSDynamicCast(OSString
, obj
)))
974 strcpy(gIOHibernateFilename
, str
->getCStringNoCopy());
978 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
979 return (kIOReturnUnsupported
);
981 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
985 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(0, 4 * page_size
, page_size
);
986 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize
, page_size
);
988 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
990 err
= kIOReturnNoMemory
;
994 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
995 &vars
->fileVars
, &vars
->fileExtents
, &data
);
996 if (KERN_SUCCESS
!= err
)
998 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1001 if (vars
->fileVars
->fileRef
)
1003 // invalidate the image file
1004 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1005 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1006 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1007 if (KERN_SUCCESS
!= err
)
1008 HIBLOG("kern_write_file(%d)\n", err
);
1011 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1013 boolean_t encryptedswap
;
1014 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1015 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1016 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1017 if (KERN_SUCCESS
!= err
)
1019 HIBLOG("hibernate_setup(%d)\n", err
);
1024 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1026 vars
->videoAllocSize
= kVideoMapSize
;
1027 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1028 vars
->videoMapping
= 0;
1030 // generate crypt keys
1031 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1032 vars
->wiredCryptKey
[i
] = random();
1033 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1034 vars
->cryptKey
[i
] = random();
1038 IORegistryEntry
* regEntry
;
1039 if (!gIOOptionsEntry
)
1041 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1042 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1043 if (regEntry
&& !gIOOptionsEntry
)
1044 regEntry
->release();
1046 if (!gIOChosenEntry
)
1047 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1049 if (gIOOptionsEntry
)
1051 const OSSymbol
* sym
;
1053 char valueString
[16];
1055 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1058 gIOOptionsEntry
->setProperty(sym
, data
);
1063 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1066 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1069 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1070 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1072 gIOOptionsEntry
->setProperty(sym
, str2
);
1079 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1082 vars
->haveFastBoot
= true;
1084 len
= sprintf(valueString
, "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1085 data
= OSData::withBytes(valueString
, len
+ 1);
1086 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1088 gIOOptionsEntry
->setProperty(sym
, data
);
1094 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1096 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1099 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1101 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1102 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1104 gIOOptionsEntry
->setProperty(sym
, data
);
1109 if (gIOHibernateBootSignature
[0])
1111 data
= OSData::withCapacity(16);
1112 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1117 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1127 value
= (value
<< 4) | c
;
1129 data
->appendBytes(&value
, sizeof(value
));
1131 gIOOptionsEntry
->setProperty(sym
, data
);
1140 if (!vars
->haveFastBoot
)
1142 // set boot volume to zero
1143 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1144 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1145 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1148 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1149 platform
->writeXPRAM(kXPRamAudioVolume
,
1150 &newVolume
, sizeof(newVolume
));
1156 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1157 gIOHibernateState
= kIOHibernateStateHibernating
;
1164 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1167 IOHibernateSystemHasSlept(void)
1169 IOHibernateVars
* vars
= &gIOHibernateVars
;
1171 if ((vars
->previewData
= OSDynamicCast(OSData
,
1172 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey
))))
1174 vars
->previewBuffer
= IOMemoryDescriptor::withAddress(
1175 (void *) vars
->previewData
->getBytesNoCopy(),
1176 vars
->previewData
->getLength(),
1179 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1181 vars
->previewBuffer
->release();
1182 vars
->previewBuffer
= 0;
1184 if (!vars
->previewBuffer
)
1185 vars
->previewData
= 0;
1187 if (gIOOptionsEntry
)
1188 gIOOptionsEntry
->sync();
1190 return (kIOReturnSuccess
);
1193 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1196 IOHibernateSystemWake(void)
1198 IOHibernateVars
* vars
= &gIOHibernateVars
;
1200 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1202 if (vars
->videoMapping
)
1204 if (vars
->videoMapSize
)
1206 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1207 if (vars
->videoAllocSize
)
1209 kmem_free(kernel_map
, trunc_page_32(vars
->videoMapping
), vars
->videoAllocSize
);
1212 if (vars
->previewBuffer
)
1214 vars
->previewBuffer
->release();
1215 vars
->previewBuffer
= 0;
1220 IOPolledFileClose(vars
->fileVars
);
1223 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1225 OSData
* data
= OSData::withCapacity(4);
1226 if (gIOOptionsEntry
&& data
)
1228 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1231 gIOOptionsEntry
->setProperty(sym
, data
);
1234 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1237 if (vars
->saveBootDevice
)
1239 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1240 vars
->saveBootDevice
->release();
1244 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1247 gIOOptionsEntry
->setProperty(sym
, data
);
1250 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1253 gIOOptionsEntry
->removeProperty(sym
);
1260 if (gIOOptionsEntry
)
1262 if (!vars
->haveFastBoot
)
1264 // reset boot audio volume
1265 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1267 platform
->writeXPRAM(kXPRamAudioVolume
,
1268 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1271 // sync now to hardware if the booter has not
1272 if (kIOHibernateStateInactive
== gIOHibernateState
)
1273 gIOOptionsEntry
->sync();
1275 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1276 gIOOptionsEntry
->syncOFVariables();
1279 if (vars
->srcBuffer
)
1280 vars
->srcBuffer
->release();
1282 vars
->ioBuffer
->release();
1283 if (vars
->fileExtents
)
1284 vars
->fileExtents
->release();
1286 bzero(vars
, sizeof(*vars
));
1288 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1290 return (kIOReturnSuccess
);
1294 IOHibernateSystemPostWake(void)
1296 if (gIOHibernateFileRef
)
1298 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1299 gIOHibernateFileRef
= 0;
1301 return (kIOReturnSuccess
);
1304 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1307 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1309 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1312 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1316 if (PE_parse_boot_arg("hfile", gIOHibernateFilename
))
1317 gIOHibernateMode
= kIOHibernateModeOn
;
1319 gIOHibernateFilename
[0] = 0;
1321 static SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1322 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1323 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1324 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1326 static SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1327 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1328 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1329 sysctl_register_oid(&sysctl__kern_bootsignature
);
1331 static SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1332 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1333 &gIOHibernateMode
, 0, "");
1334 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1337 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1340 hibernate_setup_for_wake(void)
1343 // go slow (state needed for wake)
1344 ml_set_processor_speed(1);
1348 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1350 extern "C" boolean_t
1351 hibernate_write_image(void)
1353 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1354 IOHibernateVars
* vars
= &gIOHibernateVars
;
1355 IOPolledFileExtent
* fileExtents
;
1357 uint32_t pageCount
, pagesDone
;
1360 IOItemCount page
, count
;
1363 IOByteCount pageCompressedSize
;
1364 uint64_t compressedSize
, uncompressedSize
;
1365 uint64_t image1Size
= 0;
1366 uint32_t bitmap_size
;
1367 bool iterDone
, pollerOpen
, needEncryptStart
;
1368 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1371 uint32_t pageAndCount
[2];
1373 AbsoluteTime startTime
, endTime
;
1374 AbsoluteTime allTime
, compTime
, decoTime
;
1376 uint32_t lastProgressStamp
= 0;
1377 uint32_t progressStamp
;
1379 hibernate_cryptvars_t _cryptvars
;
1380 hibernate_cryptvars_t
* cryptvars
= 0;
1382 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1383 return (false /* sleep */ );
1385 restore1Sum
= sum1
= sum2
= 0;
1387 // encryption data. "iv" is the "initial vector".
1388 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1390 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1391 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1392 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1394 cryptvars
= &gIOHibernateCryptWakeContext
;
1395 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1396 aes_encrypt_key(vars
->cryptKey
,
1397 kIOHibernateAESKeySize
,
1398 &cryptvars
->ctx
.encrypt
);
1399 aes_decrypt_key(vars
->cryptKey
,
1400 kIOHibernateAESKeySize
,
1401 &cryptvars
->ctx
.decrypt
);
1403 cryptvars
= &_cryptvars
;
1404 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1405 aes_encrypt_key(vars
->wiredCryptKey
,
1406 kIOHibernateAESKeySize
,
1407 &cryptvars
->ctx
.encrypt
);
1409 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1410 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1411 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1412 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1415 hibernate_setup_for_wake();
1417 hibernate_page_list_setall(vars
->page_list
,
1418 vars
->page_list_wired
,
1421 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1423 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1426 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1427 for (page
= 0; page
< count
; page
++)
1429 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1430 fileExtents
[page
].start
, fileExtents
[page
].length
,
1431 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1435 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1437 AbsoluteTime_to_scalar(&compTime
) = 0;
1438 AbsoluteTime_to_scalar(&decoTime
) = 0;
1440 clock_get_uptime(&allTime
);
1445 uncompressedSize
= 0;
1447 pageType
= 0; // wired pages first
1449 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1451 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1452 ml_get_interrupts_enabled());
1453 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1454 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1455 pollerOpen
= (kIOReturnSuccess
== err
);
1459 // copy file block extent list if larger than header
1461 count
= vars
->fileExtents
->getLength();
1462 if (count
> sizeof(header
->fileExtentMap
))
1464 count
-= sizeof(header
->fileExtentMap
);
1465 err
= IOPolledFileWrite(vars
->fileVars
,
1466 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1467 if (kIOReturnSuccess
!= err
)
1471 // copy out restore1 code
1473 page
= atop_32(sectHIBB
);
1474 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1475 header
->restore1CodePage
= page
;
1476 header
->restore1PageCount
= count
;
1477 header
->restore1CodeOffset
= ((uint32_t) &hibernate_machine_entrypoint
) - sectHIBB
;
1478 header
->restore1StackOffset
= ((uint32_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - sectHIBB
;
1480 // sum __HIB sect, with zeros for the stack
1481 src
= (uint8_t *) trunc_page(sectHIBB
);
1482 for (page
= 0; page
< count
; page
++)
1484 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1485 restore1Sum
+= hibernate_sum(src
, page_size
);
1487 restore1Sum
+= 0x10000001;
1492 // write the __HIB sect, with zeros for the stack
1494 src
= (uint8_t *) trunc_page(sectHIBB
);
1495 count
= ((uint32_t) &gIOHibernateRestoreStack
[0]) - trunc_page(sectHIBB
);
1498 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1499 if (kIOReturnSuccess
!= err
)
1502 err
= IOPolledFileWrite(vars
->fileVars
,
1504 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1506 if (kIOReturnSuccess
!= err
)
1508 src
= &gIOHibernateRestoreStackEnd
[0];
1509 count
= round_page(sectHIBB
+ sectSizeHIB
) - ((uint32_t) src
);
1512 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1513 if (kIOReturnSuccess
!= err
)
1517 // write the preview buffer
1522 if (vars
->previewData
)
1528 phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
);
1529 pageAndCount
[0] = atop_64(phys64
);
1530 pageAndCount
[1] = atop_32(segLen
);
1531 err
= IOPolledFileWrite(vars
->fileVars
,
1532 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1534 if (kIOReturnSuccess
!= err
)
1537 ppnum
+= sizeof(pageAndCount
);
1540 if (kIOReturnSuccess
!= err
)
1543 src
= (uint8_t *) vars
->previewData
->getBytesNoCopy();
1544 count
= vars
->previewData
->getLength();
1546 header
->previewPageListSize
= ppnum
;
1547 header
->previewSize
= count
+ ppnum
;
1549 for (page
= 0; page
< count
; page
+= page_size
)
1550 sum1
+= hibernate_sum(src
+ page
, page_size
);
1552 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1553 if (kIOReturnSuccess
!= err
)
1557 // mark areas for no save
1560 (phys64
= vars
->ioBuffer
->getPhysicalSegment64(count
, &segLen
));
1563 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1564 atop_64(phys64
), atop_32(segLen
),
1565 kIOHibernatePageStateFree
);
1566 pageCount
-= atop_32(segLen
);
1570 (phys64
= vars
->srcBuffer
->getPhysicalSegment64(count
, &segLen
));
1573 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1574 atop_64(phys64
), atop_32(segLen
),
1575 kIOHibernatePageStateFree
);
1576 pageCount
-= atop_32(segLen
);
1579 // copy out bitmap of pages available for trashing during restore
1581 bitmap_size
= vars
->page_list_wired
->list_size
;
1582 src
= (uint8_t *) vars
->page_list_wired
;
1583 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1584 if (kIOReturnSuccess
!= err
)
1587 // mark more areas for no save, but these are not available
1588 // for trashing during restore
1591 page
= atop_32(sectHIBB
);
1592 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1595 page
= atop_32(sectHIBB
& 0x3FFFFFFF);
1596 count
= atop_32(round_page((sectHIBB
+ sectSizeHIB
) & 0x3FFFFFFF)) - page
;
1598 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1600 kIOHibernatePageStateFree
);
1605 if (vars
->previewBuffer
) for (count
= 0;
1606 (phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
));
1609 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1610 atop_64(phys64
), atop_32(segLen
),
1611 kIOHibernatePageStateFree
);
1612 pageCount
-= atop_32(segLen
);
1615 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1620 HIBLOG("writing %d pages\n", pageCount
);
1624 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1626 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1630 pageAndCount
[0] = ppnum
;
1631 pageAndCount
[1] = count
;
1632 err
= IOPolledFileWrite(vars
->fileVars
,
1633 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1635 if (kIOReturnSuccess
!= err
)
1638 for (page
= 0; page
< count
; page
++)
1640 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1643 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__
, ppnum
, err
);
1647 sum
= hibernate_sum(src
, page_size
);
1649 clock_get_uptime(&startTime
);
1651 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1653 clock_get_uptime(&endTime
);
1654 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1655 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1657 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1658 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1660 if (pageCompressedSize
> page_size
)
1662 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1663 pageCompressedSize
= page_size
;
1666 if (pageCompressedSize
!= page_size
)
1667 data
= (src
+ page_size
);
1671 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1678 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
1680 // start encrypting partway into the data about to be written
1681 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
1682 & ~(AES_BLOCK_SIZE
- 1);
1683 needEncryptStart
= false;
1686 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1687 if (kIOReturnSuccess
!= err
)
1690 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1691 if (kIOReturnSuccess
!= err
)
1694 compressedSize
+= pageCompressedSize
;
1695 if (pageCompressedSize
)
1696 uncompressedSize
+= page_size
;
1700 if (0 == (8191 & pagesDone
))
1702 clock_get_uptime(&endTime
);
1703 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1704 absolutetime_to_nanoseconds(endTime
, &nsec
);
1705 progressStamp
= nsec
/ 750000000ULL;
1706 if (progressStamp
!= lastProgressStamp
)
1708 lastProgressStamp
= progressStamp
;
1709 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1713 if (kIOReturnSuccess
!= err
)
1715 if (iterDone
&& !pageType
)
1717 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1718 if (kIOReturnSuccess
!= err
)
1724 image1Size
= vars
->fileVars
->position
;
1727 bcopy(&cryptvars
->aes_iv
[0],
1728 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1729 sizeof(cryptvars
->aes_iv
));
1730 cryptvars
= &gIOHibernateCryptWakeContext
;
1732 HIBLOG("image1Size %qd\n", image1Size
);
1736 if (kIOReturnSuccess
!= err
)
1738 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1739 if (kIOReturnSuccess
!= err
)
1744 header
->imageSize
= vars
->fileVars
->position
;
1745 header
->image1Size
= image1Size
;
1746 header
->bitmapSize
= bitmap_size
;
1747 header
->pageCount
= pageCount
;
1748 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1750 header
->restore1Sum
= restore1Sum
;
1751 header
->image1Sum
= sum1
;
1752 header
->image2Sum
= sum2
;
1754 count
= vars
->fileExtents
->getLength();
1755 if (count
> sizeof(header
->fileExtentMap
))
1757 header
->fileExtentMapSize
= count
;
1758 count
= sizeof(header
->fileExtentMap
);
1761 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1762 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1764 IOPolledFileSeek(vars
->fileVars
, 0);
1765 err
= IOPolledFileWrite(vars
->fileVars
,
1766 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1768 if (kIOReturnSuccess
!= err
)
1770 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1771 if (kIOReturnSuccess
!= err
)
1773 err
= IOHibernatePollerIODone(vars
->fileVars
);
1774 if (kIOReturnSuccess
!= err
)
1779 clock_get_uptime(&endTime
);
1780 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1781 absolutetime_to_nanoseconds(endTime
, &nsec
);
1782 HIBLOG("all time: %qd ms, ",
1785 absolutetime_to_nanoseconds(compTime
, &nsec
);
1786 HIBLOG("comp time: %qd ms, ",
1789 absolutetime_to_nanoseconds(decoTime
, &nsec
);
1790 HIBLOG("deco time: %qd ms, ",
1793 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1795 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
1796 (int) ((compressedSize
* 100ULL) / uncompressedSize
),
1800 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
1802 HIBLOG("hibernate_write_image done(%x)\n", err
);
1804 // should we come back via regular wake, set the state in memory.
1805 gIOHibernateState
= kIOHibernateStateInactive
;
1807 if ((kIOReturnSuccess
== err
) && !(kIOHibernateModeSleep
& gIOHibernateMode
))
1808 return (true /* power down */ );
1810 return (false /* sleep */ );
1813 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1815 DECLARE_IOHIBERNATEPROGRESSALPHA
1818 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1820 uint32_t rowBytes
, pixelShift
;
1822 int32_t blob
, lastBlob
;
1823 uint32_t alpha
, in
, color
, result
;
1825 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1827 pixelShift
= display
->depth
>> 4;
1831 rowBytes
= display
->rowBytes
;
1833 screen
+= ((display
->width
1834 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1835 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1837 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1839 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1841 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1843 out
= screen
+ y
* rowBytes
;
1844 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1846 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1847 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1849 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1855 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1856 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1858 if (1 == pixelShift
)
1861 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1864 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1866 out
+= (1 << pixelShift
);
1868 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1873 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1876 hibernate_machine_init(void)
1881 AbsoluteTime allTime
, endTime
;
1883 uint32_t lastProgressStamp
= 0;
1884 uint32_t progressStamp
;
1885 uint64_t progressZeroPosition
= 0;
1886 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1887 hibernate_cryptvars_t
* cryptvars
= 0;
1889 IOHibernateVars
* vars
= &gIOHibernateVars
;
1891 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1894 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
1895 hibernate_page_list_discard(vars
->page_list
);
1898 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
1899 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
1901 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1902 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
1903 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
1905 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
1907 HIBLOG("regular wake\n");
1911 HIBPRINT("diag %x %x %x %x\n",
1912 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
1913 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
1915 HIBPRINT("video %x %d %d %d\n",
1916 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
1917 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1919 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
1921 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
1922 * gIOHibernateGraphicsInfo
->rowBytes
);
1923 IOMapPages(kernel_map
,
1924 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
1925 vars
->videoMapSize
, kIOMapInhibitCache
);
1928 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();;
1929 uint32_t decoOffset
;
1931 clock_get_uptime(&allTime
);
1933 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
1934 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
1935 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1937 if (gIOHibernateCurrentHeader
->previewSize
)
1938 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
1939 + gIOHibernateCurrentHeader
->fileExtentMapSize
1940 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
1941 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
1943 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
1945 if (vars
->videoMapping
)
1947 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
1948 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
1949 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
1952 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
1953 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1955 cryptvars
= &gIOHibernateCryptWakeContext
;
1956 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
1957 &cryptvars
->aes_iv
[0],
1958 sizeof(cryptvars
->aes_iv
));
1961 // kick off the read ahead
1962 vars
->fileVars
->io
= false;
1963 vars
->fileVars
->bufferHalf
= 0;
1964 vars
->fileVars
->bufferLimit
= 0;
1965 vars
->fileVars
->lastRead
= 0;
1966 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1968 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
1969 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1972 HIBLOG("hibernate_machine_init reading\n");
1974 uint32_t * header
= (uint32_t *) src
;
1982 vm_offset_t ppnum
, compressedSize
;
1984 IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
1989 // HIBPRINT("(%x, %x)\n", ppnum, count);
1994 for (page
= 0; page
< count
; page
++)
1996 IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
1998 compressedSize
= kIOHibernateTagLength
& tag
;
1999 if (!compressedSize
)
2006 IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2008 if (compressedSize
!= page_size
)
2010 decoOffset
= page_size
;
2011 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2016 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2018 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2020 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum
, err
);
2025 if (vars
->videoMapping
&& (0 == (255 & pagesDone
)))
2027 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2028 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2029 if (blob
!= lastBlob
)
2031 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2036 if (0 == (8191 & pagesDone
))
2038 clock_get_uptime(&endTime
);
2039 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2040 absolutetime_to_nanoseconds(endTime
, &nsec
);
2041 progressStamp
= nsec
/ 750000000ULL;
2042 if (progressStamp
!= lastProgressStamp
)
2044 lastProgressStamp
= progressStamp
;
2045 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2046 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2053 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2055 if (vars
->fileVars
->io
)
2056 (void) IOHibernatePollerIODone(vars
->fileVars
);
2058 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2060 if (vars
->videoMapping
)
2061 ProgressUpdate(gIOHibernateGraphicsInfo
,
2062 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2064 clock_get_uptime(&endTime
);
2065 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2066 absolutetime_to_nanoseconds(endTime
, &nsec
);
2068 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2069 pagesDone
, sum
, nsec
/ 1000000ULL);
2072 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */