2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
35 (devices awake, normal execution context)
36 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
37 grabs its extents and searches for a polling driver willing to work with that IOMedia.
38 The BSD code makes an ioctl to the storage driver to get the partition base offset to
39 the disk, and other ioctls to get the transfer constraints
40 If successful, the file is written to make sure its initially not bootable (in case of
41 later failure) and nvram set to point to the first block of the file. (Has to be done
42 here so blocking is possible in nvram support).
43 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
44 page out any pages it wants to (currently zero, but probably some percentage of memory).
45 Its assumed just allocating pages will cause the VM system to naturally select the best
46 pages for eviction. It also copies processor flags needed for the restore path and sets
47 a flag in the boot processor proc info.
48 gIOHibernateState = kIOHibernateStateHibernating.
49 - Regular sleep progresses - some drivers may inspect the root domain property
50 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
51 as usual but leaves motherboard I/O on.
52 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
53 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
54 all ppc RC bits out of the hash table and caches into the mapping structures.
55 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
56 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
57 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
58 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
59 The image header and block list are written. The header includes the second file extent so
60 only the header block is needed to read the file, regardless of filesystem.
61 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
62 (only) is used to decompress the image during wake/boot.
63 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
64 The bitmaps are written to the image.
65 More areas are removed from the bitmaps (after they have been written to the image) - the
66 section "__HIB" pages and interrupt stack.
67 Each wired page is compressed and written and then each non-wired page. Compression and
68 disk writes are in parallel.
69 The image header is written to the start of the file and the polling driver closed.
70 The machine powers down (or sleeps).
74 - BootX sees the boot-image nvram variable containing the device and block number of the image,
75 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
76 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
77 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
78 that is in the kernel's __HIB section.
79 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
80 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
81 only code & data in that section is safe to call since all the other wired pages are still
82 compressed in the image.
83 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
84 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
85 location directly, and copies those that can't to interim free pages. When the image has been
86 completed, the copies are uncompressed, overwriting the wired image pages.
87 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
88 is used to get pages into place for 64bit.
89 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
90 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
91 are removed from the software strutures, and the hash table is reinitialized.
92 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
93 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
94 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
95 for the remaining non wired pages.
96 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
97 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
102 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
103 registry, specifying an object of calls IOPolledInterface.
105 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
106 partition) that the image is going to live, looking for polled interface properties. If it finds
107 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
108 interfaces found are kept in an ordered list.
110 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
111 few different contexts things happen in:
113 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
114 up and running) and after wake - this is safe to allocate memory and do anything. The device
115 ignores sleep requests from that point since its a waste of time if it goes to sleep and
116 immediately wakes back up for the image write.
118 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
119 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
120 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
121 used to flush and set the disk to sleep.
123 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
124 immediately after sleep. These can't block or allocate memory. This is happening after the platform
125 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
128 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
129 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
130 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
131 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
132 that is called for the hardware to check for events, and complete the I/O via the callback.
133 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
137 #include <sys/systm.h>
139 #include <IOKit/IOWorkLoop.h>
140 #include <IOKit/IOCommandGate.h>
141 #include <IOKit/IOTimerEventSource.h>
142 #include <IOKit/IOPlatformExpert.h>
143 #include <IOKit/IOKitDebug.h>
144 #include <IOKit/IOTimeStamp.h>
145 #include <IOKit/pwr_mgt/RootDomain.h>
146 #include <IOKit/pwr_mgt/IOPMPrivate.h>
147 #include <IOKit/IOMessage.h>
148 #include <IOKit/IODeviceTreeSupport.h>
149 #include <IOKit/IOBSD.h>
150 #include "RootDomainUserClient.h"
151 #include <IOKit/pwr_mgt/IOPowerConnection.h>
152 #include "IOPMPowerStateQueue.h"
153 #include <IOKit/IOBufferMemoryDescriptor.h>
154 #include <crypto/aes.h>
157 #include <sys/conf.h>
158 #include <sys/stat.h>
159 #include <sys/fcntl.h> // (FWRITE, ...)
160 #include <sys/sysctl.h>
162 #include <IOKit/IOHibernatePrivate.h>
163 #include <IOKit/IOPolledInterface.h>
164 #include <IOKit/IONVRAM.h>
165 #include "IOHibernateInternal.h"
167 #include "IOKitKernelInternal.h"
169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
171 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
173 OSMetaClassDefineReservedUnused(IOPolledInterface
, 0);
174 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
175 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
176 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
177 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
178 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
179 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
180 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
181 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
182 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
183 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
184 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
185 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
186 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
187 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
188 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
190 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
192 extern uint32_t gIOHibernateState
;
193 uint32_t gIOHibernateMode
;
194 static char gIOHibernateBootSignature
[256+1];
195 static char gIOHibernateFilename
[MAXPATHLEN
+1];
196 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
197 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
199 static IODTNVRAM
* gIOOptionsEntry
;
200 static IORegistryEntry
* gIOChosenEntry
;
202 static IOPolledFileIOVars gFileVars
;
203 static IOHibernateVars gIOHibernateVars
;
204 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
205 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
207 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
209 enum { kXPRamAudioVolume
= 8 };
210 enum { kDefaultIOSize
= 128 * 1024 };
211 enum { kVideoMapSize
= 32 * 1024 * 1024 };
213 #ifndef kIOMediaPreferredBlockSizeKey
214 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
217 #ifndef kIOBootPathKey
218 #define kIOBootPathKey "bootpath"
220 #ifndef kIOSelectedBootDeviceKey
221 #define kIOSelectedBootDeviceKey "boot-device"
225 enum { kIOHibernateMinPollersNeeded
= 2 };
227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
229 // copy from phys addr to MD
232 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
233 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
235 addr64_t srcAddr
= bytes
;
236 IOByteCount remaining
;
238 remaining
= length
= min(length
, md
->getLength() - offset
);
239 while (remaining
) { // (process another target segment?)
243 dstAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
247 // Clip segment length to remaining
248 if (dstLen
> remaining
)
252 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
254 copypv(srcAddr
, dstAddr64
, dstLen
,
255 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
264 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
267 // copy from MD to phys addr
270 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
271 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
273 addr64_t dstAddr
= bytes
;
274 IOByteCount remaining
;
276 remaining
= length
= min(length
, md
->getLength() - offset
);
277 while (remaining
) { // (process another target segment?)
281 srcAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
285 // Clip segment length to remaining
286 if (dstLen
> remaining
)
290 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
292 copypv(srcAddr
, dstAddr64
, dstLen
,
293 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
302 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
308 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
309 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
314 case kIOHibernatePageStateUnwiredSave
:
316 for (; ppnum
< count
; ppnum
++)
318 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
319 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
322 case kIOHibernatePageStateWiredSave
:
324 for (; ppnum
< count
; ppnum
++)
326 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
327 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
330 case kIOHibernatePageStateFree
:
332 for (; ppnum
< count
; ppnum
++)
334 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
335 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
339 panic("hibernate_set_page_state");
344 hibernate_page_list_iterate(hibernate_page_list_t
* list
,
345 void ** iterator
, vm_offset_t
* ppnum
)
349 idx
= (uint32_t) *iterator
;
352 idx
= hibernate_page_list_count(list
, TRUE
, idx
);
355 count
= hibernate_page_list_count(list
, FALSE
, idx
);
357 idx
+= hibernate_page_list_count(list
, TRUE
, idx
);
358 *iterator
= (void *) idx
;
363 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
366 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
368 IOReturn err
= kIOReturnError
;
370 IOPolledInterface
* poller
;
372 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
374 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
375 err
= poller
->probe(target
);
378 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
387 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
389 IOReturn err
= kIOReturnError
;
391 IOPolledInterface
* poller
;
393 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
395 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
396 err
= poller
->open(state
, md
);
399 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
408 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
410 IOReturn err
= kIOReturnError
;
412 IOPolledInterface
* poller
;
415 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
418 err
= poller
->close(state
);
420 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
427 IOHibernatePollerIOComplete(void * target
,
430 UInt64 actualByteCount
)
432 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
434 vars
->ioStatus
= status
;
438 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
439 uint32_t operation
, uint32_t bufferOffset
,
440 uint64_t deviceOffset
, uint64_t length
)
443 IOReturn err
= kIOReturnError
;
444 IOPolledInterface
* poller
;
445 IOPolledCompletion completion
;
447 completion
.target
= 0;
448 completion
.action
= &IOHibernatePollerIOComplete
;
449 completion
.parameter
= vars
;
453 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
454 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
456 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
462 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
)
464 IOReturn err
= kIOReturnError
;
466 IOPolledInterface
* poller
;
468 while (-1 == vars
->ioStatus
)
471 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
474 err
= poller
->checkForWork();
476 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
480 if (kIOReturnSuccess
!= vars
->ioStatus
)
481 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars
->ioStatus
);
483 return (vars
->ioStatus
);
487 IOPolledInterface::checkAllForWork(void)
489 IOReturn err
= kIOReturnNotReady
;
491 IOPolledInterface
* poller
;
493 IOHibernateVars
* vars
= &gIOHibernateVars
;
495 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
499 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
502 err
= poller
->checkForWork();
504 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
510 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
512 struct _OpenFileContext
519 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
521 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
522 IOPolledFileExtent extent
;
524 extent
.start
= start
;
525 extent
.length
= length
;
527 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
532 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
533 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
536 IOReturn err
= kIOReturnError
;
537 IOPolledFileIOVars
* vars
;
538 _OpenFileContext ctx
;
539 OSData
* extentsData
;
541 IORegistryEntry
* part
= 0;
542 OSDictionary
* matching
;
544 dev_t hibernate_image_dev
;
550 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
551 if (sizeof(IOHibernateImageHeader
) != 512)
555 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
556 vars
->bufferHalf
= 0;
557 vars
->bufferOffset
= 0;
558 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
560 extentsData
= OSData::withCapacity(32);
562 ctx
.extents
= extentsData
;
564 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
565 &file_extent_callback
, &ctx
,
566 &hibernate_image_dev
,
571 err
= kIOReturnNoSpace
;
574 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
575 vars
->block0
, maxiobytes
);
576 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
578 err
= kIOReturnNoSpace
;
582 if (maxiobytes
< vars
->bufferSize
)
583 vars
->bufferSize
= maxiobytes
;
585 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
587 matching
= IOService::serviceMatching("IOMedia");
588 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
589 matching
->setObject(kIOBSDMajorKey
, num
);
591 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
592 matching
->setObject(kIOBSDMinorKey
, num
);
594 iter
= IOService::getMatchingServices(matching
);
598 part
= (IORegistryEntry
*) iter
->getNextObject();
604 IORegistryEntry
* next
;
605 IORegistryEntry
* child
;
608 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
611 major
= num
->unsigned32BitValue();
612 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
615 minor
= num
->unsigned32BitValue();
617 hibernate_image_dev
= makedev(major
, minor
);
619 vars
->pollers
= OSArray::withCapacity(4);
623 vars
->blockSize
= 512;
627 IOPolledInterface
* poller
;
630 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
631 if (kOSBooleanFalse
== obj
)
633 vars
->pollers
->flushCollection();
636 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
637 vars
->pollers
->setObject(poller
);
638 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
639 vars
->blockSize
= num
->unsigned32BitValue();
642 while ((next
= child
->getParentEntry(gIOServicePlane
))
643 && child
->isParent(next
, gIOServicePlane
, true));
645 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
646 major
, minor
, vars
->blockSize
, vars
->pollers
->getCount());
647 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
650 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
651 if (kIOReturnSuccess
!= err
)
654 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
655 if (kIOReturnSuccess
!= err
)
659 *fileExtents
= extentsData
;
664 int len
= sizeof(str1
);
666 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
))
667 && part
->getPath(str1
, &len
, gIODTPlane
))
669 // (strip the plane name)
670 char * tail
= strchr(str1
, ':');
673 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
674 sprintf(str2
, ",%qx", vars
->extentMap
[0]);
675 data
->appendBytes(str2
, strlen(str2
));
681 if (kIOReturnSuccess
!= err
)
683 HIBLOG("error 0x%x opening hibernation file\n", err
);
685 kern_close_file_for_direct_io(vars
->fileRef
);
695 IOPolledFileClose( IOPolledFileIOVars
* vars
)
699 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
700 vars
->pollers
->release();
703 gIOHibernateFileRef
= vars
->fileRef
;
705 bzero(vars
, sizeof(IOPolledFileIOVars
));
707 return (kIOReturnSuccess
);
711 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
713 IOPolledFileExtent
* extentMap
;
715 extentMap
= vars
->extentMap
;
717 vars
->position
= position
;
719 while (position
>= extentMap
->length
)
721 position
-= extentMap
->length
;
725 vars
->currentExtent
= extentMap
;
726 vars
->extentRemaining
= extentMap
->length
- position
;
727 vars
->extentPosition
= vars
->position
- position
;
729 if (vars
->bufferSize
<= vars
->extentRemaining
)
730 vars
->bufferLimit
= vars
->bufferSize
;
732 vars
->bufferLimit
= vars
->extentRemaining
;
734 return (kIOReturnSuccess
);
738 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
739 const uint8_t * bytes
, IOByteCount size
,
740 hibernate_cryptvars_t
* cryptvars
)
742 IOReturn err
= kIOReturnSuccess
;
750 // seek to end of block & flush
751 size
= vars
->position
& (vars
->blockSize
- 1);
753 size
= vars
->blockSize
- size
;
755 // use some garbage for the fill
756 bytes
= vars
->buffer
+ vars
->bufferOffset
;
759 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
767 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
771 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
774 vars
->bufferOffset
+= copy
;
775 vars
->position
+= copy
;
777 if (flush
&& vars
->bufferOffset
)
779 uint64_t offset
= (vars
->position
- vars
->bufferOffset
780 - vars
->extentPosition
+ vars
->currentExtent
->start
);
781 uint32_t length
= (vars
->bufferOffset
);
783 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
785 uint32_t encryptLen
, encryptStart
;
786 encryptLen
= vars
->position
- vars
->encryptStart
;
787 if (encryptLen
> length
)
789 encryptStart
= length
- encryptLen
;
791 // encrypt the buffer
792 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
793 &cryptvars
->aes_iv
[0],
794 encryptLen
/ AES_BLOCK_SIZE
,
795 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
796 &cryptvars
->ctx
.encrypt
);
797 // save initial vector for following encrypts
798 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
799 &cryptvars
->aes_iv
[0],
805 err
= IOHibernatePollerIODone(vars
);
806 if (kIOReturnSuccess
!= err
)
810 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
811 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
813 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
814 if (kIOReturnSuccess
!= err
)
818 vars
->extentRemaining
-= vars
->bufferOffset
;
819 if (!vars
->extentRemaining
)
821 vars
->currentExtent
++;
822 vars
->extentRemaining
= vars
->currentExtent
->length
;
823 vars
->extentPosition
= vars
->position
;
824 if (!vars
->extentRemaining
)
826 err
= kIOReturnOverrun
;
831 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
832 vars
->bufferOffset
= 0;
833 if (vars
->bufferSize
<= vars
->extentRemaining
)
834 vars
->bufferLimit
= vars
->bufferSize
;
836 vars
->bufferLimit
= vars
->extentRemaining
;
847 IOPolledFileRead(IOPolledFileIOVars
* vars
,
848 uint8_t * bytes
, IOByteCount size
,
849 hibernate_cryptvars_t
* cryptvars
)
851 IOReturn err
= kIOReturnSuccess
;
854 // bytesWritten += size;
858 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
864 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
868 vars
->bufferOffset
+= copy
;
869 // vars->position += copy;
871 if (vars
->bufferOffset
== vars
->bufferLimit
)
875 err
= IOHibernatePollerIODone(vars
);
876 if (kIOReturnSuccess
!= err
)
882 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
884 vars
->position
+= vars
->lastRead
;
885 vars
->extentRemaining
-= vars
->lastRead
;
886 vars
->bufferLimit
= vars
->lastRead
;
888 if (!vars
->extentRemaining
)
890 vars
->currentExtent
++;
891 vars
->extentRemaining
= vars
->currentExtent
->length
;
892 vars
->extentPosition
= vars
->position
;
893 if (!vars
->extentRemaining
)
895 err
= kIOReturnOverrun
;
900 if (vars
->extentRemaining
<= vars
->bufferSize
)
901 vars
->lastRead
= vars
->extentRemaining
;
903 vars
->lastRead
= vars
->bufferSize
;
905 uint64_t offset
= (vars
->position
906 - vars
->extentPosition
+ vars
->currentExtent
->start
);
907 uint64_t length
= (vars
->lastRead
);
909 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
911 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
912 if (kIOReturnSuccess
!= err
)
916 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
917 vars
->bufferOffset
= 0;
921 uint8_t thisVector
[AES_BLOCK_SIZE
];
922 // save initial vector for following decrypts
923 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
924 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->lastRead
- AES_BLOCK_SIZE
,
925 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
926 // decrypt the buffer
927 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
929 vars
->lastRead
/ AES_BLOCK_SIZE
,
930 vars
->buffer
+ vars
->bufferHalf
,
931 &cryptvars
->ctx
.decrypt
);
940 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
943 IOHibernateSystemSleep(void)
951 IOHibernateVars
* vars
= &gIOHibernateVars
;
953 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
954 // already on the way down
955 return (kIOReturnSuccess
);
957 gIOHibernateState
= kIOHibernateStateInactive
;
959 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
)))
961 if ((num
= OSDynamicCast(OSNumber
, obj
)))
962 gIOHibernateMode
= num
->unsigned32BitValue();
963 if (kIOHibernateModeSleep
& gIOHibernateMode
)
964 // default to discard clean for safe sleep
965 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
966 | kIOHibernateModeDiscardCleanActive
);
970 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
)))
972 if ((num
= OSDynamicCast(OSNumber
, obj
)))
973 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
976 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
978 if ((num
= OSDynamicCast(OSNumber
, obj
)))
979 gIOHibernateFreeTime
= num
->unsigned32BitValue();
982 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
984 if ((str
= OSDynamicCast(OSString
, obj
)))
985 strcpy(gIOHibernateFilename
, str
->getCStringNoCopy());
989 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
990 return (kIOReturnUnsupported
);
992 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
996 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(0, 4 * page_size
, page_size
);
997 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize
, page_size
);
999 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
1001 err
= kIOReturnNoMemory
;
1005 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1006 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1007 if (KERN_SUCCESS
!= err
)
1009 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1012 if (vars
->fileVars
->fileRef
)
1014 // invalidate the image file
1015 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1016 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1017 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1018 if (KERN_SUCCESS
!= err
)
1019 HIBLOG("kern_write_file(%d)\n", err
);
1022 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1024 boolean_t encryptedswap
;
1025 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1026 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1027 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1028 if (KERN_SUCCESS
!= err
)
1030 HIBLOG("hibernate_setup(%d)\n", err
);
1035 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1037 vars
->videoAllocSize
= kVideoMapSize
;
1038 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1039 vars
->videoMapping
= 0;
1041 // generate crypt keys
1042 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1043 vars
->wiredCryptKey
[i
] = random();
1044 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1045 vars
->cryptKey
[i
] = random();
1049 IORegistryEntry
* regEntry
;
1050 if (!gIOOptionsEntry
)
1052 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1053 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1054 if (regEntry
&& !gIOOptionsEntry
)
1055 regEntry
->release();
1057 if (!gIOChosenEntry
)
1058 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1060 if (gIOOptionsEntry
)
1062 const OSSymbol
* sym
;
1064 char valueString
[16];
1066 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1069 gIOOptionsEntry
->setProperty(sym
, data
);
1074 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1077 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1080 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1081 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1083 gIOOptionsEntry
->setProperty(sym
, str2
);
1090 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1093 vars
->haveFastBoot
= true;
1095 len
= sprintf(valueString
, "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1096 data
= OSData::withBytes(valueString
, len
+ 1);
1097 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1099 gIOOptionsEntry
->setProperty(sym
, data
);
1105 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1107 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1110 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1112 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1113 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1115 gIOOptionsEntry
->setProperty(sym
, data
);
1120 if (gIOHibernateBootSignature
[0])
1122 data
= OSData::withCapacity(16);
1123 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1128 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1138 value
= (value
<< 4) | c
;
1140 data
->appendBytes(&value
, sizeof(value
));
1142 gIOOptionsEntry
->setProperty(sym
, data
);
1151 if (!vars
->haveFastBoot
)
1153 // set boot volume to zero
1154 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1155 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1156 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1159 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1160 platform
->writeXPRAM(kXPRamAudioVolume
,
1161 &newVolume
, sizeof(newVolume
));
1167 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1168 gIOHibernateState
= kIOHibernateStateHibernating
;
1175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1178 IOHibernateSystemHasSlept(void)
1180 IOHibernateVars
* vars
= &gIOHibernateVars
;
1182 if ((vars
->previewData
= OSDynamicCast(OSData
,
1183 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey
))))
1185 vars
->previewBuffer
= IOMemoryDescriptor::withAddress(
1186 (void *) vars
->previewData
->getBytesNoCopy(),
1187 vars
->previewData
->getLength(),
1190 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1192 vars
->previewBuffer
->release();
1193 vars
->previewBuffer
= 0;
1195 if (!vars
->previewBuffer
)
1196 vars
->previewData
= 0;
1198 if (gIOOptionsEntry
)
1199 gIOOptionsEntry
->sync();
1201 return (kIOReturnSuccess
);
1204 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1207 IOHibernateSystemWake(void)
1209 IOHibernateVars
* vars
= &gIOHibernateVars
;
1211 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1213 if (vars
->videoMapping
)
1215 if (vars
->videoMapSize
)
1217 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1218 if (vars
->videoAllocSize
)
1220 kmem_free(kernel_map
, trunc_page_32(vars
->videoMapping
), vars
->videoAllocSize
);
1223 if (vars
->previewBuffer
)
1225 vars
->previewBuffer
->release();
1226 vars
->previewBuffer
= 0;
1231 IOPolledFileClose(vars
->fileVars
);
1234 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1236 OSData
* data
= OSData::withCapacity(4);
1237 if (gIOOptionsEntry
&& data
)
1239 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1242 gIOOptionsEntry
->setProperty(sym
, data
);
1245 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1248 if (vars
->saveBootDevice
)
1250 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1251 vars
->saveBootDevice
->release();
1255 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1258 gIOOptionsEntry
->setProperty(sym
, data
);
1261 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1264 gIOOptionsEntry
->removeProperty(sym
);
1271 if (gIOOptionsEntry
)
1273 if (!vars
->haveFastBoot
)
1275 // reset boot audio volume
1276 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1278 platform
->writeXPRAM(kXPRamAudioVolume
,
1279 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1282 // sync now to hardware if the booter has not
1283 if (kIOHibernateStateInactive
== gIOHibernateState
)
1284 gIOOptionsEntry
->sync();
1286 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1287 gIOOptionsEntry
->syncOFVariables();
1290 if (vars
->srcBuffer
)
1291 vars
->srcBuffer
->release();
1293 vars
->ioBuffer
->release();
1294 if (vars
->fileExtents
)
1295 vars
->fileExtents
->release();
1297 bzero(vars
, sizeof(*vars
));
1299 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1301 return (kIOReturnSuccess
);
1305 IOHibernateSystemPostWake(void)
1307 if (gIOHibernateFileRef
)
1309 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1310 gIOHibernateFileRef
= 0;
1312 return (kIOReturnSuccess
);
1315 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1318 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1320 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1323 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1327 if (PE_parse_boot_arg("hfile", gIOHibernateFilename
))
1328 gIOHibernateMode
= kIOHibernateModeOn
;
1330 gIOHibernateFilename
[0] = 0;
1332 static SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1333 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1334 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1335 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1337 static SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1338 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1339 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1340 sysctl_register_oid(&sysctl__kern_bootsignature
);
1342 static SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1343 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1344 &gIOHibernateMode
, 0, "");
1345 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1348 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1351 hibernate_setup_for_wake(void)
1354 // go slow (state needed for wake)
1355 ml_set_processor_speed(1);
1359 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1361 extern "C" boolean_t
1362 hibernate_write_image(void)
1364 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1365 IOHibernateVars
* vars
= &gIOHibernateVars
;
1366 IOPolledFileExtent
* fileExtents
;
1368 uint32_t pageCount
, pagesDone
;
1371 IOItemCount page
, count
;
1374 IOByteCount pageCompressedSize
;
1375 uint64_t compressedSize
, uncompressedSize
;
1376 uint64_t image1Size
= 0;
1377 uint32_t bitmap_size
;
1378 bool iterDone
, pollerOpen
, needEncryptStart
;
1379 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1382 uint32_t pageAndCount
[2];
1384 AbsoluteTime startTime
, endTime
;
1385 AbsoluteTime allTime
, compTime
, decoTime
;
1387 uint32_t lastProgressStamp
= 0;
1388 uint32_t progressStamp
;
1390 hibernate_cryptvars_t _cryptvars
;
1391 hibernate_cryptvars_t
* cryptvars
= 0;
1393 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1394 return (false /* sleep */ );
1396 restore1Sum
= sum1
= sum2
= 0;
1398 // encryption data. "iv" is the "initial vector".
1399 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1401 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1402 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1403 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1405 cryptvars
= &gIOHibernateCryptWakeContext
;
1406 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1407 aes_encrypt_key(vars
->cryptKey
,
1408 kIOHibernateAESKeySize
,
1409 &cryptvars
->ctx
.encrypt
);
1410 aes_decrypt_key(vars
->cryptKey
,
1411 kIOHibernateAESKeySize
,
1412 &cryptvars
->ctx
.decrypt
);
1414 cryptvars
= &_cryptvars
;
1415 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1416 aes_encrypt_key(vars
->wiredCryptKey
,
1417 kIOHibernateAESKeySize
,
1418 &cryptvars
->ctx
.encrypt
);
1420 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1421 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1422 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1423 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1426 hibernate_setup_for_wake();
1428 hibernate_page_list_setall(vars
->page_list
,
1429 vars
->page_list_wired
,
1432 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1434 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1437 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1438 for (page
= 0; page
< count
; page
++)
1440 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1441 fileExtents
[page
].start
, fileExtents
[page
].length
,
1442 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1446 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1448 AbsoluteTime_to_scalar(&compTime
) = 0;
1449 AbsoluteTime_to_scalar(&decoTime
) = 0;
1451 clock_get_uptime(&allTime
);
1456 uncompressedSize
= 0;
1458 pageType
= 0; // wired pages first
1460 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1462 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1463 ml_get_interrupts_enabled());
1464 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1465 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1466 pollerOpen
= (kIOReturnSuccess
== err
);
1470 // copy file block extent list if larger than header
1472 count
= vars
->fileExtents
->getLength();
1473 if (count
> sizeof(header
->fileExtentMap
))
1475 count
-= sizeof(header
->fileExtentMap
);
1476 err
= IOPolledFileWrite(vars
->fileVars
,
1477 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1478 if (kIOReturnSuccess
!= err
)
1482 // copy out restore1 code
1484 page
= atop_32(sectHIBB
);
1485 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1486 header
->restore1CodePage
= page
;
1487 header
->restore1PageCount
= count
;
1488 header
->restore1CodeOffset
= ((uint32_t) &hibernate_machine_entrypoint
) - sectHIBB
;
1489 header
->restore1StackOffset
= ((uint32_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - sectHIBB
;
1491 // sum __HIB sect, with zeros for the stack
1492 src
= (uint8_t *) trunc_page(sectHIBB
);
1493 for (page
= 0; page
< count
; page
++)
1495 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1496 restore1Sum
+= hibernate_sum(src
, page_size
);
1498 restore1Sum
+= 0x10000001;
1503 // write the __HIB sect, with zeros for the stack
1505 src
= (uint8_t *) trunc_page(sectHIBB
);
1506 count
= ((uint32_t) &gIOHibernateRestoreStack
[0]) - trunc_page(sectHIBB
);
1509 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1510 if (kIOReturnSuccess
!= err
)
1513 err
= IOPolledFileWrite(vars
->fileVars
,
1515 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1517 if (kIOReturnSuccess
!= err
)
1519 src
= &gIOHibernateRestoreStackEnd
[0];
1520 count
= round_page(sectHIBB
+ sectSizeHIB
) - ((uint32_t) src
);
1523 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1524 if (kIOReturnSuccess
!= err
)
1528 // write the preview buffer
1533 if (vars
->previewData
)
1539 phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
);
1540 pageAndCount
[0] = atop_64(phys64
);
1541 pageAndCount
[1] = atop_32(segLen
);
1542 err
= IOPolledFileWrite(vars
->fileVars
,
1543 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1545 if (kIOReturnSuccess
!= err
)
1548 ppnum
+= sizeof(pageAndCount
);
1551 if (kIOReturnSuccess
!= err
)
1554 src
= (uint8_t *) vars
->previewData
->getBytesNoCopy();
1555 count
= vars
->previewData
->getLength();
1557 header
->previewPageListSize
= ppnum
;
1558 header
->previewSize
= count
+ ppnum
;
1560 for (page
= 0; page
< count
; page
+= page_size
)
1561 sum1
+= hibernate_sum(src
+ page
, page_size
);
1563 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1564 if (kIOReturnSuccess
!= err
)
1568 // mark areas for no save
1571 (phys64
= vars
->ioBuffer
->getPhysicalSegment64(count
, &segLen
));
1574 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1575 atop_64(phys64
), atop_32(segLen
),
1576 kIOHibernatePageStateFree
);
1577 pageCount
-= atop_32(segLen
);
1581 (phys64
= vars
->srcBuffer
->getPhysicalSegment64(count
, &segLen
));
1584 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1585 atop_64(phys64
), atop_32(segLen
),
1586 kIOHibernatePageStateFree
);
1587 pageCount
-= atop_32(segLen
);
1590 // copy out bitmap of pages available for trashing during restore
1592 bitmap_size
= vars
->page_list_wired
->list_size
;
1593 src
= (uint8_t *) vars
->page_list_wired
;
1594 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1595 if (kIOReturnSuccess
!= err
)
1598 // mark more areas for no save, but these are not available
1599 // for trashing during restore
1602 page
= atop_32(sectHIBB
);
1603 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1606 page
= atop_32(sectHIBB
& 0x3FFFFFFF);
1607 count
= atop_32(round_page((sectHIBB
+ sectSizeHIB
) & 0x3FFFFFFF)) - page
;
1609 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1611 kIOHibernatePageStateFree
);
1616 if (vars
->previewBuffer
) for (count
= 0;
1617 (phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
));
1620 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1621 atop_64(phys64
), atop_32(segLen
),
1622 kIOHibernatePageStateFree
);
1623 pageCount
-= atop_32(segLen
);
1626 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1631 HIBLOG("writing %d pages\n", pageCount
);
1635 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1637 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1641 pageAndCount
[0] = ppnum
;
1642 pageAndCount
[1] = count
;
1643 err
= IOPolledFileWrite(vars
->fileVars
,
1644 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1646 if (kIOReturnSuccess
!= err
)
1649 for (page
= 0; page
< count
; page
++)
1651 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1654 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__
, ppnum
, err
);
1658 sum
= hibernate_sum(src
, page_size
);
1660 clock_get_uptime(&startTime
);
1662 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1664 clock_get_uptime(&endTime
);
1665 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1666 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1668 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1669 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1671 if (pageCompressedSize
> page_size
)
1673 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1674 pageCompressedSize
= page_size
;
1677 if (pageCompressedSize
!= page_size
)
1678 data
= (src
+ page_size
);
1682 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1689 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
1691 // start encrypting partway into the data about to be written
1692 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
1693 & ~(AES_BLOCK_SIZE
- 1);
1694 needEncryptStart
= false;
1697 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1698 if (kIOReturnSuccess
!= err
)
1701 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1702 if (kIOReturnSuccess
!= err
)
1705 compressedSize
+= pageCompressedSize
;
1706 if (pageCompressedSize
)
1707 uncompressedSize
+= page_size
;
1711 if (0 == (8191 & pagesDone
))
1713 clock_get_uptime(&endTime
);
1714 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1715 absolutetime_to_nanoseconds(endTime
, &nsec
);
1716 progressStamp
= nsec
/ 750000000ULL;
1717 if (progressStamp
!= lastProgressStamp
)
1719 lastProgressStamp
= progressStamp
;
1720 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1724 if (kIOReturnSuccess
!= err
)
1726 if (iterDone
&& !pageType
)
1728 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1729 if (kIOReturnSuccess
!= err
)
1735 image1Size
= vars
->fileVars
->position
;
1738 bcopy(&cryptvars
->aes_iv
[0],
1739 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1740 sizeof(cryptvars
->aes_iv
));
1741 cryptvars
= &gIOHibernateCryptWakeContext
;
1743 HIBLOG("image1Size %qd\n", image1Size
);
1747 if (kIOReturnSuccess
!= err
)
1749 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1750 if (kIOReturnSuccess
!= err
)
1755 header
->imageSize
= vars
->fileVars
->position
;
1756 header
->image1Size
= image1Size
;
1757 header
->bitmapSize
= bitmap_size
;
1758 header
->pageCount
= pageCount
;
1759 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1761 header
->restore1Sum
= restore1Sum
;
1762 header
->image1Sum
= sum1
;
1763 header
->image2Sum
= sum2
;
1765 count
= vars
->fileExtents
->getLength();
1766 if (count
> sizeof(header
->fileExtentMap
))
1768 header
->fileExtentMapSize
= count
;
1769 count
= sizeof(header
->fileExtentMap
);
1772 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1773 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1775 IOPolledFileSeek(vars
->fileVars
, 0);
1776 err
= IOPolledFileWrite(vars
->fileVars
,
1777 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1779 if (kIOReturnSuccess
!= err
)
1781 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1782 if (kIOReturnSuccess
!= err
)
1784 err
= IOHibernatePollerIODone(vars
->fileVars
);
1785 if (kIOReturnSuccess
!= err
)
1790 clock_get_uptime(&endTime
);
1791 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1792 absolutetime_to_nanoseconds(endTime
, &nsec
);
1793 HIBLOG("all time: %qd ms, ",
1796 absolutetime_to_nanoseconds(compTime
, &nsec
);
1797 HIBLOG("comp time: %qd ms, ",
1800 absolutetime_to_nanoseconds(decoTime
, &nsec
);
1801 HIBLOG("deco time: %qd ms, ",
1804 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1806 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
1807 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
1811 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
1813 HIBLOG("hibernate_write_image done(%x)\n", err
);
1815 // should we come back via regular wake, set the state in memory.
1816 gIOHibernateState
= kIOHibernateStateInactive
;
1818 if ((kIOReturnSuccess
== err
) && !(kIOHibernateModeSleep
& gIOHibernateMode
))
1819 return (true /* power down */ );
1821 return (false /* sleep */ );
1824 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1826 DECLARE_IOHIBERNATEPROGRESSALPHA
1829 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1831 uint32_t rowBytes
, pixelShift
;
1833 int32_t blob
, lastBlob
;
1834 uint32_t alpha
, in
, color
, result
;
1836 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1838 pixelShift
= display
->depth
>> 4;
1842 rowBytes
= display
->rowBytes
;
1844 screen
+= ((display
->width
1845 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1846 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1848 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1850 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1852 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1854 out
= screen
+ y
* rowBytes
;
1855 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1857 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1858 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1860 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1866 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1867 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1869 if (1 == pixelShift
)
1872 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1875 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1877 out
+= (1 << pixelShift
);
1879 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1884 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1887 hibernate_machine_init(void)
1892 AbsoluteTime allTime
, endTime
;
1894 uint32_t lastProgressStamp
= 0;
1895 uint32_t progressStamp
;
1896 uint64_t progressZeroPosition
= 0;
1897 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1898 hibernate_cryptvars_t
* cryptvars
= 0;
1900 IOHibernateVars
* vars
= &gIOHibernateVars
;
1902 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1905 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
1906 hibernate_page_list_discard(vars
->page_list
);
1909 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
1910 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
1912 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1913 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
1914 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
1916 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
1918 HIBLOG("regular wake\n");
1922 HIBPRINT("diag %x %x %x %x\n",
1923 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
1924 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
1926 HIBPRINT("video %lx %ld %ld %ld\n",
1927 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
1928 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1930 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
1932 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
1933 * gIOHibernateGraphicsInfo
->rowBytes
);
1934 IOMapPages(kernel_map
,
1935 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
1936 vars
->videoMapSize
, kIOMapInhibitCache
);
1939 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();;
1940 uint32_t decoOffset
;
1942 clock_get_uptime(&allTime
);
1944 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
1945 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
1946 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1948 if (gIOHibernateCurrentHeader
->previewSize
)
1949 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
1950 + gIOHibernateCurrentHeader
->fileExtentMapSize
1951 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
1952 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
1954 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
1956 if (vars
->videoMapping
)
1958 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
1959 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
1960 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
1963 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
1964 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1966 cryptvars
= &gIOHibernateCryptWakeContext
;
1967 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
1968 &cryptvars
->aes_iv
[0],
1969 sizeof(cryptvars
->aes_iv
));
1972 // kick off the read ahead
1973 vars
->fileVars
->io
= false;
1974 vars
->fileVars
->bufferHalf
= 0;
1975 vars
->fileVars
->bufferLimit
= 0;
1976 vars
->fileVars
->lastRead
= 0;
1977 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1979 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
1980 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1983 HIBLOG("hibernate_machine_init reading\n");
1985 uint32_t * header
= (uint32_t *) src
;
1993 vm_offset_t ppnum
, compressedSize
;
1995 IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2000 // HIBPRINT("(%x, %x)\n", ppnum, count);
2005 for (page
= 0; page
< count
; page
++)
2007 IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2009 compressedSize
= kIOHibernateTagLength
& tag
;
2010 if (!compressedSize
)
2017 IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2019 if (compressedSize
!= page_size
)
2021 decoOffset
= page_size
;
2022 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2027 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2029 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2031 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum
, err
);
2036 if (vars
->videoMapping
&& (0 == (255 & pagesDone
)))
2038 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2039 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2040 if (blob
!= lastBlob
)
2042 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2047 if (0 == (8191 & pagesDone
))
2049 clock_get_uptime(&endTime
);
2050 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2051 absolutetime_to_nanoseconds(endTime
, &nsec
);
2052 progressStamp
= nsec
/ 750000000ULL;
2053 if (progressStamp
!= lastProgressStamp
)
2055 lastProgressStamp
= progressStamp
;
2056 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2057 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2064 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2066 if (vars
->fileVars
->io
)
2067 (void) IOHibernatePollerIODone(vars
->fileVars
);
2069 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2071 if (vars
->videoMapping
)
2072 ProgressUpdate(gIOHibernateGraphicsInfo
,
2073 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2075 clock_get_uptime(&endTime
);
2076 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2077 absolutetime_to_nanoseconds(endTime
, &nsec
);
2079 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2080 pagesDone
, sum
, nsec
/ 1000000ULL);
2083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */