2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
28 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
29 (devices awake, normal execution context)
30 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
31 grabs its extents and searches for a polling driver willing to work with that IOMedia.
32 The BSD code makes an ioctl to the storage driver to get the partition base offset to
33 the disk, and other ioctls to get the transfer constraints
34 If successful, the file is written to make sure its initially not bootable (in case of
35 later failure) and nvram set to point to the first block of the file. (Has to be done
36 here so blocking is possible in nvram support).
37 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
38 page out any pages it wants to (currently zero, but probably some percentage of memory).
39 Its assumed just allocating pages will cause the VM system to naturally select the best
40 pages for eviction. It also copies processor flags needed for the restore path and sets
41 a flag in the boot processor proc info.
42 gIOHibernateState = kIOHibernateStateHibernating.
43 - Regular sleep progresses - some drivers may inspect the root domain property
44 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
45 as usual but leaves motherboard I/O on.
46 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
47 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
48 all ppc RC bits out of the hash table and caches into the mapping structures.
49 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
50 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
51 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
52 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
53 The image header and block list are written. The header includes the second file extent so
54 only the header block is needed to read the file, regardless of filesystem.
55 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
56 (only) is used to decompress the image during wake/boot.
57 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
58 The bitmaps are written to the image.
59 More areas are removed from the bitmaps (after they have been written to the image) - the
60 section "__HIB" pages and interrupt stack.
61 Each wired page is compressed and written and then each non-wired page. Compression and
62 disk writes are in parallel.
63 The image header is written to the start of the file and the polling driver closed.
64 The machine powers down (or sleeps).
68 - BootX sees the boot-image nvram variable containing the device and block number of the image,
69 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
70 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
71 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
72 that is in the kernel's __HIB section.
73 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
74 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
75 only code & data in that section is safe to call since all the other wired pages are still
76 compressed in the image.
77 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
78 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
79 location directly, and copies those that can't to interim free pages. When the image has been
80 completed, the copies are uncompressed, overwriting the wired image pages.
81 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
82 is used to get pages into place for 64bit.
83 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
84 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
85 are removed from the software strutures, and the hash table is reinitialized.
86 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
87 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
88 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
89 for the remaining non wired pages.
90 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
91 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
96 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
97 registry, specifying an object of calls IOPolledInterface.
99 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
100 partition) that the image is going to live, looking for polled interface properties. If it finds
101 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
102 interfaces found are kept in an ordered list.
104 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
105 few different contexts things happen in:
107 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
108 up and running) and after wake - this is safe to allocate memory and do anything. The device
109 ignores sleep requests from that point since its a waste of time if it goes to sleep and
110 immediately wakes back up for the image write.
112 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
113 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
114 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
115 used to flush and set the disk to sleep.
117 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
118 immediately after sleep. These can't block or allocate memory. This is happening after the platform
119 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
122 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
123 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
124 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
125 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
126 that is called for the hardware to check for events, and complete the I/O via the callback.
127 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
131 #include <sys/systm.h>
133 #include <IOKit/IOWorkLoop.h>
134 #include <IOKit/IOCommandGate.h>
135 #include <IOKit/IOTimerEventSource.h>
136 #include <IOKit/IOPlatformExpert.h>
137 #include <IOKit/IOKitDebug.h>
138 #include <IOKit/IOTimeStamp.h>
139 #include <IOKit/pwr_mgt/RootDomain.h>
140 #include <IOKit/pwr_mgt/IOPMPrivate.h>
141 #include <IOKit/IOMessage.h>
142 #include <IOKit/IODeviceTreeSupport.h>
143 #include <IOKit/IOBSD.h>
144 #include "RootDomainUserClient.h"
145 #include <IOKit/pwr_mgt/IOPowerConnection.h>
146 #include "IOPMPowerStateQueue.h"
147 #include <IOKit/IOBufferMemoryDescriptor.h>
148 #include <crypto/aes.h>
151 #include <sys/conf.h>
152 #include <sys/stat.h>
153 #include <sys/fcntl.h> // (FWRITE, ...)
154 #include <sys/sysctl.h>
156 #include <IOKit/IOHibernatePrivate.h>
157 #include <IOKit/IOPolledInterface.h>
158 #include <IOKit/IONVRAM.h>
159 #include "IOHibernateInternal.h"
161 #include "IOKitKernelInternal.h"
163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
165 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
167 OSMetaClassDefineReservedUnused(IOPolledInterface
, 0);
168 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
169 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
170 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
171 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
172 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
173 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
174 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
175 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
176 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
177 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
178 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
179 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
180 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
181 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
182 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
184 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
186 extern uint32_t gIOHibernateState
;
187 uint32_t gIOHibernateMode
;
188 static char gIOHibernateBootSignature
[256+1];
189 static char gIOHibernateFilename
[MAXPATHLEN
+1];
190 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
191 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
193 static IODTNVRAM
* gIOOptionsEntry
;
194 static IORegistryEntry
* gIOChosenEntry
;
196 static IOPolledFileIOVars gFileVars
;
197 static IOHibernateVars gIOHibernateVars
;
198 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
199 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
201 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
203 enum { kXPRamAudioVolume
= 8 };
204 enum { kDefaultIOSize
= 128 * 1024 };
205 enum { kVideoMapSize
= 32 * 1024 * 1024 };
207 #ifndef kIOMediaPreferredBlockSizeKey
208 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
211 #ifndef kIOBootPathKey
212 #define kIOBootPathKey "bootpath"
214 #ifndef kIOSelectedBootDeviceKey
215 #define kIOSelectedBootDeviceKey "boot-device"
219 enum { kIOHibernateMinPollersNeeded
= 2 };
221 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
223 // copy from phys addr to MD
226 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
227 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
229 addr64_t srcAddr
= bytes
;
230 IOByteCount remaining
;
232 remaining
= length
= min(length
, md
->getLength() - offset
);
233 while (remaining
) { // (process another target segment?)
237 dstAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
241 // Clip segment length to remaining
242 if (dstLen
> remaining
)
246 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
248 copypv(srcAddr
, dstAddr64
, dstLen
,
249 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
258 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
261 // copy from MD to phys addr
264 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
265 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
267 addr64_t dstAddr
= bytes
;
268 IOByteCount remaining
;
270 remaining
= length
= min(length
, md
->getLength() - offset
);
271 while (remaining
) { // (process another target segment?)
275 srcAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
279 // Clip segment length to remaining
280 if (dstLen
> remaining
)
284 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
286 copypv(srcAddr
, dstAddr64
, dstLen
,
287 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
296 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
299 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
302 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
303 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
308 case kIOHibernatePageStateUnwiredSave
:
310 for (; ppnum
< count
; ppnum
++)
312 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
313 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
316 case kIOHibernatePageStateWiredSave
:
318 for (; ppnum
< count
; ppnum
++)
320 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
321 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
324 case kIOHibernatePageStateFree
:
326 for (; ppnum
< count
; ppnum
++)
328 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
329 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
333 panic("hibernate_set_page_state");
338 hibernate_page_list_iterate(hibernate_page_list_t
* list
,
339 void ** iterator
, vm_offset_t
* ppnum
)
343 idx
= (uint32_t) *iterator
;
346 idx
= hibernate_page_list_count(list
, TRUE
, idx
);
349 count
= hibernate_page_list_count(list
, FALSE
, idx
);
351 idx
+= hibernate_page_list_count(list
, TRUE
, idx
);
352 *iterator
= (void *) idx
;
357 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
360 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
362 IOReturn err
= kIOReturnError
;
364 IOPolledInterface
* poller
;
366 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
368 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
369 err
= poller
->probe(target
);
372 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
381 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
383 IOReturn err
= kIOReturnError
;
385 IOPolledInterface
* poller
;
387 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
389 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
390 err
= poller
->open(state
, md
);
393 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
402 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
404 IOReturn err
= kIOReturnError
;
406 IOPolledInterface
* poller
;
409 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
412 err
= poller
->close(state
);
414 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
421 IOHibernatePollerIOComplete(void * target
,
424 UInt64 actualByteCount
)
426 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
428 vars
->ioStatus
= status
;
432 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
433 uint32_t operation
, uint32_t bufferOffset
,
434 uint64_t deviceOffset
, uint64_t length
)
437 IOReturn err
= kIOReturnError
;
438 IOPolledInterface
* poller
;
439 IOPolledCompletion completion
;
441 completion
.target
= 0;
442 completion
.action
= &IOHibernatePollerIOComplete
;
443 completion
.parameter
= vars
;
447 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
448 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
450 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
456 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
)
458 IOReturn err
= kIOReturnError
;
460 IOPolledInterface
* poller
;
462 while (-1 == vars
->ioStatus
)
465 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
468 err
= poller
->checkForWork();
470 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
474 if (kIOReturnSuccess
!= vars
->ioStatus
)
475 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars
->ioStatus
);
477 return (vars
->ioStatus
);
481 IOPolledInterface::checkAllForWork(void)
483 IOReturn err
= kIOReturnNotReady
;
485 IOPolledInterface
* poller
;
487 IOHibernateVars
* vars
= &gIOHibernateVars
;
489 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
493 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
496 err
= poller
->checkForWork();
498 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
504 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
506 struct _OpenFileContext
513 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
515 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
516 IOPolledFileExtent extent
;
518 extent
.start
= start
;
519 extent
.length
= length
;
521 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
526 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
527 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
530 IOReturn err
= kIOReturnError
;
531 IOPolledFileIOVars
* vars
;
532 _OpenFileContext ctx
;
533 OSData
* extentsData
;
535 IORegistryEntry
* part
= 0;
536 OSDictionary
* matching
;
538 dev_t hibernate_image_dev
;
544 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
545 if (sizeof(IOHibernateImageHeader
) != 512)
549 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
550 vars
->bufferHalf
= 0;
551 vars
->bufferOffset
= 0;
552 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
554 extentsData
= OSData::withCapacity(32);
556 ctx
.extents
= extentsData
;
558 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
559 &file_extent_callback
, &ctx
,
560 &hibernate_image_dev
,
565 err
= kIOReturnNoSpace
;
568 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
569 vars
->block0
, maxiobytes
);
570 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
572 err
= kIOReturnNoSpace
;
576 if (maxiobytes
< vars
->bufferSize
)
577 vars
->bufferSize
= maxiobytes
;
579 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
581 matching
= IOService::serviceMatching("IOMedia");
582 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
583 matching
->setObject(kIOBSDMajorKey
, num
);
585 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
586 matching
->setObject(kIOBSDMinorKey
, num
);
588 iter
= IOService::getMatchingServices(matching
);
592 part
= (IORegistryEntry
*) iter
->getNextObject();
598 IORegistryEntry
* next
;
599 IORegistryEntry
* child
;
602 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
605 major
= num
->unsigned32BitValue();
606 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
609 minor
= num
->unsigned32BitValue();
611 hibernate_image_dev
= makedev(major
, minor
);
613 vars
->pollers
= OSArray::withCapacity(4);
617 vars
->blockSize
= 512;
621 IOPolledInterface
* poller
;
624 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
625 if (kOSBooleanFalse
== obj
)
627 vars
->pollers
->flushCollection();
630 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
631 vars
->pollers
->setObject(poller
);
632 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
633 vars
->blockSize
= num
->unsigned32BitValue();
636 while ((next
= child
->getParentEntry(gIOServicePlane
))
637 && child
->isParent(next
, gIOServicePlane
, true));
639 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
640 major
, minor
, vars
->blockSize
, vars
->pollers
->getCount());
641 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
644 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
645 if (kIOReturnSuccess
!= err
)
648 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
649 if (kIOReturnSuccess
!= err
)
653 *fileExtents
= extentsData
;
658 int len
= sizeof(str1
);
660 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
))
661 && part
->getPath(str1
, &len
, gIODTPlane
))
663 // (strip the plane name)
664 char * tail
= strchr(str1
, ':');
667 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
668 sprintf(str2
, ",%qx", vars
->extentMap
[0]);
669 data
->appendBytes(str2
, strlen(str2
));
675 if (kIOReturnSuccess
!= err
)
677 HIBLOG("error 0x%x opening hibernation file\n", err
);
679 kern_close_file_for_direct_io(vars
->fileRef
);
689 IOPolledFileClose( IOPolledFileIOVars
* vars
)
693 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
694 vars
->pollers
->release();
697 gIOHibernateFileRef
= vars
->fileRef
;
699 bzero(vars
, sizeof(IOPolledFileIOVars
));
701 return (kIOReturnSuccess
);
705 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
707 IOPolledFileExtent
* extentMap
;
709 extentMap
= vars
->extentMap
;
711 vars
->position
= position
;
713 while (position
>= extentMap
->length
)
715 position
-= extentMap
->length
;
719 vars
->currentExtent
= extentMap
;
720 vars
->extentRemaining
= extentMap
->length
- position
;
721 vars
->extentPosition
= vars
->position
- position
;
723 if (vars
->bufferSize
<= vars
->extentRemaining
)
724 vars
->bufferLimit
= vars
->bufferSize
;
726 vars
->bufferLimit
= vars
->extentRemaining
;
728 return (kIOReturnSuccess
);
732 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
733 const uint8_t * bytes
, IOByteCount size
,
734 hibernate_cryptvars_t
* cryptvars
)
736 IOReturn err
= kIOReturnSuccess
;
744 // seek to end of block & flush
745 size
= vars
->position
& (vars
->blockSize
- 1);
747 size
= vars
->blockSize
- size
;
749 // use some garbage for the fill
750 bytes
= vars
->buffer
+ vars
->bufferOffset
;
753 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
761 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
765 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
768 vars
->bufferOffset
+= copy
;
769 vars
->position
+= copy
;
771 if (flush
&& vars
->bufferOffset
)
773 uint64_t offset
= (vars
->position
- vars
->bufferOffset
774 - vars
->extentPosition
+ vars
->currentExtent
->start
);
775 uint32_t length
= (vars
->bufferOffset
);
777 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
779 uint32_t encryptLen
, encryptStart
;
780 encryptLen
= vars
->position
- vars
->encryptStart
;
781 if (encryptLen
> length
)
783 encryptStart
= length
- encryptLen
;
785 // encrypt the buffer
786 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
787 &cryptvars
->aes_iv
[0],
788 encryptLen
/ AES_BLOCK_SIZE
,
789 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
790 &cryptvars
->ctx
.encrypt
);
791 // save initial vector for following encrypts
792 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
793 &cryptvars
->aes_iv
[0],
799 err
= IOHibernatePollerIODone(vars
);
800 if (kIOReturnSuccess
!= err
)
804 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
805 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
807 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
808 if (kIOReturnSuccess
!= err
)
812 vars
->extentRemaining
-= vars
->bufferOffset
;
813 if (!vars
->extentRemaining
)
815 vars
->currentExtent
++;
816 vars
->extentRemaining
= vars
->currentExtent
->length
;
817 vars
->extentPosition
= vars
->position
;
818 if (!vars
->extentRemaining
)
820 err
= kIOReturnOverrun
;
825 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
826 vars
->bufferOffset
= 0;
827 if (vars
->bufferSize
<= vars
->extentRemaining
)
828 vars
->bufferLimit
= vars
->bufferSize
;
830 vars
->bufferLimit
= vars
->extentRemaining
;
841 IOPolledFileRead(IOPolledFileIOVars
* vars
,
842 uint8_t * bytes
, IOByteCount size
,
843 hibernate_cryptvars_t
* cryptvars
)
845 IOReturn err
= kIOReturnSuccess
;
848 // bytesWritten += size;
852 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
858 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
862 vars
->bufferOffset
+= copy
;
863 // vars->position += copy;
865 if (vars
->bufferOffset
== vars
->bufferLimit
)
869 err
= IOHibernatePollerIODone(vars
);
870 if (kIOReturnSuccess
!= err
)
876 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
878 vars
->position
+= vars
->lastRead
;
879 vars
->extentRemaining
-= vars
->lastRead
;
880 vars
->bufferLimit
= vars
->lastRead
;
882 if (!vars
->extentRemaining
)
884 vars
->currentExtent
++;
885 vars
->extentRemaining
= vars
->currentExtent
->length
;
886 vars
->extentPosition
= vars
->position
;
887 if (!vars
->extentRemaining
)
889 err
= kIOReturnOverrun
;
894 if (vars
->extentRemaining
<= vars
->bufferSize
)
895 vars
->lastRead
= vars
->extentRemaining
;
897 vars
->lastRead
= vars
->bufferSize
;
899 uint64_t offset
= (vars
->position
900 - vars
->extentPosition
+ vars
->currentExtent
->start
);
901 uint64_t length
= (vars
->lastRead
);
903 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
905 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
906 if (kIOReturnSuccess
!= err
)
910 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
911 vars
->bufferOffset
= 0;
915 uint8_t thisVector
[AES_BLOCK_SIZE
];
916 // save initial vector for following decrypts
917 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
918 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->lastRead
- AES_BLOCK_SIZE
,
919 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
920 // decrypt the buffer
921 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
923 vars
->lastRead
/ AES_BLOCK_SIZE
,
924 vars
->buffer
+ vars
->bufferHalf
,
925 &cryptvars
->ctx
.decrypt
);
934 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
937 IOHibernateSystemSleep(void)
945 IOHibernateVars
* vars
= &gIOHibernateVars
;
947 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
948 // already on the way down
949 return (kIOReturnSuccess
);
951 gIOHibernateState
= kIOHibernateStateInactive
;
953 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
)))
955 if ((num
= OSDynamicCast(OSNumber
, obj
)))
956 gIOHibernateMode
= num
->unsigned32BitValue();
957 if (kIOHibernateModeSleep
& gIOHibernateMode
)
958 // default to discard clean for safe sleep
959 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
960 | kIOHibernateModeDiscardCleanActive
);
964 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
)))
966 if ((num
= OSDynamicCast(OSNumber
, obj
)))
967 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
970 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
972 if ((num
= OSDynamicCast(OSNumber
, obj
)))
973 gIOHibernateFreeTime
= num
->unsigned32BitValue();
976 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
978 if ((str
= OSDynamicCast(OSString
, obj
)))
979 strcpy(gIOHibernateFilename
, str
->getCStringNoCopy());
983 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
984 return (kIOReturnUnsupported
);
986 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
990 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(0, 4 * page_size
, page_size
);
991 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize
, page_size
);
993 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
995 err
= kIOReturnNoMemory
;
999 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1000 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1001 if (KERN_SUCCESS
!= err
)
1003 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1006 if (vars
->fileVars
->fileRef
)
1008 // invalidate the image file
1009 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1010 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1011 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1012 if (KERN_SUCCESS
!= err
)
1013 HIBLOG("kern_write_file(%d)\n", err
);
1016 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1018 boolean_t encryptedswap
;
1019 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1020 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1021 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1022 if (KERN_SUCCESS
!= err
)
1024 HIBLOG("hibernate_setup(%d)\n", err
);
1029 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1031 vars
->videoAllocSize
= kVideoMapSize
;
1032 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1033 vars
->videoMapping
= 0;
1035 // generate crypt keys
1036 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1037 vars
->wiredCryptKey
[i
] = random();
1038 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1039 vars
->cryptKey
[i
] = random();
1043 IORegistryEntry
* regEntry
;
1044 if (!gIOOptionsEntry
)
1046 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1047 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1048 if (regEntry
&& !gIOOptionsEntry
)
1049 regEntry
->release();
1051 if (!gIOChosenEntry
)
1052 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1054 if (gIOOptionsEntry
)
1056 const OSSymbol
* sym
;
1058 char valueString
[16];
1060 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1063 gIOOptionsEntry
->setProperty(sym
, data
);
1068 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1071 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1074 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1075 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1077 gIOOptionsEntry
->setProperty(sym
, str2
);
1084 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1087 vars
->haveFastBoot
= true;
1089 len
= sprintf(valueString
, "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1090 data
= OSData::withBytes(valueString
, len
+ 1);
1091 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1093 gIOOptionsEntry
->setProperty(sym
, data
);
1099 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1101 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1104 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1106 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1107 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1109 gIOOptionsEntry
->setProperty(sym
, data
);
1114 if (gIOHibernateBootSignature
[0])
1116 data
= OSData::withCapacity(16);
1117 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1122 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1132 value
= (value
<< 4) | c
;
1134 data
->appendBytes(&value
, sizeof(value
));
1136 gIOOptionsEntry
->setProperty(sym
, data
);
1145 if (!vars
->haveFastBoot
)
1147 // set boot volume to zero
1148 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1149 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1150 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1153 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1154 platform
->writeXPRAM(kXPRamAudioVolume
,
1155 &newVolume
, sizeof(newVolume
));
1161 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1162 gIOHibernateState
= kIOHibernateStateHibernating
;
1169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1172 IOHibernateSystemHasSlept(void)
1174 IOHibernateVars
* vars
= &gIOHibernateVars
;
1176 if ((vars
->previewData
= OSDynamicCast(OSData
,
1177 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey
))))
1179 vars
->previewBuffer
= IOMemoryDescriptor::withAddress(
1180 (void *) vars
->previewData
->getBytesNoCopy(),
1181 vars
->previewData
->getLength(),
1184 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1186 vars
->previewBuffer
->release();
1187 vars
->previewBuffer
= 0;
1189 if (!vars
->previewBuffer
)
1190 vars
->previewData
= 0;
1192 if (gIOOptionsEntry
)
1193 gIOOptionsEntry
->sync();
1195 return (kIOReturnSuccess
);
1198 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1201 IOHibernateSystemWake(void)
1203 IOHibernateVars
* vars
= &gIOHibernateVars
;
1205 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1207 if (vars
->videoMapping
)
1209 if (vars
->videoMapSize
)
1211 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1212 if (vars
->videoAllocSize
)
1214 kmem_free(kernel_map
, trunc_page_32(vars
->videoMapping
), vars
->videoAllocSize
);
1217 if (vars
->previewBuffer
)
1219 vars
->previewBuffer
->release();
1220 vars
->previewBuffer
= 0;
1225 IOPolledFileClose(vars
->fileVars
);
1228 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1230 OSData
* data
= OSData::withCapacity(4);
1231 if (gIOOptionsEntry
&& data
)
1233 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1236 gIOOptionsEntry
->setProperty(sym
, data
);
1239 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1242 if (vars
->saveBootDevice
)
1244 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1245 vars
->saveBootDevice
->release();
1249 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1252 gIOOptionsEntry
->setProperty(sym
, data
);
1255 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1258 gIOOptionsEntry
->removeProperty(sym
);
1265 if (gIOOptionsEntry
)
1267 if (!vars
->haveFastBoot
)
1269 // reset boot audio volume
1270 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1272 platform
->writeXPRAM(kXPRamAudioVolume
,
1273 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1276 // sync now to hardware if the booter has not
1277 if (kIOHibernateStateInactive
== gIOHibernateState
)
1278 gIOOptionsEntry
->sync();
1280 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1281 gIOOptionsEntry
->syncOFVariables();
1284 if (vars
->srcBuffer
)
1285 vars
->srcBuffer
->release();
1287 vars
->ioBuffer
->release();
1288 if (vars
->fileExtents
)
1289 vars
->fileExtents
->release();
1291 bzero(vars
, sizeof(*vars
));
1293 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1295 return (kIOReturnSuccess
);
1299 IOHibernateSystemPostWake(void)
1301 if (gIOHibernateFileRef
)
1303 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1304 gIOHibernateFileRef
= 0;
1306 return (kIOReturnSuccess
);
1309 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1312 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1314 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1317 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1321 if (PE_parse_boot_arg("hfile", gIOHibernateFilename
))
1322 gIOHibernateMode
= kIOHibernateModeOn
;
1324 gIOHibernateFilename
[0] = 0;
1326 static SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1327 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1328 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1329 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1331 static SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1332 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1333 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1334 sysctl_register_oid(&sysctl__kern_bootsignature
);
1336 static SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1337 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1338 &gIOHibernateMode
, 0, "");
1339 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1345 hibernate_setup_for_wake(void)
1348 // go slow (state needed for wake)
1349 ml_set_processor_speed(1);
1353 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1355 extern "C" boolean_t
1356 hibernate_write_image(void)
1358 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1359 IOHibernateVars
* vars
= &gIOHibernateVars
;
1360 IOPolledFileExtent
* fileExtents
;
1362 uint32_t pageCount
, pagesDone
;
1365 IOItemCount page
, count
;
1368 IOByteCount pageCompressedSize
;
1369 uint64_t compressedSize
, uncompressedSize
;
1370 uint64_t image1Size
= 0;
1371 uint32_t bitmap_size
;
1372 bool iterDone
, pollerOpen
, needEncryptStart
;
1373 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1376 uint32_t pageAndCount
[2];
1378 AbsoluteTime startTime
, endTime
;
1379 AbsoluteTime allTime
, compTime
, decoTime
;
1381 uint32_t lastProgressStamp
= 0;
1382 uint32_t progressStamp
;
1384 hibernate_cryptvars_t _cryptvars
;
1385 hibernate_cryptvars_t
* cryptvars
= 0;
1387 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1388 return (false /* sleep */ );
1390 restore1Sum
= sum1
= sum2
= 0;
1392 // encryption data. "iv" is the "initial vector".
1393 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1395 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1396 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1397 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1399 cryptvars
= &gIOHibernateCryptWakeContext
;
1400 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1401 aes_encrypt_key(vars
->cryptKey
,
1402 kIOHibernateAESKeySize
,
1403 &cryptvars
->ctx
.encrypt
);
1404 aes_decrypt_key(vars
->cryptKey
,
1405 kIOHibernateAESKeySize
,
1406 &cryptvars
->ctx
.decrypt
);
1408 cryptvars
= &_cryptvars
;
1409 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1410 aes_encrypt_key(vars
->wiredCryptKey
,
1411 kIOHibernateAESKeySize
,
1412 &cryptvars
->ctx
.encrypt
);
1414 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1415 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1416 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1417 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1420 hibernate_setup_for_wake();
1422 hibernate_page_list_setall(vars
->page_list
,
1423 vars
->page_list_wired
,
1426 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1428 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1431 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1432 for (page
= 0; page
< count
; page
++)
1434 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1435 fileExtents
[page
].start
, fileExtents
[page
].length
,
1436 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1440 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1442 AbsoluteTime_to_scalar(&compTime
) = 0;
1443 AbsoluteTime_to_scalar(&decoTime
) = 0;
1445 clock_get_uptime(&allTime
);
1450 uncompressedSize
= 0;
1452 pageType
= 0; // wired pages first
1454 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1456 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1457 ml_get_interrupts_enabled());
1458 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1459 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1460 pollerOpen
= (kIOReturnSuccess
== err
);
1464 // copy file block extent list if larger than header
1466 count
= vars
->fileExtents
->getLength();
1467 if (count
> sizeof(header
->fileExtentMap
))
1469 count
-= sizeof(header
->fileExtentMap
);
1470 err
= IOPolledFileWrite(vars
->fileVars
,
1471 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1472 if (kIOReturnSuccess
!= err
)
1476 // copy out restore1 code
1478 page
= atop_32(sectHIBB
);
1479 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1480 header
->restore1CodePage
= page
;
1481 header
->restore1PageCount
= count
;
1482 header
->restore1CodeOffset
= ((uint32_t) &hibernate_machine_entrypoint
) - sectHIBB
;
1483 header
->restore1StackOffset
= ((uint32_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - sectHIBB
;
1485 // sum __HIB sect, with zeros for the stack
1486 src
= (uint8_t *) trunc_page(sectHIBB
);
1487 for (page
= 0; page
< count
; page
++)
1489 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1490 restore1Sum
+= hibernate_sum(src
, page_size
);
1492 restore1Sum
+= 0x10000001;
1497 // write the __HIB sect, with zeros for the stack
1499 src
= (uint8_t *) trunc_page(sectHIBB
);
1500 count
= ((uint32_t) &gIOHibernateRestoreStack
[0]) - trunc_page(sectHIBB
);
1503 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1504 if (kIOReturnSuccess
!= err
)
1507 err
= IOPolledFileWrite(vars
->fileVars
,
1509 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1511 if (kIOReturnSuccess
!= err
)
1513 src
= &gIOHibernateRestoreStackEnd
[0];
1514 count
= round_page(sectHIBB
+ sectSizeHIB
) - ((uint32_t) src
);
1517 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1518 if (kIOReturnSuccess
!= err
)
1522 // write the preview buffer
1527 if (vars
->previewData
)
1533 phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
);
1534 pageAndCount
[0] = atop_64(phys64
);
1535 pageAndCount
[1] = atop_32(segLen
);
1536 err
= IOPolledFileWrite(vars
->fileVars
,
1537 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1539 if (kIOReturnSuccess
!= err
)
1542 ppnum
+= sizeof(pageAndCount
);
1545 if (kIOReturnSuccess
!= err
)
1548 src
= (uint8_t *) vars
->previewData
->getBytesNoCopy();
1549 count
= vars
->previewData
->getLength();
1551 header
->previewPageListSize
= ppnum
;
1552 header
->previewSize
= count
+ ppnum
;
1554 for (page
= 0; page
< count
; page
+= page_size
)
1555 sum1
+= hibernate_sum(src
+ page
, page_size
);
1557 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1558 if (kIOReturnSuccess
!= err
)
1562 // mark areas for no save
1565 (phys64
= vars
->ioBuffer
->getPhysicalSegment64(count
, &segLen
));
1568 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1569 atop_64(phys64
), atop_32(segLen
),
1570 kIOHibernatePageStateFree
);
1571 pageCount
-= atop_32(segLen
);
1575 (phys64
= vars
->srcBuffer
->getPhysicalSegment64(count
, &segLen
));
1578 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1579 atop_64(phys64
), atop_32(segLen
),
1580 kIOHibernatePageStateFree
);
1581 pageCount
-= atop_32(segLen
);
1584 // copy out bitmap of pages available for trashing during restore
1586 bitmap_size
= vars
->page_list_wired
->list_size
;
1587 src
= (uint8_t *) vars
->page_list_wired
;
1588 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1589 if (kIOReturnSuccess
!= err
)
1592 // mark more areas for no save, but these are not available
1593 // for trashing during restore
1596 page
= atop_32(sectHIBB
);
1597 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1600 page
= atop_32(sectHIBB
& 0x3FFFFFFF);
1601 count
= atop_32(round_page((sectHIBB
+ sectSizeHIB
) & 0x3FFFFFFF)) - page
;
1603 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1605 kIOHibernatePageStateFree
);
1610 if (vars
->previewBuffer
) for (count
= 0;
1611 (phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
));
1614 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1615 atop_64(phys64
), atop_32(segLen
),
1616 kIOHibernatePageStateFree
);
1617 pageCount
-= atop_32(segLen
);
1620 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1625 HIBLOG("writing %d pages\n", pageCount
);
1629 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1631 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1635 pageAndCount
[0] = ppnum
;
1636 pageAndCount
[1] = count
;
1637 err
= IOPolledFileWrite(vars
->fileVars
,
1638 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1640 if (kIOReturnSuccess
!= err
)
1643 for (page
= 0; page
< count
; page
++)
1645 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1648 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__
, ppnum
, err
);
1652 sum
= hibernate_sum(src
, page_size
);
1654 clock_get_uptime(&startTime
);
1656 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1658 clock_get_uptime(&endTime
);
1659 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1660 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1662 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1663 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1665 if (pageCompressedSize
> page_size
)
1667 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1668 pageCompressedSize
= page_size
;
1671 if (pageCompressedSize
!= page_size
)
1672 data
= (src
+ page_size
);
1676 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1683 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
1685 // start encrypting partway into the data about to be written
1686 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
1687 & ~(AES_BLOCK_SIZE
- 1);
1688 needEncryptStart
= false;
1691 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1692 if (kIOReturnSuccess
!= err
)
1695 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1696 if (kIOReturnSuccess
!= err
)
1699 compressedSize
+= pageCompressedSize
;
1700 if (pageCompressedSize
)
1701 uncompressedSize
+= page_size
;
1705 if (0 == (8191 & pagesDone
))
1707 clock_get_uptime(&endTime
);
1708 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1709 absolutetime_to_nanoseconds(endTime
, &nsec
);
1710 progressStamp
= nsec
/ 750000000ULL;
1711 if (progressStamp
!= lastProgressStamp
)
1713 lastProgressStamp
= progressStamp
;
1714 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1718 if (kIOReturnSuccess
!= err
)
1720 if (iterDone
&& !pageType
)
1722 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1723 if (kIOReturnSuccess
!= err
)
1729 image1Size
= vars
->fileVars
->position
;
1732 bcopy(&cryptvars
->aes_iv
[0],
1733 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1734 sizeof(cryptvars
->aes_iv
));
1735 cryptvars
= &gIOHibernateCryptWakeContext
;
1737 HIBLOG("image1Size %qd\n", image1Size
);
1741 if (kIOReturnSuccess
!= err
)
1743 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1744 if (kIOReturnSuccess
!= err
)
1749 header
->imageSize
= vars
->fileVars
->position
;
1750 header
->image1Size
= image1Size
;
1751 header
->bitmapSize
= bitmap_size
;
1752 header
->pageCount
= pageCount
;
1753 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1755 header
->restore1Sum
= restore1Sum
;
1756 header
->image1Sum
= sum1
;
1757 header
->image2Sum
= sum2
;
1759 count
= vars
->fileExtents
->getLength();
1760 if (count
> sizeof(header
->fileExtentMap
))
1762 header
->fileExtentMapSize
= count
;
1763 count
= sizeof(header
->fileExtentMap
);
1766 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1767 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1769 IOPolledFileSeek(vars
->fileVars
, 0);
1770 err
= IOPolledFileWrite(vars
->fileVars
,
1771 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1773 if (kIOReturnSuccess
!= err
)
1775 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1776 if (kIOReturnSuccess
!= err
)
1778 err
= IOHibernatePollerIODone(vars
->fileVars
);
1779 if (kIOReturnSuccess
!= err
)
1784 clock_get_uptime(&endTime
);
1785 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1786 absolutetime_to_nanoseconds(endTime
, &nsec
);
1787 HIBLOG("all time: %qd ms, ",
1790 absolutetime_to_nanoseconds(compTime
, &nsec
);
1791 HIBLOG("comp time: %qd ms, ",
1794 absolutetime_to_nanoseconds(decoTime
, &nsec
);
1795 HIBLOG("deco time: %qd ms, ",
1798 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1800 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
1801 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
1805 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
1807 HIBLOG("hibernate_write_image done(%x)\n", err
);
1809 // should we come back via regular wake, set the state in memory.
1810 gIOHibernateState
= kIOHibernateStateInactive
;
1812 if ((kIOReturnSuccess
== err
) && !(kIOHibernateModeSleep
& gIOHibernateMode
))
1813 return (true /* power down */ );
1815 return (false /* sleep */ );
1818 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1820 DECLARE_IOHIBERNATEPROGRESSALPHA
1823 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1825 uint32_t rowBytes
, pixelShift
;
1827 int32_t blob
, lastBlob
;
1828 uint32_t alpha
, in
, color
, result
;
1830 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1832 pixelShift
= display
->depth
>> 4;
1836 rowBytes
= display
->rowBytes
;
1838 screen
+= ((display
->width
1839 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1840 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1842 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1844 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1846 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1848 out
= screen
+ y
* rowBytes
;
1849 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1851 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1852 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1854 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1860 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1861 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1863 if (1 == pixelShift
)
1866 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1869 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1871 out
+= (1 << pixelShift
);
1873 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1878 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1881 hibernate_machine_init(void)
1886 AbsoluteTime allTime
, endTime
;
1888 uint32_t lastProgressStamp
= 0;
1889 uint32_t progressStamp
;
1890 uint64_t progressZeroPosition
= 0;
1891 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1892 hibernate_cryptvars_t
* cryptvars
= 0;
1894 IOHibernateVars
* vars
= &gIOHibernateVars
;
1896 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1899 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
1900 hibernate_page_list_discard(vars
->page_list
);
1903 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
1904 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
1906 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1907 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
1908 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
1910 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
1912 HIBLOG("regular wake\n");
1916 HIBPRINT("diag %x %x %x %x\n",
1917 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
1918 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
1920 HIBPRINT("video %lx %ld %ld %ld\n",
1921 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
1922 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1924 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
1926 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
1927 * gIOHibernateGraphicsInfo
->rowBytes
);
1928 IOMapPages(kernel_map
,
1929 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
1930 vars
->videoMapSize
, kIOMapInhibitCache
);
1933 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();;
1934 uint32_t decoOffset
;
1936 clock_get_uptime(&allTime
);
1938 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
1939 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
1940 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1942 if (gIOHibernateCurrentHeader
->previewSize
)
1943 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
1944 + gIOHibernateCurrentHeader
->fileExtentMapSize
1945 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
1946 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
1948 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
1950 if (vars
->videoMapping
)
1952 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
1953 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
1954 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
1957 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
1958 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1960 cryptvars
= &gIOHibernateCryptWakeContext
;
1961 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
1962 &cryptvars
->aes_iv
[0],
1963 sizeof(cryptvars
->aes_iv
));
1966 // kick off the read ahead
1967 vars
->fileVars
->io
= false;
1968 vars
->fileVars
->bufferHalf
= 0;
1969 vars
->fileVars
->bufferLimit
= 0;
1970 vars
->fileVars
->lastRead
= 0;
1971 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1973 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
1974 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1977 HIBLOG("hibernate_machine_init reading\n");
1979 uint32_t * header
= (uint32_t *) src
;
1987 vm_offset_t ppnum
, compressedSize
;
1989 IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
1994 // HIBPRINT("(%x, %x)\n", ppnum, count);
1999 for (page
= 0; page
< count
; page
++)
2001 IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2003 compressedSize
= kIOHibernateTagLength
& tag
;
2004 if (!compressedSize
)
2011 IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2013 if (compressedSize
!= page_size
)
2015 decoOffset
= page_size
;
2016 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2021 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2023 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2025 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum
, err
);
2030 if (vars
->videoMapping
&& (0 == (255 & pagesDone
)))
2032 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2033 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2034 if (blob
!= lastBlob
)
2036 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2041 if (0 == (8191 & pagesDone
))
2043 clock_get_uptime(&endTime
);
2044 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2045 absolutetime_to_nanoseconds(endTime
, &nsec
);
2046 progressStamp
= nsec
/ 750000000ULL;
2047 if (progressStamp
!= lastProgressStamp
)
2049 lastProgressStamp
= progressStamp
;
2050 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2051 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2058 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2060 if (vars
->fileVars
->io
)
2061 (void) IOHibernatePollerIODone(vars
->fileVars
);
2063 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2065 if (vars
->videoMapping
)
2066 ProgressUpdate(gIOHibernateGraphicsInfo
,
2067 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2069 clock_get_uptime(&endTime
);
2070 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2071 absolutetime_to_nanoseconds(endTime
, &nsec
);
2073 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2074 pagesDone
, sum
, nsec
/ 1000000ULL);
2077 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */