2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
28 - PMRootDomain calls IOHibernateSystemSleep() before system sleep
29 (devices awake, normal execution context)
30 - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
31 grabs its extents and searches for a polling driver willing to work with that IOMedia.
32 The BSD code makes an ioctl to the storage driver to get the partition base offset to
33 the disk, and other ioctls to get the transfer constraints
34 If successful, the file is written to make sure its initially not bootable (in case of
35 later failure) and nvram set to point to the first block of the file. (Has to be done
36 here so blocking is possible in nvram support).
37 hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
38 page out any pages it wants to (currently zero, but probably some percentage of memory).
39 Its assumed just allocating pages will cause the VM system to naturally select the best
40 pages for eviction. It also copies processor flags needed for the restore path and sets
41 a flag in the boot processor proc info.
42 gIOHibernateState = kIOHibernateStateHibernating.
43 - Regular sleep progresses - some drivers may inspect the root domain property
44 kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
45 as usual but leaves motherboard I/O on.
46 - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
47 at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
48 all ppc RC bits out of the hash table and caches into the mapping structures.
49 - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
50 hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
51 All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
52 by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
53 The image header and block list are written. The header includes the second file extent so
54 only the header block is needed to read the file, regardless of filesystem.
55 The kernel section "__HIB" is written uncompressed to the image. This section of code and data
56 (only) is used to decompress the image during wake/boot.
57 Some additional pages are removed from the bitmaps - the buffers used for hibernation.
58 The bitmaps are written to the image.
59 More areas are removed from the bitmaps (after they have been written to the image) - the
60 section "__HIB" pages and interrupt stack.
61 Each wired page is compressed and written and then each non-wired page. Compression and
62 disk writes are in parallel.
63 The image header is written to the start of the file and the polling driver closed.
64 The machine powers down (or sleeps).
68 - BootX sees the boot-image nvram variable containing the device and block number of the image,
69 reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
70 - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
71 in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
72 that is in the kernel's __HIB section.
73 - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
74 hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
75 only code & data in that section is safe to call since all the other wired pages are still
76 compressed in the image.
77 - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
78 It uses the bitmaps to work out which pages can be uncompressed from the image to their final
79 location directly, and copies those that can't to interim free pages. When the image has been
80 completed, the copies are uncompressed, overwriting the wired image pages.
81 hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
82 is used to get pages into place for 64bit.
83 - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
84 changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
85 are removed from the software strutures, and the hash table is reinitialized.
86 - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
87 of memory, using the polled mode driver, before other threads can run or any devices are turned on.
88 This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
89 for the remaining non wired pages.
90 - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
91 (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
96 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
97 registry, specifying an object of calls IOPolledInterface.
99 Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
100 partition) that the image is going to live, looking for polled interface properties. If it finds
101 one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
102 interfaces found are kept in an ordered list.
104 There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
105 few different contexts things happen in:
107 - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
108 up and running) and after wake - this is safe to allocate memory and do anything. The device
109 ignores sleep requests from that point since its a waste of time if it goes to sleep and
110 immediately wakes back up for the image write.
112 - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
113 immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
114 from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
115 used to flush and set the disk to sleep.
117 - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
118 immediately after sleep. These can't block or allocate memory. This is happening after the platform
119 expert has woken the low level bits of the system, but most of the I/O system has not. There is only
122 For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
123 (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
124 the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
125 Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
126 that is called for the hardware to check for events, and complete the I/O via the callback.
127 The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
131 #include <sys/systm.h>
133 #include <IOKit/IOWorkLoop.h>
134 #include <IOKit/IOCommandGate.h>
135 #include <IOKit/IOTimerEventSource.h>
136 #include <IOKit/IOPlatformExpert.h>
137 #include <IOKit/IOKitDebug.h>
138 #include <IOKit/IOTimeStamp.h>
139 #include <IOKit/pwr_mgt/RootDomain.h>
140 #include <IOKit/pwr_mgt/IOPMPrivate.h>
141 #include <IOKit/IOMessage.h>
142 #include <IOKit/IODeviceTreeSupport.h>
143 #include <IOKit/IOBSD.h>
144 #include "RootDomainUserClient.h"
145 #include <IOKit/pwr_mgt/IOPowerConnection.h>
146 #include "IOPMPowerStateQueue.h"
147 #include <IOKit/IOBufferMemoryDescriptor.h>
148 #include <crypto/aes.h>
151 #include <sys/conf.h>
152 #include <sys/stat.h>
153 #include <sys/fcntl.h> // (FWRITE, ...)
154 #include <sys/sysctl.h>
156 #include <IOKit/IOHibernatePrivate.h>
157 #include <IOKit/IOPolledInterface.h>
158 #include <IOKit/IONVRAM.h>
159 #include "IOHibernateInternal.h"
161 #include "IOKitKernelInternal.h"
163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
165 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
167 OSMetaClassDefineReservedUnused(IOPolledInterface
, 0);
168 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
169 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
170 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
171 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
172 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
173 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
174 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
175 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
176 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
177 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
178 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
179 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
180 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
181 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
182 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
184 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
186 extern uint32_t gIOHibernateState
;
187 uint32_t gIOHibernateMode
;
188 static char gIOHibernateBootSignature
[256+1];
189 static char gIOHibernateFilename
[MAXPATHLEN
+1];
190 static uint32_t gIOHibernateFreeRatio
= 0; // free page target (percent)
191 uint32_t gIOHibernateFreeTime
= 0*1000; // max time to spend freeing pages (ms)
193 static IODTNVRAM
* gIOOptionsEntry
;
194 static IORegistryEntry
* gIOChosenEntry
;
196 static const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
199 static IOPolledFileIOVars gFileVars
;
200 static IOHibernateVars gIOHibernateVars
;
201 static struct kern_direct_file_io_ref_t
* gIOHibernateFileRef
;
202 static hibernate_cryptvars_t gIOHibernateCryptWakeContext
;
204 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
206 enum { kXPRamAudioVolume
= 8 };
207 enum { kDefaultIOSize
= 128 * 1024 };
208 enum { kVideoMapSize
= 32 * 1024 * 1024 };
210 #ifndef kIOMediaPreferredBlockSizeKey
211 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
214 #ifndef kIOBootPathKey
215 #define kIOBootPathKey "bootpath"
217 #ifndef kIOSelectedBootDeviceKey
218 #define kIOSelectedBootDeviceKey "boot-device"
222 enum { kIOHibernateMinPollersNeeded
= 2 };
224 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
226 // copy from phys addr to MD
229 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
230 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
232 addr64_t srcAddr
= bytes
;
233 IOByteCount remaining
;
235 remaining
= length
= min(length
, md
->getLength() - offset
);
236 while (remaining
) { // (process another target segment?)
240 dstAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
244 // Clip segment length to remaining
245 if (dstLen
> remaining
)
249 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
251 copypv(srcAddr
, dstAddr64
, dstLen
,
252 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
261 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
264 // copy from MD to phys addr
267 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
268 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
270 addr64_t dstAddr
= bytes
;
271 IOByteCount remaining
;
273 remaining
= length
= min(length
, md
->getLength() - offset
);
274 while (remaining
) { // (process another target segment?)
278 srcAddr64
= md
->getPhysicalSegment64(offset
, &dstLen
);
282 // Clip segment length to remaining
283 if (dstLen
> remaining
)
287 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
289 copypv(srcAddr
, dstAddr64
, dstLen
,
290 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
299 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
302 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
305 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
306 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
311 case kIOHibernatePageStateUnwiredSave
:
313 for (; ppnum
< count
; ppnum
++)
315 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
316 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
319 case kIOHibernatePageStateWiredSave
:
321 for (; ppnum
< count
; ppnum
++)
323 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
324 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
327 case kIOHibernatePageStateFree
:
329 for (; ppnum
< count
; ppnum
++)
331 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
332 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
336 panic("hibernate_set_page_state");
341 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
343 uint32_t page
= *pPage
;
345 hibernate_bitmap_t
* bitmap
;
347 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
349 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
353 if (page
<= bitmap
->last_page
)
359 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
366 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
369 IOHibernatePollerProbe(IOPolledFileIOVars
* vars
, IOService
* target
)
371 IOReturn err
= kIOReturnError
;
373 IOPolledInterface
* poller
;
375 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
377 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
378 err
= poller
->probe(target
);
381 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
390 IOHibernatePollerOpen(IOPolledFileIOVars
* vars
, uint32_t state
, IOMemoryDescriptor
* md
)
392 IOReturn err
= kIOReturnError
;
394 IOPolledInterface
* poller
;
396 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--)
398 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
399 err
= poller
->open(state
, md
);
402 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
411 IOHibernatePollerClose(IOPolledFileIOVars
* vars
, uint32_t state
)
413 IOReturn err
= kIOReturnError
;
415 IOPolledInterface
* poller
;
418 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
421 err
= poller
->close(state
);
423 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
430 IOHibernatePollerIOComplete(void * target
,
433 UInt64 actualByteCount
)
435 IOPolledFileIOVars
* vars
= (IOPolledFileIOVars
*) parameter
;
437 vars
->ioStatus
= status
;
441 IOHibernatePollerIO(IOPolledFileIOVars
* vars
,
442 uint32_t operation
, uint32_t bufferOffset
,
443 uint64_t deviceOffset
, uint64_t length
)
446 IOReturn err
= kIOReturnError
;
447 IOPolledInterface
* poller
;
448 IOPolledCompletion completion
;
450 completion
.target
= 0;
451 completion
.action
= &IOHibernatePollerIOComplete
;
452 completion
.parameter
= vars
;
456 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
457 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
+ vars
->block0
, length
, completion
);
459 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
465 IOHibernatePollerIODone(IOPolledFileIOVars
* vars
)
467 IOReturn err
= kIOReturnError
;
469 IOPolledInterface
* poller
;
471 while (-1 == vars
->ioStatus
)
474 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
477 err
= poller
->checkForWork();
479 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
483 if (kIOReturnSuccess
!= vars
->ioStatus
)
484 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars
->ioStatus
);
486 return (vars
->ioStatus
);
490 IOPolledInterface::checkAllForWork(void)
492 IOReturn err
= kIOReturnNotReady
;
494 IOPolledInterface
* poller
;
496 IOHibernateVars
* vars
= &gIOHibernateVars
;
498 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
502 (poller
= (IOPolledInterface
*) vars
->fileVars
->pollers
->getObject(idx
));
505 err
= poller
->checkForWork();
507 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx
, err
);
513 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
515 struct _OpenFileContext
522 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
524 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
525 IOPolledFileExtent extent
;
527 extent
.start
= start
;
528 extent
.length
= length
;
530 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
535 IOPolledFileOpen( const char * filename
, IOBufferMemoryDescriptor
* ioBuffer
,
536 IOPolledFileIOVars
** fileVars
, OSData
** fileExtents
,
539 IOReturn err
= kIOReturnError
;
540 IOPolledFileIOVars
* vars
;
541 _OpenFileContext ctx
;
542 OSData
* extentsData
;
544 IORegistryEntry
* part
= 0;
545 OSDictionary
* matching
;
547 dev_t hibernate_image_dev
;
553 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader
));
554 if (sizeof(IOHibernateImageHeader
) != 512)
558 vars
->buffer
= (uint8_t *) ioBuffer
->getBytesNoCopy();
559 vars
->bufferHalf
= 0;
560 vars
->bufferOffset
= 0;
561 vars
->bufferSize
= ioBuffer
->getLength() >> 1;
563 extentsData
= OSData::withCapacity(32);
565 ctx
.extents
= extentsData
;
567 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
568 &file_extent_callback
, &ctx
,
569 &hibernate_image_dev
,
574 err
= kIOReturnNoSpace
;
577 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx\n", filename
, ctx
.size
,
578 vars
->block0
, maxiobytes
);
579 if (ctx
.size
< 1*1024*1024) // check against image size estimate!
581 err
= kIOReturnNoSpace
;
585 if (maxiobytes
< vars
->bufferSize
)
586 vars
->bufferSize
= maxiobytes
;
588 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
590 matching
= IOService::serviceMatching("IOMedia");
591 num
= OSNumber::withNumber(major(hibernate_image_dev
), 32);
592 matching
->setObject(kIOBSDMajorKey
, num
);
594 num
= OSNumber::withNumber(minor(hibernate_image_dev
), 32);
595 matching
->setObject(kIOBSDMinorKey
, num
);
597 iter
= IOService::getMatchingServices(matching
);
601 part
= (IORegistryEntry
*) iter
->getNextObject();
607 IORegistryEntry
* next
;
608 IORegistryEntry
* child
;
611 num
= (OSNumber
*) part
->getProperty(kIOBSDMajorKey
);
614 major
= num
->unsigned32BitValue();
615 num
= (OSNumber
*) part
->getProperty(kIOBSDMinorKey
);
618 minor
= num
->unsigned32BitValue();
620 hibernate_image_dev
= makedev(major
, minor
);
622 vars
->pollers
= OSArray::withCapacity(4);
626 vars
->blockSize
= 512;
630 IOPolledInterface
* poller
;
633 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
634 if (kOSBooleanFalse
== obj
)
636 vars
->pollers
->flushCollection();
639 else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
)))
640 vars
->pollers
->setObject(poller
);
641 if ((num
= OSDynamicCast(OSNumber
, next
->getProperty(kIOMediaPreferredBlockSizeKey
))))
642 vars
->blockSize
= num
->unsigned32BitValue();
645 while ((next
= child
->getParentEntry(gIOServicePlane
))
646 && child
->isParent(next
, gIOServicePlane
, true));
648 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
649 major
, minor
, vars
->blockSize
, vars
->pollers
->getCount());
650 if (vars
->pollers
->getCount() < kIOHibernateMinPollersNeeded
)
653 err
= IOHibernatePollerProbe(vars
, (IOService
*) part
);
654 if (kIOReturnSuccess
!= err
)
657 err
= IOHibernatePollerOpen(vars
, kIOPolledPreflightState
, ioBuffer
);
658 if (kIOReturnSuccess
!= err
)
662 *fileExtents
= extentsData
;
666 if ((extentsData
->getLength() >= sizeof(IOPolledFileExtent
)))
671 if (!gIOCreateEFIDevicePathSymbol
)
672 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
674 sprintf(str2
, "%qx", vars
->extentMap
[0]);
676 err
= IOService::getPlatform()->callPlatformFunction(
677 gIOCreateEFIDevicePathSymbol
, false,
678 (void *) part
, (void *) str2
, (void *) true,
682 int len
= sizeof(str1
);
684 if (!part
->getPath(str1
, &len
, gIODTPlane
))
685 err
= kIOReturnNotFound
;
688 sprintf(str2
, ",%qx", vars
->extentMap
[0]);
689 // (strip the plane name)
690 char * tail
= strchr(str1
, ':');
693 data
= OSData::withBytes(tail
+ 1, strlen(tail
+ 1));
694 data
->appendBytes(str2
, strlen(str2
));
697 if (kIOReturnSuccess
== err
)
700 HIBLOG("error 0x%x getting path\n", err
);
705 if (kIOReturnSuccess
!= err
)
707 HIBLOG("error 0x%x opening hibernation file\n", err
);
709 kern_close_file_for_direct_io(vars
->fileRef
);
719 IOPolledFileClose( IOPolledFileIOVars
* vars
)
723 IOHibernatePollerClose(vars
, kIOPolledPostflightState
);
724 vars
->pollers
->release();
727 gIOHibernateFileRef
= vars
->fileRef
;
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
);
807 if (cryptvars
&& vars
->encryptStart
&& (vars
->position
> vars
->encryptStart
))
809 uint32_t encryptLen
, encryptStart
;
810 encryptLen
= vars
->position
- vars
->encryptStart
;
811 if (encryptLen
> length
)
813 encryptStart
= length
- encryptLen
;
815 // encrypt the buffer
816 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
817 &cryptvars
->aes_iv
[0],
818 encryptLen
/ AES_BLOCK_SIZE
,
819 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
820 &cryptvars
->ctx
.encrypt
);
821 // save initial vector for following encrypts
822 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
823 &cryptvars
->aes_iv
[0],
829 err
= IOHibernatePollerIODone(vars
);
830 if (kIOReturnSuccess
!= err
)
834 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
835 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
837 err
= IOHibernatePollerIO(vars
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
838 if (kIOReturnSuccess
!= err
)
842 vars
->extentRemaining
-= vars
->bufferOffset
;
843 if (!vars
->extentRemaining
)
845 vars
->currentExtent
++;
846 vars
->extentRemaining
= vars
->currentExtent
->length
;
847 vars
->extentPosition
= vars
->position
;
848 if (!vars
->extentRemaining
)
850 err
= kIOReturnOverrun
;
855 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
856 vars
->bufferOffset
= 0;
857 if (vars
->bufferSize
<= vars
->extentRemaining
)
858 vars
->bufferLimit
= vars
->bufferSize
;
860 vars
->bufferLimit
= vars
->extentRemaining
;
871 IOPolledFileRead(IOPolledFileIOVars
* vars
,
872 uint8_t * bytes
, IOByteCount size
,
873 hibernate_cryptvars_t
* cryptvars
)
875 IOReturn err
= kIOReturnSuccess
;
878 // bytesWritten += size;
882 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
888 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
892 vars
->bufferOffset
+= copy
;
893 // vars->position += copy;
895 if (vars
->bufferOffset
== vars
->bufferLimit
)
899 err
= IOHibernatePollerIODone(vars
);
900 if (kIOReturnSuccess
!= err
)
906 if (vars
->position
& (vars
->blockSize
- 1)) HIBLOG("misaligned file pos %qx\n", vars
->position
);
908 vars
->position
+= vars
->lastRead
;
909 vars
->extentRemaining
-= vars
->lastRead
;
910 vars
->bufferLimit
= vars
->lastRead
;
912 if (!vars
->extentRemaining
)
914 vars
->currentExtent
++;
915 vars
->extentRemaining
= vars
->currentExtent
->length
;
916 vars
->extentPosition
= vars
->position
;
917 if (!vars
->extentRemaining
)
919 err
= kIOReturnOverrun
;
924 if (vars
->extentRemaining
<= vars
->bufferSize
)
925 vars
->lastRead
= vars
->extentRemaining
;
927 vars
->lastRead
= vars
->bufferSize
;
929 uint64_t offset
= (vars
->position
930 - vars
->extentPosition
+ vars
->currentExtent
->start
);
931 uint64_t length
= (vars
->lastRead
);
933 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
935 err
= IOHibernatePollerIO(vars
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
936 if (kIOReturnSuccess
!= err
)
940 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
941 vars
->bufferOffset
= 0;
945 uint8_t thisVector
[AES_BLOCK_SIZE
];
946 // save initial vector for following decrypts
947 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
948 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->lastRead
- AES_BLOCK_SIZE
,
949 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
950 // decrypt the buffer
951 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
953 vars
->lastRead
/ AES_BLOCK_SIZE
,
954 vars
->buffer
+ vars
->bufferHalf
,
955 &cryptvars
->ctx
.decrypt
);
964 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
967 IOHibernateSystemSleep(void)
975 IOHibernateVars
* vars
= &gIOHibernateVars
;
977 if (vars
->fileVars
&& vars
->fileVars
->fileRef
)
978 // already on the way down
979 return (kIOReturnSuccess
);
981 gIOHibernateState
= kIOHibernateStateInactive
;
983 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey
)))
985 if ((num
= OSDynamicCast(OSNumber
, obj
)))
986 gIOHibernateMode
= num
->unsigned32BitValue();
987 if (kIOHibernateModeSleep
& gIOHibernateMode
)
988 // default to discard clean for safe sleep
989 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
990 | kIOHibernateModeDiscardCleanActive
);
994 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey
)))
996 if ((num
= OSDynamicCast(OSNumber
, obj
)))
997 gIOHibernateFreeRatio
= num
->unsigned32BitValue();
1000 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey
)))
1002 if ((num
= OSDynamicCast(OSNumber
, obj
)))
1003 gIOHibernateFreeTime
= num
->unsigned32BitValue();
1006 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
1008 if ((str
= OSDynamicCast(OSString
, obj
)))
1009 strcpy(gIOHibernateFilename
, str
->getCStringNoCopy());
1013 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
1014 return (kIOReturnUnsupported
);
1016 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
1020 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1021 4 * page_size
, page_size
);
1022 vars
->ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
1023 2 * kDefaultIOSize
, page_size
);
1025 if (!vars
->srcBuffer
|| !vars
->ioBuffer
)
1027 err
= kIOReturnNoMemory
;
1031 err
= IOPolledFileOpen(gIOHibernateFilename
, vars
->ioBuffer
,
1032 &vars
->fileVars
, &vars
->fileExtents
, &data
);
1033 if (KERN_SUCCESS
!= err
)
1035 HIBLOG("IOPolledFileOpen(%x)\n", err
);
1038 if (vars
->fileVars
->fileRef
)
1040 // invalidate the image file
1041 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1042 int err
= kern_write_file(vars
->fileVars
->fileRef
, 0,
1043 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1044 if (KERN_SUCCESS
!= err
)
1045 HIBLOG("kern_write_file(%d)\n", err
);
1048 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1050 boolean_t encryptedswap
;
1051 err
= hibernate_setup(gIOHibernateCurrentHeader
,
1052 gIOHibernateFreeRatio
, gIOHibernateFreeTime
,
1053 &vars
->page_list
, &vars
->page_list_wired
, &encryptedswap
);
1054 if (KERN_SUCCESS
!= err
)
1056 HIBLOG("hibernate_setup(%d)\n", err
);
1061 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
1063 vars
->videoAllocSize
= kVideoMapSize
;
1064 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
))
1065 vars
->videoMapping
= 0;
1067 // generate crypt keys
1068 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
1069 vars
->wiredCryptKey
[i
] = random();
1070 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
1071 vars
->cryptKey
[i
] = random();
1075 IORegistryEntry
* regEntry
;
1076 if (!gIOOptionsEntry
)
1078 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
1079 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
1080 if (regEntry
&& !gIOOptionsEntry
)
1081 regEntry
->release();
1083 if (!gIOChosenEntry
)
1084 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1086 if (gIOOptionsEntry
)
1088 const OSSymbol
* sym
;
1090 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1093 gIOOptionsEntry
->setProperty(sym
, data
);
1100 char valueString
[16];
1102 vars
->saveBootDevice
= gIOOptionsEntry
->copyProperty(kIOSelectedBootDeviceKey
);
1105 OSData
* bootDevice
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOBootPathKey
));
1108 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1109 OSString
* str2
= OSString::withCStringNoCopy((const char *) bootDevice
->getBytesNoCopy());
1111 gIOOptionsEntry
->setProperty(sym
, str2
);
1117 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMemorySignatureKey
));
1120 vars
->haveFastBoot
= true;
1122 len
= sprintf(valueString
, "0x%lx", *((UInt32
*)data
->getBytesNoCopy()));
1123 data
= OSData::withBytes(valueString
, len
+ 1);
1124 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1126 gIOOptionsEntry
->setProperty(sym
, data
);
1132 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1134 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1136 #endif /* __ppc__ */
1138 struct AppleRTCHibernateVars
1140 uint8_t signature
[4];
1142 uint8_t booterSignature
[20];
1143 uint8_t wiredCryptKey
[16];
1145 AppleRTCHibernateVars rtcVars
;
1147 rtcVars
.signature
[0] = 'A';
1148 rtcVars
.signature
[1] = 'A';
1149 rtcVars
.signature
[2] = 'P';
1150 rtcVars
.signature
[3] = 'L';
1151 rtcVars
.revision
= 1;
1152 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
1153 if (gIOHibernateBootSignature
[0])
1157 for (uint32_t i
= 0;
1158 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
1169 value
= (value
<< 4) | c
;
1171 rtcVars
.booterSignature
[i
>> 1] = value
;
1174 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
1177 IOService::getPMRootDomain()->setProperty(kIOHibernateRTCVariablesKey
, data
);
1182 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
1184 gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
1186 #else /* !__i386__ */
1187 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1189 data
= OSData::withBytes(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1190 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1192 gIOOptionsEntry
->setProperty(sym
, data
);
1197 if (gIOHibernateBootSignature
[0])
1199 data
= OSData::withCapacity(16);
1200 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey
);
1205 for (uint32_t i
= 0; (c
= gIOHibernateBootSignature
[i
]); i
++)
1215 value
= (value
<< 4) | c
;
1217 data
->appendBytes(&value
, sizeof(value
));
1219 gIOOptionsEntry
->setProperty(sym
, data
);
1227 if (!vars
->haveFastBoot
)
1229 // set boot volume to zero
1230 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1231 if (platform
&& (kIOReturnSuccess
== platform
->readXPRAM(kXPRamAudioVolume
,
1232 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
))))
1235 newVolume
= vars
->saveBootAudioVolume
& 0xf8;
1236 platform
->writeXPRAM(kXPRamAudioVolume
,
1237 &newVolume
, sizeof(newVolume
));
1240 #endif /* !__i386__ */
1244 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
1245 gIOHibernateState
= kIOHibernateStateHibernating
;
1252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1255 IOHibernateSystemHasSlept(void)
1257 IOHibernateVars
* vars
= &gIOHibernateVars
;
1259 if ((vars
->previewData
= OSDynamicCast(OSData
,
1260 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey
))))
1262 vars
->previewBuffer
= IOMemoryDescriptor::withAddress(
1263 (void *) vars
->previewData
->getBytesNoCopy(),
1264 vars
->previewData
->getLength(),
1267 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1269 vars
->previewBuffer
->release();
1270 vars
->previewBuffer
= 0;
1272 if (!vars
->previewBuffer
)
1273 vars
->previewData
= 0;
1275 if (gIOOptionsEntry
)
1276 gIOOptionsEntry
->sync();
1278 return (kIOReturnSuccess
);
1281 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1284 IOHibernateSystemWake(void)
1286 IOHibernateVars
* vars
= &gIOHibernateVars
;
1288 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
);
1290 if (vars
->videoMapping
)
1292 if (vars
->videoMapSize
)
1294 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1295 if (vars
->videoAllocSize
)
1297 kmem_free(kernel_map
, trunc_page_32(vars
->videoMapping
), vars
->videoAllocSize
);
1300 if (vars
->previewBuffer
)
1302 vars
->previewBuffer
->release();
1303 vars
->previewBuffer
= 0;
1308 IOPolledFileClose(vars
->fileVars
);
1311 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1314 OSData
* data
= OSData::withCapacity(4);
1315 if (gIOOptionsEntry
&& data
)
1317 const OSSymbol
* sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1320 gIOOptionsEntry
->setProperty(sym
, data
);
1323 sym
= OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey
);
1326 if (vars
->saveBootDevice
)
1328 gIOOptionsEntry
->setProperty(sym
, vars
->saveBootDevice
);
1329 vars
->saveBootDevice
->release();
1333 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey
);
1336 gIOOptionsEntry
->setProperty(sym
, data
);
1339 sym
= OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey
);
1342 gIOOptionsEntry
->removeProperty(sym
);
1349 if (gIOOptionsEntry
)
1351 if (!vars
->haveFastBoot
)
1353 // reset boot audio volume
1354 IODTPlatformExpert
* platform
= OSDynamicCast(IODTPlatformExpert
, IOService::getPlatform());
1356 platform
->writeXPRAM(kXPRamAudioVolume
,
1357 &vars
->saveBootAudioVolume
, sizeof(vars
->saveBootAudioVolume
));
1360 // sync now to hardware if the booter has not
1361 if (kIOHibernateStateInactive
== gIOHibernateState
)
1362 gIOOptionsEntry
->sync();
1364 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1365 gIOOptionsEntry
->syncOFVariables();
1370 IOService::getPMRootDomain()->removeProperty(kIOHibernateRTCVariablesKey
);
1373 if (vars
->srcBuffer
)
1374 vars
->srcBuffer
->release();
1376 vars
->ioBuffer
->release();
1377 if (vars
->fileExtents
)
1378 vars
->fileExtents
->release();
1380 bzero(vars
, sizeof(*vars
));
1382 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1384 return (kIOReturnSuccess
);
1388 IOHibernateSystemPostWake(void)
1390 if (gIOHibernateFileRef
)
1392 // invalidate the image file
1393 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1394 int err
= kern_write_file(gIOHibernateFileRef
, 0,
1395 (caddr_t
) gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
1396 if (KERN_SUCCESS
!= err
)
1397 HIBLOG("kern_write_file(%d)\n", err
);
1399 kern_close_file_for_direct_io(gIOHibernateFileRef
);
1400 gIOHibernateFileRef
= 0;
1402 return (kIOReturnSuccess
);
1405 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1408 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1410 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1413 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1417 if (PE_parse_boot_arg("hfile", gIOHibernateFilename
))
1418 gIOHibernateMode
= kIOHibernateModeOn
;
1420 gIOHibernateFilename
[0] = 0;
1422 static SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1423 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1424 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1425 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1427 static SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1428 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1429 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1430 sysctl_register_oid(&sysctl__kern_bootsignature
);
1432 static SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1433 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
,
1434 &gIOHibernateMode
, 0, "");
1435 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1438 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1441 hibernate_setup_for_wake(void)
1444 // go slow (state needed for wake)
1445 ml_set_processor_speed(1);
1449 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1451 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1453 extern "C" boolean_t
1454 hibernate_write_image(void)
1456 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1457 IOHibernateVars
* vars
= &gIOHibernateVars
;
1458 IOPolledFileExtent
* fileExtents
;
1460 C_ASSERT(sizeof(IOHibernateImageHeader
) == 512);
1462 uint32_t pageCount
, pagesDone
;
1465 IOItemCount page
, count
;
1468 IOByteCount pageCompressedSize
;
1469 uint64_t compressedSize
, uncompressedSize
;
1470 uint64_t image1Size
= 0;
1471 uint32_t bitmap_size
;
1472 bool iterDone
, pollerOpen
, needEncryptStart
;
1473 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1476 uint32_t pageAndCount
[2];
1478 AbsoluteTime startTime
, endTime
;
1479 AbsoluteTime allTime
, compTime
, decoTime
;
1481 uint32_t lastProgressStamp
= 0;
1482 uint32_t progressStamp
;
1484 hibernate_cryptvars_t _cryptvars
;
1485 hibernate_cryptvars_t
* cryptvars
= 0;
1487 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1488 return (false /* sleep */ );
1490 restore1Sum
= sum1
= sum2
= 0;
1492 // encryption data. "iv" is the "initial vector".
1493 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1495 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1496 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1497 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1499 cryptvars
= &gIOHibernateCryptWakeContext
;
1500 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1501 aes_encrypt_key(vars
->cryptKey
,
1502 kIOHibernateAESKeySize
,
1503 &cryptvars
->ctx
.encrypt
);
1504 aes_decrypt_key(vars
->cryptKey
,
1505 kIOHibernateAESKeySize
,
1506 &cryptvars
->ctx
.decrypt
);
1508 cryptvars
= &_cryptvars
;
1509 bzero(cryptvars
, sizeof(hibernate_cryptvars_t
));
1510 aes_encrypt_key(vars
->wiredCryptKey
,
1511 kIOHibernateAESKeySize
,
1512 &cryptvars
->ctx
.encrypt
);
1514 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1515 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1516 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1517 bzero(gIOHibernateCryptWakeVars
, sizeof(hibernate_cryptwakevars_t
));
1520 hibernate_setup_for_wake();
1522 hibernate_page_list_setall(vars
->page_list
,
1523 vars
->page_list_wired
,
1526 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1528 fileExtents
= (IOPolledFileExtent
*) vars
->fileExtents
->getBytesNoCopy();
1531 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1532 for (page
= 0; page
< count
; page
++)
1534 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1535 fileExtents
[page
].start
, fileExtents
[page
].length
,
1536 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1540 needEncryptStart
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1542 AbsoluteTime_to_scalar(&compTime
) = 0;
1543 AbsoluteTime_to_scalar(&decoTime
) = 0;
1545 clock_get_uptime(&allTime
);
1550 uncompressedSize
= 0;
1552 pageType
= 0; // wired pages first
1554 IOPolledFileSeek(vars
->fileVars
, sizeof(IOHibernateImageHeader
));
1556 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1557 ml_get_interrupts_enabled());
1558 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, vars
->ioBuffer
);
1559 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1560 pollerOpen
= (kIOReturnSuccess
== err
);
1564 // copy file block extent list if larger than header
1566 count
= vars
->fileExtents
->getLength();
1567 if (count
> sizeof(header
->fileExtentMap
))
1569 count
-= sizeof(header
->fileExtentMap
);
1570 err
= IOPolledFileWrite(vars
->fileVars
,
1571 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1572 if (kIOReturnSuccess
!= err
)
1576 // copy out restore1 code
1578 page
= atop_32(sectHIBB
);
1579 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1580 header
->restore1CodePage
= page
;
1581 header
->restore1PageCount
= count
;
1582 header
->restore1CodeOffset
= ((uint32_t) &hibernate_machine_entrypoint
) - sectHIBB
;
1583 header
->restore1StackOffset
= ((uint32_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - sectHIBB
;
1585 // sum __HIB sect, with zeros for the stack
1586 src
= (uint8_t *) trunc_page(sectHIBB
);
1587 for (page
= 0; page
< count
; page
++)
1589 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1590 restore1Sum
+= hibernate_sum(src
, page_size
);
1592 restore1Sum
+= 0x10000001;
1597 // write the __HIB sect, with zeros for the stack
1599 src
= (uint8_t *) trunc_page(sectHIBB
);
1600 count
= ((uint32_t) &gIOHibernateRestoreStack
[0]) - trunc_page(sectHIBB
);
1603 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1604 if (kIOReturnSuccess
!= err
)
1607 err
= IOPolledFileWrite(vars
->fileVars
,
1609 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1611 if (kIOReturnSuccess
!= err
)
1613 src
= &gIOHibernateRestoreStackEnd
[0];
1614 count
= round_page(sectHIBB
+ sectSizeHIB
) - ((uint32_t) src
);
1617 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1618 if (kIOReturnSuccess
!= err
)
1622 // write the preview buffer
1627 if (vars
->previewData
)
1633 phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
);
1634 pageAndCount
[0] = atop_64(phys64
);
1635 pageAndCount
[1] = atop_32(segLen
);
1636 err
= IOPolledFileWrite(vars
->fileVars
,
1637 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1639 if (kIOReturnSuccess
!= err
)
1642 ppnum
+= sizeof(pageAndCount
);
1645 if (kIOReturnSuccess
!= err
)
1648 src
= (uint8_t *) vars
->previewData
->getBytesNoCopy();
1649 count
= vars
->previewData
->getLength();
1651 header
->previewPageListSize
= ppnum
;
1652 header
->previewSize
= count
+ ppnum
;
1654 for (page
= 0; page
< count
; page
+= page_size
)
1655 sum1
+= hibernate_sum(src
+ page
, page_size
);
1657 err
= IOPolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1658 if (kIOReturnSuccess
!= err
)
1662 // mark areas for no save
1665 (phys64
= vars
->ioBuffer
->getPhysicalSegment64(count
, &segLen
));
1668 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1669 atop_64(phys64
), atop_32(segLen
),
1670 kIOHibernatePageStateFree
);
1671 pageCount
-= atop_32(segLen
);
1675 (phys64
= vars
->srcBuffer
->getPhysicalSegment64(count
, &segLen
));
1678 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1679 atop_64(phys64
), atop_32(segLen
),
1680 kIOHibernatePageStateFree
);
1681 pageCount
-= atop_32(segLen
);
1684 // copy out bitmap of pages available for trashing during restore
1686 bitmap_size
= vars
->page_list_wired
->list_size
;
1687 src
= (uint8_t *) vars
->page_list_wired
;
1688 err
= IOPolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1689 if (kIOReturnSuccess
!= err
)
1692 // mark more areas for no save, but these are not available
1693 // for trashing during restore
1695 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1697 page
= atop_32(sectHIBB
);
1698 count
= atop_32(round_page(sectHIBB
+ sectSizeHIB
)) - page
;
1699 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1701 kIOHibernatePageStateFree
);
1704 if (vars
->previewBuffer
) for (count
= 0;
1705 (phys64
= vars
->previewBuffer
->getPhysicalSegment64(count
, &segLen
));
1708 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1709 atop_64(phys64
), atop_32(segLen
),
1710 kIOHibernatePageStateFree
);
1711 pageCount
-= atop_32(segLen
);
1714 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1719 HIBLOG("writing %d pages\n", pageCount
);
1723 count
= hibernate_page_list_iterate(pageType
? vars
->page_list
: vars
->page_list_wired
,
1725 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1729 pageAndCount
[0] = ppnum
;
1730 pageAndCount
[1] = count
;
1731 err
= IOPolledFileWrite(vars
->fileVars
,
1732 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1734 if (kIOReturnSuccess
!= err
)
1737 for (page
= 0; page
< count
; page
++)
1739 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(ppnum
), page_size
);
1742 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__
, ppnum
, err
);
1746 sum
= hibernate_sum(src
, page_size
);
1748 clock_get_uptime(&startTime
);
1750 pageCompressedSize
= WKdm_compress ((WK_word
*) src
, (WK_word
*) (src
+ page_size
), PAGE_SIZE_IN_WORDS
);
1752 clock_get_uptime(&endTime
);
1753 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1754 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1756 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1757 pageCompressedSize
= (pageCompressedSize
+ AES_BLOCK_SIZE
- 1) & ~(AES_BLOCK_SIZE
- 1);
1759 if (pageCompressedSize
> page_size
)
1761 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1762 pageCompressedSize
= page_size
;
1765 if (pageCompressedSize
!= page_size
)
1766 data
= (src
+ page_size
);
1770 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1777 if (needEncryptStart
&& (ppnum
>= atop_32(sectDATAB
)))
1779 // start encrypting partway into the data about to be written
1780 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
+ AES_BLOCK_SIZE
- 1)
1781 & ~(AES_BLOCK_SIZE
- 1);
1782 needEncryptStart
= false;
1785 err
= IOPolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1786 if (kIOReturnSuccess
!= err
)
1789 err
= IOPolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1790 if (kIOReturnSuccess
!= err
)
1793 compressedSize
+= pageCompressedSize
;
1794 if (pageCompressedSize
)
1795 uncompressedSize
+= page_size
;
1799 if (0 == (8191 & pagesDone
))
1801 clock_get_uptime(&endTime
);
1802 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1803 absolutetime_to_nanoseconds(endTime
, &nsec
);
1804 progressStamp
= nsec
/ 750000000ULL;
1805 if (progressStamp
!= lastProgressStamp
)
1807 lastProgressStamp
= progressStamp
;
1808 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1812 if (kIOReturnSuccess
!= err
)
1814 if (iterDone
&& !pageType
)
1816 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1817 if (kIOReturnSuccess
!= err
)
1823 image1Size
= vars
->fileVars
->position
;
1826 bcopy(&cryptvars
->aes_iv
[0],
1827 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1828 sizeof(cryptvars
->aes_iv
));
1829 cryptvars
= &gIOHibernateCryptWakeContext
;
1831 HIBLOG("image1Size %qd\n", image1Size
);
1835 if (kIOReturnSuccess
!= err
)
1837 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1838 if (kIOReturnSuccess
!= err
)
1843 header
->imageSize
= vars
->fileVars
->position
;
1844 header
->image1Size
= image1Size
;
1845 header
->bitmapSize
= bitmap_size
;
1846 header
->pageCount
= pageCount
;
1847 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1849 header
->restore1Sum
= restore1Sum
;
1850 header
->image1Sum
= sum1
;
1851 header
->image2Sum
= sum2
;
1853 count
= vars
->fileExtents
->getLength();
1854 if (count
> sizeof(header
->fileExtentMap
))
1856 header
->fileExtentMapSize
= count
;
1857 count
= sizeof(header
->fileExtentMap
);
1860 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1861 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1863 IOPolledFileSeek(vars
->fileVars
, 0);
1864 err
= IOPolledFileWrite(vars
->fileVars
,
1865 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1867 if (kIOReturnSuccess
!= err
)
1869 err
= IOPolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1870 if (kIOReturnSuccess
!= err
)
1872 err
= IOHibernatePollerIODone(vars
->fileVars
);
1873 if (kIOReturnSuccess
!= err
)
1878 clock_get_uptime(&endTime
);
1879 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1880 absolutetime_to_nanoseconds(endTime
, &nsec
);
1881 HIBLOG("all time: %qd ms, ",
1884 absolutetime_to_nanoseconds(compTime
, &nsec
);
1885 HIBLOG("comp time: %qd ms, ",
1888 absolutetime_to_nanoseconds(decoTime
, &nsec
);
1889 HIBLOG("deco time: %qd ms, ",
1892 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1894 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
1895 (int) ((compressedSize
* 100ULL) / uncompressedSize
),
1899 IOHibernatePollerClose(vars
->fileVars
, kIOPolledBeforeSleepState
);
1901 HIBLOG("hibernate_write_image done(%x)\n", err
);
1903 // should we come back via regular wake, set the state in memory.
1904 gIOHibernateState
= kIOHibernateStateInactive
;
1906 if ((kIOReturnSuccess
== err
) && !(kIOHibernateModeSleep
& gIOHibernateMode
))
1907 return (true /* power down */ );
1909 return (false /* sleep */ );
1912 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1914 DECLARE_IOHIBERNATEPROGRESSALPHA
1917 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
1919 uint32_t rowBytes
, pixelShift
;
1921 int32_t blob
, lastBlob
;
1922 uint32_t alpha
, in
, color
, result
;
1924 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
1926 pixelShift
= display
->depth
>> 4;
1930 rowBytes
= display
->rowBytes
;
1932 screen
+= ((display
->width
1933 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
1934 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
1936 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
1938 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
1940 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
1942 out
= screen
+ y
* rowBytes
;
1943 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
1945 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
1946 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
1948 alpha
= gIOHibernateProgressAlpha
[y
][x
];
1954 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
1955 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
1957 if (1 == pixelShift
)
1960 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1963 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1965 out
+= (1 << pixelShift
);
1967 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1972 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1975 hibernate_machine_init(void)
1980 AbsoluteTime allTime
, endTime
;
1982 uint32_t lastProgressStamp
= 0;
1983 uint32_t progressStamp
;
1984 uint64_t progressZeroPosition
= 0;
1985 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1986 hibernate_cryptvars_t
* cryptvars
= 0;
1988 IOHibernateVars
* vars
= &gIOHibernateVars
;
1990 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
|| !vars
->fileExtents
)
1993 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
1994 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
1996 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1997 gIOHibernateState
, pagesDone
, sum
, gIOHibernateCurrentHeader
->image1Size
,
1998 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2000 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2002 HIBLOG("regular wake\n");
2006 HIBPRINT("diag %x %x %x %x\n",
2007 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2008 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2010 HIBPRINT("video %x %d %d %d\n",
2011 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2012 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
);
2014 if ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)
2015 hibernate_page_list_discard(vars
->page_list
);
2017 boot_args
*args
= (boot_args
*) PE_state
.bootArgs
;
2019 if (vars
->videoMapping
2020 && gIOHibernateGraphicsInfo
->physicalAddress
2021 && (args
->Video
.v_baseAddr
== gIOHibernateGraphicsInfo
->physicalAddress
))
2023 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2024 * gIOHibernateGraphicsInfo
->rowBytes
);
2025 IOMapPages(kernel_map
,
2026 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2027 vars
->videoMapSize
, kIOMapInhibitCache
);
2030 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2032 if (gIOHibernateWakeMapSize
)
2034 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(gIOHibernateWakeMap
),
2035 gIOHibernateWakeMapSize
);
2036 if (kIOReturnSuccess
== err
)
2037 hibernate_newruntime_map(src
, gIOHibernateWakeMapSize
,
2038 gIOHibernateCurrentHeader
->systemTableOffset
);
2039 gIOHibernateWakeMap
= 0;
2040 gIOHibernateWakeMapSize
= 0;
2043 uint32_t decoOffset
;
2045 clock_get_uptime(&allTime
);
2047 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2048 err
= IOHibernatePollerOpen(vars
->fileVars
, kIOPolledAfterSleepState
, 0);
2049 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
2051 if (gIOHibernateCurrentHeader
->previewSize
)
2052 progressZeroPosition
= gIOHibernateCurrentHeader
->previewSize
2053 + gIOHibernateCurrentHeader
->fileExtentMapSize
2054 - sizeof(gIOHibernateCurrentHeader
->fileExtentMap
)
2055 + ptoa_64(gIOHibernateCurrentHeader
->restore1PageCount
);
2057 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2059 if (vars
->videoMapping
)
2061 lastBlob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2062 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2063 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, 0, lastBlob
);
2066 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2067 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
2069 cryptvars
= &gIOHibernateCryptWakeContext
;
2070 bcopy(&gIOHibernateCryptWakeVars
->aes_iv
[0],
2071 &cryptvars
->aes_iv
[0],
2072 sizeof(cryptvars
->aes_iv
));
2075 // kick off the read ahead
2076 vars
->fileVars
->io
= false;
2077 vars
->fileVars
->bufferHalf
= 0;
2078 vars
->fileVars
->bufferLimit
= 0;
2079 vars
->fileVars
->lastRead
= 0;
2080 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2082 IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2083 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2086 HIBLOG("hibernate_machine_init reading\n");
2088 uint32_t * header
= (uint32_t *) src
;
2096 vm_offset_t ppnum
, compressedSize
;
2098 IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2103 // HIBPRINT("(%x, %x)\n", ppnum, count);
2108 for (page
= 0; page
< count
; page
++)
2110 IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2112 compressedSize
= kIOHibernateTagLength
& tag
;
2113 if (!compressedSize
)
2120 IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2122 if (compressedSize
!= page_size
)
2124 decoOffset
= page_size
;
2125 WKdm_decompress((WK_word
*) src
, (WK_word
*) (src
+ decoOffset
), PAGE_SIZE_IN_WORDS
);
2130 sum
+= hibernate_sum((src
+ decoOffset
), page_size
);
2132 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2134 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum
, err
);
2139 if (vars
->videoMapping
&& (0 == (255 & pagesDone
)))
2141 blob
= ((vars
->fileVars
->position
- progressZeroPosition
) * kIOHibernateProgressCount
)
2142 / (gIOHibernateCurrentHeader
->imageSize
- progressZeroPosition
);
2143 if (blob
!= lastBlob
)
2145 ProgressUpdate(gIOHibernateGraphicsInfo
, (uint8_t *) vars
->videoMapping
, lastBlob
, blob
);
2150 if (0 == (8191 & pagesDone
))
2152 clock_get_uptime(&endTime
);
2153 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2154 absolutetime_to_nanoseconds(endTime
, &nsec
);
2155 progressStamp
= nsec
/ 750000000ULL;
2156 if (progressStamp
!= lastProgressStamp
)
2158 lastProgressStamp
= progressStamp
;
2159 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2160 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2167 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2169 if (vars
->fileVars
->io
)
2170 (void) IOHibernatePollerIODone(vars
->fileVars
);
2172 err
= IOHibernatePollerClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2174 if (vars
->videoMapping
)
2175 ProgressUpdate(gIOHibernateGraphicsInfo
,
2176 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2178 clock_get_uptime(&endTime
);
2179 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2180 absolutetime_to_nanoseconds(endTime
, &nsec
);
2182 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2183 pagesDone
, sum
, nsec
/ 1000000ULL);
2186 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */