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 extern unsigned int save_kdebug_enable
;
172 extern uint32_t gIOHibernateState
;
173 uint32_t gIOHibernateMode
;
174 static char gIOHibernateBootSignature
[256+1];
175 static char gIOHibernateFilename
[MAXPATHLEN
+1];
176 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
177 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
179 static IODTNVRAM
* gIOOptionsEntry
;
180 static IORegistryEntry
* gIOChosenEntry
;
181 #if defined(__i386__) || defined(__x86_64__)
182 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
183 static const OSSymbol
* gIOHibernateRTCVariablesKey
;
184 static const OSSymbol
* gIOHibernateBoot0082Key
;
185 static const OSSymbol
* gIOHibernateBootNextKey
;
186 static OSData
* gIOHibernateBoot0082Data
;
187 static OSData
* gIOHibernateBootNextData
;
188 static OSObject
* gIOHibernateBootNextSave
;
191 static IOPolledFileIOVars gFileVars
;
192 static IOHibernateVars gIOHibernateVars
;
193 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
194 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
198 enum { kXPRamAudioVolume
= 8 };
199 enum { kDefaultIOSize
= 128 * 1024 };
200 enum { kVideoMapSize
= 32 * 1024 * 1024 };
202 #ifndef kIOMediaPreferredBlockSizeKey
203 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
206 #ifndef kIOBootPathKey
207 #define kIOBootPathKey "bootpath"
209 #ifndef kIOSelectedBootDeviceKey
210 #define kIOSelectedBootDeviceKey "boot-device"
214 enum { kIOHibernateMinPollersNeeded
= 2 };
216 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
218 // copy from phys addr to MD
221 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
222 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
224 addr64_t srcAddr
= bytes
;
225 IOByteCount remaining
;
227 remaining
= length
= min(length
, md
->getLength() - offset
);
228 while (remaining
) { // (process another target segment?)
232 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
236 // Clip segment length to remaining
237 if (dstLen
> remaining
)
241 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
243 copypv(srcAddr
, dstAddr64
, dstLen
,
244 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
253 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
256 // copy from MD to phys addr
259 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
260 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
262 addr64_t dstAddr
= bytes
;
263 IOByteCount remaining
;
265 remaining
= length
= min(length
, md
->getLength() - offset
);
266 while (remaining
) { // (process another target segment?)
270 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
274 // Clip segment length to remaining
275 if (dstLen
> remaining
)
279 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
281 copypv(srcAddr
, dstAddr64
, dstLen
,
282 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
291 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
294 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
297 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
298 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
303 case kIOHibernatePageStateUnwiredSave
:
305 for (; ppnum
< count
; ppnum
++)
307 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
308 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
311 case kIOHibernatePageStateWiredSave
:
313 for (; ppnum
< count
; ppnum
++)
315 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
316 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
319 case kIOHibernatePageStateFree
:
321 for (; ppnum
< count
; ppnum
++)
323 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
324 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
328 panic("hibernate_set_page_state");
333 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
335 uint32_t page
= *pPage
;
337 hibernate_bitmap_t
* bitmap
;
339 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
341 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
345 if (page
<= bitmap
->last_page
)
351 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
358 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
361 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
363 IOReturn err
= kIOReturnError
;
365 IOPolledInterface
* poller
;
367 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
369 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
370 err
= poller
->probe(target
);
373 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
382 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
384 IOReturn err
= kIOReturnError
;
386 IOPolledInterface
* poller
;
388 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
390 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
391 err
= poller
->open(state
, md
);
394 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
403 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
405 IOReturn err
= kIOReturnError
;
407 IOPolledInterface
* poller
;
410 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
413 err
= poller
->close(state
);
415 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
422 IOHibernatePollerIOComplete(void * target
,
425 UInt64 actualByteCount
)
427 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
429 vars
->ioStatus
= status
;
433 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
434 uint32_t operation
, uint32_t bufferOffset
,
435 uint64_t deviceOffset
, uint64_t length
)
438 IOReturn err
= kIOReturnError
;
439 IOPolledInterface
* poller
;
440 IOPolledCompletion completion
;
442 completion
.target
= 0;
443 completion
.action
= &IOHibernatePollerIOComplete
;
444 completion
.parameter
= vars
;
448 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
449 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
451 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
457 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
, bool abortable
)
459 IOReturn err
= kIOReturnSuccess
;
461 IOPolledInterface
* poller
;
463 while (-1 == vars
->ioStatus
)
466 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
470 newErr
= poller
->checkForWork();
471 if ((newErr
== kIOReturnAborted
) && !abortable
)
472 newErr
= kIOReturnSuccess
;
473 if (kIOReturnSuccess
== err
)
478 if ((kIOReturnSuccess
== err
) && abortable
&& hibernate_should_abort())
480 err
= kIOReturnAborted
;
481 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
486 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
490 err
= vars
->ioStatus
;
491 if (kIOReturnSuccess
!= err
)
492 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
499 IOPolledInterface::checkAllForWork(void)
501 IOReturn err
= kIOReturnNotReady
;
503 IOPolledInterface
* poller
;
505 IOHibernateVars
* vars
= &gIOHibernateVars
;
507 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
511 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
514 err
= poller
->checkForWork();
516 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
522 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
524 struct _OpenFileContext
531 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
533 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
534 IOPolledFileExtent extent
;
536 extent
.start
= start
;
537 extent
.length
= length
;
539 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
544 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
545 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
548 IOReturn err
= kIOReturnError
;
549 IOPolledFileIOVars
* vars
;
550 _OpenFileContext ctx
;
551 OSData
* extentsData
;
553 IORegistryEntry
* part
= 0;
554 OSDictionary
* matching
;
556 dev_t hibernate_image_dev
;
562 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
563 if (sizeof(IOHibernateImageHeader
) != 512)
567 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
568 vars
->bufferHalf
= 0;
569 vars
->bufferOffset
= 0;
570 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
572 extentsData
= OSData::withCapacity(32);
574 ctx
.extents
= extentsData
;
576 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
577 &file_extent_callback
, &ctx
,
578 &hibernate_image_dev
,
584 err
= kIOReturnNoSpace
;
587 gIOHibernateFileRef
= vars
->fileRef
;
589 if (kIOHibernateModeSSDInvert
& gIOHibernateMode
)
590 vars
->solid_state
= vars
->solid_state
? false : true;
592 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename
, ctx
.size
,
593 vars
->block0
, maxiobytes
, vars
->solid_state
);
594 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
596 err
= kIOReturnNoSpace
;
600 if (maxiobytes
< vars
->bufferSize
)
601 vars
->bufferSize
= maxiobytes
;
603 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
605 matching
= IOService::serviceMatching("IOMedia");
606 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
607 matching
->setObject(kIOBSDMajorKey
, num
);
609 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
610 matching
->setObject(kIOBSDMinorKey
, num
);
612 iter
= IOService::getMatchingServices(matching
);
616 part
= (IORegistryEntry
*) iter
->getNextObject();
624 IORegistryEntry
* next
;
625 IORegistryEntry
* child
;
628 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
631 major
= num
->unsigned32BitValue();
632 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
635 minor
= num
->unsigned32BitValue();
637 hibernate_image_dev
= makedev(major
, minor
);
639 vars
->pollers
= OSArray::withCapacity(4);
643 vars
->blockSize
= 512;
647 IOPolledInterface
* poller
;
650 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
651 if (kOSBooleanFalse
== obj
)
653 vars
->pollers
->flushCollection();
656 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
657 vars
->pollers
->setObject(poller
);
658 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
659 vars
->blockSize
= num
->unsigned32BitValue();
662 while ((next
= child
->getParentEntry(gIOServicePlane
))
663 && child
->isParent(next
, gIOServicePlane
, true));
665 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
666 major
, minor
, (long)vars
->blockSize
, vars
->pollers
->getCount());
667 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
670 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
671 if (kIOReturnSuccess
!= err
)
674 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
675 if (kIOReturnSuccess
!= err
)
679 *fileExtents
= extentsData
;
683 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
687 #if defined(__i386__) || defined(__x86_64__)
688 if (!gIOCreateEFIDevicePathSymbol
)
689 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
691 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
693 err
= IOService::getPlatform()->callPlatformFunction(
694 gIOCreateEFIDevicePathSymbol
, false,
695 (void *) part
, (void *) str2
, (void *) true,
699 int len
= sizeof(str1
);
701 if (!part
->getPath(str1
, &len
, gIODTPlane
))
702 err
= kIOReturnNotFound
;
705 snprintf(str2
, sizeof(str2
), ",%qx", vars
->extentMap
[0].start
);
706 // (strip the plane name)
707 char * tail
= strchr(str1
, ':');
710 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
711 data
->appendBytes(str2
, strlen(str2
));
714 if (kIOReturnSuccess
== err
)
717 HIBLOG("error 0x%x getting path\n", err
);
722 if (kIOReturnSuccess
!= err
)
724 HIBLOG("error 0x%x opening hibernation file\n", err
);
727 kern_close_file_for_direct_io(vars
->fileRef
);
728 gIOHibernateFileRef
= vars
->fileRef
= NULL
;
739 IOPolledFileClose( IOPolledFileIOVars
* vars
)
743 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
744 vars
->pollers
->release();
747 bzero(vars
, sizeof(IOPolledFileIOVars
));
749 return (kIOReturnSuccess
);
753 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
755 IOPolledFileExtent
* extentMap
;
757 extentMap
= vars
->extentMap
;
759 vars
->position
= position
;
761 while (position
>= extentMap
->length
)
763 position
-= extentMap
->length
;
767 vars
->currentExtent
= extentMap
;
768 vars
->extentRemaining
= extentMap
->length
- position
;
769 vars
->extentPosition
= vars
->position
- position
;
771 if (vars
->bufferSize
<= vars
->extentRemaining
)
772 vars
->bufferLimit
= vars
->bufferSize
;
774 vars
->bufferLimit
= vars
->extentRemaining
;
776 return (kIOReturnSuccess
);
780 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
781 const uint8_t * bytes
, IOByteCount size
,
782 hibernate_cryptvars_t
* cryptvars
)
784 IOReturn err
= kIOReturnSuccess
;
792 // seek to end of block & flush
793 size
= vars
->position
& (vars
->blockSize
- 1);
795 size
= vars
->blockSize
- size
;
797 // use some garbage for the fill
798 bytes
= vars
->buffer
+ vars
->bufferOffset
;
801 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
809 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
813 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
816 vars
->bufferOffset
+= copy
;
817 vars
->position
+= copy
;
819 if (flush
&& vars
->bufferOffset
)
821 uint64_t offset
= (vars
->position
- vars
->bufferOffset
822 - vars
->extentPosition
+ vars
->currentExtent
->start
);
823 uint32_t length
= (vars
->bufferOffset
);
826 if (cryptvars
&& vars
->encryptStart
827 && (vars
->position
> vars
->encryptStart
)
828 && ((vars
->position
- length
) < vars
->encryptEnd
))
830 uint32_t encryptLen
, encryptStart
;
831 encryptLen
= vars
->position
- vars
->encryptStart
;
832 if (encryptLen
> length
)
834 encryptStart
= length
- encryptLen
;
835 if (vars
->position
> vars
->encryptEnd
)
836 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
838 // encrypt the buffer
839 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
840 &cryptvars
->aes_iv
[0],
841 encryptLen
/ AES_BLOCK_SIZE
,
842 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
843 &cryptvars
->ctx
.encrypt
);
844 // save initial vector for following encrypts
845 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
846 &cryptvars
->aes_iv
[0],
853 err
= IOHibernatePollerIODone(vars
, true);
854 if (kIOReturnSuccess
!= err
)
858 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
859 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
861 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
862 if (kIOReturnSuccess
!= err
)
866 vars
->extentRemaining
-= vars
->bufferOffset
;
867 if (!vars
->extentRemaining
)
869 vars
->currentExtent
++;
870 vars
->extentRemaining
= vars
->currentExtent
->length
;
871 vars
->extentPosition
= vars
->position
;
872 if (!vars
->extentRemaining
)
874 err
= kIOReturnOverrun
;
879 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
880 vars
->bufferOffset
= 0;
881 if (vars
->bufferSize
<= vars
->extentRemaining
)
882 vars
->bufferLimit
= vars
->bufferSize
;
884 vars
->bufferLimit
= vars
->extentRemaining
;
895 IOPolledFileRead(IOPolledFileIOVars
* vars
,
896 uint8_t * bytes
, IOByteCount size
,
897 hibernate_cryptvars_t
* cryptvars
)
899 IOReturn err
= kIOReturnSuccess
;
902 // bytesWritten += size;
906 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
912 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
916 vars
->bufferOffset
+= copy
;
917 // vars->position += copy;
919 if (vars
->bufferOffset
== vars
->bufferLimit
)
923 err
= IOHibernatePollerIODone(vars
, false);
924 if (kIOReturnSuccess
!= err
)
930 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
932 vars
->position
+= vars
->lastRead
;
933 vars
->extentRemaining
-= vars
->lastRead
;
934 vars
->bufferLimit
= vars
->lastRead
;
936 if (!vars
->extentRemaining
)
938 vars
->currentExtent
++;
939 vars
->extentRemaining
= vars
->currentExtent
->length
;
940 vars
->extentPosition
= vars
->position
;
941 if (!vars
->extentRemaining
)
943 err
= kIOReturnOverrun
;
949 uint64_t lastReadLength
= vars
->lastRead
;
950 uint64_t offset
= (vars
->position
951 - vars
->extentPosition
+ vars
->currentExtent
->start
);
952 if (vars
->extentRemaining
<= vars
->bufferSize
)
953 length
= vars
->extentRemaining
;
955 length
= vars
->bufferSize
;
956 vars
->lastRead
= length
;
958 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
960 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
961 if (kIOReturnSuccess
!= err
)
965 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
966 vars
->bufferOffset
= 0;
971 uint8_t thisVector
[AES_BLOCK_SIZE
];
972 // save initial vector for following decrypts
973 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
974 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
975 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
976 // decrypt the buffer
977 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
979 lastReadLength
/ AES_BLOCK_SIZE
,
980 vars
->buffer
+ vars
->bufferHalf
,
981 &cryptvars
->ctx
.decrypt
);
991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
994 IOHibernateSystemSleep(void)
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 if (IOService::getPMRootDomain()->getHibernateSettings(
1015 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
1016 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1017 // default to discard clean for safe sleep
1018 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
1019 | kIOHibernateModeDiscardCleanActive
);
1021 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1023 if ((str
= OSDynamicCast(OSString
, obj
)))
1024 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1025 sizeof(gIOHibernateFilename
));
1029 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1030 return (kIOReturnUnsupported
);
1032 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1037 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1038 4 * page_size
, page_size
);
1039 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1040 2 * kDefaultIOSize
, page_size
);
1042 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
1044 err
= kIOReturnNoMemory
;
1048 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1049 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1050 if (KERN_SUCCESS
!= err
)
1052 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1055 if (vars
->fileVars
->fileRef
)
1057 // invalidate the image file
1058 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1059 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1060 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1061 if (KERN_SUCCESS
!= err
)
1062 HIBLOG("kern_write_file(%d)\n", err
);
1065 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1066 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1068 dsSSD
= (vars
->fileVars
->solid_state
1069 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
1073 gIOHibernateCurrentHeader
->options
|=
1074 kIOHibernateOptionSSD
1075 | kIOHibernateOptionColor
;
1079 gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
1082 boolean_t encryptedswap
;
1083 AbsoluteTime startTime
, endTime
;
1086 clock_get_uptime(&startTime
);
1087 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1088 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1090 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1091 clock_get_uptime(&endTime
);
1092 SUB_ABSOLUTETIME(&endTime
, &startTime
);
1093 absolutetime_to_nanoseconds(endTime
, &nsec
);
1094 HIBLOG("hibernate_setup(%d) took %qd ms\n", err
, nsec
/ 1000000ULL);
1096 if (KERN_SUCCESS
!= err
)
1100 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1102 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1104 vars
->videoAllocSize
= kVideoMapSize
;
1105 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1106 vars
->videoMapping
= 0;
1109 // generate crypt keys
1110 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1111 vars
->wiredCryptKey
[i
] = random();
1112 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1113 vars
->cryptKey
[i
] = random();
1117 IORegistryEntry
* regEntry
;
1118 if (!gIOOptionsEntry
)
1120 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1121 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1122 if (regEntry
&& !gIOOptionsEntry
)
1123 regEntry
->release();
1125 if (!gIOChosenEntry
)
1126 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1128 if (gIOOptionsEntry
)
1130 const OSSymbol
* sym
;
1132 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1135 gIOOptionsEntry
->setProperty(sym
, data
);
1140 #if defined(__ppc__)
1142 char valueString
[16];
1144 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1147 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1150 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1151 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1153 gIOOptionsEntry
->setProperty(sym
, str2
);
1159 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1162 vars
->haveFastBoot
= true;
1164 len
= snprintf(valueString
, sizeof(valueString
), "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1165 data
= OSData::withBytes(valueString
, len
+ 1);
1166 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1168 gIOOptionsEntry
->setProperty(sym
, data
);
1174 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1176 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1178 #endif /* __ppc__ */
1179 #if defined(__i386__) || defined(__x86_64__)
1180 struct AppleRTCHibernateVars
1182 uint8_t signature
[4];
1184 uint8_t booterSignature
[20];
1185 uint8_t wiredCryptKey
[16];
1187 AppleRTCHibernateVars rtcVars
;
1189 rtcVars
.signature
[0] = 'A';
1190 rtcVars
.signature
[1] = 'A';
1191 rtcVars
.signature
[2] = 'P';
1192 rtcVars
.signature
[3] = 'L';
1193 rtcVars
.revision
= 1;
1194 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1195 if (gIOHibernateBootSignature
[0])
1199 for (uint32_t i
= 0;
1200 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1211 value
= (value
<< 4) | c
;
1213 rtcVars
.booterSignature
[i
>> 1] = value
;
1216 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1219 if (!gIOHibernateRTCVariablesKey
)
1220 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1221 if (gIOHibernateRTCVariablesKey
)
1222 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
1224 if( gIOOptionsEntry
)
1226 if( gIOHibernateMode
& kIOHibernateModeSwitch
)
1228 const OSSymbol
*sym
;
1229 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey
);
1232 gIOOptionsEntry
->setProperty(sym
, data
); /* intentional insecure backup of rtc boot vars */
1242 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1244 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1248 if (!gIOHibernateBoot0082Data
)
1250 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
1253 // AppleNVRAM_EFI_LOAD_OPTION
1255 uint32_t Attributes
;
1256 uint16_t FilePathLength
;
1259 loadOptionHeader
.Attributes
= 1;
1260 loadOptionHeader
.FilePathLength
= data
->getLength();
1261 loadOptionHeader
.Desc
= 0;
1262 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
1263 if (gIOHibernateBoot0082Data
)
1265 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
1266 gIOHibernateBoot0082Data
->appendBytes(data
);
1270 if (!gIOHibernateBoot0082Key
)
1271 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1272 if (!gIOHibernateBootNextKey
)
1273 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1274 if (!gIOHibernateBootNextData
)
1276 uint16_t bits
= 0x0082;
1277 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
1279 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
1281 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
1282 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
1283 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
1287 #else /* !i386 && !x86_64 */
1288 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1290 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1291 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1293 gIOOptionsEntry
->setProperty(sym
, data
);
1298 if (false && gIOHibernateBootSignature
[0])
1300 data
= OSData::withCapacity(16);
1301 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1306 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1316 value
= (value
<< 4) | c
;
1318 data
->appendBytes(&value
, sizeof(value
));
1320 gIOOptionsEntry
->setProperty(sym
, data
);
1328 if (!vars
->haveFastBoot
)
1330 // set boot volume to zero
1331 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1332 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1333 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1336 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1337 platform
->writeXPRAM(kXPRamAudioVolume
,
1338 &newVolume
, sizeof(newVolume
));
1341 #endif /* !i386 && !x86_64 */
1345 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1346 gIOHibernateState
= kIOHibernateStateHibernating
;
1353 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1355 DECLARE_IOHIBERNATEPROGRESSALPHA
1358 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
1360 uint32_t rowBytes
, pixelShift
;
1363 uint32_t alpha
, in
, color
, result
;
1365 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1367 rowBytes
= display
->rowBytes
;
1368 pixelShift
= display
->depth
>> 4;
1369 if (pixelShift
< 1) return;
1371 screen
+= ((display
->width
1372 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1373 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1375 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1377 out
= screen
+ y
* rowBytes
;
1378 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
1380 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
1381 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1383 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1389 if (1 == pixelShift
)
1391 in
= *((uint16_t *)out
) & 0x1f; // 16
1392 in
= (in
<< 3) | (in
>> 2);
1395 in
= *((uint32_t *)out
) & 0xff; // 32
1396 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1397 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1399 if (1 == pixelShift
)
1402 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1405 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1407 out
+= (1 << pixelShift
);
1409 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1416 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1418 uint32_t rowBytes
, pixelShift
;
1420 int32_t blob
, lastBlob
;
1421 uint32_t alpha
, in
, color
, result
;
1423 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1425 pixelShift
= display
->depth
>> 4;
1429 rowBytes
= display
->rowBytes
;
1431 screen
+= ((display
->width
1432 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1433 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1435 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1437 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1439 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1441 out
= screen
+ y
* rowBytes
;
1442 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1444 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1445 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1447 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1453 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1454 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1456 if (1 == pixelShift
)
1459 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1462 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1464 out
+= (1 << pixelShift
);
1466 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1471 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1474 IOHibernateSystemHasSlept(void)
1476 IOHibernateVars
* vars
= &gIOHibernateVars
;
1480 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1481 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1482 if (obj
&& !vars
->previewBuffer
)
1485 vars
->consoleMapping
= NULL
;
1486 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1488 vars
->previewBuffer
->release();
1489 vars
->previewBuffer
= 0;
1492 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1493 && vars
->previewBuffer
1494 && (data
= OSDynamicCast(OSData
,
1495 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1497 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1498 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1500 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1502 if (kIOHibernatePreviewUpdates
& flags
)
1504 PE_Video consoleInfo
;
1505 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1507 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1509 graphicsInfo
->width
= consoleInfo
.v_width
;
1510 graphicsInfo
->height
= consoleInfo
.v_height
;
1511 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1512 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1513 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1515 HIBPRINT("video %p %d %d %d\n",
1516 vars
->consoleMapping
, graphicsInfo
->depth
,
1517 graphicsInfo
->width
, graphicsInfo
->height
);
1518 if (vars
->consoleMapping
)
1519 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1520 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1524 if (gIOOptionsEntry
)
1525 gIOOptionsEntry
->sync();
1527 return (kIOReturnSuccess
);
1530 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1533 IOHibernateSystemWake(void)
1535 IOHibernateVars
* vars
= &gIOHibernateVars
;
1537 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1539 if (vars
->videoMapping
)
1541 if (vars
->videoMapSize
)
1543 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1544 if (vars
->videoAllocSize
)
1546 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1549 if (vars
->previewBuffer
)
1551 vars
->previewBuffer
->release();
1552 vars
->previewBuffer
= 0;
1555 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1557 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1558 gIOHibernateCurrentHeader
->options
, 32);
1562 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1565 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1566 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1568 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1569 &gIOHibernateGraphicsInfo
->gfxStatus
,
1570 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1574 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1580 IOPolledFileClose(vars
->fileVars
);
1583 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1586 OSData
* data
= OSData::withCapacity(4);
1587 if (gIOOptionsEntry
&& data
)
1589 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1592 gIOOptionsEntry
->setProperty(sym
, data
);
1595 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1598 if (vars
->saveBootDevice
)
1600 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1601 vars
->saveBootDevice
->release();
1605 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1608 gIOOptionsEntry
->setProperty(sym
, data
);
1611 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1614 gIOOptionsEntry
->removeProperty(sym
);
1621 if (gIOOptionsEntry
)
1623 if (!vars
->haveFastBoot
)
1625 // reset boot audio volume
1626 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1628 platform
->writeXPRAM(kXPRamAudioVolume
,
1629 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1632 // sync now to hardware if the booter has not
1633 if (kIOHibernateStateInactive
== gIOHibernateState
)
1634 gIOOptionsEntry
->sync();
1636 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1637 gIOOptionsEntry
->syncOFVariables();
1641 #if defined(__i386__) || defined(__x86_64__)
1642 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1645 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1646 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1648 if (gIOOptionsEntry
) {
1650 if (gIOHibernateRTCVariablesKey
) {
1651 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1652 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1656 if (gIOHibernateBootNextKey
)
1658 if (gIOHibernateBootNextSave
)
1660 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1661 gIOHibernateBootNextSave
->release();
1662 gIOHibernateBootNextSave
= NULL
;
1665 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1667 gIOOptionsEntry
->sync();
1671 if (vars
->srcBuffer
)
1672 vars
->srcBuffer
->release();
1674 vars
->ioBuffer
->release();
1675 if (vars
->fileExtents
)
1676 vars
->fileExtents
->release();
1678 bzero(vars
, sizeof(*vars
));
1680 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1682 return (kIOReturnSuccess
);
1686 IOHibernateSystemPostWake(void)
1688 if (gIOHibernateFileRef
)
1690 // invalidate the image file
1691 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1692 int err
= kern_write_file(gIOHibernateFileRef
, 0,
1693 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1694 if (KERN_SUCCESS
!= err
)
1695 HIBLOG("kern_write_file(%d)\n", err
);
1697 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1698 gIOHibernateFileRef
= 0;
1700 return (kIOReturnSuccess
);
1703 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1705 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1706 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1707 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1708 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1709 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1710 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1711 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1712 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1713 &gIOHibernateMode
, 0, "");
1716 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1718 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1721 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1725 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1726 gIOHibernateMode
= kIOHibernateModeOn
;
1728 gIOHibernateFilename
[0] = 0;
1730 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1731 sysctl_register_oid(&sysctl__kern_bootsignature
);
1732 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1736 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1739 hibernate_setup_for_wake(void)
1742 // go slow (state needed for wake)
1743 ml_set_processor_speed(1);
1747 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1749 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1752 no_encrypt_page(vm_offset_t ppnum
)
1754 if (pmap_is_noencrypt((ppnum_t
)ppnum
) == TRUE
)
1761 uint32_t wired_pages_encrypted
= 0;
1762 uint32_t dirty_pages_encrypted
= 0;
1763 uint32_t wired_pages_clear
= 0;
1766 hibernate_write_image(void)
1768 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1769 IOHibernateVars
* vars
= &gIOHibernateVars
;
1770 IOPolledFileExtent
* fileExtents
;
1772 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
1774 uint32_t pageCount
, pagesDone
;
1776 vm_offset_t ppnum
, page
;
1780 IOByteCount pageCompressedSize
;
1781 uint64_t compressedSize
, uncompressedSize
;
1782 uint64_t image1Size
= 0;
1783 uint32_t bitmap_size
;
1784 bool iterDone
, pollerOpen
, needEncrypt
;
1785 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1788 uint32_t pageAndCount
[2];
1790 AbsoluteTime startTime
, endTime
;
1791 AbsoluteTime allTime
, compTime
, decoTime
;
1794 uint32_t lastProgressStamp
= 0;
1795 uint32_t progressStamp
;
1796 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1798 hibernate_cryptvars_t _cryptvars
;
1799 hibernate_cryptvars_t
* cryptvars
= 0;
1801 wired_pages_encrypted
= 0;
1802 dirty_pages_encrypted
= 0;
1803 wired_pages_clear
= 0;
1805 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1806 return (false /* sleep */ );
1808 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1809 kdebug_enable
= save_kdebug_enable
;
1811 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
, 0, 0, 0, 0, 0);
1813 restore1Sum
= sum1
= sum2
= 0;
1816 // encryption data. "iv" is the "initial vector".
1817 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1819 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1820 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1821 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1823 cryptvars
= &gIOHibernateCryptWakeContext
;
1824 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1825 aes_encrypt_key(vars
->cryptKey
,
1826 kIOHibernateAESKeySize
,
1827 &cryptvars
->ctx
.encrypt
);
1828 aes_decrypt_key(vars
->cryptKey
,
1829 kIOHibernateAESKeySize
,
1830 &cryptvars
->ctx
.decrypt
);
1832 cryptvars
= &_cryptvars
;
1833 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1834 aes_encrypt_key(vars
->wiredCryptKey
,
1835 kIOHibernateAESKeySize
,
1836 &cryptvars
->ctx
.encrypt
);
1838 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1839 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1840 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1841 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1845 hibernate_setup_for_wake();
1847 hibernate_page_list_setall(vars
->page_list
,
1848 vars
->page_list_wired
,
1851 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1853 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1856 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1857 for (page
= 0; page
< count
; page
++)
1859 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1860 fileExtents
[page
].start
, fileExtents
[page
].length
,
1861 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1865 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1867 AbsoluteTime_to_scalar(&compTime
) = 0;
1868 AbsoluteTime_to_scalar(&decoTime
) = 0;
1870 clock_get_uptime(&allTime
);
1871 IOService::getPMRootDomain()->pmStatsRecordEvent(
1872 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1877 uncompressedSize
= 0;
1879 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1881 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1882 ml_get_interrupts_enabled());
1883 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1884 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1885 pollerOpen
= (kIOReturnSuccess
== err
);
1889 // copy file block extent list if larger than header
1891 count
= vars
->fileExtents
->getLength();
1892 if (count
> sizeof(header
->fileExtentMap
))
1894 count
-= sizeof(header
->fileExtentMap
);
1895 err
= IOPolledFileWrite(vars
->fileVars
,
1896 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1897 if (kIOReturnSuccess
!= err
)
1901 uintptr_t hibernateBase
;
1902 uintptr_t hibernateEnd
;
1904 #if defined(__i386__) || defined(__x86_64__)
1905 hibernateBase
= sectINITPTB
;
1907 hibernateBase
= sectHIBB
;
1910 hibernateEnd
= (sectHIBB
+ sectSizeHIB
);
1911 // copy out restore1 code
1913 page
= atop_32(hibernateBase
);
1914 count
= atop_32(round_page(hibernateEnd
)) - page
;
1915 header
->restore1CodePage
= page
;
1916 header
->restore1PageCount
= count
;
1917 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1918 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1920 // sum __HIB sect, with zeros for the stack
1921 src
= (uint8_t *) trunc_page(hibernateBase
);
1922 for (page
= 0; page
< count
; page
++)
1924 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1925 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodePage
+ page
);
1927 restore1Sum
+= 0x00000000;
1932 // write the __HIB sect, with zeros for the stack
1934 src
= (uint8_t *) trunc_page(hibernateBase
);
1935 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1938 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1939 if (kIOReturnSuccess
!= err
)
1942 err
= IOPolledFileWrite(vars
->fileVars
,
1944 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1946 if (kIOReturnSuccess
!= err
)
1948 src
= &gIOHibernateRestoreStackEnd
[0];
1949 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1952 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1953 if (kIOReturnSuccess
!= err
)
1957 // write the preview buffer
1962 if (vars
->previewBuffer
)
1968 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1969 pageAndCount
[0] = atop_64(phys64
);
1970 pageAndCount
[1] = atop_32(segLen
);
1971 err
= IOPolledFileWrite(vars
->fileVars
,
1972 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1974 if (kIOReturnSuccess
!= err
)
1977 ppnum
+= sizeof(pageAndCount
);
1980 if (kIOReturnSuccess
!= err
)
1983 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1984 count
= vars
->previewBuffer
->getLength();
1986 header
->previewPageListSize
= ppnum
;
1987 header
->previewSize
= count
+ ppnum
;
1989 for (page
= 0; page
< count
; page
+= page_size
)
1991 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
1992 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
1994 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1995 if (kIOReturnSuccess
!= err
)
1999 // mark areas for no save
2002 (phys64
= vars
->ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2005 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2006 atop_64(phys64
), atop_32(segLen
),
2007 kIOHibernatePageStateFree
);
2008 pageCount
-= atop_32(segLen
);
2012 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2015 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2016 atop_64(phys64
), atop_32(segLen
),
2017 kIOHibernatePageStateFree
);
2018 pageCount
-= atop_32(segLen
);
2021 // copy out bitmap of pages available for trashing during restore
2023 bitmap_size
= vars
->page_list_wired
->list_size
;
2024 src
= (uint8_t *) vars
->page_list_wired
;
2025 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
2026 if (kIOReturnSuccess
!= err
)
2029 // mark more areas for no save, but these are not available
2030 // for trashing during restore
2032 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
2034 page
= atop_32(hibernateBase
);
2035 count
= atop_32(round_page(hibernateEnd
)) - page
;
2036 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2038 kIOHibernatePageStateFree
);
2041 if (vars
->previewBuffer
) for (count
= 0;
2042 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
2045 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
2046 atop_64(phys64
), atop_32(segLen
),
2047 kIOHibernatePageStateFree
);
2048 pageCount
-= atop_32(segLen
);
2051 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2056 HIBLOG("writing %d pages\n", pageCount
);
2063 kWiredEncrypt
= kWired
| kEncrypt
,
2064 kWiredClear
= kWired
,
2065 kUnwiredEncrypt
= kEncrypt
2068 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
2070 if (needEncrypt
&& (kEncrypt
& pageType
))
2072 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
2073 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
2074 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
2076 if (kUnwiredEncrypt
== pageType
)
2078 // start unwired image
2079 bcopy(&cryptvars
->aes_iv
[0],
2080 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2081 sizeof(cryptvars
->aes_iv
));
2082 cryptvars
= &gIOHibernateCryptWakeContext
;
2085 for (iterDone
= false, ppnum
= 0; !iterDone
; )
2087 count
= hibernate_page_list_iterate((kWired
& pageType
)
2088 ? vars
->page_list_wired
: vars
->page_list
,
2090 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2093 if (count
&& (kWired
& pageType
) && needEncrypt
)
2095 uint32_t checkIndex
;
2096 for (checkIndex
= 0;
2097 (checkIndex
< count
)
2098 && (((kEncrypt
& pageType
) == 0) == no_encrypt_page(ppnum
+ checkIndex
));
2111 case kWiredEncrypt
: wired_pages_encrypted
+= count
; break;
2112 case kWiredClear
: wired_pages_clear
+= count
; break;
2113 case kUnwiredEncrypt
: dirty_pages_encrypted
+= count
; break;
2116 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
2119 pageAndCount
[0] = ppnum
;
2120 pageAndCount
[1] = count
;
2121 err
= IOPolledFileWrite(vars
->fileVars
,
2122 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
2124 if (kIOReturnSuccess
!= err
)
2128 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
2130 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
2133 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
2137 sum
= hibernate_sum_page(src
, page
);
2138 if (kWired
& pageType
)
2143 clock_get_uptime(&startTime
);
2145 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
2147 clock_get_uptime(&endTime
);
2148 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2149 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2150 compBytes
+= page_size
;
2152 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2153 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
2155 if (pageCompressedSize
> page_size
)
2157 // HIBLOG("------------lose: %d\n", pageCompressedSize);
2158 pageCompressedSize
= page_size
;
2161 if (pageCompressedSize
!= page_size
)
2162 data
= (src
+ page_size
);
2166 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2167 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2168 if (kIOReturnSuccess
!= err
)
2171 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2172 if (kIOReturnSuccess
!= err
)
2175 compressedSize
+= pageCompressedSize
;
2176 if (pageCompressedSize
)
2177 uncompressedSize
+= page_size
;
2180 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2182 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2183 if (blob
!= lastBlob
)
2185 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2189 if (0 == (8191 & pagesDone
))
2191 clock_get_uptime(&endTime
);
2192 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2193 absolutetime_to_nanoseconds(endTime
, &nsec
);
2194 progressStamp
= nsec
/ 750000000ULL;
2195 if (progressStamp
!= lastProgressStamp
)
2197 lastProgressStamp
= progressStamp
;
2198 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2202 if (kIOReturnSuccess
!= err
)
2207 if (kIOReturnSuccess
!= err
)
2210 if ((kEncrypt
& pageType
))
2212 vars
->fileVars
->encryptEnd
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
2213 & ~(AES_BLOCK_SIZE
- 1);
2214 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
2217 if (kWiredEncrypt
!= pageType
)
2219 // end of image1/2 - fill to next block
2220 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2221 if (kIOReturnSuccess
!= err
)
2224 if (kWiredClear
== pageType
)
2227 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2228 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
2229 image1Size
= vars
->fileVars
->position
;
2230 HIBLOG("image1Size %qd, encryptStart1 %qx, End1 %qx\n",
2231 image1Size
, header
->encryptStart
, header
->encryptEnd
);
2234 if (kIOReturnSuccess
!= err
)
2239 header
->imageSize
= vars
->fileVars
->position
;
2240 header
->image1Size
= image1Size
;
2241 header
->bitmapSize
= bitmap_size
;
2242 header
->pageCount
= pageCount
;
2244 header
->restore1Sum
= restore1Sum
;
2245 header
->image1Sum
= sum1
;
2246 header
->image2Sum
= sum2
;
2248 count
= vars
->fileExtents
->getLength();
2249 if (count
> sizeof(header
->fileExtentMap
))
2251 header
->fileExtentMapSize
= count
;
2252 count
= sizeof(header
->fileExtentMap
);
2255 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2256 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2258 header
->deviceBase
= vars
->fileVars
->block0
;
2260 IOPolledFileSeek(vars
->fileVars
, 0);
2261 err
= IOPolledFileWrite(vars
->fileVars
,
2262 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2264 if (kIOReturnSuccess
!= err
)
2266 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2267 if (kIOReturnSuccess
!= err
)
2269 err
= IOHibernatePollerIODone(vars
->fileVars
, true);
2270 if (kIOReturnSuccess
!= err
)
2275 clock_get_uptime(&endTime
);
2277 IOService::getPMRootDomain()->pmStatsRecordEvent(
2278 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2280 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2281 absolutetime_to_nanoseconds(endTime
, &nsec
);
2282 HIBLOG("all time: %qd ms, ",
2285 absolutetime_to_nanoseconds(compTime
, &nsec
);
2286 HIBLOG("comp time: %qd ms, ",
2289 absolutetime_to_nanoseconds(decoTime
, &nsec
);
2290 HIBLOG("deco time: %qd ms, ",
2293 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2295 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2296 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2299 HIBLOG("wired_pages_encrypted %d, wired_pages_clear %d, dirty_pages_encrypted %d\n",
2300 wired_pages_encrypted
, wired_pages_clear
, dirty_pages_encrypted
);
2302 if (vars
->fileVars
->io
)
2303 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2306 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
2308 if (vars
->consoleMapping
)
2309 ProgressUpdate(gIOHibernateGraphicsInfo
,
2310 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2312 HIBLOG("hibernate_write_image done(%x)\n", err
);
2314 // should we come back via regular wake, set the state in memory.
2315 gIOHibernateState
= kIOHibernateStateInactive
;
2317 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
,
2318 wired_pages_encrypted
, wired_pages_clear
, dirty_pages_encrypted
, 0, 0);
2320 if (kIOReturnSuccess
== err
)
2322 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2324 return (kIOHibernatePostWriteSleep
);
2326 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2328 return (kIOHibernatePostWriteRestart
);
2332 /* by default, power down */
2333 return (kIOHibernatePostWriteHalt
);
2336 else if (kIOReturnAborted
== err
)
2338 return (kIOHibernatePostWriteWake
);
2342 /* on error, sleep */
2343 return (kIOHibernatePostWriteSleep
);
2347 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2350 hibernate_machine_init(void)
2355 uint32_t pagesRead
= 0;
2356 AbsoluteTime allTime
, endTime
;
2358 uint32_t lastProgressStamp
= 0;
2359 uint32_t progressStamp
;
2360 uint64_t progressZeroPosition
= 0;
2361 uint32_t blob
, lastBlob
= (uint32_t) -1L;
2362 hibernate_cryptvars_t
* cryptvars
= 0;
2364 IOHibernateVars
* vars
= &gIOHibernateVars
;
2366 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2369 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2370 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2372 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
2373 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
2374 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2376 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2378 HIBLOG("regular wake\n");
2382 HIBPRINT("diag %x %x %x %x\n",
2383 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2384 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2386 HIBPRINT("video %x %d %d %d status %x\n",
2387 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2388 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2390 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
2391 hibernate_page_list_discard(vars
->page_list
);
2393 boot_args
*args
= (boot_args
*) PE_state
.bootArgs
;
2395 if (vars
->videoMapping
2396 && gIOHibernateGraphicsInfo
->physicalAddress
2397 && (args
->Video
.v_baseAddr
== gIOHibernateGraphicsInfo
->physicalAddress
))
2399 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2400 * gIOHibernateGraphicsInfo
->rowBytes
);
2401 IOMapPages(kernel_map
,
2402 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2403 vars
->videoMapSize
, kIOMapInhibitCache
);
2406 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2408 if (gIOHibernateWakeMapSize
)
2410 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(gIOHibernateWakeMap
),
2411 gIOHibernateWakeMapSize
);
2412 if (kIOReturnSuccess
== err
)
2413 hibernate_newruntime_map(src
, gIOHibernateWakeMapSize
,
2414 gIOHibernateCurrentHeader
->systemTableOffset
);
2415 gIOHibernateWakeMap
= 0;
2416 gIOHibernateWakeMapSize
= 0;
2419 uint32_t decoOffset
;
2421 clock_get_uptime(&allTime
);
2423 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2424 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
2425 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2427 if (gIOHibernateCurrentHeader
->previewSize
)
2428 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
2429 + gIOHibernateCurrentHeader
->fileExtentMapSize
2430 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
2431 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
2433 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2435 if (vars
->videoMapSize
)
2437 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2438 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2439 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
2442 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2443 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2445 cryptvars
= &gIOHibernateCryptWakeContext
;
2446 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
2447 &cryptvars
->aes_iv
[0],
2448 sizeof(cryptvars
->aes_iv
));
2451 // kick off the read ahead
2452 vars
->fileVars
->io
= false;
2453 vars
->fileVars
->bufferHalf
= 0;
2454 vars
->fileVars
->bufferLimit
= 0;
2455 vars
->fileVars
->lastRead
= 0;
2456 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2458 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2459 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2462 HIBLOG("hibernate_machine_init reading\n");
2464 uint32_t * header
= (uint32_t *) src
;
2472 vm_offset_t ppnum
, compressedSize
;
2474 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2475 if (kIOReturnSuccess
!= err
)
2481 // HIBPRINT("(%x, %x)\n", ppnum, count);
2486 for (page
= 0; page
< count
; page
++)
2488 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2489 if (kIOReturnSuccess
!= err
)
2492 compressedSize
= kIOHibernateTagLength
& tag
;
2493 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2495 err
= kIOReturnIPCError
;
2499 if (!compressedSize
)
2506 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2507 if (kIOReturnSuccess
!= err
)
2510 if (compressedSize
< page_size
)
2512 decoOffset
= page_size
;
2513 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2518 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
2520 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2523 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2531 if (vars
->videoMapSize
&& (0 == (1023 & pagesDone
)))
2533 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2534 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2535 if (blob
!= lastBlob
)
2537 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2542 if (0 == (8191 & pagesDone
))
2544 clock_get_uptime(&endTime
);
2545 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2546 absolutetime_to_nanoseconds(endTime
, &nsec
);
2547 progressStamp
= nsec
/ 750000000ULL;
2548 if (progressStamp
!= lastProgressStamp
)
2550 lastProgressStamp
= progressStamp
;
2551 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2552 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2559 if (kIOReturnSuccess
!= err
)
2560 panic("Hibernate restore error %x", err
);
2562 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2564 if (vars
->fileVars
->io
)
2565 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2567 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2569 if (vars
->videoMapSize
)
2570 ProgressUpdate(gIOHibernateGraphicsInfo
,
2571 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2573 clock_get_uptime(&endTime
);
2575 IOService::getPMRootDomain()->pmStatsRecordEvent(
2576 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2577 IOService::getPMRootDomain()->pmStatsRecordEvent(
2578 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2580 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2581 absolutetime_to_nanoseconds(endTime
, &nsec
);
2583 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2584 pagesDone
, sum
, nsec
/ 1000000ULL);
2586 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 2) | DBG_FUNC_NONE
, pagesRead
, pagesDone
, 0, 0, 0);
2589 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */