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, ...)
155 #include <sys/sysctl.h>
158 #include <IOKit/IOHibernatePrivate.h>
159 #include <IOKit/IOPolledInterface.h>
160 #include <IOKit/IONVRAM.h>
161 #include "IOHibernateInternal.h"
163 #include "IOKitKernelInternal.h"
165 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
167 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
169 OSMetaClassDefineReservedUnused(IOPolledInterface
, 0);
170 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
171 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
172 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
173 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
174 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
175 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
176 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
177 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
178 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
179 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
180 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
181 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
182 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
183 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
184 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
186 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
188 extern uint32_t gIOHibernateState
;
189 uint32_t gIOHibernateMode
;
190 static char gIOHibernateBootSignature
[256+1];
191 static char gIOHibernateFilename
[MAXPATHLEN
+1];
192 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
193 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
195 static IODTNVRAM
* gIOOptionsEntry
;
196 static IORegistryEntry
* gIOChosenEntry
;
198 static IOPolledFileIOVars gFileVars
;
199 static IOHibernateVars gIOHibernateVars
;
200 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
201 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
203 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
205 enum { kXPRamAudioVolume
= 8 };
206 enum { kDefaultIOSize
= 128 * 1024 };
207 enum { kVideoMapSize
= 32 * 1024 * 1024 };
209 #ifndef kIOMediaPreferredBlockSizeKey
210 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
213 #ifndef kIOBootPathKey
214 #define kIOBootPathKey "bootpath"
216 #ifndef kIOSelectedBootDeviceKey
217 #define kIOSelectedBootDeviceKey "boot-device"
221 enum { kIOHibernateMinPollersNeeded
= 2 };
223 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
225 // copy from phys addr to MD
228 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
229 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
231 addr64_t srcAddr
= bytes
;
232 IOByteCount remaining
;
234 remaining
= length
= min(length
, md
->getLength() - offset
);
235 while (remaining
) { // (process another target segment?)
239 dstAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
243 // Clip segment length to remaining
244 if (dstLen
> remaining
)
248 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
250 copypv(srcAddr
, dstAddr64
, dstLen
,
251 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
260 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
263 // copy from MD to phys addr
266 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
267 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
269 addr64_t dstAddr
= bytes
;
270 IOByteCount remaining
;
272 remaining
= length
= min(length
, md
->getLength() - offset
);
273 while (remaining
) { // (process another target segment?)
277 srcAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
281 // Clip segment length to remaining
282 if (dstLen
> remaining
)
286 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
288 copypv(srcAddr
, dstAddr64
, dstLen
,
289 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
298 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
301 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
304 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
305 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
310 case kIOHibernatePageStateUnwiredSave
:
312 for (; ppnum
< count
; ppnum
++)
314 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
315 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
318 case kIOHibernatePageStateWiredSave
:
320 for (; ppnum
< count
; ppnum
++)
322 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
323 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
326 case kIOHibernatePageStateFree
:
328 for (; ppnum
< count
; ppnum
++)
330 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
331 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
335 panic("hibernate_set_page_state");
340 hibernate_page_list_iterate(hibernate_page_list_t
* list
,
341 void ** iterator
, vm_offset_t
* ppnum
)
345 idx
= (uint32_t) *iterator
;
348 idx
= hibernate_page_list_count(list
, TRUE
, idx
);
351 count
= hibernate_page_list_count(list
, FALSE
, idx
);
353 idx
+= hibernate_page_list_count(list
, TRUE
, idx
);
354 *iterator
= (void *) idx
;
359 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
362 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
364 IOReturn err
= kIOReturnError
;
366 IOPolledInterface
* poller
;
368 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
370 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
371 err
= poller
->probe(target
);
374 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
383 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
385 IOReturn err
= kIOReturnError
;
387 IOPolledInterface
* poller
;
389 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
391 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
392 err
= poller
->open(state
, md
);
395 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
404 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
406 IOReturn err
= kIOReturnError
;
408 IOPolledInterface
* poller
;
411 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
414 err
= poller
->close(state
);
416 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
423 IOHibernatePollerIOComplete(void * target
,
426 UInt64 actualByteCount
)
428 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
430 vars
->ioStatus
= status
;
434 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
435 uint32_t operation
, uint32_t bufferOffset
,
436 uint64_t deviceOffset
, uint64_t length
)
439 IOReturn err
= kIOReturnError
;
440 IOPolledInterface
* poller
;
441 IOPolledCompletion completion
;
443 completion
.target
= 0;
444 completion
.action
= &IOHibernatePollerIOComplete
;
445 completion
.parameter
= vars
;
449 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
450 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
452 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
458 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
)
460 IOReturn err
= kIOReturnError
;
462 IOPolledInterface
* poller
;
464 while (-1 == vars
->ioStatus
)
467 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
470 err
= poller
->checkForWork();
472 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
476 if (kIOReturnSuccess
!= vars
->ioStatus
)
477 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars
->ioStatus
);
479 return (vars
->ioStatus
);
483 IOPolledInterface::checkAllForWork(void)
485 IOReturn err
= kIOReturnNotReady
;
487 IOPolledInterface
* poller
;
489 IOHibernateVars
* vars
= &gIOHibernateVars
;
491 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
495 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
498 err
= poller
->checkForWork();
500 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
506 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
508 struct _OpenFileContext
515 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
517 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
518 IOPolledFileExtent extent
;
520 extent
.start
= start
;
521 extent
.length
= length
;
523 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
528 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
529 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
532 IOReturn err
= kIOReturnError
;
533 IOPolledFileIOVars
* vars
;
534 _OpenFileContext ctx
;
535 OSData
* extentsData
;
537 IORegistryEntry
* part
= 0;
538 OSDictionary
* matching
;
540 dev_t hibernate_image_dev
;
546 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
547 if (sizeof(IOHibernateImageHeader
) != 512)
551 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
552 vars
->bufferHalf
= 0;
553 vars
->bufferOffset
= 0;
554 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
556 extentsData
= OSData::withCapacity(32);
558 ctx
.extents
= extentsData
;
560 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
561 &file_extent_callback
, &ctx
,
562 &hibernate_image_dev
,
567 err
= kIOReturnNoSpace
;
570 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
571 vars
->block0
, maxiobytes
);
572 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
574 err
= kIOReturnNoSpace
;
578 if (maxiobytes
< vars
->bufferSize
)
579 vars
->bufferSize
= maxiobytes
;
581 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
583 matching
= IOService::serviceMatching("IOMedia");
584 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
585 matching
->setObject(kIOBSDMajorKey
, num
);
587 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
588 matching
->setObject(kIOBSDMinorKey
, num
);
590 iter
= IOService::getMatchingServices(matching
);
594 part
= (IORegistryEntry
*) iter
->getNextObject();
600 IORegistryEntry
* next
;
601 IORegistryEntry
* child
;
604 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
607 major
= num
->unsigned32BitValue();
608 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
611 minor
= num
->unsigned32BitValue();
613 hibernate_image_dev
= makedev(major
, minor
);
615 vars
->pollers
= OSArray::withCapacity(4);
619 vars
->blockSize
= 512;
623 IOPolledInterface
* poller
;
624 if ((poller
= OSDynamicCast(IOPolledInterface
, next
->getProperty(kIOPolledInterfaceSupportKey
))))
625 vars
->pollers
->setObject(poller
);
626 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
627 vars
->blockSize
= num
->unsigned32BitValue();
630 while ((next
= child
->getParentEntry(gIOServicePlane
))
631 && child
->isParent(next
, gIOServicePlane
, true));
633 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
634 major
, minor
, vars
->blockSize
, vars
->pollers
->getCount());
635 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
638 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
639 if (kIOReturnSuccess
!= err
)
642 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
643 if (kIOReturnSuccess
!= err
)
647 *fileExtents
= extentsData
;
652 int len
= sizeof(str1
);
654 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
))
655 && part
->getPath(str1
, &len
, gIODTPlane
))
657 // (strip the plane name)
658 char * tail
= strchr(str1
, ':');
661 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
662 sprintf(str2
, ",%qx", vars
->extentMap
[0]);
663 data
->appendBytes(str2
, strlen(str2
));
669 if (kIOReturnSuccess
!= err
)
671 HIBLOG("error 0x%x opening hibernation file\n", err
);
673 kern_close_file_for_direct_io(vars
->fileRef
);
683 IOPolledFileClose( IOPolledFileIOVars
* vars
)
687 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
688 vars
->pollers
->release();
691 gIOHibernateFileRef
= vars
->fileRef
;
693 bzero(vars
, sizeof(IOPolledFileIOVars
));
695 return (kIOReturnSuccess
);
699 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
701 IOPolledFileExtent
* extentMap
;
703 extentMap
= vars
->extentMap
;
705 vars
->position
= position
;
707 while (position
>= extentMap
->length
)
709 position
-= extentMap
->length
;
713 vars
->currentExtent
= extentMap
;
714 vars
->extentRemaining
= extentMap
->length
- position
;
715 vars
->extentPosition
= vars
->position
- position
;
717 if (vars
->bufferSize
<= vars
->extentRemaining
)
718 vars
->bufferLimit
= vars
->bufferSize
;
720 vars
->bufferLimit
= vars
->extentRemaining
;
722 return (kIOReturnSuccess
);
726 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
727 const uint8_t * bytes
, IOByteCount size
,
728 hibernate_cryptvars_t
* cryptvars
)
730 IOReturn err
= kIOReturnSuccess
;
738 // seek to end of block & flush
739 size
= vars
->position
& (vars
->blockSize
- 1);
741 size
= vars
->blockSize
- size
;
743 // use some garbage for the fill
744 bytes
= vars
->buffer
+ vars
->bufferOffset
;
747 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
755 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
759 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
762 vars
->bufferOffset
+= copy
;
763 vars
->position
+= copy
;
765 if (flush
&& vars
->bufferOffset
)
767 uint64_t offset
= (vars
->position
- vars
->bufferOffset
768 - vars
->extentPosition
+ vars
->currentExtent
->start
);
769 uint32_t length
= (vars
->bufferOffset
);
771 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
773 uint32_t encryptLen
, encryptStart
;
774 encryptLen
= vars
->position
- vars
->encryptStart
;
775 if (encryptLen
> length
)
777 encryptStart
= length
- encryptLen
;
779 // encrypt the buffer
780 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
781 &cryptvars
->aes_iv
[0],
782 encryptLen
/ AES_BLOCK_SIZE
,
783 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
784 &cryptvars
->ctx
.encrypt
);
785 // save initial vector for following encrypts
786 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
787 &cryptvars
->aes_iv
[0],
793 err
= IOHibernatePollerIODone(vars
);
794 if (kIOReturnSuccess
!= err
)
798 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
799 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
801 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
802 if (kIOReturnSuccess
!= err
)
806 vars
->extentRemaining
-= vars
->bufferOffset
;
807 if (!vars
->extentRemaining
)
809 vars
->currentExtent
++;
810 vars
->extentRemaining
= vars
->currentExtent
->length
;
811 vars
->extentPosition
= vars
->position
;
812 if (!vars
->extentRemaining
)
814 err
= kIOReturnOverrun
;
819 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
820 vars
->bufferOffset
= 0;
821 if (vars
->bufferSize
<= vars
->extentRemaining
)
822 vars
->bufferLimit
= vars
->bufferSize
;
824 vars
->bufferLimit
= vars
->extentRemaining
;
835 IOPolledFileRead(IOPolledFileIOVars
* vars
,
836 uint8_t * bytes
, IOByteCount size
,
837 hibernate_cryptvars_t
* cryptvars
)
839 IOReturn err
= kIOReturnSuccess
;
842 // bytesWritten += size;
846 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
852 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
856 vars
->bufferOffset
+= copy
;
857 // vars->position += copy;
859 if (vars
->bufferOffset
== vars
->bufferLimit
)
863 err
= IOHibernatePollerIODone(vars
);
864 if (kIOReturnSuccess
!= err
)
870 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
872 vars
->position
+= vars
->lastRead
;
873 vars
->extentRemaining
-= vars
->lastRead
;
874 vars
->bufferLimit
= vars
->lastRead
;
876 if (!vars
->extentRemaining
)
878 vars
->currentExtent
++;
879 vars
->extentRemaining
= vars
->currentExtent
->length
;
880 vars
->extentPosition
= vars
->position
;
881 if (!vars
->extentRemaining
)
883 err
= kIOReturnOverrun
;
888 if (vars
->extentRemaining
<= vars
->bufferSize
)
889 vars
->lastRead
= vars
->extentRemaining
;
891 vars
->lastRead
= vars
->bufferSize
;
893 uint64_t offset
= (vars
->position
894 - vars
->extentPosition
+ vars
->currentExtent
->start
);
895 uint64_t length
= (vars
->lastRead
);
897 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
899 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
900 if (kIOReturnSuccess
!= err
)
904 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
905 vars
->bufferOffset
= 0;
909 uint8_t thisVector
[AES_BLOCK_SIZE
];
910 // save initial vector for following decrypts
911 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
912 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->lastRead
- AES_BLOCK_SIZE
,
913 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
914 // decrypt the buffer
915 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
917 vars
->lastRead
/ AES_BLOCK_SIZE
,
918 vars
->buffer
+ vars
->bufferHalf
,
919 &cryptvars
->ctx
.decrypt
);
928 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
931 IOHibernateSystemSleep(void)
939 IOHibernateVars
* vars
= &gIOHibernateVars
;
941 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
942 // already on the way down
943 return (kIOReturnSuccess
);
945 gIOHibernateState
= kIOHibernateStateInactive
;
947 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
)))
949 if ((num
= OSDynamicCast(OSNumber
, obj
)))
950 gIOHibernateMode
= num
->unsigned32BitValue();
951 if (kIOHibernateModeSleep
& gIOHibernateMode
)
952 // default to discard clean for safe sleep
953 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
954 | kIOHibernateModeDiscardCleanActive
);
958 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
)))
960 if ((num
= OSDynamicCast(OSNumber
, obj
)))
961 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
964 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
966 if ((num
= OSDynamicCast(OSNumber
, obj
)))
967 gIOHibernateFreeTime
= num
->unsigned32BitValue();
970 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
972 if ((str
= OSDynamicCast(OSString
, obj
)))
973 strcpy(gIOHibernateFilename
, str
->getCStringNoCopy());
977 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
978 return (kIOReturnUnsupported
);
980 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
984 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(0, 4 * page_size
, page_size
);
985 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize
, page_size
);
987 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
989 err
= kIOReturnNoMemory
;
993 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
994 &vars
->fileVars
, &vars
->fileExtents
, &data
);
995 if (KERN_SUCCESS
!= err
)
997 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1000 if (vars
->fileVars
->fileRef
)
1002 // invalidate the image file
1003 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1004 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1005 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1006 if (KERN_SUCCESS
!= err
)
1007 HIBLOG("kern_write_file(%d)\n", err
);
1010 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1012 boolean_t encryptedswap
;
1013 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1014 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1015 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1016 if (KERN_SUCCESS
!= err
)
1018 HIBLOG("hibernate_setup(%d)\n", err
);
1023 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1025 vars
->videoAllocSize
= kVideoMapSize
;
1026 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1027 vars
->videoMapping
= 0;
1029 // generate crypt keys
1030 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1031 vars
->wiredCryptKey
[i
] = random();
1032 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1033 vars
->cryptKey
[i
] = random();
1037 IORegistryEntry
* regEntry
;
1038 if (!gIOOptionsEntry
)
1040 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1041 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1042 if (regEntry
&& !gIOOptionsEntry
)
1043 regEntry
->release();
1045 if (!gIOChosenEntry
)
1046 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1048 if (gIOOptionsEntry
)
1050 const OSSymbol
* sym
;
1052 char valueString
[16];
1054 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1057 gIOOptionsEntry
->setProperty(sym
, data
);
1062 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1065 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1068 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1069 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1071 gIOOptionsEntry
->setProperty(sym
, str2
);
1078 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1081 vars
->haveFastBoot
= true;
1083 len
= sprintf(valueString
, "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1084 data
= OSData::withBytes(valueString
, len
+ 1);
1085 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1087 gIOOptionsEntry
->setProperty(sym
, data
);
1093 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1095 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1098 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1100 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1101 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1103 gIOOptionsEntry
->setProperty(sym
, data
);
1108 if (gIOHibernateBootSignature
[0])
1110 data
= OSData::withCapacity(16);
1111 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1116 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1126 value
= (value
<< 4) | c
;
1128 data
->appendBytes(&value
, sizeof(value
));
1130 gIOOptionsEntry
->setProperty(sym
, data
);
1139 if (!vars
->haveFastBoot
)
1141 // set boot volume to zero
1142 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1143 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1144 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1147 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1148 platform
->writeXPRAM(kXPRamAudioVolume
,
1149 &newVolume
, sizeof(newVolume
));
1155 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1156 gIOHibernateState
= kIOHibernateStateHibernating
;
1163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1166 IOHibernateSystemHasSlept(void)
1168 IOHibernateVars
* vars
= &gIOHibernateVars
;
1170 if ((vars
->previewData
= OSDynamicCast(OSData
,
1171 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey
))))
1173 vars
->previewBuffer
= IOMemoryDescriptor::withAddress(
1174 (void *) vars
->previewData
->getBytesNoCopy(),
1175 vars
->previewData
->getLength(),
1178 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1180 vars
->previewBuffer
->release();
1181 vars
->previewBuffer
= 0;
1183 if (!vars
->previewBuffer
)
1184 vars
->previewData
= 0;
1186 if (gIOOptionsEntry
)
1187 gIOOptionsEntry
->sync();
1189 return (kIOReturnSuccess
);
1192 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1195 IOHibernateSystemWake(void)
1197 IOHibernateVars
* vars
= &gIOHibernateVars
;
1199 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1201 if (vars
->videoMapping
)
1203 if (vars
->videoMapSize
)
1205 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1206 if (vars
->videoAllocSize
)
1208 kmem_free(kernel_map
, trunc_page_32(vars
->videoMapping
), vars
->videoAllocSize
);
1211 if (vars
->previewBuffer
)
1213 vars
->previewBuffer
->release();
1214 vars
->previewBuffer
= 0;
1219 IOPolledFileClose(vars
->fileVars
);
1222 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1224 OSData
* data
= OSData::withCapacity(4);
1225 if (gIOOptionsEntry
&& data
)
1227 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1230 gIOOptionsEntry
->setProperty(sym
, data
);
1233 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1236 if (vars
->saveBootDevice
)
1238 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1239 vars
->saveBootDevice
->release();
1243 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1246 gIOOptionsEntry
->setProperty(sym
, data
);
1249 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1252 gIOOptionsEntry
->removeProperty(sym
);
1259 if (gIOOptionsEntry
)
1261 if (!vars
->haveFastBoot
)
1263 // reset boot audio volume
1264 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1266 platform
->writeXPRAM(kXPRamAudioVolume
,
1267 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1270 // sync now to hardware if the booter has not
1271 if (kIOHibernateStateInactive
== gIOHibernateState
)
1272 gIOOptionsEntry
->sync();
1274 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1275 gIOOptionsEntry
->syncOFVariables();
1278 if (vars
->srcBuffer
)
1279 vars
->srcBuffer
->release();
1281 vars
->ioBuffer
->release();
1282 if (vars
->fileExtents
)
1283 vars
->fileExtents
->release();
1285 bzero(vars
, sizeof(*vars
));
1287 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1289 return (kIOReturnSuccess
);
1293 IOHibernateSystemPostWake(void)
1295 if (gIOHibernateFileRef
)
1297 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1298 gIOHibernateFileRef
= 0;
1300 return (kIOReturnSuccess
);
1303 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1306 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1308 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1311 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1315 if (PE_parse_boot_arg("hfile", gIOHibernateFilename
))
1316 gIOHibernateMode
= kIOHibernateModeOn
;
1318 gIOHibernateFilename
[0] = 0;
1320 static SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1321 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1322 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1323 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1325 static SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1326 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1327 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1328 sysctl_register_oid(&sysctl__kern_bootsignature
);
1330 static SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1331 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1332 &gIOHibernateMode
, 0, "");
1333 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1336 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1339 hibernate_setup_for_wake(void)
1342 // go slow (state needed for wake)
1343 ml_set_processor_speed(1);
1347 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1349 extern "C" boolean_t
1350 hibernate_write_image(void)
1352 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1353 IOHibernateVars
* vars
= &gIOHibernateVars
;
1354 IOPolledFileExtent
* fileExtents
;
1356 uint32_t pageCount
, pagesDone
;
1359 IOItemCount page
, count
;
1362 IOByteCount pageCompressedSize
;
1363 uint64_t compressedSize
, uncompressedSize
;
1364 uint64_t image1Size
= 0;
1365 uint32_t bitmap_size
;
1366 bool iterDone
, pollerOpen
, needEncryptStart
;
1367 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1370 uint32_t pageAndCount
[2];
1372 AbsoluteTime startTime
, endTime
;
1373 AbsoluteTime allTime
, compTime
, decoTime
;
1375 uint32_t lastProgressStamp
= 0;
1376 uint32_t progressStamp
;
1378 hibernate_cryptvars_t _cryptvars
;
1379 hibernate_cryptvars_t
* cryptvars
= 0;
1381 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1382 return (false /* sleep */ );
1384 restore1Sum
= sum1
= sum2
= 0;
1386 // encryption data. "iv" is the "initial vector".
1387 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1389 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1390 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1391 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1393 cryptvars
= &gIOHibernateCryptWakeContext
;
1394 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1395 aes_encrypt_key(vars
->cryptKey
,
1396 kIOHibernateAESKeySize
,
1397 &cryptvars
->ctx
.encrypt
);
1398 aes_decrypt_key(vars
->cryptKey
,
1399 kIOHibernateAESKeySize
,
1400 &cryptvars
->ctx
.decrypt
);
1402 cryptvars
= &_cryptvars
;
1403 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1404 aes_encrypt_key(vars
->wiredCryptKey
,
1405 kIOHibernateAESKeySize
,
1406 &cryptvars
->ctx
.encrypt
);
1408 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1409 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1410 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1411 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1414 hibernate_setup_for_wake();
1416 hibernate_page_list_setall(vars
->page_list
,
1417 vars
->page_list_wired
,
1420 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1422 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1425 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1426 for (page
= 0; page
< count
; page
++)
1428 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1429 fileExtents
[page
].start
, fileExtents
[page
].length
,
1430 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1434 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1436 AbsoluteTime_to_scalar(&compTime
) = 0;
1437 AbsoluteTime_to_scalar(&decoTime
) = 0;
1439 clock_get_uptime(&allTime
);
1444 uncompressedSize
= 0;
1446 pageType
= 0; // wired pages first
1448 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1450 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1451 ml_get_interrupts_enabled());
1452 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1453 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1454 pollerOpen
= (kIOReturnSuccess
== err
);
1458 // copy file block extent list if larger than header
1460 count
= vars
->fileExtents
->getLength();
1461 if (count
> sizeof(header
->fileExtentMap
))
1463 count
-= sizeof(header
->fileExtentMap
);
1464 err
= IOPolledFileWrite(vars
->fileVars
,
1465 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1466 if (kIOReturnSuccess
!= err
)
1470 // copy out restore1 code
1472 page
= atop_32(sectHIBB
);
1473 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1474 header
->restore1CodePage
= page
;
1475 header
->restore1PageCount
= count
;
1476 header
->restore1CodeOffset
= ((uint32_t) &hibernate_machine_entrypoint
) - sectHIBB
;
1477 header
->restore1StackOffset
= ((uint32_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - sectHIBB
;
1479 // sum __HIB sect, with zeros for the stack
1480 src
= (uint8_t *) trunc_page(sectHIBB
);
1481 for (page
= 0; page
< count
; page
++)
1483 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1484 restore1Sum
+= hibernate_sum(src
, page_size
);
1486 restore1Sum
+= 0x10000001;
1491 // write the __HIB sect, with zeros for the stack
1493 src
= (uint8_t *) trunc_page(sectHIBB
);
1494 count
= ((uint32_t) &gIOHibernateRestoreStack
[0]) - trunc_page(sectHIBB
);
1497 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1498 if (kIOReturnSuccess
!= err
)
1501 err
= IOPolledFileWrite(vars
->fileVars
,
1503 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1505 if (kIOReturnSuccess
!= err
)
1507 src
= &gIOHibernateRestoreStackEnd
[0];
1508 count
= round_page(sectHIBB
+ sectSizeHIB
) - ((uint32_t) src
);
1511 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1512 if (kIOReturnSuccess
!= err
)
1516 // write the preview buffer
1521 if (vars
->previewData
)
1527 phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
);
1528 pageAndCount
[0] = atop_64(phys64
);
1529 pageAndCount
[1] = atop_32(segLen
);
1530 err
= IOPolledFileWrite(vars
->fileVars
,
1531 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1533 if (kIOReturnSuccess
!= err
)
1536 ppnum
+= sizeof(pageAndCount
);
1539 if (kIOReturnSuccess
!= err
)
1542 src
= (uint8_t *) vars
->previewData
->getBytesNoCopy();
1543 count
= vars
->previewData
->getLength();
1545 header
->previewPageListSize
= ppnum
;
1546 header
->previewSize
= count
+ ppnum
;
1548 for (page
= 0; page
< count
; page
+= page_size
)
1549 sum1
+= hibernate_sum(src
+ page
, page_size
);
1551 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1552 if (kIOReturnSuccess
!= err
)
1556 // mark areas for no save
1559 (phys64
= vars
->ioBuffer
->getPhysicalSegment64(count
, &segLen
));
1562 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1563 atop_64(phys64
), atop_32(segLen
),
1564 kIOHibernatePageStateFree
);
1565 pageCount
-= atop_32(segLen
);
1569 (phys64
= vars
->srcBuffer
->getPhysicalSegment64(count
, &segLen
));
1572 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1573 atop_64(phys64
), atop_32(segLen
),
1574 kIOHibernatePageStateFree
);
1575 pageCount
-= atop_32(segLen
);
1578 // copy out bitmap of pages available for trashing during restore
1580 bitmap_size
= vars
->page_list_wired
->list_size
;
1581 src
= (uint8_t *) vars
->page_list_wired
;
1582 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1583 if (kIOReturnSuccess
!= err
)
1586 // mark more areas for no save, but these are not available
1587 // for trashing during restore
1590 page
= atop_32(sectHIBB
);
1591 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1594 page
= atop_32(sectHIBB
& 0x3FFFFFFF);
1595 count
= atop_32(round_page((sectHIBB
+ sectSizeHIB
) & 0x3FFFFFFF)) - page
;
1597 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1599 kIOHibernatePageStateFree
);
1604 if (vars
->previewBuffer
) for (count
= 0;
1605 (phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
));
1608 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1609 atop_64(phys64
), atop_32(segLen
),
1610 kIOHibernatePageStateFree
);
1611 pageCount
-= atop_32(segLen
);
1614 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1619 HIBLOG("writing %d pages\n", pageCount
);
1623 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1625 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1629 pageAndCount
[0] = ppnum
;
1630 pageAndCount
[1] = count
;
1631 err
= IOPolledFileWrite(vars
->fileVars
,
1632 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1634 if (kIOReturnSuccess
!= err
)
1637 for (page
= 0; page
< count
; page
++)
1639 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1642 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__
, ppnum
, err
);
1646 sum
= hibernate_sum(src
, page_size
);
1648 clock_get_uptime(&startTime
);
1650 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1652 clock_get_uptime(&endTime
);
1653 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1654 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1656 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1657 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1659 if (pageCompressedSize
> page_size
)
1661 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1662 pageCompressedSize
= page_size
;
1665 if (pageCompressedSize
!= page_size
)
1666 data
= (src
+ page_size
);
1670 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1677 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
1679 // start encrypting partway into the data about to be written
1680 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
1681 & ~(AES_BLOCK_SIZE
- 1);
1682 needEncryptStart
= false;
1685 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1686 if (kIOReturnSuccess
!= err
)
1689 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1690 if (kIOReturnSuccess
!= err
)
1693 compressedSize
+= pageCompressedSize
;
1694 if (pageCompressedSize
)
1695 uncompressedSize
+= page_size
;
1699 if (0 == (8191 & pagesDone
))
1701 clock_get_uptime(&endTime
);
1702 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1703 absolutetime_to_nanoseconds(endTime
, &nsec
);
1704 progressStamp
= nsec
/ 750000000ULL;
1705 if (progressStamp
!= lastProgressStamp
)
1707 lastProgressStamp
= progressStamp
;
1708 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1712 if (kIOReturnSuccess
!= err
)
1714 if (iterDone
&& !pageType
)
1716 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1717 if (kIOReturnSuccess
!= err
)
1723 image1Size
= vars
->fileVars
->position
;
1726 bcopy(&cryptvars
->aes_iv
[0],
1727 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1728 sizeof(cryptvars
->aes_iv
));
1729 cryptvars
= &gIOHibernateCryptWakeContext
;
1731 HIBLOG("image1Size %qd\n", image1Size
);
1735 if (kIOReturnSuccess
!= err
)
1737 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1738 if (kIOReturnSuccess
!= err
)
1743 header
->imageSize
= vars
->fileVars
->position
;
1744 header
->image1Size
= image1Size
;
1745 header
->bitmapSize
= bitmap_size
;
1746 header
->pageCount
= pageCount
;
1747 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1749 header
->restore1Sum
= restore1Sum
;
1750 header
->image1Sum
= sum1
;
1751 header
->image2Sum
= sum2
;
1753 count
= vars
->fileExtents
->getLength();
1754 if (count
> sizeof(header
->fileExtentMap
))
1756 header
->fileExtentMapSize
= count
;
1757 count
= sizeof(header
->fileExtentMap
);
1760 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1761 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1763 IOPolledFileSeek(vars
->fileVars
, 0);
1764 err
= IOPolledFileWrite(vars
->fileVars
,
1765 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1767 if (kIOReturnSuccess
!= err
)
1769 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1770 if (kIOReturnSuccess
!= err
)
1772 err
= IOHibernatePollerIODone(vars
->fileVars
);
1773 if (kIOReturnSuccess
!= err
)
1778 clock_get_uptime(&endTime
);
1779 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1780 absolutetime_to_nanoseconds(endTime
, &nsec
);
1781 HIBLOG("all time: %qd ms, ",
1784 absolutetime_to_nanoseconds(compTime
, &nsec
);
1785 HIBLOG("comp time: %qd ms, ",
1788 absolutetime_to_nanoseconds(decoTime
, &nsec
);
1789 HIBLOG("deco time: %qd ms, ",
1792 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1794 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
1795 (int) ((compressedSize
* 100ULL) / uncompressedSize
),
1799 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
1801 HIBLOG("hibernate_write_image done(%x)\n", err
);
1803 // should we come back via regular wake, set the state in memory.
1804 gIOHibernateState
= kIOHibernateStateInactive
;
1806 if ((kIOReturnSuccess
== err
) && !(kIOHibernateModeSleep
& gIOHibernateMode
))
1807 return (true /* power down */ );
1809 return (false /* sleep */ );
1812 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1814 DECLARE_IOHIBERNATEPROGRESSALPHA
1817 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1819 uint32_t rowBytes
, pixelShift
;
1821 int32_t blob
, lastBlob
;
1822 uint32_t alpha
, in
, color
, result
;
1824 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1826 pixelShift
= display
->depth
>> 4;
1830 rowBytes
= display
->rowBytes
;
1832 screen
+= ((display
->width
1833 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1834 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1836 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1838 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1840 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1842 out
= screen
+ y
* rowBytes
;
1843 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1845 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1846 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1848 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1854 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1855 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1857 if (1 == pixelShift
)
1860 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1863 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1865 out
+= (1 << pixelShift
);
1867 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1872 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1875 hibernate_machine_init(void)
1880 AbsoluteTime allTime
, endTime
;
1882 uint32_t lastProgressStamp
= 0;
1883 uint32_t progressStamp
;
1884 uint64_t progressZeroPosition
= 0;
1885 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1886 hibernate_cryptvars_t
* cryptvars
= 0;
1888 IOHibernateVars
* vars
= &gIOHibernateVars
;
1890 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1893 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
1894 hibernate_page_list_discard(vars
->page_list
);
1897 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
1898 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
1900 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1901 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
1902 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
1904 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
1906 HIBLOG("regular wake\n");
1910 HIBPRINT("diag %x %x %x %x\n",
1911 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
1912 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
1914 HIBPRINT("video %x %d %d %d\n",
1915 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
1916 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1918 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
1920 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
1921 * gIOHibernateGraphicsInfo
->rowBytes
);
1922 IOMapPages(kernel_map
,
1923 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
1924 vars
->videoMapSize
, kIOMapInhibitCache
);
1927 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();;
1928 uint32_t decoOffset
;
1930 clock_get_uptime(&allTime
);
1932 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
1933 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
1934 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1936 if (gIOHibernateCurrentHeader
->previewSize
)
1937 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
1938 + gIOHibernateCurrentHeader
->fileExtentMapSize
1939 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
1940 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
1942 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
1944 if (vars
->videoMapping
)
1946 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
1947 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
1948 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
1951 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
1952 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1954 cryptvars
= &gIOHibernateCryptWakeContext
;
1955 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
1956 &cryptvars
->aes_iv
[0],
1957 sizeof(cryptvars
->aes_iv
));
1960 // kick off the read ahead
1961 vars
->fileVars
->io
= false;
1962 vars
->fileVars
->bufferHalf
= 0;
1963 vars
->fileVars
->bufferLimit
= 0;
1964 vars
->fileVars
->lastRead
= 0;
1965 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1967 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
1968 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
1971 HIBLOG("hibernate_machine_init reading\n");
1973 uint32_t * header
= (uint32_t *) src
;
1981 vm_offset_t ppnum
, compressedSize
;
1983 IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
1988 // HIBPRINT("(%x, %x)\n", ppnum, count);
1993 for (page
= 0; page
< count
; page
++)
1995 IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
1997 compressedSize
= kIOHibernateTagLength
& tag
;
1998 if (!compressedSize
)
2005 IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2007 if (compressedSize
!= page_size
)
2009 decoOffset
= page_size
;
2010 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2015 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2017 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2019 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum
, err
);
2024 if (vars
->videoMapping
&& (0 == (255 & pagesDone
)))
2026 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2027 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2028 if (blob
!= lastBlob
)
2030 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2035 if (0 == (8191 & pagesDone
))
2037 clock_get_uptime(&endTime
);
2038 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2039 absolutetime_to_nanoseconds(endTime
, &nsec
);
2040 progressStamp
= nsec
/ 750000000ULL;
2041 if (progressStamp
!= lastProgressStamp
)
2043 lastProgressStamp
= progressStamp
;
2044 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2045 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2052 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2054 if (vars
->fileVars
->io
)
2055 (void) IOHibernatePollerIODone(vars
->fileVars
);
2057 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2059 if (vars
->videoMapping
)
2060 ProgressUpdate(gIOHibernateGraphicsInfo
,
2061 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2063 clock_get_uptime(&endTime
);
2064 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2065 absolutetime_to_nanoseconds(endTime
, &nsec
);
2067 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2068 pagesDone
, sum
, nsec
/ 1000000ULL);
2071 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */