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