2 * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
35 (devices awake, normal execution context)
36 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
37 grabs its extents and searches for a polling driver willing to work with that IOMedia.
38 The BSD code makes an ioctl to the storage driver to get the partition base offset to
39 the disk, and other ioctls to get the transfer constraints
40 If successful, the file is written to make sure its initially not bootable (in case of
41 later failure) and nvram set to point to the first block of the file. (Has to be done
42 here so blocking is possible in nvram support).
43 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
44 page out any pages it wants to (currently zero, but probably some percentage of memory).
45 Its assumed just allocating pages will cause the VM system to naturally select the best
46 pages for eviction. It also copies processor flags needed for the restore path and sets
47 a flag in the boot processor proc info.
48 gIOHibernateState = kIOHibernateStateHibernating.
49 - Regular sleep progresses - some drivers may inspect the root domain property
50 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
51 as usual but leaves motherboard I/O on.
52 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
53 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
54 all ppc RC bits out of the hash table and caches into the mapping structures.
55 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
56 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
57 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
58 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
59 The image header and block list are written. The header includes the second file extent so
60 only the header block is needed to read the file, regardless of filesystem.
61 The kernel 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
;
201 #if defined(__i386__) || defined(__x86_64__)
202 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
205 static IOPolledFileIOVars gFileVars
;
206 static IOHibernateVars gIOHibernateVars
;
207 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
208 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
210 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
212 enum { kXPRamAudioVolume
= 8 };
213 enum { kDefaultIOSize
= 128 * 1024 };
214 enum { kVideoMapSize
= 32 * 1024 * 1024 };
216 #ifndef kIOMediaPreferredBlockSizeKey
217 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
220 #ifndef kIOBootPathKey
221 #define kIOBootPathKey "bootpath"
223 #ifndef kIOSelectedBootDeviceKey
224 #define kIOSelectedBootDeviceKey "boot-device"
228 enum { kIOHibernateMinPollersNeeded
= 2 };
230 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
232 // copy from phys addr to MD
235 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
236 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
238 addr64_t srcAddr
= bytes
;
239 IOByteCount remaining
;
241 remaining
= length
= min(length
, md
->getLength() - offset
);
242 while (remaining
) { // (process another target segment?)
246 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
250 // Clip segment length to remaining
251 if (dstLen
> remaining
)
255 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
257 copypv(srcAddr
, dstAddr64
, dstLen
,
258 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
267 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
270 // copy from MD to phys addr
273 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
274 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
276 addr64_t dstAddr
= bytes
;
277 IOByteCount remaining
;
279 remaining
= length
= min(length
, md
->getLength() - offset
);
280 while (remaining
) { // (process another target segment?)
284 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
288 // Clip segment length to remaining
289 if (dstLen
> remaining
)
293 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
295 copypv(srcAddr
, dstAddr64
, dstLen
,
296 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
305 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
308 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
311 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
312 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
317 case kIOHibernatePageStateUnwiredSave
:
319 for (; ppnum
< count
; ppnum
++)
321 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
322 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
325 case kIOHibernatePageStateWiredSave
:
327 for (; ppnum
< count
; ppnum
++)
329 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
330 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
333 case kIOHibernatePageStateFree
:
335 for (; ppnum
< count
; ppnum
++)
337 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
338 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
342 panic("hibernate_set_page_state");
347 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
349 uint32_t page
= *pPage
;
351 hibernate_bitmap_t
* bitmap
;
353 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
355 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
359 if (page
<= bitmap
->last_page
)
365 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
375 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
377 IOReturn err
= kIOReturnError
;
379 IOPolledInterface
* poller
;
381 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
383 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
384 err
= poller
->probe(target
);
387 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
396 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
398 IOReturn err
= kIOReturnError
;
400 IOPolledInterface
* poller
;
402 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
404 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
405 err
= poller
->open(state
, md
);
408 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
417 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
419 IOReturn err
= kIOReturnError
;
421 IOPolledInterface
* poller
;
424 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
427 err
= poller
->close(state
);
429 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
436 IOHibernatePollerIOComplete(void * target
,
439 UInt64 actualByteCount
)
441 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
443 vars
->ioStatus
= status
;
447 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
448 uint32_t operation
, uint32_t bufferOffset
,
449 uint64_t deviceOffset
, uint64_t length
)
452 IOReturn err
= kIOReturnError
;
453 IOPolledInterface
* poller
;
454 IOPolledCompletion completion
;
456 completion
.target
= 0;
457 completion
.action
= &IOHibernatePollerIOComplete
;
458 completion
.parameter
= vars
;
462 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
463 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
465 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
471 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
, bool abortable
)
473 IOReturn err
= kIOReturnSuccess
;
475 IOPolledInterface
* poller
;
477 while (-1 == vars
->ioStatus
)
480 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
484 newErr
= poller
->checkForWork();
485 if ((newErr
== kIOReturnAborted
) && !abortable
)
486 newErr
= kIOReturnSuccess
;
487 if (kIOReturnSuccess
== err
)
494 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
498 err
= vars
->ioStatus
;
499 if (kIOReturnSuccess
!= err
)
500 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
507 IOPolledInterface::checkAllForWork(void)
509 IOReturn err
= kIOReturnNotReady
;
511 IOPolledInterface
* poller
;
513 IOHibernateVars
* vars
= &gIOHibernateVars
;
515 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
519 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
522 err
= poller
->checkForWork();
524 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
530 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
532 struct _OpenFileContext
539 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
541 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
542 IOPolledFileExtent extent
;
544 extent
.start
= start
;
545 extent
.length
= length
;
547 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
552 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
553 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
556 IOReturn err
= kIOReturnError
;
557 IOPolledFileIOVars
* vars
;
558 _OpenFileContext ctx
;
559 OSData
* extentsData
;
561 IORegistryEntry
* part
= 0;
562 OSDictionary
* matching
;
564 dev_t hibernate_image_dev
;
570 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
571 if (sizeof(IOHibernateImageHeader
) != 512)
575 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
576 vars
->bufferHalf
= 0;
577 vars
->bufferOffset
= 0;
578 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
580 extentsData
= OSData::withCapacity(32);
582 ctx
.extents
= extentsData
;
584 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
585 &file_extent_callback
, &ctx
,
586 &hibernate_image_dev
,
591 err
= kIOReturnNoSpace
;
594 gIOHibernateFileRef
= vars
->fileRef
;
595 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
596 vars
->block0
, maxiobytes
);
597 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
599 err
= kIOReturnNoSpace
;
603 if (maxiobytes
< vars
->bufferSize
)
604 vars
->bufferSize
= maxiobytes
;
606 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
608 matching
= IOService::serviceMatching("IOMedia");
609 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
610 matching
->setObject(kIOBSDMajorKey
, num
);
612 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
613 matching
->setObject(kIOBSDMinorKey
, num
);
615 iter
= IOService::getMatchingServices(matching
);
619 part
= (IORegistryEntry
*) iter
->getNextObject();
627 IORegistryEntry
* next
;
628 IORegistryEntry
* child
;
631 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
634 major
= num
->unsigned32BitValue();
635 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
638 minor
= num
->unsigned32BitValue();
640 hibernate_image_dev
= makedev(major
, minor
);
642 vars
->pollers
= OSArray::withCapacity(4);
646 vars
->blockSize
= 512;
650 IOPolledInterface
* poller
;
653 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
654 if (kOSBooleanFalse
== obj
)
656 vars
->pollers
->flushCollection();
659 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
660 vars
->pollers
->setObject(poller
);
661 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
662 vars
->blockSize
= num
->unsigned32BitValue();
665 while ((next
= child
->getParentEntry(gIOServicePlane
))
666 && child
->isParent(next
, gIOServicePlane
, true));
668 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
669 major
, minor
, (long)vars
->blockSize
, vars
->pollers
->getCount());
670 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
673 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
674 if (kIOReturnSuccess
!= err
)
677 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
678 if (kIOReturnSuccess
!= err
)
682 *fileExtents
= extentsData
;
686 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
690 #if defined(__i386__) || defined(__x86_64__)
691 if (!gIOCreateEFIDevicePathSymbol
)
692 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
694 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
696 err
= IOService::getPlatform()->callPlatformFunction(
697 gIOCreateEFIDevicePathSymbol
, false,
698 (void *) part
, (void *) str2
, (void *) true,
702 int len
= sizeof(str1
);
704 if (!part
->getPath(str1
, &len
, gIODTPlane
))
705 err
= kIOReturnNotFound
;
708 snprintf(str2
, sizeof(str2
), ",%qx", vars
->extentMap
[0].start
);
709 // (strip the plane name)
710 char * tail
= strchr(str1
, ':');
713 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
714 data
->appendBytes(str2
, strlen(str2
));
717 if (kIOReturnSuccess
== err
)
720 HIBLOG("error 0x%x getting path\n", err
);
725 if (kIOReturnSuccess
!= err
)
727 HIBLOG("error 0x%x opening hibernation file\n", err
);
730 kern_close_file_for_direct_io(vars
->fileRef
);
731 gIOHibernateFileRef
= vars
->fileRef
= NULL
;
742 IOPolledFileClose( IOPolledFileIOVars
* vars
)
746 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
747 vars
->pollers
->release();
750 bzero(vars
, sizeof(IOPolledFileIOVars
));
752 return (kIOReturnSuccess
);
756 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
758 IOPolledFileExtent
* extentMap
;
760 extentMap
= vars
->extentMap
;
762 vars
->position
= position
;
764 while (position
>= extentMap
->length
)
766 position
-= extentMap
->length
;
770 vars
->currentExtent
= extentMap
;
771 vars
->extentRemaining
= extentMap
->length
- position
;
772 vars
->extentPosition
= vars
->position
- position
;
774 if (vars
->bufferSize
<= vars
->extentRemaining
)
775 vars
->bufferLimit
= vars
->bufferSize
;
777 vars
->bufferLimit
= vars
->extentRemaining
;
779 return (kIOReturnSuccess
);
783 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
784 const uint8_t * bytes
, IOByteCount size
,
785 hibernate_cryptvars_t
* cryptvars
)
787 IOReturn err
= kIOReturnSuccess
;
795 // seek to end of block & flush
796 size
= vars
->position
& (vars
->blockSize
- 1);
798 size
= vars
->blockSize
- size
;
800 // use some garbage for the fill
801 bytes
= vars
->buffer
+ vars
->bufferOffset
;
804 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
812 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
816 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
819 vars
->bufferOffset
+= copy
;
820 vars
->position
+= copy
;
822 if (flush
&& vars
->bufferOffset
)
824 uint64_t offset
= (vars
->position
- vars
->bufferOffset
825 - vars
->extentPosition
+ vars
->currentExtent
->start
);
826 uint32_t length
= (vars
->bufferOffset
);
829 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
831 uint32_t encryptLen
, encryptStart
;
832 encryptLen
= vars
->position
- vars
->encryptStart
;
833 if (encryptLen
> length
)
835 encryptStart
= length
- encryptLen
;
837 // encrypt the buffer
838 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
839 &cryptvars
->aes_iv
[0],
840 encryptLen
/ AES_BLOCK_SIZE
,
841 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
842 &cryptvars
->ctx
.encrypt
);
843 // save initial vector for following encrypts
844 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
845 &cryptvars
->aes_iv
[0],
852 err
= IOHibernatePollerIODone(vars
, true);
853 if (kIOReturnSuccess
!= err
)
857 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
858 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
860 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
861 if (kIOReturnSuccess
!= err
)
865 vars
->extentRemaining
-= vars
->bufferOffset
;
866 if (!vars
->extentRemaining
)
868 vars
->currentExtent
++;
869 vars
->extentRemaining
= vars
->currentExtent
->length
;
870 vars
->extentPosition
= vars
->position
;
871 if (!vars
->extentRemaining
)
873 err
= kIOReturnOverrun
;
878 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
879 vars
->bufferOffset
= 0;
880 if (vars
->bufferSize
<= vars
->extentRemaining
)
881 vars
->bufferLimit
= vars
->bufferSize
;
883 vars
->bufferLimit
= vars
->extentRemaining
;
894 IOPolledFileRead(IOPolledFileIOVars
* vars
,
895 uint8_t * bytes
, IOByteCount size
,
896 hibernate_cryptvars_t
* cryptvars
)
898 IOReturn err
= kIOReturnSuccess
;
901 // bytesWritten += size;
905 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
911 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
915 vars
->bufferOffset
+= copy
;
916 // vars->position += copy;
918 if (vars
->bufferOffset
== vars
->bufferLimit
)
922 err
= IOHibernatePollerIODone(vars
, false);
923 if (kIOReturnSuccess
!= err
)
929 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
931 vars
->position
+= vars
->lastRead
;
932 vars
->extentRemaining
-= vars
->lastRead
;
933 vars
->bufferLimit
= vars
->lastRead
;
935 if (!vars
->extentRemaining
)
937 vars
->currentExtent
++;
938 vars
->extentRemaining
= vars
->currentExtent
->length
;
939 vars
->extentPosition
= vars
->position
;
940 if (!vars
->extentRemaining
)
942 err
= kIOReturnOverrun
;
948 uint64_t lastReadLength
= vars
->lastRead
;
949 uint64_t offset
= (vars
->position
950 - vars
->extentPosition
+ vars
->currentExtent
->start
);
951 if (vars
->extentRemaining
<= vars
->bufferSize
)
952 length
= vars
->extentRemaining
;
954 length
= vars
->bufferSize
;
955 vars
->lastRead
= length
;
957 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
959 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
960 if (kIOReturnSuccess
!= err
)
964 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
965 vars
->bufferOffset
= 0;
970 uint8_t thisVector
[AES_BLOCK_SIZE
];
971 // save initial vector for following decrypts
972 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
973 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
974 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
975 // decrypt the buffer
976 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
978 lastReadLength
/ AES_BLOCK_SIZE
,
979 vars
->buffer
+ vars
->bufferHalf
,
980 &cryptvars
->ctx
.decrypt
);
990 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
993 IOHibernateSystemSleep(void)
1000 OSDictionary
*sleepOverrideOptions
;
1002 IOHibernateVars
* vars
= &gIOHibernateVars
;
1004 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
1005 // already on the way down
1006 return (kIOReturnSuccess
);
1008 gIOHibernateState
= kIOHibernateStateInactive
;
1010 gIOHibernateDebugFlags
= 0;
1011 if (kIOLogHibernate
& gIOKitDebug
)
1012 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
1014 /* The invocation of IOPMSleepSystemWithOptions() may override
1015 * existing hibernation settings.
1017 sleepOverrideOptions
= (OSDictionary
*)OSDynamicCast( OSDictionary
,
1018 IOService::getPMRootDomain()->copyProperty(kRootDomainSleepOptionsKey
));
1021 /* Hibernate mode overriden by sleep otions ? */
1024 if (sleepOverrideOptions
) {
1025 obj
= sleepOverrideOptions
->getObject(kIOHibernateModeKey
);
1026 if (obj
) obj
->retain();
1030 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
);
1033 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)) )
1035 gIOHibernateMode
= num
->unsigned32BitValue();
1036 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1037 // default to discard clean for safe sleep
1038 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
1039 | kIOHibernateModeDiscardCleanActive
);
1042 if (obj
) obj
->release();
1044 /* Hibernate free rotio overriden by sleep options ? */
1047 if (sleepOverrideOptions
) {
1048 obj
= sleepOverrideOptions
->getObject(kIOHibernateFreeRatioKey
);
1049 if (obj
) obj
->retain();
1053 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
);
1055 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
1057 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
1059 if (obj
) obj
->release();
1061 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
1063 if ((num
= OSDynamicCast(OSNumber
, obj
)))
1064 gIOHibernateFreeTime
= num
->unsigned32BitValue();
1067 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1069 if ((str
= OSDynamicCast(OSString
, obj
)))
1070 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1071 sizeof(gIOHibernateFilename
));
1075 if (sleepOverrideOptions
)
1076 sleepOverrideOptions
->release();
1078 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1079 return (kIOReturnUnsupported
);
1081 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1086 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1087 4 * page_size
, page_size
);
1088 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1089 2 * kDefaultIOSize
, page_size
);
1091 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
1093 err
= kIOReturnNoMemory
;
1097 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1098 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1099 if (KERN_SUCCESS
!= err
)
1101 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1104 if (vars
->fileVars
->fileRef
)
1106 // invalidate the image file
1107 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1108 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1109 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1110 if (KERN_SUCCESS
!= err
)
1111 HIBLOG("kern_write_file(%d)\n", err
);
1114 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1115 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1117 boolean_t encryptedswap
;
1118 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1119 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1120 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1121 if (KERN_SUCCESS
!= err
)
1123 HIBLOG("hibernate_setup(%d)\n", err
);
1128 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1130 vars
->videoAllocSize
= kVideoMapSize
;
1131 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1132 vars
->videoMapping
= 0;
1134 // generate crypt keys
1135 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1136 vars
->wiredCryptKey
[i
] = random();
1137 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1138 vars
->cryptKey
[i
] = random();
1142 IORegistryEntry
* regEntry
;
1143 if (!gIOOptionsEntry
)
1145 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1146 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1147 if (regEntry
&& !gIOOptionsEntry
)
1148 regEntry
->release();
1150 if (!gIOChosenEntry
)
1151 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1153 if (gIOOptionsEntry
)
1155 const OSSymbol
* sym
;
1157 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1160 gIOOptionsEntry
->setProperty(sym
, data
);
1165 #if defined(__ppc__)
1167 char valueString
[16];
1169 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1172 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1175 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1176 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1178 gIOOptionsEntry
->setProperty(sym
, str2
);
1184 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1187 vars
->haveFastBoot
= true;
1189 len
= snprintf(valueString
, sizeof(valueString
), "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1190 data
= OSData::withBytes(valueString
, len
+ 1);
1191 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1193 gIOOptionsEntry
->setProperty(sym
, data
);
1199 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1201 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1203 #endif /* __ppc__ */
1204 #if defined(__i386__) || defined(__x86_64__)
1205 struct AppleRTCHibernateVars
1207 uint8_t signature
[4];
1209 uint8_t booterSignature
[20];
1210 uint8_t wiredCryptKey
[16];
1212 AppleRTCHibernateVars rtcVars
;
1214 rtcVars
.signature
[0] = 'A';
1215 rtcVars
.signature
[1] = 'A';
1216 rtcVars
.signature
[2] = 'P';
1217 rtcVars
.signature
[3] = 'L';
1218 rtcVars
.revision
= 1;
1219 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1220 if (gIOHibernateBootSignature
[0])
1224 for (uint32_t i
= 0;
1225 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1236 value
= (value
<< 4) | c
;
1238 rtcVars
.booterSignature
[i
>> 1] = value
;
1241 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1244 IOService::getPMRootDomain()->setProperty(kIOHibernateRTCVariablesKey
, data
);
1246 if( gIOOptionsEntry
)
1248 if( gIOHibernateMode
& kIOHibernateModeSwitch
)
1250 const OSSymbol
*sym
;
1251 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey
);
1254 gIOOptionsEntry
->setProperty(sym
, data
); /* intentional insecure backup of rtc boot vars */
1264 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1266 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1268 #else /* !i386 && !x86_64 */
1269 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1271 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1272 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1274 gIOOptionsEntry
->setProperty(sym
, data
);
1279 if (false && gIOHibernateBootSignature
[0])
1281 data
= OSData::withCapacity(16);
1282 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1287 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1297 value
= (value
<< 4) | c
;
1299 data
->appendBytes(&value
, sizeof(value
));
1301 gIOOptionsEntry
->setProperty(sym
, data
);
1309 if (!vars
->haveFastBoot
)
1311 // set boot volume to zero
1312 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1313 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1314 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1317 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1318 platform
->writeXPRAM(kXPRamAudioVolume
,
1319 &newVolume
, sizeof(newVolume
));
1322 #endif /* !i386 && !x86_64 */
1326 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1327 gIOHibernateState
= kIOHibernateStateHibernating
;
1334 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1336 DECLARE_IOHIBERNATEPROGRESSALPHA
1339 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
1341 uint32_t rowBytes
, pixelShift
;
1344 uint32_t alpha
, in
, color
, result
;
1346 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1348 rowBytes
= display
->rowBytes
;
1349 pixelShift
= display
->depth
>> 4;
1350 if (pixelShift
< 1) return;
1352 screen
+= ((display
->width
1353 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1354 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1356 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1358 out
= screen
+ y
* rowBytes
;
1359 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
1361 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
1362 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1364 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1370 if (1 == pixelShift
)
1372 in
= *((uint16_t *)out
) & 0x1f; // 16
1373 in
= (in
<< 3) | (in
>> 2);
1376 in
= *((uint32_t *)out
) & 0xff; // 32
1377 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1378 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1380 if (1 == pixelShift
)
1383 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1386 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1388 out
+= (1 << pixelShift
);
1390 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1397 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1399 uint32_t rowBytes
, pixelShift
;
1401 int32_t blob
, lastBlob
;
1402 uint32_t alpha
, in
, color
, result
;
1404 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1406 pixelShift
= display
->depth
>> 4;
1410 rowBytes
= display
->rowBytes
;
1412 screen
+= ((display
->width
1413 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1414 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1416 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1418 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1420 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1422 out
= screen
+ y
* rowBytes
;
1423 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1425 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1426 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1428 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1434 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1435 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1437 if (1 == pixelShift
)
1440 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1443 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1445 out
+= (1 << pixelShift
);
1447 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1452 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1455 IOHibernateSystemHasSlept(void)
1457 IOHibernateVars
* vars
= &gIOHibernateVars
;
1461 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1462 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1463 if (obj
&& !vars
->previewBuffer
)
1466 vars
->consoleMapping
= NULL
;
1467 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1469 vars
->previewBuffer
->release();
1470 vars
->previewBuffer
= 0;
1473 if (vars
->previewBuffer
&& (data
= OSDynamicCast(OSData
,
1474 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1476 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1477 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1479 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1481 if (kIOHibernatePreviewUpdates
& flags
)
1483 PE_Video consoleInfo
;
1484 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1486 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1488 graphicsInfo
->width
= consoleInfo
.v_width
;
1489 graphicsInfo
->height
= consoleInfo
.v_height
;
1490 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1491 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1492 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1494 HIBPRINT("video %p %d %d %d\n",
1495 vars
->consoleMapping
, gIOHibernateGraphicsInfo
->depth
,
1496 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1497 if (vars
->consoleMapping
)
1498 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1499 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1503 if (gIOOptionsEntry
)
1504 gIOOptionsEntry
->sync();
1506 return (kIOReturnSuccess
);
1509 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1512 IOHibernateSystemWake(void)
1514 IOHibernateVars
* vars
= &gIOHibernateVars
;
1516 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1518 if (vars
->videoMapping
)
1520 if (vars
->videoMapSize
)
1522 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1523 if (vars
->videoAllocSize
)
1525 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1528 if (vars
->previewBuffer
)
1530 vars
->previewBuffer
->release();
1531 vars
->previewBuffer
= 0;
1536 IOPolledFileClose(vars
->fileVars
);
1539 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1542 OSData
* data
= OSData::withCapacity(4);
1543 if (gIOOptionsEntry
&& data
)
1545 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1548 gIOOptionsEntry
->setProperty(sym
, data
);
1551 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1554 if (vars
->saveBootDevice
)
1556 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1557 vars
->saveBootDevice
->release();
1561 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1564 gIOOptionsEntry
->setProperty(sym
, data
);
1567 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1570 gIOOptionsEntry
->removeProperty(sym
);
1577 if (gIOOptionsEntry
)
1579 if (!vars
->haveFastBoot
)
1581 // reset boot audio volume
1582 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1584 platform
->writeXPRAM(kXPRamAudioVolume
,
1585 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1588 // sync now to hardware if the booter has not
1589 if (kIOHibernateStateInactive
== gIOHibernateState
)
1590 gIOOptionsEntry
->sync();
1592 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1593 gIOOptionsEntry
->syncOFVariables();
1597 #if defined(__i386__) || defined(__x86_64__)
1598 IOService::getPMRootDomain()->removeProperty(kIOHibernateRTCVariablesKey
);
1601 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1602 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1604 if (gIOOptionsEntry
) {
1605 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1608 if (gIOOptionsEntry
->getProperty(sym
)) {
1609 gIOOptionsEntry
->removeProperty(sym
);
1610 gIOOptionsEntry
->sync();
1617 if (vars
->srcBuffer
)
1618 vars
->srcBuffer
->release();
1620 vars
->ioBuffer
->release();
1621 if (vars
->fileExtents
)
1622 vars
->fileExtents
->release();
1624 bzero(vars
, sizeof(*vars
));
1626 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1628 return (kIOReturnSuccess
);
1632 IOHibernateSystemPostWake(void)
1634 if (gIOHibernateFileRef
)
1636 // invalidate the image file
1637 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1638 int err
= kern_write_file(gIOHibernateFileRef
, 0,
1639 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1640 if (KERN_SUCCESS
!= err
)
1641 HIBLOG("kern_write_file(%d)\n", err
);
1643 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1644 gIOHibernateFileRef
= 0;
1646 return (kIOReturnSuccess
);
1649 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1651 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1652 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1653 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1654 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1655 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1656 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1657 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1658 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1659 &gIOHibernateMode
, 0, "");
1662 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1664 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1667 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1671 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1672 gIOHibernateMode
= kIOHibernateModeOn
;
1674 gIOHibernateFilename
[0] = 0;
1676 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1677 sysctl_register_oid(&sysctl__kern_bootsignature
);
1678 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1682 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1685 hibernate_setup_for_wake(void)
1688 // go slow (state needed for wake)
1689 ml_set_processor_speed(1);
1693 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1695 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1698 hibernate_write_image(void)
1700 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1701 IOHibernateVars
* vars
= &gIOHibernateVars
;
1702 IOPolledFileExtent
* fileExtents
;
1704 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
1706 uint32_t pageCount
, pagesDone
;
1709 IOItemCount page
, count
;
1712 IOByteCount pageCompressedSize
;
1713 uint64_t compressedSize
, uncompressedSize
;
1714 uint64_t image1Size
= 0;
1715 uint32_t bitmap_size
;
1716 bool iterDone
, pollerOpen
, needEncryptStart
;
1717 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1720 uint32_t pageAndCount
[2];
1722 AbsoluteTime startTime
, endTime
;
1723 AbsoluteTime allTime
, compTime
, decoTime
;
1725 uint32_t lastProgressStamp
= 0;
1726 uint32_t progressStamp
;
1727 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1729 hibernate_cryptvars_t _cryptvars
;
1730 hibernate_cryptvars_t
* cryptvars
= 0;
1732 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1733 return (false /* sleep */ );
1735 restore1Sum
= sum1
= sum2
= 0;
1738 // encryption data. "iv" is the "initial vector".
1739 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1741 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1742 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1743 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1745 cryptvars
= &gIOHibernateCryptWakeContext
;
1746 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1747 aes_encrypt_key(vars
->cryptKey
,
1748 kIOHibernateAESKeySize
,
1749 &cryptvars
->ctx
.encrypt
);
1750 aes_decrypt_key(vars
->cryptKey
,
1751 kIOHibernateAESKeySize
,
1752 &cryptvars
->ctx
.decrypt
);
1754 cryptvars
= &_cryptvars
;
1755 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1756 aes_encrypt_key(vars
->wiredCryptKey
,
1757 kIOHibernateAESKeySize
,
1758 &cryptvars
->ctx
.encrypt
);
1760 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1761 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1762 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1763 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1767 hibernate_setup_for_wake();
1769 hibernate_page_list_setall(vars
->page_list
,
1770 vars
->page_list_wired
,
1773 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1775 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1778 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1779 for (page
= 0; page
< count
; page
++)
1781 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1782 fileExtents
[page
].start
, fileExtents
[page
].length
,
1783 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1787 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1789 AbsoluteTime_to_scalar(&compTime
) = 0;
1790 AbsoluteTime_to_scalar(&decoTime
) = 0;
1792 clock_get_uptime(&allTime
);
1793 IOService::getPMRootDomain()->pmStatsRecordEvent(
1794 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1799 uncompressedSize
= 0;
1801 pageType
= 0; // wired pages first
1803 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1805 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1806 ml_get_interrupts_enabled());
1807 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1808 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1809 pollerOpen
= (kIOReturnSuccess
== err
);
1813 // copy file block extent list if larger than header
1815 count
= vars
->fileExtents
->getLength();
1816 if (count
> sizeof(header
->fileExtentMap
))
1818 count
-= sizeof(header
->fileExtentMap
);
1819 err
= IOPolledFileWrite(vars
->fileVars
,
1820 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1821 if (kIOReturnSuccess
!= err
)
1825 uintptr_t hibernateBase
;
1826 uintptr_t hibernateEnd
;
1828 #if defined(__i386__) || defined(__x86_64__)
1829 hibernateBase
= sectINITPTB
;
1831 hibernateBase
= sectHIBB
;
1834 hibernateEnd
= (sectHIBB
+ sectSizeHIB
);
1835 // copy out restore1 code
1837 page
= atop_32(hibernateBase
);
1838 count
= atop_32(round_page(hibernateEnd
)) - page
;
1839 header
->restore1CodePage
= page
;
1840 header
->restore1PageCount
= count
;
1841 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1842 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1844 // sum __HIB sect, with zeros for the stack
1845 src
= (uint8_t *) trunc_page(hibernateBase
);
1846 for (page
= 0; page
< count
; page
++)
1848 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1849 restore1Sum
+= hibernate_sum(src
, page_size
);
1851 restore1Sum
+= 0x10000001;
1856 // write the __HIB sect, with zeros for the stack
1858 src
= (uint8_t *) trunc_page(hibernateBase
);
1859 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1862 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1863 if (kIOReturnSuccess
!= err
)
1866 err
= IOPolledFileWrite(vars
->fileVars
,
1868 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1870 if (kIOReturnSuccess
!= err
)
1872 src
= &gIOHibernateRestoreStackEnd
[0];
1873 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1876 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1877 if (kIOReturnSuccess
!= err
)
1881 // write the preview buffer
1886 if (vars
->previewBuffer
)
1892 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1893 pageAndCount
[0] = atop_64(phys64
);
1894 pageAndCount
[1] = atop_32(segLen
);
1895 err
= IOPolledFileWrite(vars
->fileVars
,
1896 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1898 if (kIOReturnSuccess
!= err
)
1901 ppnum
+= sizeof(pageAndCount
);
1904 if (kIOReturnSuccess
!= err
)
1907 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1908 count
= vars
->previewBuffer
->getLength();
1910 header
->previewPageListSize
= ppnum
;
1911 header
->previewSize
= count
+ ppnum
;
1913 for (page
= 0; page
< count
; page
+= page_size
)
1914 sum1
+= hibernate_sum(src
+ page
, page_size
);
1916 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1917 if (kIOReturnSuccess
!= err
)
1921 // mark areas for no save
1924 (phys64
= vars
->ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1927 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1928 atop_64(phys64
), atop_32(segLen
),
1929 kIOHibernatePageStateFree
);
1930 pageCount
-= atop_32(segLen
);
1934 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1937 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1938 atop_64(phys64
), atop_32(segLen
),
1939 kIOHibernatePageStateFree
);
1940 pageCount
-= atop_32(segLen
);
1943 // copy out bitmap of pages available for trashing during restore
1945 bitmap_size
= vars
->page_list_wired
->list_size
;
1946 src
= (uint8_t *) vars
->page_list_wired
;
1947 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1948 if (kIOReturnSuccess
!= err
)
1951 // mark more areas for no save, but these are not available
1952 // for trashing during restore
1954 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1956 page
= atop_32(hibernateBase
);
1957 count
= atop_32(round_page(hibernateEnd
)) - page
;
1958 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1960 kIOHibernatePageStateFree
);
1963 if (vars
->previewBuffer
) for (count
= 0;
1964 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1967 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1968 atop_64(phys64
), atop_32(segLen
),
1969 kIOHibernatePageStateFree
);
1970 pageCount
-= atop_32(segLen
);
1973 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1979 HIBLOG("writing %d pages\n", pageCount
);
1983 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1985 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1989 pageAndCount
[0] = ppnum
;
1990 pageAndCount
[1] = count
;
1991 err
= IOPolledFileWrite(vars
->fileVars
,
1992 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1994 if (kIOReturnSuccess
!= err
)
1997 for (page
= 0; page
< count
; page
++)
1999 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
2002 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)ppnum
, err
);
2006 sum
= hibernate_sum(src
, page_size
);
2008 clock_get_uptime(&startTime
);
2010 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
2012 clock_get_uptime(&endTime
);
2013 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2014 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2016 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2017 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
2019 if (pageCompressedSize
> page_size
)
2021 // HIBLOG("------------lose: %d\n", pageCompressedSize);
2022 pageCompressedSize
= page_size
;
2025 if (pageCompressedSize
!= page_size
)
2026 data
= (src
+ page_size
);
2030 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2037 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
2039 // start encrypting partway into the data about to be written
2040 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
2041 & ~(AES_BLOCK_SIZE
- 1);
2042 needEncryptStart
= false;
2045 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2046 if (kIOReturnSuccess
!= err
)
2049 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2050 if (kIOReturnSuccess
!= err
)
2053 compressedSize
+= pageCompressedSize
;
2054 if (pageCompressedSize
)
2055 uncompressedSize
+= page_size
;
2059 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2061 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2062 if (blob
!= lastBlob
)
2064 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2068 if (0 == (8191 & pagesDone
))
2070 clock_get_uptime(&endTime
);
2071 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2072 absolutetime_to_nanoseconds(endTime
, &nsec
);
2073 progressStamp
= nsec
/ 750000000ULL;
2074 if (progressStamp
!= lastProgressStamp
)
2076 lastProgressStamp
= progressStamp
;
2077 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2081 if (kIOReturnSuccess
!= err
)
2083 if (iterDone
&& !pageType
)
2085 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2086 if (kIOReturnSuccess
!= err
)
2092 image1Size
= vars
->fileVars
->position
;
2095 bcopy(&cryptvars
->aes_iv
[0],
2096 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2097 sizeof(cryptvars
->aes_iv
));
2098 cryptvars
= &gIOHibernateCryptWakeContext
;
2100 HIBLOG("image1Size %qd\n", image1Size
);
2104 if (kIOReturnSuccess
!= err
)
2106 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2107 if (kIOReturnSuccess
!= err
)
2112 header
->imageSize
= vars
->fileVars
->position
;
2113 header
->image1Size
= image1Size
;
2114 header
->bitmapSize
= bitmap_size
;
2115 header
->pageCount
= pageCount
;
2116 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2118 header
->restore1Sum
= restore1Sum
;
2119 header
->image1Sum
= sum1
;
2120 header
->image2Sum
= sum2
;
2122 count
= vars
->fileExtents
->getLength();
2123 if (count
> sizeof(header
->fileExtentMap
))
2125 header
->fileExtentMapSize
= count
;
2126 count
= sizeof(header
->fileExtentMap
);
2129 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2130 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2132 IOPolledFileSeek(vars
->fileVars
, 0);
2133 err
= IOPolledFileWrite(vars
->fileVars
,
2134 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2136 if (kIOReturnSuccess
!= err
)
2138 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2139 if (kIOReturnSuccess
!= err
)
2141 err
= IOHibernatePollerIODone(vars
->fileVars
, true);
2142 if (kIOReturnSuccess
!= err
)
2147 clock_get_uptime(&endTime
);
2149 IOService::getPMRootDomain()->pmStatsRecordEvent(
2150 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2152 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2153 absolutetime_to_nanoseconds(endTime
, &nsec
);
2154 HIBLOG("all time: %qd ms, ",
2157 absolutetime_to_nanoseconds(compTime
, &nsec
);
2158 HIBLOG("comp time: %qd ms, ",
2161 absolutetime_to_nanoseconds(decoTime
, &nsec
);
2162 HIBLOG("deco time: %qd ms, ",
2165 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2167 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2168 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2171 if (vars
->fileVars
->io
)
2172 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2175 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
2177 if (vars
->consoleMapping
)
2178 ProgressUpdate(gIOHibernateGraphicsInfo
,
2179 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2181 HIBLOG("hibernate_write_image done(%x)\n", err
);
2183 // should we come back via regular wake, set the state in memory.
2184 gIOHibernateState
= kIOHibernateStateInactive
;
2186 if (kIOReturnSuccess
== err
)
2188 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2190 return (kIOHibernatePostWriteSleep
);
2192 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2194 return (kIOHibernatePostWriteRestart
);
2198 /* by default, power down */
2199 return (kIOHibernatePostWriteHalt
);
2202 else if (kIOReturnAborted
== err
)
2204 return (kIOHibernatePostWriteWake
);
2208 /* on error, sleep */
2209 return (kIOHibernatePostWriteSleep
);
2213 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2216 hibernate_machine_init(void)
2221 AbsoluteTime allTime
, endTime
;
2223 uint32_t lastProgressStamp
= 0;
2224 uint32_t progressStamp
;
2225 uint64_t progressZeroPosition
= 0;
2226 uint32_t blob
, lastBlob
= (uint32_t) -1L;
2227 hibernate_cryptvars_t
* cryptvars
= 0;
2229 IOHibernateVars
* vars
= &gIOHibernateVars
;
2231 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2234 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2235 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2237 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
2238 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
2239 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2241 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2243 HIBLOG("regular wake\n");
2247 HIBPRINT("diag %x %x %x %x\n",
2248 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2249 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2251 HIBPRINT("video %x %d %d %d\n",
2252 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2253 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
2255 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
2256 hibernate_page_list_discard(vars
->page_list
);
2258 boot_args
*args
= (boot_args
*) PE_state
.bootArgs
;
2260 if (vars
->videoMapping
2261 && gIOHibernateGraphicsInfo
->physicalAddress
2262 && (args
->Video
.v_baseAddr
== gIOHibernateGraphicsInfo
->physicalAddress
))
2264 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2265 * gIOHibernateGraphicsInfo
->rowBytes
);
2266 IOMapPages(kernel_map
,
2267 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2268 vars
->videoMapSize
, kIOMapInhibitCache
);
2271 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2273 if (gIOHibernateWakeMapSize
)
2275 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(gIOHibernateWakeMap
),
2276 gIOHibernateWakeMapSize
);
2277 if (kIOReturnSuccess
== err
)
2278 hibernate_newruntime_map(src
, gIOHibernateWakeMapSize
,
2279 gIOHibernateCurrentHeader
->systemTableOffset
);
2280 gIOHibernateWakeMap
= 0;
2281 gIOHibernateWakeMapSize
= 0;
2284 uint32_t decoOffset
;
2286 clock_get_uptime(&allTime
);
2288 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2289 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
2290 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2292 if (gIOHibernateCurrentHeader
->previewSize
)
2293 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
2294 + gIOHibernateCurrentHeader
->fileExtentMapSize
2295 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
2296 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
2298 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2300 if (vars
->videoMapSize
)
2302 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2303 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2304 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
2307 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2308 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2310 cryptvars
= &gIOHibernateCryptWakeContext
;
2311 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
2312 &cryptvars
->aes_iv
[0],
2313 sizeof(cryptvars
->aes_iv
));
2316 // kick off the read ahead
2317 vars
->fileVars
->io
= false;
2318 vars
->fileVars
->bufferHalf
= 0;
2319 vars
->fileVars
->bufferLimit
= 0;
2320 vars
->fileVars
->lastRead
= 0;
2321 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2323 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2324 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2327 HIBLOG("hibernate_machine_init reading\n");
2329 uint32_t * header
= (uint32_t *) src
;
2337 vm_offset_t ppnum
, compressedSize
;
2339 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2340 if (kIOReturnSuccess
!= err
)
2346 // HIBPRINT("(%x, %x)\n", ppnum, count);
2351 for (page
= 0; page
< count
; page
++)
2353 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2354 if (kIOReturnSuccess
!= err
)
2357 compressedSize
= kIOHibernateTagLength
& tag
;
2358 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2360 err
= kIOReturnIPCError
;
2364 if (!compressedSize
)
2371 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2372 if (kIOReturnSuccess
!= err
)
2375 if (compressedSize
< page_size
)
2377 decoOffset
= page_size
;
2378 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2383 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2385 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2388 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2395 if (vars
->videoMapSize
&& (0 == (1023 & pagesDone
)))
2397 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2398 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2399 if (blob
!= lastBlob
)
2401 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2406 if (0 == (8191 & pagesDone
))
2408 clock_get_uptime(&endTime
);
2409 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2410 absolutetime_to_nanoseconds(endTime
, &nsec
);
2411 progressStamp
= nsec
/ 750000000ULL;
2412 if (progressStamp
!= lastProgressStamp
)
2414 lastProgressStamp
= progressStamp
;
2415 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2416 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2423 if (kIOReturnSuccess
!= err
)
2424 panic("Hibernate restore error %x", err
);
2426 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2428 if (vars
->fileVars
->io
)
2429 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2431 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2433 if (vars
->videoMapSize
)
2434 ProgressUpdate(gIOHibernateGraphicsInfo
,
2435 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2437 clock_get_uptime(&endTime
);
2439 IOService::getPMRootDomain()->pmStatsRecordEvent(
2440 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2441 IOService::getPMRootDomain()->pmStatsRecordEvent(
2442 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2444 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2445 absolutetime_to_nanoseconds(endTime
, &nsec
);
2447 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2448 pagesDone
, sum
, nsec
/ 1000000ULL);
2451 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */