]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOHibernateIO.cpp
bc5c9c9652147dcbbc29761a1e2d1945db4a9c43
[apple/xnu.git] / iokit / Kernel / IOHibernateIO.cpp
1 /*
2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30 /*
31
32 Sleep:
33
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).
71
72 Boot/Wake:
73
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
98 is closed via bsd.
99
100 Polled Mode I/O:
101
102 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
103 registry, specifying an object of calls IOPolledInterface.
104
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.
109
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:
112
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.
117
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.
122
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
126 one thread running.
127
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
134 to restrict I/O ops.
135 */
136
137 #include <sys/systm.h>
138
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>
155
156 #include <sys/uio.h>
157 #include <sys/conf.h>
158 #include <sys/stat.h>
159 #include <sys/fcntl.h> // (FWRITE, ...)
160 #include <sys/sysctl.h>
161
162 #include <IOKit/IOHibernatePrivate.h>
163 #include <IOKit/IOPolledInterface.h>
164 #include <IOKit/IONVRAM.h>
165 #include "IOHibernateInternal.h"
166 #include "WKdm.h"
167 #include "IOKitKernelInternal.h"
168
169 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170
171 OSDefineMetaClassAndAbstractStructors(IOPolledInterface, OSObject);
172
173 OSMetaClassDefineReservedUnused(IOPolledInterface, 0);
174 OSMetaClassDefineReservedUnused(IOPolledInterface, 1);
175 OSMetaClassDefineReservedUnused(IOPolledInterface, 2);
176 OSMetaClassDefineReservedUnused(IOPolledInterface, 3);
177 OSMetaClassDefineReservedUnused(IOPolledInterface, 4);
178 OSMetaClassDefineReservedUnused(IOPolledInterface, 5);
179 OSMetaClassDefineReservedUnused(IOPolledInterface, 6);
180 OSMetaClassDefineReservedUnused(IOPolledInterface, 7);
181 OSMetaClassDefineReservedUnused(IOPolledInterface, 8);
182 OSMetaClassDefineReservedUnused(IOPolledInterface, 9);
183 OSMetaClassDefineReservedUnused(IOPolledInterface, 10);
184 OSMetaClassDefineReservedUnused(IOPolledInterface, 11);
185 OSMetaClassDefineReservedUnused(IOPolledInterface, 12);
186 OSMetaClassDefineReservedUnused(IOPolledInterface, 13);
187 OSMetaClassDefineReservedUnused(IOPolledInterface, 14);
188 OSMetaClassDefineReservedUnused(IOPolledInterface, 15);
189
190 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
191
192 extern uint32_t gIOHibernateState;
193 uint32_t gIOHibernateMode;
194 static char gIOHibernateBootSignature[256+1];
195 static char gIOHibernateFilename[MAXPATHLEN+1];
196 static uint32_t gIOHibernateFreeRatio = 0; // free page target (percent)
197 uint32_t gIOHibernateFreeTime = 0*1000; // max time to spend freeing pages (ms)
198
199 static IODTNVRAM * gIOOptionsEntry;
200 static IORegistryEntry * gIOChosenEntry;
201
202 static IOPolledFileIOVars gFileVars;
203 static IOHibernateVars gIOHibernateVars;
204 static struct kern_direct_file_io_ref_t * gIOHibernateFileRef;
205 static hibernate_cryptvars_t gIOHibernateCryptWakeContext;
206
207 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
208
209 enum { kXPRamAudioVolume = 8 };
210 enum { kDefaultIOSize = 128 * 1024 };
211 enum { kVideoMapSize = 32 * 1024 * 1024 };
212
213 #ifndef kIOMediaPreferredBlockSizeKey
214 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
215 #endif
216
217 #ifndef kIOBootPathKey
218 #define kIOBootPathKey "bootpath"
219 #endif
220 #ifndef kIOSelectedBootDeviceKey
221 #define kIOSelectedBootDeviceKey "boot-device"
222 #endif
223
224
225 enum { kIOHibernateMinPollersNeeded = 2 };
226
227 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
228
229 // copy from phys addr to MD
230
231 static IOReturn
232 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,
233 IOByteCount offset, addr64_t bytes, IOByteCount length)
234 {
235 addr64_t srcAddr = bytes;
236 IOByteCount remaining;
237
238 remaining = length = min(length, md->getLength() - offset);
239 while (remaining) { // (process another target segment?)
240 addr64_t dstAddr64;
241 IOByteCount dstLen;
242
243 dstAddr64 = md->getPhysicalSegment64(offset, &dstLen);
244 if (!dstAddr64)
245 break;
246
247 // Clip segment length to remaining
248 if (dstLen > remaining)
249 dstLen = remaining;
250
251 #if 1
252 bcopy_phys(srcAddr, dstAddr64, dstLen);
253 #else
254 copypv(srcAddr, dstAddr64, dstLen,
255 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
256 #endif
257 srcAddr += dstLen;
258 offset += dstLen;
259 remaining -= dstLen;
260 }
261
262 assert(!remaining);
263
264 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
265 }
266
267 // copy from MD to phys addr
268
269 static IOReturn
270 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,
271 IOByteCount offset, addr64_t bytes, IOByteCount length)
272 {
273 addr64_t dstAddr = bytes;
274 IOByteCount remaining;
275
276 remaining = length = min(length, md->getLength() - offset);
277 while (remaining) { // (process another target segment?)
278 addr64_t srcAddr64;
279 IOByteCount dstLen;
280
281 srcAddr64 = md->getPhysicalSegment64(offset, &dstLen);
282 if (!srcAddr64)
283 break;
284
285 // Clip segment length to remaining
286 if (dstLen > remaining)
287 dstLen = remaining;
288
289 #if 1
290 bcopy_phys(srcAddr64, dstAddr, dstLen);
291 #else
292 copypv(srcAddr, dstAddr64, dstLen,
293 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
294 #endif
295 dstAddr += dstLen;
296 offset += dstLen;
297 remaining -= dstLen;
298 }
299
300 assert(!remaining);
301
302 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
303 }
304
305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
306
307 void
308 hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_t * page_list_wired,
309 vm_offset_t ppnum, vm_offset_t count, uint32_t kind)
310 {
311 count += ppnum;
312 switch (kind)
313 {
314 case kIOHibernatePageStateUnwiredSave:
315 // unwired save
316 for (; ppnum < count; ppnum++)
317 {
318 hibernate_page_bitset(page_list, FALSE, ppnum);
319 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
320 }
321 break;
322 case kIOHibernatePageStateWiredSave:
323 // wired save
324 for (; ppnum < count; ppnum++)
325 {
326 hibernate_page_bitset(page_list, FALSE, ppnum);
327 hibernate_page_bitset(page_list_wired, FALSE, ppnum);
328 }
329 break;
330 case kIOHibernatePageStateFree:
331 // free page
332 for (; ppnum < count; ppnum++)
333 {
334 hibernate_page_bitset(page_list, TRUE, ppnum);
335 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
336 }
337 break;
338 default:
339 panic("hibernate_set_page_state");
340 }
341 }
342
343 static vm_offset_t
344 hibernate_page_list_iterate(hibernate_page_list_t * list,
345 void ** iterator, vm_offset_t * ppnum)
346 {
347 uint32_t count, idx;
348
349 idx = (uint32_t) *iterator;
350
351 if (!idx)
352 idx = hibernate_page_list_count(list, TRUE, idx);
353
354 *ppnum = idx;
355 count = hibernate_page_list_count(list, FALSE, idx);
356 idx += count;
357 idx += hibernate_page_list_count(list, TRUE, idx);
358 *iterator = (void *) idx;
359
360 return (count);
361 }
362
363 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
364
365 static IOReturn
366 IOHibernatePollerProbe(IOPolledFileIOVars * vars, IOService * target)
367 {
368 IOReturn err = kIOReturnError;
369 int32_t idx;
370 IOPolledInterface * poller;
371
372 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
373 {
374 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
375 err = poller->probe(target);
376 if (err)
377 {
378 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx, err);
379 break;
380 }
381 }
382
383 return (err);
384 }
385
386 static IOReturn
387 IOHibernatePollerOpen(IOPolledFileIOVars * vars, uint32_t state, IOMemoryDescriptor * md)
388 {
389 IOReturn err = kIOReturnError;
390 int32_t idx;
391 IOPolledInterface * poller;
392
393 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
394 {
395 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
396 err = poller->open(state, md);
397 if (err)
398 {
399 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx, err);
400 break;
401 }
402 }
403
404 return (err);
405 }
406
407 static IOReturn
408 IOHibernatePollerClose(IOPolledFileIOVars * vars, uint32_t state)
409 {
410 IOReturn err = kIOReturnError;
411 int32_t idx;
412 IOPolledInterface * poller;
413
414 for (idx = 0;
415 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
416 idx++)
417 {
418 err = poller->close(state);
419 if (err)
420 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx, err);
421 }
422
423 return (err);
424 }
425
426 static void
427 IOHibernatePollerIOComplete(void * target,
428 void * parameter,
429 IOReturn status,
430 UInt64 actualByteCount)
431 {
432 IOPolledFileIOVars * vars = (IOPolledFileIOVars *) parameter;
433
434 vars->ioStatus = status;
435 }
436
437 static IOReturn
438 IOHibernatePollerIO(IOPolledFileIOVars * vars,
439 uint32_t operation, uint32_t bufferOffset,
440 uint64_t deviceOffset, uint64_t length)
441 {
442
443 IOReturn err = kIOReturnError;
444 IOPolledInterface * poller;
445 IOPolledCompletion completion;
446
447 completion.target = 0;
448 completion.action = &IOHibernatePollerIOComplete;
449 completion.parameter = vars;
450
451 vars->ioStatus = -1;
452
453 poller = (IOPolledInterface *) vars->pollers->getObject(0);
454 err = poller->startIO(operation, bufferOffset, deviceOffset + vars->block0, length, completion);
455 if (err)
456 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err);
457
458 return (err);
459 }
460
461 static IOReturn
462 IOHibernatePollerIODone(IOPolledFileIOVars * vars)
463 {
464 IOReturn err = kIOReturnError;
465 int32_t idx;
466 IOPolledInterface * poller;
467
468 while (-1 == vars->ioStatus)
469 {
470 for (idx = 0;
471 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
472 idx++)
473 {
474 err = poller->checkForWork();
475 if (err)
476 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err);
477 }
478 }
479
480 if (kIOReturnSuccess != vars->ioStatus)
481 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", vars->ioStatus);
482
483 return (vars->ioStatus);
484 }
485
486 IOReturn
487 IOPolledInterface::checkAllForWork(void)
488 {
489 IOReturn err = kIOReturnNotReady;
490 int32_t idx;
491 IOPolledInterface * poller;
492
493 IOHibernateVars * vars = &gIOHibernateVars;
494
495 if (!vars->fileVars || !vars->fileVars->pollers)
496 return (err);
497
498 for (idx = 0;
499 (poller = (IOPolledInterface *) vars->fileVars->pollers->getObject(idx));
500 idx++)
501 {
502 err = poller->checkForWork();
503 if (err)
504 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx, err);
505 }
506
507 return (err);
508 }
509
510 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
511
512 struct _OpenFileContext
513 {
514 OSData * extents;
515 uint64_t size;
516 };
517
518 static void
519 file_extent_callback(void * ref, uint64_t start, uint64_t length)
520 {
521 _OpenFileContext * ctx = (_OpenFileContext *) ref;
522 IOPolledFileExtent extent;
523
524 extent.start = start;
525 extent.length = length;
526
527 ctx->extents->appendBytes(&extent, sizeof(extent));
528 ctx->size += length;
529 }
530
531 IOReturn
532 IOPolledFileOpen( const char * filename, IOBufferMemoryDescriptor * ioBuffer,
533 IOPolledFileIOVars ** fileVars, OSData ** fileExtents,
534 OSData ** imagePath)
535 {
536 IOReturn err = kIOReturnError;
537 IOPolledFileIOVars * vars;
538 _OpenFileContext ctx;
539 OSData * extentsData;
540 OSNumber * num;
541 IORegistryEntry * part = 0;
542 OSDictionary * matching;
543 OSIterator * iter;
544 dev_t hibernate_image_dev;
545 uint64_t maxiobytes;
546
547 vars = &gFileVars;
548 do
549 {
550 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader));
551 if (sizeof(IOHibernateImageHeader) != 512)
552 continue;
553
554 vars->io = false;
555 vars->buffer = (uint8_t *) ioBuffer->getBytesNoCopy();
556 vars->bufferHalf = 0;
557 vars->bufferOffset = 0;
558 vars->bufferSize = ioBuffer->getLength() >> 1;
559
560 extentsData = OSData::withCapacity(32);
561
562 ctx.extents = extentsData;
563 ctx.size = 0;
564 vars->fileRef = kern_open_file_for_direct_io(filename,
565 &file_extent_callback, &ctx,
566 &hibernate_image_dev,
567 &vars->block0,
568 &maxiobytes);
569 if (!vars->fileRef)
570 {
571 err = kIOReturnNoSpace;
572 break;
573 }
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!
577 {
578 err = kIOReturnNoSpace;
579 break;
580 }
581
582 if (maxiobytes < vars->bufferSize)
583 vars->bufferSize = maxiobytes;
584
585 vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();
586
587 matching = IOService::serviceMatching("IOMedia");
588 num = OSNumber::withNumber(major(hibernate_image_dev), 32);
589 matching->setObject(kIOBSDMajorKey, num);
590 num->release();
591 num = OSNumber::withNumber(minor(hibernate_image_dev), 32);
592 matching->setObject(kIOBSDMinorKey, num);
593 num->release();
594 iter = IOService::getMatchingServices(matching);
595 matching->release();
596 if (iter)
597 {
598 part = (IORegistryEntry *) iter->getNextObject();
599 part->retain();
600 iter->release();
601 }
602
603 int minor, major;
604 IORegistryEntry * next;
605 IORegistryEntry * child;
606 OSData * data;
607
608 num = (OSNumber *) part->getProperty(kIOBSDMajorKey);
609 if (!num)
610 break;
611 major = num->unsigned32BitValue();
612 num = (OSNumber *) part->getProperty(kIOBSDMinorKey);
613 if (!num)
614 break;
615 minor = num->unsigned32BitValue();
616
617 hibernate_image_dev = makedev(major, minor);
618
619 vars->pollers = OSArray::withCapacity(4);
620 if (!vars->pollers)
621 break;
622
623 vars->blockSize = 512;
624 next = part;
625 do
626 {
627 IOPolledInterface * poller;
628 OSObject * obj;
629
630 obj = next->getProperty(kIOPolledInterfaceSupportKey);
631 if (kOSBooleanFalse == obj)
632 {
633 vars->pollers->flushCollection();
634 break;
635 }
636 else if ((poller = OSDynamicCast(IOPolledInterface, obj)))
637 vars->pollers->setObject(poller);
638 if ((num = OSDynamicCast(OSNumber, next->getProperty(kIOMediaPreferredBlockSizeKey))))
639 vars->blockSize = num->unsigned32BitValue();
640 child = next;
641 }
642 while ((next = child->getParentEntry(gIOServicePlane))
643 && child->isParent(next, gIOServicePlane, true));
644
645 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
646 major, minor, vars->blockSize, vars->pollers->getCount());
647 if (vars->pollers->getCount() < kIOHibernateMinPollersNeeded)
648 continue;
649
650 err = IOHibernatePollerProbe(vars, (IOService *) part);
651 if (kIOReturnSuccess != err)
652 break;
653
654 err = IOHibernatePollerOpen(vars, kIOPolledPreflightState, ioBuffer);
655 if (kIOReturnSuccess != err)
656 break;
657
658 *fileVars = vars;
659 *fileExtents = extentsData;
660
661 // make imagePath
662 char str1[256];
663 char str2[24];
664 int len = sizeof(str1);
665
666 if ((extentsData->getLength() >= sizeof(IOPolledFileExtent))
667 && part->getPath(str1, &len, gIODTPlane))
668 {
669 // (strip the plane name)
670 char * tail = strchr(str1, ':');
671 if (!tail)
672 tail = str1 - 1;
673 data = OSData::withBytes(tail + 1, strlen(tail + 1));
674 sprintf(str2, ",%qx", vars->extentMap[0]);
675 data->appendBytes(str2, strlen(str2));
676 *imagePath = data;
677 }
678 }
679 while (false);
680
681 if (kIOReturnSuccess != err)
682 {
683 HIBLOG("error 0x%x opening hibernation file\n", err);
684 if (vars->fileRef)
685 kern_close_file_for_direct_io(vars->fileRef);
686 }
687
688 if (part)
689 part->release();
690
691 return (err);
692 }
693
694 IOReturn
695 IOPolledFileClose( IOPolledFileIOVars * vars )
696 {
697 if (vars->pollers)
698 {
699 IOHibernatePollerClose(vars, kIOPolledPostflightState);
700 vars->pollers->release();
701 }
702
703 gIOHibernateFileRef = vars->fileRef;
704
705 bzero(vars, sizeof(IOPolledFileIOVars));
706
707 return (kIOReturnSuccess);
708 }
709
710 static IOReturn
711 IOPolledFileSeek(IOPolledFileIOVars * vars, uint64_t position)
712 {
713 IOPolledFileExtent * extentMap;
714
715 extentMap = vars->extentMap;
716
717 vars->position = position;
718
719 while (position >= extentMap->length)
720 {
721 position -= extentMap->length;
722 extentMap++;
723 }
724
725 vars->currentExtent = extentMap;
726 vars->extentRemaining = extentMap->length - position;
727 vars->extentPosition = vars->position - position;
728
729 if (vars->bufferSize <= vars->extentRemaining)
730 vars->bufferLimit = vars->bufferSize;
731 else
732 vars->bufferLimit = vars->extentRemaining;
733
734 return (kIOReturnSuccess);
735 }
736
737 static IOReturn
738 IOPolledFileWrite(IOPolledFileIOVars * vars,
739 const uint8_t * bytes, IOByteCount size,
740 hibernate_cryptvars_t * cryptvars)
741 {
742 IOReturn err = kIOReturnSuccess;
743 IOByteCount copy;
744 bool flush = false;
745
746 do
747 {
748 if (!bytes && !size)
749 {
750 // seek to end of block & flush
751 size = vars->position & (vars->blockSize - 1);
752 if (size)
753 size = vars->blockSize - size;
754 flush = true;
755 // use some garbage for the fill
756 bytes = vars->buffer + vars->bufferOffset;
757 }
758
759 copy = vars->bufferLimit - vars->bufferOffset;
760 if (copy > size)
761 copy = size;
762 else
763 flush = true;
764
765 if (bytes)
766 {
767 bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
768 bytes += copy;
769 }
770 else
771 bzero(vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
772
773 size -= copy;
774 vars->bufferOffset += copy;
775 vars->position += copy;
776
777 if (flush && vars->bufferOffset)
778 {
779 uint64_t offset = (vars->position - vars->bufferOffset
780 - vars->extentPosition + vars->currentExtent->start);
781 uint32_t length = (vars->bufferOffset);
782
783 if (cryptvars && vars->encryptStart && (vars->position > vars->encryptStart))
784 {
785 uint32_t encryptLen, encryptStart;
786 encryptLen = vars->position - vars->encryptStart;
787 if (encryptLen > length)
788 encryptLen = length;
789 encryptStart = length - encryptLen;
790
791 // encrypt the buffer
792 aes_encrypt_cbc(vars->buffer + vars->bufferHalf + encryptStart,
793 &cryptvars->aes_iv[0],
794 encryptLen / AES_BLOCK_SIZE,
795 vars->buffer + vars->bufferHalf + encryptStart,
796 &cryptvars->ctx.encrypt);
797 // save initial vector for following encrypts
798 bcopy(vars->buffer + vars->bufferHalf + encryptStart + encryptLen - AES_BLOCK_SIZE,
799 &cryptvars->aes_iv[0],
800 AES_BLOCK_SIZE);
801 }
802
803 if (vars->io)
804 {
805 err = IOHibernatePollerIODone(vars);
806 if (kIOReturnSuccess != err)
807 break;
808 }
809
810 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
811 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
812
813 err = IOHibernatePollerIO(vars, kIOPolledWrite, vars->bufferHalf, offset, length);
814 if (kIOReturnSuccess != err)
815 break;
816 vars->io = true;
817
818 vars->extentRemaining -= vars->bufferOffset;
819 if (!vars->extentRemaining)
820 {
821 vars->currentExtent++;
822 vars->extentRemaining = vars->currentExtent->length;
823 vars->extentPosition = vars->position;
824 if (!vars->extentRemaining)
825 {
826 err = kIOReturnOverrun;
827 break;
828 }
829 }
830
831 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
832 vars->bufferOffset = 0;
833 if (vars->bufferSize <= vars->extentRemaining)
834 vars->bufferLimit = vars->bufferSize;
835 else
836 vars->bufferLimit = vars->extentRemaining;
837
838 flush = false;
839 }
840 }
841 while (size);
842
843 return (err);
844 }
845
846 static IOReturn
847 IOPolledFileRead(IOPolledFileIOVars * vars,
848 uint8_t * bytes, IOByteCount size,
849 hibernate_cryptvars_t * cryptvars)
850 {
851 IOReturn err = kIOReturnSuccess;
852 IOByteCount copy;
853
854 // bytesWritten += size;
855
856 do
857 {
858 copy = vars->bufferLimit - vars->bufferOffset;
859 if (copy > size)
860 copy = size;
861
862 if (bytes)
863 {
864 bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
865 bytes += copy;
866 }
867 size -= copy;
868 vars->bufferOffset += copy;
869 // vars->position += copy;
870
871 if (vars->bufferOffset == vars->bufferLimit)
872 {
873 if (vars->io)
874 {
875 err = IOHibernatePollerIODone(vars);
876 if (kIOReturnSuccess != err)
877 break;
878 }
879 else
880 cryptvars = 0;
881
882 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
883
884 vars->position += vars->lastRead;
885 vars->extentRemaining -= vars->lastRead;
886 vars->bufferLimit = vars->lastRead;
887
888 if (!vars->extentRemaining)
889 {
890 vars->currentExtent++;
891 vars->extentRemaining = vars->currentExtent->length;
892 vars->extentPosition = vars->position;
893 if (!vars->extentRemaining)
894 {
895 err = kIOReturnOverrun;
896 break;
897 }
898 }
899
900 if (vars->extentRemaining <= vars->bufferSize)
901 vars->lastRead = vars->extentRemaining;
902 else
903 vars->lastRead = vars->bufferSize;
904
905 uint64_t offset = (vars->position
906 - vars->extentPosition + vars->currentExtent->start);
907 uint64_t length = (vars->lastRead);
908
909 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
910
911 err = IOHibernatePollerIO(vars, kIOPolledRead, vars->bufferHalf, offset, length);
912 if (kIOReturnSuccess != err)
913 break;
914 vars->io = true;
915
916 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
917 vars->bufferOffset = 0;
918
919 if (cryptvars)
920 {
921 uint8_t thisVector[AES_BLOCK_SIZE];
922 // save initial vector for following decrypts
923 bcopy(&cryptvars->aes_iv[0], &thisVector[0], AES_BLOCK_SIZE);
924 bcopy(vars->buffer + vars->bufferHalf + vars->lastRead - AES_BLOCK_SIZE,
925 &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
926 // decrypt the buffer
927 aes_decrypt_cbc(vars->buffer + vars->bufferHalf,
928 &thisVector[0],
929 vars->lastRead / AES_BLOCK_SIZE,
930 vars->buffer + vars->bufferHalf,
931 &cryptvars->ctx.decrypt);
932 }
933 }
934 }
935 while (size);
936
937 return (err);
938 }
939
940 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
941
942 IOReturn
943 IOHibernateSystemSleep(void)
944 {
945 IOReturn err;
946 OSData * data;
947 OSObject * obj;
948 OSString * str;
949 OSNumber * num;
950
951 IOHibernateVars * vars = &gIOHibernateVars;
952
953 if (vars->fileVars && vars->fileVars->fileRef)
954 // already on the way down
955 return (kIOReturnSuccess);
956
957 gIOHibernateState = kIOHibernateStateInactive;
958
959 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateModeKey)))
960 {
961 if ((num = OSDynamicCast(OSNumber, obj)))
962 gIOHibernateMode = num->unsigned32BitValue();
963 if (kIOHibernateModeSleep & gIOHibernateMode)
964 // default to discard clean for safe sleep
965 gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
966 | kIOHibernateModeDiscardCleanActive);
967
968 obj->release();
969 }
970 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeRatioKey)))
971 {
972 if ((num = OSDynamicCast(OSNumber, obj)))
973 gIOHibernateFreeRatio = num->unsigned32BitValue();
974 obj->release();
975 }
976 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFreeTimeKey)))
977 {
978 if ((num = OSDynamicCast(OSNumber, obj)))
979 gIOHibernateFreeTime = num->unsigned32BitValue();
980 obj->release();
981 }
982 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey)))
983 {
984 if ((str = OSDynamicCast(OSString, obj)))
985 strcpy(gIOHibernateFilename, str->getCStringNoCopy());
986 obj->release();
987 }
988
989 if (!gIOHibernateMode || !gIOHibernateFilename[0])
990 return (kIOReturnUnsupported);
991
992 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
993
994 do
995 {
996 vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(0, 4 * page_size, page_size);
997 vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(0, 2 * kDefaultIOSize, page_size);
998
999 if (!vars->srcBuffer || !vars->ioBuffer)
1000 {
1001 err = kIOReturnNoMemory;
1002 break;
1003 }
1004
1005 err = IOPolledFileOpen(gIOHibernateFilename, vars->ioBuffer,
1006 &vars->fileVars, &vars->fileExtents, &data);
1007 if (KERN_SUCCESS != err)
1008 {
1009 HIBLOG("IOPolledFileOpen(%x)\n", err);
1010 break;
1011 }
1012 if (vars->fileVars->fileRef)
1013 {
1014 // invalidate the image file
1015 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1016 int err = kern_write_file(vars->fileVars->fileRef, 0,
1017 (caddr_t) gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1018 if (KERN_SUCCESS != err)
1019 HIBLOG("kern_write_file(%d)\n", err);
1020 }
1021
1022 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1023
1024 boolean_t encryptedswap;
1025 err = hibernate_setup(gIOHibernateCurrentHeader,
1026 gIOHibernateFreeRatio, gIOHibernateFreeTime,
1027 &vars->page_list, &vars->page_list_wired, &encryptedswap);
1028 if (KERN_SUCCESS != err)
1029 {
1030 HIBLOG("hibernate_setup(%d)\n", err);
1031 break;
1032 }
1033
1034 if (encryptedswap)
1035 gIOHibernateMode ^= kIOHibernateModeEncrypt;
1036
1037 vars->videoAllocSize = kVideoMapSize;
1038 if (KERN_SUCCESS != kmem_alloc_pageable(kernel_map, &vars->videoMapping, vars->videoAllocSize))
1039 vars->videoMapping = 0;
1040
1041 // generate crypt keys
1042 for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++)
1043 vars->wiredCryptKey[i] = random();
1044 for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++)
1045 vars->cryptKey[i] = random();
1046
1047 // set nvram
1048
1049 IORegistryEntry * regEntry;
1050 if (!gIOOptionsEntry)
1051 {
1052 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1053 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
1054 if (regEntry && !gIOOptionsEntry)
1055 regEntry->release();
1056 }
1057 if (!gIOChosenEntry)
1058 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
1059
1060 if (gIOOptionsEntry)
1061 {
1062 const OSSymbol * sym;
1063 size_t len;
1064 char valueString[16];
1065
1066 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1067 if (sym)
1068 {
1069 gIOOptionsEntry->setProperty(sym, data);
1070 sym->release();
1071 }
1072 data->release();
1073
1074 vars->saveBootDevice = gIOOptionsEntry->copyProperty(kIOSelectedBootDeviceKey);
1075 if (gIOChosenEntry)
1076 {
1077 OSData * bootDevice = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOBootPathKey));
1078 if (bootDevice)
1079 {
1080 sym = OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey);
1081 OSString * str2 = OSString::withCStringNoCopy((const char *) bootDevice->getBytesNoCopy());
1082 if (sym && str2)
1083 gIOOptionsEntry->setProperty(sym, str2);
1084 if (sym)
1085 sym->release();
1086 if (str2)
1087 str2->release();
1088 }
1089
1090 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMemorySignatureKey));
1091 if (data)
1092 {
1093 vars->haveFastBoot = true;
1094
1095 len = sprintf(valueString, "0x%lx", *((UInt32 *)data->getBytesNoCopy()));
1096 data = OSData::withBytes(valueString, len + 1);
1097 sym = OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey);
1098 if (sym && data)
1099 gIOOptionsEntry->setProperty(sym, data);
1100 if (sym)
1101 sym->release();
1102 if (data)
1103 data->release();
1104 }
1105 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
1106 if (data)
1107 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
1108 }
1109
1110 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1111 {
1112 data = OSData::withBytes(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1113 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
1114 if (sym && data)
1115 gIOOptionsEntry->setProperty(sym, data);
1116 if (sym)
1117 sym->release();
1118 if (data)
1119 data->release();
1120 if (gIOHibernateBootSignature[0])
1121 {
1122 data = OSData::withCapacity(16);
1123 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
1124 if (sym && data)
1125 {
1126 char c;
1127 uint8_t value;
1128 for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++)
1129 {
1130 if (c >= 'a')
1131 c -= 'a' - 10;
1132 else if (c >= 'A')
1133 c -= 'A' - 10;
1134 else if (c >= '0')
1135 c -= '0';
1136 else
1137 continue;
1138 value = (value << 4) | c;
1139 if (i & 1)
1140 data->appendBytes(&value, sizeof(value));
1141 }
1142 gIOOptionsEntry->setProperty(sym, data);
1143 }
1144 if (sym)
1145 sym->release();
1146 if (data)
1147 data->release();
1148 }
1149 }
1150
1151 if (!vars->haveFastBoot)
1152 {
1153 // set boot volume to zero
1154 IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
1155 if (platform && (kIOReturnSuccess == platform->readXPRAM(kXPRamAudioVolume,
1156 &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume))))
1157 {
1158 uint8_t newVolume;
1159 newVolume = vars->saveBootAudioVolume & 0xf8;
1160 platform->writeXPRAM(kXPRamAudioVolume,
1161 &newVolume, sizeof(newVolume));
1162 }
1163 }
1164 }
1165 // --
1166
1167 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderSignature;
1168 gIOHibernateState = kIOHibernateStateHibernating;
1169 }
1170 while (false);
1171
1172 return (err);
1173 }
1174
1175 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1176
1177 IOReturn
1178 IOHibernateSystemHasSlept(void)
1179 {
1180 IOHibernateVars * vars = &gIOHibernateVars;
1181
1182 if ((vars->previewData = OSDynamicCast(OSData,
1183 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewBufferKey))))
1184 {
1185 vars->previewBuffer = IOMemoryDescriptor::withAddress(
1186 (void *) vars->previewData->getBytesNoCopy(),
1187 vars->previewData->getLength(),
1188 kIODirectionInOut);
1189
1190 if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare()))
1191 {
1192 vars->previewBuffer->release();
1193 vars->previewBuffer = 0;
1194 }
1195 if (!vars->previewBuffer)
1196 vars->previewData = 0;
1197 }
1198 if (gIOOptionsEntry)
1199 gIOOptionsEntry->sync();
1200
1201 return (kIOReturnSuccess);
1202 }
1203
1204 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1205
1206 IOReturn
1207 IOHibernateSystemWake(void)
1208 {
1209 IOHibernateVars * vars = &gIOHibernateVars;
1210
1211 hibernate_teardown(vars->page_list, vars->page_list_wired);
1212
1213 if (vars->videoMapping)
1214 {
1215 if (vars->videoMapSize)
1216 // remove mappings
1217 IOUnmapPages(kernel_map, vars->videoMapping, vars->videoMapSize);
1218 if (vars->videoAllocSize)
1219 // dealloc range
1220 kmem_free(kernel_map, trunc_page_32(vars->videoMapping), vars->videoAllocSize);
1221 }
1222
1223 if (vars->previewBuffer)
1224 {
1225 vars->previewBuffer->release();
1226 vars->previewBuffer = 0;
1227 }
1228
1229 if (vars->fileVars)
1230 {
1231 IOPolledFileClose(vars->fileVars);
1232 }
1233
1234 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1235
1236 OSData * data = OSData::withCapacity(4);
1237 if (gIOOptionsEntry && data)
1238 {
1239 const OSSymbol * sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1240 if (sym)
1241 {
1242 gIOOptionsEntry->setProperty(sym, data);
1243 sym->release();
1244 }
1245 sym = OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey);
1246 if (sym)
1247 {
1248 if (vars->saveBootDevice)
1249 {
1250 gIOOptionsEntry->setProperty(sym, vars->saveBootDevice);
1251 vars->saveBootDevice->release();
1252 }
1253 sym->release();
1254 }
1255 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
1256 if (sym)
1257 {
1258 gIOOptionsEntry->setProperty(sym, data);
1259 sym->release();
1260 }
1261 sym = OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey);
1262 if (sym)
1263 {
1264 gIOOptionsEntry->removeProperty(sym);
1265 sym->release();
1266 }
1267 }
1268 if (data)
1269 data->release();
1270
1271 if (gIOOptionsEntry)
1272 {
1273 if (!vars->haveFastBoot)
1274 {
1275 // reset boot audio volume
1276 IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
1277 if (platform)
1278 platform->writeXPRAM(kXPRamAudioVolume,
1279 &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume));
1280 }
1281
1282 // sync now to hardware if the booter has not
1283 if (kIOHibernateStateInactive == gIOHibernateState)
1284 gIOOptionsEntry->sync();
1285 else
1286 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1287 gIOOptionsEntry->syncOFVariables();
1288 }
1289
1290 if (vars->srcBuffer)
1291 vars->srcBuffer->release();
1292 if (vars->ioBuffer)
1293 vars->ioBuffer->release();
1294 if (vars->fileExtents)
1295 vars->fileExtents->release();
1296
1297 bzero(vars, sizeof(*vars));
1298
1299 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1300
1301 return (kIOReturnSuccess);
1302 }
1303
1304 IOReturn
1305 IOHibernateSystemPostWake(void)
1306 {
1307 if (gIOHibernateFileRef)
1308 {
1309 kern_close_file_for_direct_io(gIOHibernateFileRef);
1310 gIOHibernateFileRef = 0;
1311 }
1312 return (kIOReturnSuccess);
1313 }
1314
1315 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1316
1317 void
1318 IOHibernateSystemInit(IOPMrootDomain * rootDomain)
1319 {
1320 OSData * data = OSData::withBytesNoCopy(&gIOHibernateState, sizeof(gIOHibernateState));
1321 if (data)
1322 {
1323 rootDomain->setProperty(kIOHibernateStateKey, data);
1324 data->release();
1325 }
1326
1327 if (PE_parse_boot_arg("hfile", gIOHibernateFilename))
1328 gIOHibernateMode = kIOHibernateModeOn;
1329 else
1330 gIOHibernateFilename[0] = 0;
1331
1332 static SYSCTL_STRING(_kern, OID_AUTO, hibernatefile,
1333 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
1334 gIOHibernateFilename, sizeof(gIOHibernateFilename), "");
1335 sysctl_register_oid(&sysctl__kern_hibernatefile);
1336
1337 static SYSCTL_STRING(_kern, OID_AUTO, bootsignature,
1338 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
1339 gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), "");
1340 sysctl_register_oid(&sysctl__kern_bootsignature);
1341
1342 static SYSCTL_UINT(_kern, OID_AUTO, hibernatemode,
1343 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
1344 &gIOHibernateMode, 0, "");
1345 sysctl_register_oid(&sysctl__kern_hibernatemode);
1346 }
1347
1348 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1349
1350 static void
1351 hibernate_setup_for_wake(void)
1352 {
1353 #if __ppc__
1354 // go slow (state needed for wake)
1355 ml_set_processor_speed(1);
1356 #endif
1357 }
1358
1359 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1360
1361 extern "C" boolean_t
1362 hibernate_write_image(void)
1363 {
1364 IOHibernateImageHeader * header = gIOHibernateCurrentHeader;
1365 IOHibernateVars * vars = &gIOHibernateVars;
1366 IOPolledFileExtent * fileExtents;
1367
1368 uint32_t pageCount, pagesDone;
1369 IOReturn err;
1370 vm_offset_t ppnum;
1371 IOItemCount page, count;
1372 uint8_t * src;
1373 uint8_t * data;
1374 IOByteCount pageCompressedSize;
1375 uint64_t compressedSize, uncompressedSize;
1376 uint64_t image1Size = 0;
1377 uint32_t bitmap_size;
1378 bool iterDone, pollerOpen, needEncryptStart;
1379 uint32_t restore1Sum, sum, sum1, sum2;
1380 uint32_t tag;
1381 uint32_t pageType;
1382 uint32_t pageAndCount[2];
1383
1384 AbsoluteTime startTime, endTime;
1385 AbsoluteTime allTime, compTime, decoTime;
1386 uint64_t nsec;
1387 uint32_t lastProgressStamp = 0;
1388 uint32_t progressStamp;
1389
1390 hibernate_cryptvars_t _cryptvars;
1391 hibernate_cryptvars_t * cryptvars = 0;
1392
1393 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
1394 return (false /* sleep */ );
1395
1396 restore1Sum = sum1 = sum2 = 0;
1397
1398 // encryption data. "iv" is the "initial vector".
1399 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1400 {
1401 static const unsigned char first_iv[AES_BLOCK_SIZE]
1402 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1403 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1404
1405 cryptvars = &gIOHibernateCryptWakeContext;
1406 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
1407 aes_encrypt_key(vars->cryptKey,
1408 kIOHibernateAESKeySize,
1409 &cryptvars->ctx.encrypt);
1410 aes_decrypt_key(vars->cryptKey,
1411 kIOHibernateAESKeySize,
1412 &cryptvars->ctx.decrypt);
1413
1414 cryptvars = &_cryptvars;
1415 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
1416 aes_encrypt_key(vars->wiredCryptKey,
1417 kIOHibernateAESKeySize,
1418 &cryptvars->ctx.encrypt);
1419
1420 bcopy(&first_iv[0], &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1421 bzero(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1422 bzero(&vars->cryptKey[0], sizeof(vars->cryptKey));
1423 bzero(gIOHibernateCryptWakeVars, sizeof(hibernate_cryptwakevars_t));
1424 }
1425
1426 hibernate_setup_for_wake();
1427
1428 hibernate_page_list_setall(vars->page_list,
1429 vars->page_list_wired,
1430 &pageCount);
1431
1432 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount);
1433
1434 fileExtents = (IOPolledFileExtent *) vars->fileExtents->getBytesNoCopy();
1435
1436 #if 0
1437 count = vars->fileExtents->getLength() / sizeof(IOPolledFileExtent);
1438 for (page = 0; page < count; page++)
1439 {
1440 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page,
1441 fileExtents[page].start, fileExtents[page].length,
1442 fileExtents[page].start + fileExtents[page].length);
1443 }
1444 #endif
1445
1446 needEncryptStart = (0 != (kIOHibernateModeEncrypt & gIOHibernateMode));
1447
1448 AbsoluteTime_to_scalar(&compTime) = 0;
1449 AbsoluteTime_to_scalar(&decoTime) = 0;
1450
1451 clock_get_uptime(&allTime);
1452
1453 do
1454 {
1455 compressedSize = 0;
1456 uncompressedSize = 0;
1457 iterDone = false;
1458 pageType = 0; // wired pages first
1459
1460 IOPolledFileSeek(vars->fileVars, sizeof(IOHibernateImageHeader));
1461
1462 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1463 ml_get_interrupts_enabled());
1464 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledBeforeSleepState, vars->ioBuffer);
1465 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
1466 pollerOpen = (kIOReturnSuccess == err);
1467 if (!pollerOpen)
1468 break;
1469
1470 // copy file block extent list if larger than header
1471
1472 count = vars->fileExtents->getLength();
1473 if (count > sizeof(header->fileExtentMap))
1474 {
1475 count -= sizeof(header->fileExtentMap);
1476 err = IOPolledFileWrite(vars->fileVars,
1477 ((uint8_t *) &fileExtents[0]) + sizeof(header->fileExtentMap), count, cryptvars);
1478 if (kIOReturnSuccess != err)
1479 break;
1480 }
1481
1482 // copy out restore1 code
1483
1484 page = atop_32(sectHIBB);
1485 count = atop_32(round_page(sectHIBB + sectSizeHIB)) - page;
1486 header->restore1CodePage = page;
1487 header->restore1PageCount = count;
1488 header->restore1CodeOffset = ((uint32_t) &hibernate_machine_entrypoint) - sectHIBB;
1489 header->restore1StackOffset = ((uint32_t) &gIOHibernateRestoreStackEnd[0]) - 64 - sectHIBB;
1490
1491 // sum __HIB sect, with zeros for the stack
1492 src = (uint8_t *) trunc_page(sectHIBB);
1493 for (page = 0; page < count; page++)
1494 {
1495 if ((src < &gIOHibernateRestoreStack[0]) || (src >= &gIOHibernateRestoreStackEnd[0]))
1496 restore1Sum += hibernate_sum(src, page_size);
1497 else
1498 restore1Sum += 0x10000001;
1499 src += page_size;
1500 }
1501 sum1 = restore1Sum;
1502
1503 // write the __HIB sect, with zeros for the stack
1504
1505 src = (uint8_t *) trunc_page(sectHIBB);
1506 count = ((uint32_t) &gIOHibernateRestoreStack[0]) - trunc_page(sectHIBB);
1507 if (count)
1508 {
1509 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
1510 if (kIOReturnSuccess != err)
1511 break;
1512 }
1513 err = IOPolledFileWrite(vars->fileVars,
1514 (uint8_t *) 0,
1515 &gIOHibernateRestoreStackEnd[0] - &gIOHibernateRestoreStack[0],
1516 cryptvars);
1517 if (kIOReturnSuccess != err)
1518 break;
1519 src = &gIOHibernateRestoreStackEnd[0];
1520 count = round_page(sectHIBB + sectSizeHIB) - ((uint32_t) src);
1521 if (count)
1522 {
1523 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
1524 if (kIOReturnSuccess != err)
1525 break;
1526 }
1527
1528 // write the preview buffer
1529
1530 addr64_t phys64;
1531 IOByteCount segLen;
1532
1533 if (vars->previewData)
1534 {
1535 ppnum = 0;
1536 count = 0;
1537 do
1538 {
1539 phys64 = vars->previewBuffer->getPhysicalSegment64(count, &segLen);
1540 pageAndCount[0] = atop_64(phys64);
1541 pageAndCount[1] = atop_32(segLen);
1542 err = IOPolledFileWrite(vars->fileVars,
1543 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
1544 cryptvars);
1545 if (kIOReturnSuccess != err)
1546 break;
1547 count += segLen;
1548 ppnum += sizeof(pageAndCount);
1549 }
1550 while (phys64);
1551 if (kIOReturnSuccess != err)
1552 break;
1553
1554 src = (uint8_t *) vars->previewData->getBytesNoCopy();
1555 count = vars->previewData->getLength();
1556
1557 header->previewPageListSize = ppnum;
1558 header->previewSize = count + ppnum;
1559
1560 for (page = 0; page < count; page += page_size)
1561 sum1 += hibernate_sum(src + page, page_size);
1562
1563 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
1564 if (kIOReturnSuccess != err)
1565 break;
1566 }
1567
1568 // mark areas for no save
1569
1570 for (count = 0;
1571 (phys64 = vars->ioBuffer->getPhysicalSegment64(count, &segLen));
1572 count += segLen)
1573 {
1574 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1575 atop_64(phys64), atop_32(segLen),
1576 kIOHibernatePageStateFree);
1577 pageCount -= atop_32(segLen);
1578 }
1579
1580 for (count = 0;
1581 (phys64 = vars->srcBuffer->getPhysicalSegment64(count, &segLen));
1582 count += segLen)
1583 {
1584 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1585 atop_64(phys64), atop_32(segLen),
1586 kIOHibernatePageStateFree);
1587 pageCount -= atop_32(segLen);
1588 }
1589
1590 // copy out bitmap of pages available for trashing during restore
1591
1592 bitmap_size = vars->page_list_wired->list_size;
1593 src = (uint8_t *) vars->page_list_wired;
1594 err = IOPolledFileWrite(vars->fileVars, src, bitmap_size, cryptvars);
1595 if (kIOReturnSuccess != err)
1596 break;
1597
1598 // mark more areas for no save, but these are not available
1599 // for trashing during restore
1600
1601 #if !__i386__
1602 page = atop_32(sectHIBB);
1603 count = atop_32(round_page(sectHIBB + sectSizeHIB)) - page;
1604 #else
1605 // XXX
1606 page = atop_32(sectHIBB & 0x3FFFFFFF);
1607 count = atop_32(round_page((sectHIBB + sectSizeHIB) & 0x3FFFFFFF)) - page;
1608 #endif
1609 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1610 page, count,
1611 kIOHibernatePageStateFree);
1612 pageCount -= count;
1613
1614
1615
1616 if (vars->previewBuffer) for (count = 0;
1617 (phys64 = vars->previewBuffer->getPhysicalSegment64(count, &segLen));
1618 count += segLen)
1619 {
1620 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1621 atop_64(phys64), atop_32(segLen),
1622 kIOHibernatePageStateFree);
1623 pageCount -= atop_32(segLen);
1624 }
1625
1626 src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
1627
1628 void * iter = 0;
1629 pagesDone = 0;
1630
1631 HIBLOG("writing %d pages\n", pageCount);
1632
1633 do
1634 {
1635 count = hibernate_page_list_iterate(pageType ? vars->page_list : vars->page_list_wired,
1636 &iter, &ppnum);
1637 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1638
1639 iterDone = !count;
1640
1641 pageAndCount[0] = ppnum;
1642 pageAndCount[1] = count;
1643 err = IOPolledFileWrite(vars->fileVars,
1644 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
1645 cryptvars);
1646 if (kIOReturnSuccess != err)
1647 break;
1648
1649 for (page = 0; page < count; page++)
1650 {
1651 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(ppnum), page_size);
1652 if (err)
1653 {
1654 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%d] %x\n", __LINE__, ppnum, err);
1655 break;
1656 }
1657
1658 sum = hibernate_sum(src, page_size);
1659
1660 clock_get_uptime(&startTime);
1661
1662 pageCompressedSize = WKdm_compress ((WK_word*) src, (WK_word*) (src + page_size), PAGE_SIZE_IN_WORDS);
1663
1664 clock_get_uptime(&endTime);
1665 ADD_ABSOLUTETIME(&compTime, &endTime);
1666 SUB_ABSOLUTETIME(&compTime, &startTime);
1667
1668 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1669 pageCompressedSize = (pageCompressedSize + AES_BLOCK_SIZE - 1) & ~(AES_BLOCK_SIZE - 1);
1670
1671 if (pageCompressedSize > page_size)
1672 {
1673 // HIBLOG("------------lose: %d\n", pageCompressedSize);
1674 pageCompressedSize = page_size;
1675 }
1676
1677 if (pageCompressedSize != page_size)
1678 data = (src + page_size);
1679 else
1680 data = src;
1681
1682 tag = pageCompressedSize | kIOHibernateTagSignature;
1683
1684 if (pageType)
1685 sum2 += sum;
1686 else
1687 sum1 += sum;
1688
1689 if (needEncryptStart && (ppnum >= atop_32(sectDATAB)))
1690 {
1691 // start encrypting partway into the data about to be written
1692 vars->fileVars->encryptStart = (vars->fileVars->position + AES_BLOCK_SIZE - 1)
1693 & ~(AES_BLOCK_SIZE - 1);
1694 needEncryptStart = false;
1695 }
1696
1697 err = IOPolledFileWrite(vars->fileVars, (const uint8_t *) &tag, sizeof(tag), cryptvars);
1698 if (kIOReturnSuccess != err)
1699 break;
1700
1701 err = IOPolledFileWrite(vars->fileVars, data, (pageCompressedSize + 3) & ~3, cryptvars);
1702 if (kIOReturnSuccess != err)
1703 break;
1704
1705 compressedSize += pageCompressedSize;
1706 if (pageCompressedSize)
1707 uncompressedSize += page_size;
1708 ppnum++;
1709 pagesDone++;
1710
1711 if (0 == (8191 & pagesDone))
1712 {
1713 clock_get_uptime(&endTime);
1714 SUB_ABSOLUTETIME(&endTime, &allTime);
1715 absolutetime_to_nanoseconds(endTime, &nsec);
1716 progressStamp = nsec / 750000000ULL;
1717 if (progressStamp != lastProgressStamp)
1718 {
1719 lastProgressStamp = progressStamp;
1720 HIBPRINT("pages %d (%d%%)\n", pagesDone, (100 * pagesDone) / pageCount);
1721 }
1722 }
1723 }
1724 if (kIOReturnSuccess != err)
1725 break;
1726 if (iterDone && !pageType)
1727 {
1728 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
1729 if (kIOReturnSuccess != err)
1730 break;
1731
1732 iterDone = false;
1733 pageType = 1;
1734 iter = 0;
1735 image1Size = vars->fileVars->position;
1736 if (cryptvars)
1737 {
1738 bcopy(&cryptvars->aes_iv[0],
1739 &gIOHibernateCryptWakeContext.aes_iv[0],
1740 sizeof(cryptvars->aes_iv));
1741 cryptvars = &gIOHibernateCryptWakeContext;
1742 }
1743 HIBLOG("image1Size %qd\n", image1Size);
1744 }
1745 }
1746 while (!iterDone);
1747 if (kIOReturnSuccess != err)
1748 break;
1749 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
1750 if (kIOReturnSuccess != err)
1751 break;
1752
1753 // Header:
1754
1755 header->imageSize = vars->fileVars->position;
1756 header->image1Size = image1Size;
1757 header->bitmapSize = bitmap_size;
1758 header->pageCount = pageCount;
1759 header->encryptStart = vars->fileVars->encryptStart;
1760
1761 header->restore1Sum = restore1Sum;
1762 header->image1Sum = sum1;
1763 header->image2Sum = sum2;
1764
1765 count = vars->fileExtents->getLength();
1766 if (count > sizeof(header->fileExtentMap))
1767 {
1768 header->fileExtentMapSize = count;
1769 count = sizeof(header->fileExtentMap);
1770 }
1771 else
1772 header->fileExtentMapSize = sizeof(header->fileExtentMap);
1773 bcopy(&fileExtents[0], &header->fileExtentMap[0], count);
1774
1775 IOPolledFileSeek(vars->fileVars, 0);
1776 err = IOPolledFileWrite(vars->fileVars,
1777 (uint8_t *) header, sizeof(IOHibernateImageHeader),
1778 cryptvars);
1779 if (kIOReturnSuccess != err)
1780 break;
1781 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
1782 if (kIOReturnSuccess != err)
1783 break;
1784 err = IOHibernatePollerIODone(vars->fileVars);
1785 if (kIOReturnSuccess != err)
1786 break;
1787 }
1788 while (false);
1789
1790 clock_get_uptime(&endTime);
1791 SUB_ABSOLUTETIME(&endTime, &allTime);
1792 absolutetime_to_nanoseconds(endTime, &nsec);
1793 HIBLOG("all time: %qd ms, ",
1794 nsec / 1000000ULL);
1795
1796 absolutetime_to_nanoseconds(compTime, &nsec);
1797 HIBLOG("comp time: %qd ms, ",
1798 nsec / 1000000ULL);
1799
1800 absolutetime_to_nanoseconds(decoTime, &nsec);
1801 HIBLOG("deco time: %qd ms, ",
1802 nsec / 1000000ULL);
1803
1804 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
1805 header->imageSize,
1806 uncompressedSize, atop_32(uncompressedSize), compressedSize,
1807 uncompressedSize ? ((int) ((compressedSize * 100ULL) / uncompressedSize)) : 0,
1808 sum1, sum2);
1809
1810 if (pollerOpen)
1811 IOHibernatePollerClose(vars->fileVars, kIOPolledBeforeSleepState);
1812
1813 HIBLOG("hibernate_write_image done(%x)\n", err);
1814
1815 // should we come back via regular wake, set the state in memory.
1816 gIOHibernateState = kIOHibernateStateInactive;
1817
1818 if ((kIOReturnSuccess == err) && !(kIOHibernateModeSleep & gIOHibernateMode))
1819 return (true /* power down */ );
1820 else
1821 return (false /* sleep */ );
1822 }
1823
1824 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1825
1826 DECLARE_IOHIBERNATEPROGRESSALPHA
1827
1828 static void
1829 ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select)
1830 {
1831 uint32_t rowBytes, pixelShift;
1832 uint32_t x, y;
1833 int32_t blob, lastBlob;
1834 uint32_t alpha, in, color, result;
1835 uint8_t * out;
1836 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1837
1838 pixelShift = display->depth >> 4;
1839 if (pixelShift < 1)
1840 return;
1841
1842 rowBytes = display->rowBytes;
1843
1844 screen += ((display->width
1845 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1846 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1847
1848 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1849
1850 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1851
1852 for (y = 0; y < kIOHibernateProgressHeight; y++)
1853 {
1854 out = screen + y * rowBytes;
1855 for (blob = firstBlob; blob <= lastBlob; blob++)
1856 {
1857 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1858 for (x = 0; x < kIOHibernateProgressWidth; x++)
1859 {
1860 alpha = gIOHibernateProgressAlpha[y][x];
1861 result = color;
1862 if (alpha)
1863 {
1864 if (0xff != alpha)
1865 {
1866 in = display->progressSaveUnder[blob][saveindex[blob]++];
1867 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1868 }
1869 if (1 == pixelShift)
1870 {
1871 result >>= 3;
1872 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1873 }
1874 else
1875 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1876 }
1877 out += (1 << pixelShift);
1878 }
1879 out += (kIOHibernateProgressSpacing << pixelShift);
1880 }
1881 }
1882 }
1883
1884 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1885
1886 extern "C" void
1887 hibernate_machine_init(void)
1888 {
1889 IOReturn err;
1890 uint32_t sum;
1891 uint32_t pagesDone;
1892 AbsoluteTime allTime, endTime;
1893 uint64_t nsec;
1894 uint32_t lastProgressStamp = 0;
1895 uint32_t progressStamp;
1896 uint64_t progressZeroPosition = 0;
1897 uint32_t blob, lastBlob = (uint32_t) -1L;
1898 hibernate_cryptvars_t * cryptvars = 0;
1899
1900 IOHibernateVars * vars = &gIOHibernateVars;
1901
1902 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
1903 return;
1904
1905 if ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode)
1906 hibernate_page_list_discard(vars->page_list);
1907
1908
1909 sum = gIOHibernateCurrentHeader->actualImage1Sum;
1910 pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages;
1911
1912 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
1913 gIOHibernateState, pagesDone, sum, gIOHibernateCurrentHeader->image1Size,
1914 gIOHibernateCurrentHeader->conflictCount, gIOHibernateCurrentHeader->nextFree);
1915
1916 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState)
1917 {
1918 HIBLOG("regular wake\n");
1919 return;
1920 }
1921
1922 HIBPRINT("diag %x %x %x %x\n",
1923 gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1],
1924 gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]);
1925
1926 HIBPRINT("video %lx %ld %ld %ld\n",
1927 gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth,
1928 gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height);
1929
1930 if (vars->videoMapping && gIOHibernateGraphicsInfo->physicalAddress)
1931 {
1932 vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height
1933 * gIOHibernateGraphicsInfo->rowBytes);
1934 IOMapPages(kernel_map,
1935 vars->videoMapping, gIOHibernateGraphicsInfo->physicalAddress,
1936 vars->videoMapSize, kIOMapInhibitCache );
1937 }
1938
1939 uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();;
1940 uint32_t decoOffset;
1941
1942 clock_get_uptime(&allTime);
1943
1944 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
1945 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledAfterSleepState, 0);
1946 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
1947
1948 if (gIOHibernateCurrentHeader->previewSize)
1949 progressZeroPosition = gIOHibernateCurrentHeader->previewSize
1950 + gIOHibernateCurrentHeader->fileExtentMapSize
1951 - sizeof(gIOHibernateCurrentHeader->fileExtentMap)
1952 + ptoa_64(gIOHibernateCurrentHeader->restore1PageCount);
1953
1954 IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size);
1955
1956 if (vars->videoMapping)
1957 {
1958 lastBlob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount)
1959 / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition);
1960 ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, 0, lastBlob);
1961 }
1962
1963 cryptvars = (kIOHibernateModeEncrypt & gIOHibernateMode) ? &gIOHibernateCryptWakeContext : 0;
1964 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1965 {
1966 cryptvars = &gIOHibernateCryptWakeContext;
1967 bcopy(&gIOHibernateCryptWakeVars->aes_iv[0],
1968 &cryptvars->aes_iv[0],
1969 sizeof(cryptvars->aes_iv));
1970 }
1971
1972 // kick off the read ahead
1973 vars->fileVars->io = false;
1974 vars->fileVars->bufferHalf = 0;
1975 vars->fileVars->bufferLimit = 0;
1976 vars->fileVars->lastRead = 0;
1977 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
1978
1979 IOPolledFileRead(vars->fileVars, 0, 0, cryptvars);
1980 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
1981 // --
1982
1983 HIBLOG("hibernate_machine_init reading\n");
1984
1985 uint32_t * header = (uint32_t *) src;
1986 sum = 0;
1987
1988 do
1989 {
1990 unsigned int count;
1991 unsigned int page;
1992 uint32_t tag;
1993 vm_offset_t ppnum, compressedSize;
1994
1995 IOPolledFileRead(vars->fileVars, src, 8, cryptvars);
1996
1997 ppnum = header[0];
1998 count = header[1];
1999
2000 // HIBPRINT("(%x, %x)\n", ppnum, count);
2001
2002 if (!count)
2003 break;
2004
2005 for (page = 0; page < count; page++)
2006 {
2007 IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars);
2008
2009 compressedSize = kIOHibernateTagLength & tag;
2010 if (!compressedSize)
2011 {
2012 ppnum++;
2013 pagesDone++;
2014 continue;
2015 }
2016
2017 IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars);
2018
2019 if (compressedSize != page_size)
2020 {
2021 decoOffset = page_size;
2022 WKdm_decompress((WK_word*) src, (WK_word*) (src + decoOffset), PAGE_SIZE_IN_WORDS);
2023 }
2024 else
2025 decoOffset = 0;
2026
2027 sum += hibernate_sum((src + decoOffset), page_size);
2028
2029 err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size);
2030 if (err)
2031 HIBLOG("IOMemoryDescriptorReadToPhysical [%d] %x\n", ppnum, err);
2032
2033 ppnum++;
2034 pagesDone++;
2035
2036 if (vars->videoMapping && (0 == (255 & pagesDone)))
2037 {
2038 blob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount)
2039 / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition);
2040 if (blob != lastBlob)
2041 {
2042 ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, lastBlob, blob);
2043 lastBlob = blob;
2044 }
2045 }
2046
2047 if (0 == (8191 & pagesDone))
2048 {
2049 clock_get_uptime(&endTime);
2050 SUB_ABSOLUTETIME(&endTime, &allTime);
2051 absolutetime_to_nanoseconds(endTime, &nsec);
2052 progressStamp = nsec / 750000000ULL;
2053 if (progressStamp != lastProgressStamp)
2054 {
2055 lastProgressStamp = progressStamp;
2056 HIBPRINT("pages %d (%d%%)\n", pagesDone,
2057 (100 * pagesDone) / gIOHibernateCurrentHeader->pageCount);
2058 }
2059 }
2060 }
2061 }
2062 while (true);
2063
2064 gIOHibernateCurrentHeader->actualImage2Sum = sum;
2065
2066 if (vars->fileVars->io)
2067 (void) IOHibernatePollerIODone(vars->fileVars);
2068
2069 err = IOHibernatePollerClose(vars->fileVars, kIOPolledAfterSleepState);
2070
2071 if (vars->videoMapping)
2072 ProgressUpdate(gIOHibernateGraphicsInfo,
2073 (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);
2074
2075 clock_get_uptime(&endTime);
2076 SUB_ABSOLUTETIME(&endTime, &allTime);
2077 absolutetime_to_nanoseconds(endTime, &nsec);
2078
2079 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2080 pagesDone, sum, nsec / 1000000ULL);
2081 }
2082
2083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */