2 * Copyright (c) 2004-2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
35 (devices awake, normal execution context)
36 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
37 grabs its extents and searches for a polling driver willing to work with that IOMedia.
38 The BSD code makes an ioctl to the storage driver to get the partition base offset to
39 the disk, and other ioctls to get the transfer constraints
40 If successful, the file is written to make sure its initially not bootable (in case of
41 later failure) and nvram set to point to the first block of the file. (Has to be done
42 here so blocking is possible in nvram support).
43 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
44 page out any pages it wants to (currently zero, but probably some percentage of memory).
45 Its assumed just allocating pages will cause the VM system to naturally select the best
46 pages for eviction. It also copies processor flags needed for the restore path and sets
47 a flag in the boot processor proc info.
48 gIOHibernateState = kIOHibernateStateHibernating.
49 - Regular sleep progresses - some drivers may inspect the root domain property
50 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
51 as usual but leaves motherboard I/O on.
52 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
53 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
54 all ppc RC bits out of the hash table and caches into the mapping structures.
55 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
56 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
57 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
58 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
59 The image header and block list are written. The header includes the second file extent so
60 only the header block is needed to read the file, regardless of filesystem.
61 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
62 (only) is used to decompress the image during wake/boot.
63 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
64 The bitmaps are written to the image.
65 More areas are removed from the bitmaps (after they have been written to the image) - the
66 section "__HIB" pages and interrupt stack.
67 Each wired page is compressed and written and then each non-wired page. Compression and
68 disk writes are in parallel.
69 The image header is written to the start of the file and the polling driver closed.
70 The machine powers down (or sleeps).
74 - BootX sees the boot-image nvram variable containing the device and block number of the image,
75 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
76 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
77 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
78 that is in the kernel's __HIB section.
79 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
80 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
81 only code & data in that section is safe to call since all the other wired pages are still
82 compressed in the image.
83 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
84 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
85 location directly, and copies those that can't to interim free pages. When the image has been
86 completed, the copies are uncompressed, overwriting the wired image pages.
87 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
88 is used to get pages into place for 64bit.
89 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
90 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
91 are removed from the software strutures, and the hash table is reinitialized.
92 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
93 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
94 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
95 for the remaining non wired pages.
96 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
97 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
102 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
103 registry, specifying an object of calls IOPolledInterface.
105 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
106 partition) that the image is going to live, looking for polled interface properties. If it finds
107 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
108 interfaces found are kept in an ordered list.
110 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
111 few different contexts things happen in:
113 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
114 up and running) and after wake - this is safe to allocate memory and do anything. The device
115 ignores sleep requests from that point since its a waste of time if it goes to sleep and
116 immediately wakes back up for the image write.
118 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
119 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
120 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
121 used to flush and set the disk to sleep.
123 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
124 immediately after sleep. These can't block or allocate memory. This is happening after the platform
125 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
128 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
129 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
130 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
131 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
132 that is called for the hardware to check for events, and complete the I/O via the callback.
133 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
137 #include <sys/systm.h>
139 #include <IOKit/IOWorkLoop.h>
140 #include <IOKit/IOCommandGate.h>
141 #include <IOKit/IOTimerEventSource.h>
142 #include <IOKit/IOPlatformExpert.h>
143 #include <IOKit/IOKitDebug.h>
144 #include <IOKit/IOTimeStamp.h>
145 #include <IOKit/pwr_mgt/RootDomain.h>
146 #include <IOKit/pwr_mgt/IOPMPrivate.h>
147 #include <IOKit/IOMessage.h>
148 #include <IOKit/IODeviceTreeSupport.h>
149 #include <IOKit/IOBSD.h>
150 #include "RootDomainUserClient.h"
151 #include <IOKit/pwr_mgt/IOPowerConnection.h>
152 #include "IOPMPowerStateQueue.h"
153 #include <IOKit/IOBufferMemoryDescriptor.h>
154 #include <crypto/aes.h>
157 #include <sys/conf.h>
158 #include <sys/stat.h>
159 #include <sys/fcntl.h> // (FWRITE, ...)
160 #include <sys/sysctl.h>
162 #include <IOKit/IOHibernatePrivate.h>
163 #include <IOKit/IOPolledInterface.h>
164 #include <IOKit/IONVRAM.h>
165 #include "IOHibernateInternal.h"
167 #include "IOKitKernelInternal.h"
169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
171 extern uint32_t gIOHibernateState
;
172 uint32_t gIOHibernateMode
;
173 static char gIOHibernateBootSignature
[256+1];
174 static char gIOHibernateFilename
[MAXPATHLEN
+1];
175 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
176 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
178 static IODTNVRAM
* gIOOptionsEntry
;
179 static IORegistryEntry
* gIOChosenEntry
;
180 #if defined(__i386__) || defined(__x86_64__)
181 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
184 static IOPolledFileIOVars gFileVars
;
185 static IOHibernateVars gIOHibernateVars
;
186 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
187 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
189 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
191 enum { kXPRamAudioVolume
= 8 };
192 enum { kDefaultIOSize
= 128 * 1024 };
193 enum { kVideoMapSize
= 32 * 1024 * 1024 };
195 #ifndef kIOMediaPreferredBlockSizeKey
196 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
199 #ifndef kIOBootPathKey
200 #define kIOBootPathKey "bootpath"
202 #ifndef kIOSelectedBootDeviceKey
203 #define kIOSelectedBootDeviceKey "boot-device"
207 enum { kIOHibernateMinPollersNeeded
= 2 };
209 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
211 // copy from phys addr to MD
214 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
215 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
217 addr64_t srcAddr
= bytes
;
218 IOByteCount remaining
;
220 remaining
= length
= min(length
, md
->getLength() - offset
);
221 while (remaining
) { // (process another target segment?)
225 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
229 // Clip segment length to remaining
230 if (dstLen
> remaining
)
234 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
236 copypv(srcAddr
, dstAddr64
, dstLen
,
237 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
246 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
249 // copy from MD to phys addr
252 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
253 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
255 addr64_t dstAddr
= bytes
;
256 IOByteCount remaining
;
258 remaining
= length
= min(length
, md
->getLength() - offset
);
259 while (remaining
) { // (process another target segment?)
263 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
267 // Clip segment length to remaining
268 if (dstLen
> remaining
)
272 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
274 copypv(srcAddr
, dstAddr64
, dstLen
,
275 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
284 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
287 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
290 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
291 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
296 case kIOHibernatePageStateUnwiredSave
:
298 for (; ppnum
< count
; ppnum
++)
300 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
301 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
304 case kIOHibernatePageStateWiredSave
:
306 for (; ppnum
< count
; ppnum
++)
308 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
309 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
312 case kIOHibernatePageStateFree
:
314 for (; ppnum
< count
; ppnum
++)
316 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
317 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
321 panic("hibernate_set_page_state");
326 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
328 uint32_t page
= *pPage
;
330 hibernate_bitmap_t
* bitmap
;
332 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
334 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
338 if (page
<= bitmap
->last_page
)
344 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
351 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
354 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
356 IOReturn err
= kIOReturnError
;
358 IOPolledInterface
* poller
;
360 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
362 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
363 err
= poller
->probe(target
);
366 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
375 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
377 IOReturn err
= kIOReturnError
;
379 IOPolledInterface
* poller
;
381 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
383 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
384 err
= poller
->open(state
, md
);
387 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
396 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
398 IOReturn err
= kIOReturnError
;
400 IOPolledInterface
* poller
;
403 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
406 err
= poller
->close(state
);
408 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
415 IOHibernatePollerIOComplete(void * target
,
418 UInt64 actualByteCount
)
420 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
422 vars
->ioStatus
= status
;
426 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
427 uint32_t operation
, uint32_t bufferOffset
,
428 uint64_t deviceOffset
, uint64_t length
)
431 IOReturn err
= kIOReturnError
;
432 IOPolledInterface
* poller
;
433 IOPolledCompletion completion
;
435 completion
.target
= 0;
436 completion
.action
= &IOHibernatePollerIOComplete
;
437 completion
.parameter
= vars
;
441 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
442 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
444 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
450 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
, bool abortable
)
452 IOReturn err
= kIOReturnSuccess
;
454 IOPolledInterface
* poller
;
456 while (-1 == vars
->ioStatus
)
459 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
463 newErr
= poller
->checkForWork();
464 if ((newErr
== kIOReturnAborted
) && !abortable
)
465 newErr
= kIOReturnSuccess
;
466 if (kIOReturnSuccess
== err
)
473 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
477 err
= vars
->ioStatus
;
478 if (kIOReturnSuccess
!= err
)
479 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
486 IOPolledInterface::checkAllForWork(void)
488 IOReturn err
= kIOReturnNotReady
;
490 IOPolledInterface
* poller
;
492 IOHibernateVars
* vars
= &gIOHibernateVars
;
494 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
498 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
501 err
= poller
->checkForWork();
503 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
509 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
511 struct _OpenFileContext
518 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
520 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
521 IOPolledFileExtent extent
;
523 extent
.start
= start
;
524 extent
.length
= length
;
526 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
531 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
532 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
535 IOReturn err
= kIOReturnError
;
536 IOPolledFileIOVars
* vars
;
537 _OpenFileContext ctx
;
538 OSData
* extentsData
;
540 IORegistryEntry
* part
= 0;
541 OSDictionary
* matching
;
543 dev_t hibernate_image_dev
;
549 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
550 if (sizeof(IOHibernateImageHeader
) != 512)
554 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
555 vars
->bufferHalf
= 0;
556 vars
->bufferOffset
= 0;
557 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
559 extentsData
= OSData::withCapacity(32);
561 ctx
.extents
= extentsData
;
563 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
564 &file_extent_callback
, &ctx
,
565 &hibernate_image_dev
,
570 err
= kIOReturnNoSpace
;
573 gIOHibernateFileRef
= vars
->fileRef
;
574 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
575 vars
->block0
, maxiobytes
);
576 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
578 err
= kIOReturnNoSpace
;
582 if (maxiobytes
< vars
->bufferSize
)
583 vars
->bufferSize
= maxiobytes
;
585 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
587 matching
= IOService::serviceMatching("IOMedia");
588 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
589 matching
->setObject(kIOBSDMajorKey
, num
);
591 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
592 matching
->setObject(kIOBSDMinorKey
, num
);
594 iter
= IOService::getMatchingServices(matching
);
598 part
= (IORegistryEntry
*) iter
->getNextObject();
606 IORegistryEntry
* next
;
607 IORegistryEntry
* child
;
610 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
613 major
= num
->unsigned32BitValue();
614 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
617 minor
= num
->unsigned32BitValue();
619 hibernate_image_dev
= makedev(major
, minor
);
621 vars
->pollers
= OSArray::withCapacity(4);
625 vars
->blockSize
= 512;
629 IOPolledInterface
* poller
;
632 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
633 if (kOSBooleanFalse
== obj
)
635 vars
->pollers
->flushCollection();
638 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
639 vars
->pollers
->setObject(poller
);
640 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
641 vars
->blockSize
= num
->unsigned32BitValue();
644 while ((next
= child
->getParentEntry(gIOServicePlane
))
645 && child
->isParent(next
, gIOServicePlane
, true));
647 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
648 major
, minor
, (long)vars
->blockSize
, vars
->pollers
->getCount());
649 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
652 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
653 if (kIOReturnSuccess
!= err
)
656 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
657 if (kIOReturnSuccess
!= err
)
661 *fileExtents
= extentsData
;
665 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
669 #if defined(__i386__) || defined(__x86_64__)
670 if (!gIOCreateEFIDevicePathSymbol
)
671 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
673 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
675 err
= IOService::getPlatform()->callPlatformFunction(
676 gIOCreateEFIDevicePathSymbol
, false,
677 (void *) part
, (void *) str2
, (void *) true,
681 int len
= sizeof(str1
);
683 if (!part
->getPath(str1
, &len
, gIODTPlane
))
684 err
= kIOReturnNotFound
;
687 snprintf(str2
, sizeof(str2
), ",%qx", vars
->extentMap
[0].start
);
688 // (strip the plane name)
689 char * tail
= strchr(str1
, ':');
692 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
693 data
->appendBytes(str2
, strlen(str2
));
696 if (kIOReturnSuccess
== err
)
699 HIBLOG("error 0x%x getting path\n", err
);
704 if (kIOReturnSuccess
!= err
)
706 HIBLOG("error 0x%x opening hibernation file\n", err
);
709 kern_close_file_for_direct_io(vars
->fileRef
);
710 gIOHibernateFileRef
= vars
->fileRef
= NULL
;
721 IOPolledFileClose( IOPolledFileIOVars
* vars
)
725 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
726 vars
->pollers
->release();
729 bzero(vars
, sizeof(IOPolledFileIOVars
));
731 return (kIOReturnSuccess
);
735 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
737 IOPolledFileExtent
* extentMap
;
739 extentMap
= vars
->extentMap
;
741 vars
->position
= position
;
743 while (position
>= extentMap
->length
)
745 position
-= extentMap
->length
;
749 vars
->currentExtent
= extentMap
;
750 vars
->extentRemaining
= extentMap
->length
- position
;
751 vars
->extentPosition
= vars
->position
- position
;
753 if (vars
->bufferSize
<= vars
->extentRemaining
)
754 vars
->bufferLimit
= vars
->bufferSize
;
756 vars
->bufferLimit
= vars
->extentRemaining
;
758 return (kIOReturnSuccess
);
762 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
763 const uint8_t * bytes
, IOByteCount size
,
764 hibernate_cryptvars_t
* cryptvars
)
766 IOReturn err
= kIOReturnSuccess
;
774 // seek to end of block & flush
775 size
= vars
->position
& (vars
->blockSize
- 1);
777 size
= vars
->blockSize
- size
;
779 // use some garbage for the fill
780 bytes
= vars
->buffer
+ vars
->bufferOffset
;
783 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
791 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
795 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
798 vars
->bufferOffset
+= copy
;
799 vars
->position
+= copy
;
801 if (flush
&& vars
->bufferOffset
)
803 uint64_t offset
= (vars
->position
- vars
->bufferOffset
804 - vars
->extentPosition
+ vars
->currentExtent
->start
);
805 uint32_t length
= (vars
->bufferOffset
);
808 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
810 uint32_t encryptLen
, encryptStart
;
811 encryptLen
= vars
->position
- vars
->encryptStart
;
812 if (encryptLen
> length
)
814 encryptStart
= length
- encryptLen
;
816 // encrypt the buffer
817 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
818 &cryptvars
->aes_iv
[0],
819 encryptLen
/ AES_BLOCK_SIZE
,
820 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
821 &cryptvars
->ctx
.encrypt
);
822 // save initial vector for following encrypts
823 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
824 &cryptvars
->aes_iv
[0],
831 err
= IOHibernatePollerIODone(vars
, true);
832 if (kIOReturnSuccess
!= err
)
836 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
837 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
839 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
840 if (kIOReturnSuccess
!= err
)
844 vars
->extentRemaining
-= vars
->bufferOffset
;
845 if (!vars
->extentRemaining
)
847 vars
->currentExtent
++;
848 vars
->extentRemaining
= vars
->currentExtent
->length
;
849 vars
->extentPosition
= vars
->position
;
850 if (!vars
->extentRemaining
)
852 err
= kIOReturnOverrun
;
857 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
858 vars
->bufferOffset
= 0;
859 if (vars
->bufferSize
<= vars
->extentRemaining
)
860 vars
->bufferLimit
= vars
->bufferSize
;
862 vars
->bufferLimit
= vars
->extentRemaining
;
873 IOPolledFileRead(IOPolledFileIOVars
* vars
,
874 uint8_t * bytes
, IOByteCount size
,
875 hibernate_cryptvars_t
* cryptvars
)
877 IOReturn err
= kIOReturnSuccess
;
880 // bytesWritten += size;
884 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
890 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
894 vars
->bufferOffset
+= copy
;
895 // vars->position += copy;
897 if (vars
->bufferOffset
== vars
->bufferLimit
)
901 err
= IOHibernatePollerIODone(vars
, false);
902 if (kIOReturnSuccess
!= err
)
908 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
910 vars
->position
+= vars
->lastRead
;
911 vars
->extentRemaining
-= vars
->lastRead
;
912 vars
->bufferLimit
= vars
->lastRead
;
914 if (!vars
->extentRemaining
)
916 vars
->currentExtent
++;
917 vars
->extentRemaining
= vars
->currentExtent
->length
;
918 vars
->extentPosition
= vars
->position
;
919 if (!vars
->extentRemaining
)
921 err
= kIOReturnOverrun
;
927 uint64_t lastReadLength
= vars
->lastRead
;
928 uint64_t offset
= (vars
->position
929 - vars
->extentPosition
+ vars
->currentExtent
->start
);
930 if (vars
->extentRemaining
<= vars
->bufferSize
)
931 length
= vars
->extentRemaining
;
933 length
= vars
->bufferSize
;
934 vars
->lastRead
= length
;
936 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
938 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
939 if (kIOReturnSuccess
!= err
)
943 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
944 vars
->bufferOffset
= 0;
949 uint8_t thisVector
[AES_BLOCK_SIZE
];
950 // save initial vector for following decrypts
951 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
952 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
953 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
954 // decrypt the buffer
955 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
957 lastReadLength
/ AES_BLOCK_SIZE
,
958 vars
->buffer
+ vars
->bufferHalf
,
959 &cryptvars
->ctx
.decrypt
);
969 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
972 IOHibernateSystemSleep(void)
979 OSDictionary
*sleepOverrideOptions
;
981 IOHibernateVars
* vars
= &gIOHibernateVars
;
983 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
984 // already on the way down
985 return (kIOReturnSuccess
);
987 gIOHibernateState
= kIOHibernateStateInactive
;
989 gIOHibernateDebugFlags
= 0;
990 if (kIOLogHibernate
& gIOKitDebug
)
991 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
993 /* The invocation of IOPMSleepSystemWithOptions() may override
994 * existing hibernation settings.
996 sleepOverrideOptions
= (OSDictionary
*)OSDynamicCast( OSDictionary
,
997 IOService::getPMRootDomain()->copyProperty(kRootDomainSleepOptionsKey
));
1000 /* Hibernate mode overriden by sleep otions ? */
1003 if (sleepOverrideOptions
) {
1004 obj
= sleepOverrideOptions
->getObject(kIOHibernateModeKey
);
1005 if (obj
) obj
->retain();
1009 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
);
1012 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)) )
1014 gIOHibernateMode
= num
->unsigned32BitValue();
1015 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1016 // default to discard clean for safe sleep
1017 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
1018 | kIOHibernateModeDiscardCleanActive
);
1021 if (obj
) obj
->release();
1023 /* Hibernate free rotio overriden by sleep options ? */
1026 if (sleepOverrideOptions
) {
1027 obj
= sleepOverrideOptions
->getObject(kIOHibernateFreeRatioKey
);
1028 if (obj
) obj
->retain();
1032 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
);
1034 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
1036 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
1038 if (obj
) obj
->release();
1040 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
1042 if ((num
= OSDynamicCast(OSNumber
, obj
)))
1043 gIOHibernateFreeTime
= num
->unsigned32BitValue();
1046 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1048 if ((str
= OSDynamicCast(OSString
, obj
)))
1049 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
1050 sizeof(gIOHibernateFilename
));
1054 if (sleepOverrideOptions
)
1055 sleepOverrideOptions
->release();
1057 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1058 return (kIOReturnUnsupported
);
1060 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1065 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1066 4 * page_size
, page_size
);
1067 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1068 2 * kDefaultIOSize
, page_size
);
1070 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
1072 err
= kIOReturnNoMemory
;
1076 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1077 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1078 if (KERN_SUCCESS
!= err
)
1080 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1083 if (vars
->fileVars
->fileRef
)
1085 // invalidate the image file
1086 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1087 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1088 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1089 if (KERN_SUCCESS
!= err
)
1090 HIBLOG("kern_write_file(%d)\n", err
);
1093 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1094 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
1096 boolean_t encryptedswap
;
1097 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1098 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1099 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1100 if (KERN_SUCCESS
!= err
)
1102 HIBLOG("hibernate_setup(%d)\n", err
);
1107 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1109 vars
->videoAllocSize
= kVideoMapSize
;
1110 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1111 vars
->videoMapping
= 0;
1113 // generate crypt keys
1114 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1115 vars
->wiredCryptKey
[i
] = random();
1116 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1117 vars
->cryptKey
[i
] = random();
1121 IORegistryEntry
* regEntry
;
1122 if (!gIOOptionsEntry
)
1124 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1125 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1126 if (regEntry
&& !gIOOptionsEntry
)
1127 regEntry
->release();
1129 if (!gIOChosenEntry
)
1130 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1132 if (gIOOptionsEntry
)
1134 const OSSymbol
* sym
;
1136 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1139 gIOOptionsEntry
->setProperty(sym
, data
);
1144 #if defined(__ppc__)
1146 char valueString
[16];
1148 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1151 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1154 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1155 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1157 gIOOptionsEntry
->setProperty(sym
, str2
);
1163 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1166 vars
->haveFastBoot
= true;
1168 len
= snprintf(valueString
, sizeof(valueString
), "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1169 data
= OSData::withBytes(valueString
, len
+ 1);
1170 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1172 gIOOptionsEntry
->setProperty(sym
, data
);
1178 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1180 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1182 #endif /* __ppc__ */
1183 #if defined(__i386__) || defined(__x86_64__)
1184 struct AppleRTCHibernateVars
1186 uint8_t signature
[4];
1188 uint8_t booterSignature
[20];
1189 uint8_t wiredCryptKey
[16];
1191 AppleRTCHibernateVars rtcVars
;
1193 rtcVars
.signature
[0] = 'A';
1194 rtcVars
.signature
[1] = 'A';
1195 rtcVars
.signature
[2] = 'P';
1196 rtcVars
.signature
[3] = 'L';
1197 rtcVars
.revision
= 1;
1198 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1199 if (gIOHibernateBootSignature
[0])
1203 for (uint32_t i
= 0;
1204 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1215 value
= (value
<< 4) | c
;
1217 rtcVars
.booterSignature
[i
>> 1] = value
;
1220 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1223 IOService::getPMRootDomain()->setProperty(kIOHibernateRTCVariablesKey
, data
);
1225 if( gIOOptionsEntry
)
1227 if( gIOHibernateMode
& kIOHibernateModeSwitch
)
1229 const OSSymbol
*sym
;
1230 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey
);
1233 gIOOptionsEntry
->setProperty(sym
, data
); /* intentional insecure backup of rtc boot vars */
1243 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1245 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1247 #else /* !i386 && !x86_64 */
1248 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1250 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1251 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1253 gIOOptionsEntry
->setProperty(sym
, data
);
1258 if (false && gIOHibernateBootSignature
[0])
1260 data
= OSData::withCapacity(16);
1261 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1266 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1276 value
= (value
<< 4) | c
;
1278 data
->appendBytes(&value
, sizeof(value
));
1280 gIOOptionsEntry
->setProperty(sym
, data
);
1288 if (!vars
->haveFastBoot
)
1290 // set boot volume to zero
1291 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1292 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1293 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1296 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1297 platform
->writeXPRAM(kXPRamAudioVolume
,
1298 &newVolume
, sizeof(newVolume
));
1301 #endif /* !i386 && !x86_64 */
1305 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1306 gIOHibernateState
= kIOHibernateStateHibernating
;
1313 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1315 DECLARE_IOHIBERNATEPROGRESSALPHA
1318 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
1320 uint32_t rowBytes
, pixelShift
;
1323 uint32_t alpha
, in
, color
, result
;
1325 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1327 rowBytes
= display
->rowBytes
;
1328 pixelShift
= display
->depth
>> 4;
1329 if (pixelShift
< 1) return;
1331 screen
+= ((display
->width
1332 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1333 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1335 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1337 out
= screen
+ y
* rowBytes
;
1338 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
1340 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
1341 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1343 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1349 if (1 == pixelShift
)
1351 in
= *((uint16_t *)out
) & 0x1f; // 16
1352 in
= (in
<< 3) | (in
>> 2);
1355 in
= *((uint32_t *)out
) & 0xff; // 32
1356 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
1357 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
1359 if (1 == pixelShift
)
1362 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1365 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1367 out
+= (1 << pixelShift
);
1369 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1376 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1378 uint32_t rowBytes
, pixelShift
;
1380 int32_t blob
, lastBlob
;
1381 uint32_t alpha
, in
, color
, result
;
1383 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1385 pixelShift
= display
->depth
>> 4;
1389 rowBytes
= display
->rowBytes
;
1391 screen
+= ((display
->width
1392 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1393 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1395 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1397 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1399 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1401 out
= screen
+ y
* rowBytes
;
1402 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1404 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1405 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1407 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1413 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1414 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1416 if (1 == pixelShift
)
1419 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1422 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1424 out
+= (1 << pixelShift
);
1426 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1431 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1434 IOHibernateSystemHasSlept(void)
1436 IOHibernateVars
* vars
= &gIOHibernateVars
;
1440 obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1441 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1442 if (obj
&& !vars
->previewBuffer
)
1445 vars
->consoleMapping
= NULL
;
1446 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1448 vars
->previewBuffer
->release();
1449 vars
->previewBuffer
= 0;
1452 if (vars
->previewBuffer
&& (data
= OSDynamicCast(OSData
,
1453 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1455 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1456 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1458 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1460 if (kIOHibernatePreviewUpdates
& flags
)
1462 PE_Video consoleInfo
;
1463 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1465 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1467 graphicsInfo
->width
= consoleInfo
.v_width
;
1468 graphicsInfo
->height
= consoleInfo
.v_height
;
1469 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1470 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1471 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1473 HIBPRINT("video %p %d %d %d\n",
1474 vars
->consoleMapping
, gIOHibernateGraphicsInfo
->depth
,
1475 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
1476 if (vars
->consoleMapping
)
1477 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1478 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1482 if (gIOOptionsEntry
)
1483 gIOOptionsEntry
->sync();
1485 return (kIOReturnSuccess
);
1488 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1491 IOHibernateSystemWake(void)
1493 IOHibernateVars
* vars
= &gIOHibernateVars
;
1495 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1497 if (vars
->videoMapping
)
1499 if (vars
->videoMapSize
)
1501 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1502 if (vars
->videoAllocSize
)
1504 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1507 if (vars
->previewBuffer
)
1509 vars
->previewBuffer
->release();
1510 vars
->previewBuffer
= 0;
1515 IOPolledFileClose(vars
->fileVars
);
1518 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1521 OSData
* data
= OSData::withCapacity(4);
1522 if (gIOOptionsEntry
&& data
)
1524 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1527 gIOOptionsEntry
->setProperty(sym
, data
);
1530 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1533 if (vars
->saveBootDevice
)
1535 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1536 vars
->saveBootDevice
->release();
1540 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1543 gIOOptionsEntry
->setProperty(sym
, data
);
1546 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1549 gIOOptionsEntry
->removeProperty(sym
);
1556 if (gIOOptionsEntry
)
1558 if (!vars
->haveFastBoot
)
1560 // reset boot audio volume
1561 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1563 platform
->writeXPRAM(kXPRamAudioVolume
,
1564 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1567 // sync now to hardware if the booter has not
1568 if (kIOHibernateStateInactive
== gIOHibernateState
)
1569 gIOOptionsEntry
->sync();
1571 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1572 gIOOptionsEntry
->syncOFVariables();
1576 #if defined(__i386__) || defined(__x86_64__)
1577 IOService::getPMRootDomain()->removeProperty(kIOHibernateRTCVariablesKey
);
1580 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1581 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1583 if (gIOOptionsEntry
) {
1584 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1587 if (gIOOptionsEntry
->getProperty(sym
)) {
1588 gIOOptionsEntry
->removeProperty(sym
);
1589 gIOOptionsEntry
->sync();
1596 if (vars
->srcBuffer
)
1597 vars
->srcBuffer
->release();
1599 vars
->ioBuffer
->release();
1600 if (vars
->fileExtents
)
1601 vars
->fileExtents
->release();
1603 bzero(vars
, sizeof(*vars
));
1605 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1607 return (kIOReturnSuccess
);
1611 IOHibernateSystemPostWake(void)
1613 if (gIOHibernateFileRef
)
1615 // invalidate the image file
1616 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1617 int err
= kern_write_file(gIOHibernateFileRef
, 0,
1618 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1619 if (KERN_SUCCESS
!= err
)
1620 HIBLOG("kern_write_file(%d)\n", err
);
1622 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1623 gIOHibernateFileRef
= 0;
1625 return (kIOReturnSuccess
);
1628 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1630 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1631 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1632 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1633 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1634 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1635 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1636 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1637 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1638 &gIOHibernateMode
, 0, "");
1641 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1643 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1646 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1650 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1651 gIOHibernateMode
= kIOHibernateModeOn
;
1653 gIOHibernateFilename
[0] = 0;
1655 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1656 sysctl_register_oid(&sysctl__kern_bootsignature
);
1657 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1661 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1664 hibernate_setup_for_wake(void)
1667 // go slow (state needed for wake)
1668 ml_set_processor_speed(1);
1672 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1674 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1677 hibernate_write_image(void)
1679 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1680 IOHibernateVars
* vars
= &gIOHibernateVars
;
1681 IOPolledFileExtent
* fileExtents
;
1683 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
1685 uint32_t pageCount
, pagesDone
;
1688 IOItemCount page
, count
;
1691 IOByteCount pageCompressedSize
;
1692 uint64_t compressedSize
, uncompressedSize
;
1693 uint64_t image1Size
= 0;
1694 uint32_t bitmap_size
;
1695 bool iterDone
, pollerOpen
, needEncryptStart
;
1696 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1699 uint32_t pageAndCount
[2];
1701 AbsoluteTime startTime
, endTime
;
1702 AbsoluteTime allTime
, compTime
, decoTime
;
1704 uint32_t lastProgressStamp
= 0;
1705 uint32_t progressStamp
;
1706 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1708 hibernate_cryptvars_t _cryptvars
;
1709 hibernate_cryptvars_t
* cryptvars
= 0;
1711 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1712 return (false /* sleep */ );
1714 restore1Sum
= sum1
= sum2
= 0;
1717 // encryption data. "iv" is the "initial vector".
1718 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1720 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1721 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1722 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1724 cryptvars
= &gIOHibernateCryptWakeContext
;
1725 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1726 aes_encrypt_key(vars
->cryptKey
,
1727 kIOHibernateAESKeySize
,
1728 &cryptvars
->ctx
.encrypt
);
1729 aes_decrypt_key(vars
->cryptKey
,
1730 kIOHibernateAESKeySize
,
1731 &cryptvars
->ctx
.decrypt
);
1733 cryptvars
= &_cryptvars
;
1734 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1735 aes_encrypt_key(vars
->wiredCryptKey
,
1736 kIOHibernateAESKeySize
,
1737 &cryptvars
->ctx
.encrypt
);
1739 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1740 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1741 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1742 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1746 hibernate_setup_for_wake();
1748 hibernate_page_list_setall(vars
->page_list
,
1749 vars
->page_list_wired
,
1752 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1754 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1757 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1758 for (page
= 0; page
< count
; page
++)
1760 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1761 fileExtents
[page
].start
, fileExtents
[page
].length
,
1762 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1766 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1768 AbsoluteTime_to_scalar(&compTime
) = 0;
1769 AbsoluteTime_to_scalar(&decoTime
) = 0;
1771 clock_get_uptime(&allTime
);
1772 IOService::getPMRootDomain()->pmStatsRecordEvent(
1773 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1778 uncompressedSize
= 0;
1780 pageType
= 0; // wired pages first
1782 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1784 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1785 ml_get_interrupts_enabled());
1786 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1787 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1788 pollerOpen
= (kIOReturnSuccess
== err
);
1792 // copy file block extent list if larger than header
1794 count
= vars
->fileExtents
->getLength();
1795 if (count
> sizeof(header
->fileExtentMap
))
1797 count
-= sizeof(header
->fileExtentMap
);
1798 err
= IOPolledFileWrite(vars
->fileVars
,
1799 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1800 if (kIOReturnSuccess
!= err
)
1804 uintptr_t hibernateBase
;
1805 uintptr_t hibernateEnd
;
1807 #if defined(__i386__) || defined(__x86_64__)
1808 hibernateBase
= sectINITPTB
;
1810 hibernateBase
= sectHIBB
;
1813 hibernateEnd
= (sectHIBB
+ sectSizeHIB
);
1814 // copy out restore1 code
1816 page
= atop_32(hibernateBase
);
1817 count
= atop_32(round_page(hibernateEnd
)) - page
;
1818 header
->restore1CodePage
= page
;
1819 header
->restore1PageCount
= count
;
1820 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1821 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1823 // sum __HIB sect, with zeros for the stack
1824 src
= (uint8_t *) trunc_page(hibernateBase
);
1825 for (page
= 0; page
< count
; page
++)
1827 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1828 restore1Sum
+= hibernate_sum(src
, page_size
);
1830 restore1Sum
+= 0x10000001;
1835 // write the __HIB sect, with zeros for the stack
1837 src
= (uint8_t *) trunc_page(hibernateBase
);
1838 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1841 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1842 if (kIOReturnSuccess
!= err
)
1845 err
= IOPolledFileWrite(vars
->fileVars
,
1847 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1849 if (kIOReturnSuccess
!= err
)
1851 src
= &gIOHibernateRestoreStackEnd
[0];
1852 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1855 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1856 if (kIOReturnSuccess
!= err
)
1860 // write the preview buffer
1865 if (vars
->previewBuffer
)
1871 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1872 pageAndCount
[0] = atop_64(phys64
);
1873 pageAndCount
[1] = atop_32(segLen
);
1874 err
= IOPolledFileWrite(vars
->fileVars
,
1875 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1877 if (kIOReturnSuccess
!= err
)
1880 ppnum
+= sizeof(pageAndCount
);
1883 if (kIOReturnSuccess
!= err
)
1886 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1887 count
= vars
->previewBuffer
->getLength();
1889 header
->previewPageListSize
= ppnum
;
1890 header
->previewSize
= count
+ ppnum
;
1892 for (page
= 0; page
< count
; page
+= page_size
)
1893 sum1
+= hibernate_sum(src
+ page
, page_size
);
1895 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1896 if (kIOReturnSuccess
!= err
)
1900 // mark areas for no save
1903 (phys64
= vars
->ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1906 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1907 atop_64(phys64
), atop_32(segLen
),
1908 kIOHibernatePageStateFree
);
1909 pageCount
-= atop_32(segLen
);
1913 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1916 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1917 atop_64(phys64
), atop_32(segLen
),
1918 kIOHibernatePageStateFree
);
1919 pageCount
-= atop_32(segLen
);
1922 // copy out bitmap of pages available for trashing during restore
1924 bitmap_size
= vars
->page_list_wired
->list_size
;
1925 src
= (uint8_t *) vars
->page_list_wired
;
1926 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1927 if (kIOReturnSuccess
!= err
)
1930 // mark more areas for no save, but these are not available
1931 // for trashing during restore
1933 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1935 page
= atop_32(hibernateBase
);
1936 count
= atop_32(round_page(hibernateEnd
)) - page
;
1937 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1939 kIOHibernatePageStateFree
);
1942 if (vars
->previewBuffer
) for (count
= 0;
1943 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1946 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1947 atop_64(phys64
), atop_32(segLen
),
1948 kIOHibernatePageStateFree
);
1949 pageCount
-= atop_32(segLen
);
1952 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1958 HIBLOG("writing %d pages\n", pageCount
);
1962 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1964 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1968 pageAndCount
[0] = ppnum
;
1969 pageAndCount
[1] = count
;
1970 err
= IOPolledFileWrite(vars
->fileVars
,
1971 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1973 if (kIOReturnSuccess
!= err
)
1976 for (page
= 0; page
< count
; page
++)
1978 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1981 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)ppnum
, err
);
1985 sum
= hibernate_sum(src
, page_size
);
1987 clock_get_uptime(&startTime
);
1989 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1991 clock_get_uptime(&endTime
);
1992 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1993 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1995 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1996 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1998 if (pageCompressedSize
> page_size
)
2000 // HIBLOG("------------lose: %d\n", pageCompressedSize);
2001 pageCompressedSize
= page_size
;
2004 if (pageCompressedSize
!= page_size
)
2005 data
= (src
+ page_size
);
2009 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
2016 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
2018 // start encrypting partway into the data about to be written
2019 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
2020 & ~(AES_BLOCK_SIZE
- 1);
2021 needEncryptStart
= false;
2024 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
2025 if (kIOReturnSuccess
!= err
)
2028 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
2029 if (kIOReturnSuccess
!= err
)
2032 compressedSize
+= pageCompressedSize
;
2033 if (pageCompressedSize
)
2034 uncompressedSize
+= page_size
;
2038 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
2040 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
2041 if (blob
!= lastBlob
)
2043 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
2047 if (0 == (8191 & pagesDone
))
2049 clock_get_uptime(&endTime
);
2050 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2051 absolutetime_to_nanoseconds(endTime
, &nsec
);
2052 progressStamp
= nsec
/ 750000000ULL;
2053 if (progressStamp
!= lastProgressStamp
)
2055 lastProgressStamp
= progressStamp
;
2056 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
2060 if (kIOReturnSuccess
!= err
)
2062 if (iterDone
&& !pageType
)
2064 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2065 if (kIOReturnSuccess
!= err
)
2071 image1Size
= vars
->fileVars
->position
;
2074 bcopy(&cryptvars
->aes_iv
[0],
2075 &gIOHibernateCryptWakeContext
.aes_iv
[0],
2076 sizeof(cryptvars
->aes_iv
));
2077 cryptvars
= &gIOHibernateCryptWakeContext
;
2079 HIBLOG("image1Size %qd\n", image1Size
);
2083 if (kIOReturnSuccess
!= err
)
2085 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2086 if (kIOReturnSuccess
!= err
)
2091 header
->imageSize
= vars
->fileVars
->position
;
2092 header
->image1Size
= image1Size
;
2093 header
->bitmapSize
= bitmap_size
;
2094 header
->pageCount
= pageCount
;
2095 header
->encryptStart
= vars
->fileVars
->encryptStart
;
2097 header
->restore1Sum
= restore1Sum
;
2098 header
->image1Sum
= sum1
;
2099 header
->image2Sum
= sum2
;
2101 count
= vars
->fileExtents
->getLength();
2102 if (count
> sizeof(header
->fileExtentMap
))
2104 header
->fileExtentMapSize
= count
;
2105 count
= sizeof(header
->fileExtentMap
);
2108 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
2109 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
2111 IOPolledFileSeek(vars
->fileVars
, 0);
2112 err
= IOPolledFileWrite(vars
->fileVars
,
2113 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
2115 if (kIOReturnSuccess
!= err
)
2117 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
2118 if (kIOReturnSuccess
!= err
)
2120 err
= IOHibernatePollerIODone(vars
->fileVars
, true);
2121 if (kIOReturnSuccess
!= err
)
2126 clock_get_uptime(&endTime
);
2128 IOService::getPMRootDomain()->pmStatsRecordEvent(
2129 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2131 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2132 absolutetime_to_nanoseconds(endTime
, &nsec
);
2133 HIBLOG("all time: %qd ms, ",
2136 absolutetime_to_nanoseconds(compTime
, &nsec
);
2137 HIBLOG("comp time: %qd ms, ",
2140 absolutetime_to_nanoseconds(decoTime
, &nsec
);
2141 HIBLOG("deco time: %qd ms, ",
2144 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2146 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2147 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2150 if (vars
->fileVars
->io
)
2151 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2154 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
2156 if (vars
->consoleMapping
)
2157 ProgressUpdate(gIOHibernateGraphicsInfo
,
2158 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2160 HIBLOG("hibernate_write_image done(%x)\n", err
);
2162 // should we come back via regular wake, set the state in memory.
2163 gIOHibernateState
= kIOHibernateStateInactive
;
2165 if (kIOReturnSuccess
== err
)
2167 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2169 return (kIOHibernatePostWriteSleep
);
2171 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2173 return (kIOHibernatePostWriteRestart
);
2177 /* by default, power down */
2178 return (kIOHibernatePostWriteHalt
);
2181 else if (kIOReturnAborted
== err
)
2183 return (kIOHibernatePostWriteWake
);
2187 /* on error, sleep */
2188 return (kIOHibernatePostWriteSleep
);
2192 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2195 hibernate_machine_init(void)
2200 AbsoluteTime allTime
, endTime
;
2202 uint32_t lastProgressStamp
= 0;
2203 uint32_t progressStamp
;
2204 uint64_t progressZeroPosition
= 0;
2205 uint32_t blob
, lastBlob
= (uint32_t) -1L;
2206 hibernate_cryptvars_t
* cryptvars
= 0;
2208 IOHibernateVars
* vars
= &gIOHibernateVars
;
2210 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
2213 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2214 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2216 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
2217 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
2218 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2220 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2222 HIBLOG("regular wake\n");
2226 HIBPRINT("diag %x %x %x %x\n",
2227 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2228 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2230 HIBPRINT("video %x %d %d %d\n",
2231 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2232 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
2234 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
2235 hibernate_page_list_discard(vars
->page_list
);
2237 boot_args
*args
= (boot_args
*) PE_state
.bootArgs
;
2239 if (vars
->videoMapping
2240 && gIOHibernateGraphicsInfo
->physicalAddress
2241 && (args
->Video
.v_baseAddr
== gIOHibernateGraphicsInfo
->physicalAddress
))
2243 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2244 * gIOHibernateGraphicsInfo
->rowBytes
);
2245 IOMapPages(kernel_map
,
2246 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2247 vars
->videoMapSize
, kIOMapInhibitCache
);
2250 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2252 if (gIOHibernateWakeMapSize
)
2254 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(gIOHibernateWakeMap
),
2255 gIOHibernateWakeMapSize
);
2256 if (kIOReturnSuccess
== err
)
2257 hibernate_newruntime_map(src
, gIOHibernateWakeMapSize
,
2258 gIOHibernateCurrentHeader
->systemTableOffset
);
2259 gIOHibernateWakeMap
= 0;
2260 gIOHibernateWakeMapSize
= 0;
2263 uint32_t decoOffset
;
2265 clock_get_uptime(&allTime
);
2267 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2268 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
2269 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2271 if (gIOHibernateCurrentHeader
->previewSize
)
2272 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
2273 + gIOHibernateCurrentHeader
->fileExtentMapSize
2274 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
2275 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
2277 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2279 if (vars
->videoMapSize
)
2281 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2282 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2283 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
2286 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2287 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2289 cryptvars
= &gIOHibernateCryptWakeContext
;
2290 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
2291 &cryptvars
->aes_iv
[0],
2292 sizeof(cryptvars
->aes_iv
));
2295 // kick off the read ahead
2296 vars
->fileVars
->io
= false;
2297 vars
->fileVars
->bufferHalf
= 0;
2298 vars
->fileVars
->bufferLimit
= 0;
2299 vars
->fileVars
->lastRead
= 0;
2300 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2302 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2303 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2306 HIBLOG("hibernate_machine_init reading\n");
2308 uint32_t * header
= (uint32_t *) src
;
2316 vm_offset_t ppnum
, compressedSize
;
2318 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2319 if (kIOReturnSuccess
!= err
)
2325 // HIBPRINT("(%x, %x)\n", ppnum, count);
2330 for (page
= 0; page
< count
; page
++)
2332 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2333 if (kIOReturnSuccess
!= err
)
2336 compressedSize
= kIOHibernateTagLength
& tag
;
2337 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2339 err
= kIOReturnIPCError
;
2343 if (!compressedSize
)
2350 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2351 if (kIOReturnSuccess
!= err
)
2354 if (compressedSize
< page_size
)
2356 decoOffset
= page_size
;
2357 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2362 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2364 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2367 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2374 if (vars
->videoMapSize
&& (0 == (1023 & pagesDone
)))
2376 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2377 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2378 if (blob
!= lastBlob
)
2380 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2385 if (0 == (8191 & pagesDone
))
2387 clock_get_uptime(&endTime
);
2388 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2389 absolutetime_to_nanoseconds(endTime
, &nsec
);
2390 progressStamp
= nsec
/ 750000000ULL;
2391 if (progressStamp
!= lastProgressStamp
)
2393 lastProgressStamp
= progressStamp
;
2394 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2395 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2402 if (kIOReturnSuccess
!= err
)
2403 panic("Hibernate restore error %x", err
);
2405 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2407 if (vars
->fileVars
->io
)
2408 (void) IOHibernatePollerIODone(vars
->fileVars
, false);
2410 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2412 if (vars
->videoMapSize
)
2413 ProgressUpdate(gIOHibernateGraphicsInfo
,
2414 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2416 clock_get_uptime(&endTime
);
2418 IOService::getPMRootDomain()->pmStatsRecordEvent(
2419 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2420 IOService::getPMRootDomain()->pmStatsRecordEvent(
2421 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2423 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2424 absolutetime_to_nanoseconds(endTime
, &nsec
);
2426 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2427 pagesDone
, sum
, nsec
/ 1000000ULL);
2430 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */