]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOHibernateIO.cpp
bc180fb5bf2f753383dd1055eaba64bc8986e1b9
[apple/xnu.git] / iokit / Kernel / IOHibernateIO.cpp
1 /*
2 * Copyright (c) 2004-2008 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 extern unsigned int save_kdebug_enable;
172 extern uint32_t gIOHibernateState;
173 uint32_t gIOHibernateMode;
174 static char gIOHibernateBootSignature[256+1];
175 static char gIOHibernateFilename[MAXPATHLEN+1];
176 static uint32_t gIOHibernateFreeRatio = 0; // free page target (percent)
177 uint32_t gIOHibernateFreeTime = 0*1000; // max time to spend freeing pages (ms)
178
179 static IODTNVRAM * gIOOptionsEntry;
180 static IORegistryEntry * gIOChosenEntry;
181 #if defined(__i386__) || defined(__x86_64__)
182 static const OSSymbol * gIOCreateEFIDevicePathSymbol;
183 static const OSSymbol * gIOHibernateRTCVariablesKey;
184 static const OSSymbol * gIOHibernateBoot0082Key;
185 static const OSSymbol * gIOHibernateBootNextKey;
186 static OSData * gIOHibernateBoot0082Data;
187 static OSData * gIOHibernateBootNextData;
188 static OSObject * gIOHibernateBootNextSave;
189 #endif
190
191 static IOPolledFileIOVars gFileVars;
192 static IOHibernateVars gIOHibernateVars;
193 static struct kern_direct_file_io_ref_t * gIOHibernateFileRef;
194 static hibernate_cryptvars_t gIOHibernateCryptWakeContext;
195
196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
197
198 enum { kXPRamAudioVolume = 8 };
199 enum { kDefaultIOSize = 128 * 1024 };
200 enum { kVideoMapSize = 32 * 1024 * 1024 };
201
202 #ifndef kIOMediaPreferredBlockSizeKey
203 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
204 #endif
205
206 #ifndef kIOBootPathKey
207 #define kIOBootPathKey "bootpath"
208 #endif
209 #ifndef kIOSelectedBootDeviceKey
210 #define kIOSelectedBootDeviceKey "boot-device"
211 #endif
212
213
214 enum { kIOHibernateMinPollersNeeded = 2 };
215
216 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
217
218 // copy from phys addr to MD
219
220 static IOReturn
221 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,
222 IOByteCount offset, addr64_t bytes, IOByteCount length)
223 {
224 addr64_t srcAddr = bytes;
225 IOByteCount remaining;
226
227 remaining = length = min(length, md->getLength() - offset);
228 while (remaining) { // (process another target segment?)
229 addr64_t dstAddr64;
230 IOByteCount dstLen;
231
232 dstAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
233 if (!dstAddr64)
234 break;
235
236 // Clip segment length to remaining
237 if (dstLen > remaining)
238 dstLen = remaining;
239
240 #if 1
241 bcopy_phys(srcAddr, dstAddr64, dstLen);
242 #else
243 copypv(srcAddr, dstAddr64, dstLen,
244 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
245 #endif
246 srcAddr += dstLen;
247 offset += dstLen;
248 remaining -= dstLen;
249 }
250
251 assert(!remaining);
252
253 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
254 }
255
256 // copy from MD to phys addr
257
258 static IOReturn
259 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,
260 IOByteCount offset, addr64_t bytes, IOByteCount length)
261 {
262 addr64_t dstAddr = bytes;
263 IOByteCount remaining;
264
265 remaining = length = min(length, md->getLength() - offset);
266 while (remaining) { // (process another target segment?)
267 addr64_t srcAddr64;
268 IOByteCount dstLen;
269
270 srcAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
271 if (!srcAddr64)
272 break;
273
274 // Clip segment length to remaining
275 if (dstLen > remaining)
276 dstLen = remaining;
277
278 #if 1
279 bcopy_phys(srcAddr64, dstAddr, dstLen);
280 #else
281 copypv(srcAddr, dstAddr64, dstLen,
282 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
283 #endif
284 dstAddr += dstLen;
285 offset += dstLen;
286 remaining -= dstLen;
287 }
288
289 assert(!remaining);
290
291 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
292 }
293
294 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
295
296 void
297 hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_t * page_list_wired,
298 vm_offset_t ppnum, vm_offset_t count, uint32_t kind)
299 {
300 count += ppnum;
301 switch (kind)
302 {
303 case kIOHibernatePageStateUnwiredSave:
304 // unwired save
305 for (; ppnum < count; ppnum++)
306 {
307 hibernate_page_bitset(page_list, FALSE, ppnum);
308 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
309 }
310 break;
311 case kIOHibernatePageStateWiredSave:
312 // wired save
313 for (; ppnum < count; ppnum++)
314 {
315 hibernate_page_bitset(page_list, FALSE, ppnum);
316 hibernate_page_bitset(page_list_wired, FALSE, ppnum);
317 }
318 break;
319 case kIOHibernatePageStateFree:
320 // free page
321 for (; ppnum < count; ppnum++)
322 {
323 hibernate_page_bitset(page_list, TRUE, ppnum);
324 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
325 }
326 break;
327 default:
328 panic("hibernate_set_page_state");
329 }
330 }
331
332 static vm_offset_t
333 hibernate_page_list_iterate(hibernate_page_list_t * list, vm_offset_t * pPage)
334 {
335 uint32_t page = *pPage;
336 uint32_t count;
337 hibernate_bitmap_t * bitmap;
338
339 while ((bitmap = hibernate_page_bitmap_pin(list, &page)))
340 {
341 count = hibernate_page_bitmap_count(bitmap, TRUE, page);
342 if (!count)
343 break;
344 page += count;
345 if (page <= bitmap->last_page)
346 break;
347 }
348
349 *pPage = page;
350 if (bitmap)
351 count = hibernate_page_bitmap_count(bitmap, FALSE, page);
352 else
353 count = 0;
354
355 return (count);
356 }
357
358 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
359
360 static IOReturn
361 IOHibernatePollerProbe(IOPolledFileIOVars * vars, IOService * target)
362 {
363 IOReturn err = kIOReturnError;
364 int32_t idx;
365 IOPolledInterface * poller;
366
367 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
368 {
369 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
370 err = poller->probe(target);
371 if (err)
372 {
373 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx, err);
374 break;
375 }
376 }
377
378 return (err);
379 }
380
381 static IOReturn
382 IOHibernatePollerOpen(IOPolledFileIOVars * vars, uint32_t state, IOMemoryDescriptor * md)
383 {
384 IOReturn err = kIOReturnError;
385 int32_t idx;
386 IOPolledInterface * poller;
387
388 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
389 {
390 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
391 err = poller->open(state, md);
392 if (err)
393 {
394 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx, err);
395 break;
396 }
397 }
398
399 return (err);
400 }
401
402 static IOReturn
403 IOHibernatePollerClose(IOPolledFileIOVars * vars, uint32_t state)
404 {
405 IOReturn err = kIOReturnError;
406 int32_t idx;
407 IOPolledInterface * poller;
408
409 for (idx = 0;
410 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
411 idx++)
412 {
413 err = poller->close(state);
414 if (err)
415 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx, err);
416 }
417
418 return (err);
419 }
420
421 static void
422 IOHibernatePollerIOComplete(void * target,
423 void * parameter,
424 IOReturn status,
425 UInt64 actualByteCount)
426 {
427 IOPolledFileIOVars * vars = (IOPolledFileIOVars *) parameter;
428
429 vars->ioStatus = status;
430 }
431
432 static IOReturn
433 IOHibernatePollerIO(IOPolledFileIOVars * vars,
434 uint32_t operation, uint32_t bufferOffset,
435 uint64_t deviceOffset, uint64_t length)
436 {
437
438 IOReturn err = kIOReturnError;
439 IOPolledInterface * poller;
440 IOPolledCompletion completion;
441
442 completion.target = 0;
443 completion.action = &IOHibernatePollerIOComplete;
444 completion.parameter = vars;
445
446 vars->ioStatus = -1;
447
448 poller = (IOPolledInterface *) vars->pollers->getObject(0);
449 err = poller->startIO(operation, bufferOffset, deviceOffset + vars->block0, length, completion);
450 if (err)
451 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err);
452
453 return (err);
454 }
455
456 static IOReturn
457 IOHibernatePollerIODone(IOPolledFileIOVars * vars, bool abortable)
458 {
459 IOReturn err = kIOReturnSuccess;
460 int32_t idx = 0;
461 IOPolledInterface * poller;
462
463 while (-1 == vars->ioStatus)
464 {
465 for (idx = 0;
466 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
467 idx++)
468 {
469 IOReturn newErr;
470 newErr = poller->checkForWork();
471 if ((newErr == kIOReturnAborted) && !abortable)
472 newErr = kIOReturnSuccess;
473 if (kIOReturnSuccess == err)
474 err = newErr;
475 }
476 }
477
478 if ((kIOReturnSuccess == err) && abortable && hibernate_should_abort())
479 {
480 err = kIOReturnAborted;
481 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
482 }
483
484 if (err)
485 {
486 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err);
487 }
488 else
489 {
490 err = vars->ioStatus;
491 if (kIOReturnSuccess != err)
492 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err);
493 }
494
495 return (err);
496 }
497
498 IOReturn
499 IOPolledInterface::checkAllForWork(void)
500 {
501 IOReturn err = kIOReturnNotReady;
502 int32_t idx;
503 IOPolledInterface * poller;
504
505 IOHibernateVars * vars = &gIOHibernateVars;
506
507 if (!vars->fileVars || !vars->fileVars->pollers)
508 return (err);
509
510 for (idx = 0;
511 (poller = (IOPolledInterface *) vars->fileVars->pollers->getObject(idx));
512 idx++)
513 {
514 err = poller->checkForWork();
515 if (err)
516 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx, err);
517 }
518
519 return (err);
520 }
521
522 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
523
524 struct _OpenFileContext
525 {
526 OSData * extents;
527 uint64_t size;
528 };
529
530 static void
531 file_extent_callback(void * ref, uint64_t start, uint64_t length)
532 {
533 _OpenFileContext * ctx = (_OpenFileContext *) ref;
534 IOPolledFileExtent extent;
535
536 extent.start = start;
537 extent.length = length;
538
539 ctx->extents->appendBytes(&extent, sizeof(extent));
540 ctx->size += length;
541 }
542
543 IOReturn
544 IOPolledFileOpen( const char * filename, IOBufferMemoryDescriptor * ioBuffer,
545 IOPolledFileIOVars ** fileVars, OSData ** fileExtents,
546 OSData ** imagePath)
547 {
548 IOReturn err = kIOReturnError;
549 IOPolledFileIOVars * vars;
550 _OpenFileContext ctx;
551 OSData * extentsData;
552 OSNumber * num;
553 IORegistryEntry * part = 0;
554 OSDictionary * matching;
555 OSIterator * iter;
556 dev_t hibernate_image_dev;
557 uint64_t maxiobytes;
558
559 vars = &gFileVars;
560 do
561 {
562 HIBLOG("sizeof(IOHibernateImageHeader) == %ld\n", sizeof(IOHibernateImageHeader));
563 if (sizeof(IOHibernateImageHeader) != 512)
564 continue;
565
566 vars->io = false;
567 vars->buffer = (uint8_t *) ioBuffer->getBytesNoCopy();
568 vars->bufferHalf = 0;
569 vars->bufferOffset = 0;
570 vars->bufferSize = ioBuffer->getLength() >> 1;
571
572 extentsData = OSData::withCapacity(32);
573
574 ctx.extents = extentsData;
575 ctx.size = 0;
576 vars->fileRef = kern_open_file_for_direct_io(filename,
577 &file_extent_callback, &ctx,
578 &hibernate_image_dev,
579 &vars->block0,
580 &maxiobytes,
581 &vars->solid_state);
582 if (!vars->fileRef)
583 {
584 err = kIOReturnNoSpace;
585 break;
586 }
587 gIOHibernateFileRef = vars->fileRef;
588
589 if (kIOHibernateModeSSDInvert & gIOHibernateMode)
590 vars->solid_state = vars->solid_state ? false : true;
591
592 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename, ctx.size,
593 vars->block0, maxiobytes, vars->solid_state);
594 if (ctx.size < 1*1024*1024) // check against image size estimate!
595 {
596 err = kIOReturnNoSpace;
597 break;
598 }
599
600 if (maxiobytes < vars->bufferSize)
601 vars->bufferSize = maxiobytes;
602
603 vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();
604
605 matching = IOService::serviceMatching("IOMedia");
606 num = OSNumber::withNumber(major(hibernate_image_dev), 32);
607 matching->setObject(kIOBSDMajorKey, num);
608 num->release();
609 num = OSNumber::withNumber(minor(hibernate_image_dev), 32);
610 matching->setObject(kIOBSDMinorKey, num);
611 num->release();
612 iter = IOService::getMatchingServices(matching);
613 matching->release();
614 if (iter)
615 {
616 part = (IORegistryEntry *) iter->getNextObject();
617 part->retain();
618 iter->release();
619 }
620 if (!part)
621 break;
622
623 int minor, major;
624 IORegistryEntry * next;
625 IORegistryEntry * child;
626 OSData * data;
627
628 num = (OSNumber *) part->getProperty(kIOBSDMajorKey);
629 if (!num)
630 break;
631 major = num->unsigned32BitValue();
632 num = (OSNumber *) part->getProperty(kIOBSDMinorKey);
633 if (!num)
634 break;
635 minor = num->unsigned32BitValue();
636
637 hibernate_image_dev = makedev(major, minor);
638
639 vars->pollers = OSArray::withCapacity(4);
640 if (!vars->pollers)
641 break;
642
643 vars->blockSize = 512;
644 next = part;
645 do
646 {
647 IOPolledInterface * poller;
648 OSObject * obj;
649
650 obj = next->getProperty(kIOPolledInterfaceSupportKey);
651 if (kOSBooleanFalse == obj)
652 {
653 vars->pollers->flushCollection();
654 break;
655 }
656 else if ((poller = OSDynamicCast(IOPolledInterface, obj)))
657 vars->pollers->setObject(poller);
658 if ((num = OSDynamicCast(OSNumber, next->getProperty(kIOMediaPreferredBlockSizeKey))))
659 vars->blockSize = num->unsigned32BitValue();
660 child = next;
661 }
662 while ((next = child->getParentEntry(gIOServicePlane))
663 && child->isParent(next, gIOServicePlane, true));
664
665 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
666 major, minor, (long)vars->blockSize, vars->pollers->getCount());
667 if (vars->pollers->getCount() < kIOHibernateMinPollersNeeded)
668 continue;
669
670 err = IOHibernatePollerProbe(vars, (IOService *) part);
671 if (kIOReturnSuccess != err)
672 break;
673
674 err = IOHibernatePollerOpen(vars, kIOPolledPreflightState, ioBuffer);
675 if (kIOReturnSuccess != err)
676 break;
677
678 *fileVars = vars;
679 *fileExtents = extentsData;
680
681 // make imagePath
682
683 if ((extentsData->getLength() >= sizeof(IOPolledFileExtent)))
684 {
685 char str2[24];
686
687 #if defined(__i386__) || defined(__x86_64__)
688 if (!gIOCreateEFIDevicePathSymbol)
689 gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath");
690
691 snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start);
692
693 err = IOService::getPlatform()->callPlatformFunction(
694 gIOCreateEFIDevicePathSymbol, false,
695 (void *) part, (void *) str2, (void *) true,
696 (void *) &data);
697 #else
698 char str1[256];
699 int len = sizeof(str1);
700
701 if (!part->getPath(str1, &len, gIODTPlane))
702 err = kIOReturnNotFound;
703 else
704 {
705 snprintf(str2, sizeof(str2), ",%qx", vars->extentMap[0].start);
706 // (strip the plane name)
707 char * tail = strchr(str1, ':');
708 if (!tail)
709 tail = str1 - 1;
710 data = OSData::withBytes(tail + 1, strlen(tail + 1));
711 data->appendBytes(str2, strlen(str2));
712 }
713 #endif
714 if (kIOReturnSuccess == err)
715 *imagePath = data;
716 else
717 HIBLOG("error 0x%x getting path\n", err);
718 }
719 }
720 while (false);
721
722 if (kIOReturnSuccess != err)
723 {
724 HIBLOG("error 0x%x opening hibernation file\n", err);
725 if (vars->fileRef)
726 {
727 kern_close_file_for_direct_io(vars->fileRef);
728 gIOHibernateFileRef = vars->fileRef = NULL;
729 }
730 }
731
732 if (part)
733 part->release();
734
735 return (err);
736 }
737
738 IOReturn
739 IOPolledFileClose( IOPolledFileIOVars * vars )
740 {
741 if (vars->pollers)
742 {
743 IOHibernatePollerClose(vars, kIOPolledPostflightState);
744 vars->pollers->release();
745 }
746
747 bzero(vars, sizeof(IOPolledFileIOVars));
748
749 return (kIOReturnSuccess);
750 }
751
752 static IOReturn
753 IOPolledFileSeek(IOPolledFileIOVars * vars, uint64_t position)
754 {
755 IOPolledFileExtent * extentMap;
756
757 extentMap = vars->extentMap;
758
759 vars->position = position;
760
761 while (position >= extentMap->length)
762 {
763 position -= extentMap->length;
764 extentMap++;
765 }
766
767 vars->currentExtent = extentMap;
768 vars->extentRemaining = extentMap->length - position;
769 vars->extentPosition = vars->position - position;
770
771 if (vars->bufferSize <= vars->extentRemaining)
772 vars->bufferLimit = vars->bufferSize;
773 else
774 vars->bufferLimit = vars->extentRemaining;
775
776 return (kIOReturnSuccess);
777 }
778
779 static IOReturn
780 IOPolledFileWrite(IOPolledFileIOVars * vars,
781 const uint8_t * bytes, IOByteCount size,
782 hibernate_cryptvars_t * cryptvars)
783 {
784 IOReturn err = kIOReturnSuccess;
785 IOByteCount copy;
786 bool flush = false;
787
788 do
789 {
790 if (!bytes && !size)
791 {
792 // seek to end of block & flush
793 size = vars->position & (vars->blockSize - 1);
794 if (size)
795 size = vars->blockSize - size;
796 flush = true;
797 // use some garbage for the fill
798 bytes = vars->buffer + vars->bufferOffset;
799 }
800
801 copy = vars->bufferLimit - vars->bufferOffset;
802 if (copy > size)
803 copy = size;
804 else
805 flush = true;
806
807 if (bytes)
808 {
809 bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
810 bytes += copy;
811 }
812 else
813 bzero(vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
814
815 size -= copy;
816 vars->bufferOffset += copy;
817 vars->position += copy;
818
819 if (flush && vars->bufferOffset)
820 {
821 uint64_t offset = (vars->position - vars->bufferOffset
822 - vars->extentPosition + vars->currentExtent->start);
823 uint32_t length = (vars->bufferOffset);
824
825 #if CRYPTO
826 if (cryptvars && vars->encryptStart
827 && (vars->position > vars->encryptStart)
828 && ((vars->position - length) < vars->encryptEnd))
829 {
830 uint32_t encryptLen, encryptStart;
831 encryptLen = vars->position - vars->encryptStart;
832 if (encryptLen > length)
833 encryptLen = length;
834 encryptStart = length - encryptLen;
835 if (vars->position > vars->encryptEnd)
836 encryptLen -= (vars->position - vars->encryptEnd);
837
838 // encrypt the buffer
839 aes_encrypt_cbc(vars->buffer + vars->bufferHalf + encryptStart,
840 &cryptvars->aes_iv[0],
841 encryptLen / AES_BLOCK_SIZE,
842 vars->buffer + vars->bufferHalf + encryptStart,
843 &cryptvars->ctx.encrypt);
844 // save initial vector for following encrypts
845 bcopy(vars->buffer + vars->bufferHalf + encryptStart + encryptLen - AES_BLOCK_SIZE,
846 &cryptvars->aes_iv[0],
847 AES_BLOCK_SIZE);
848 }
849 #endif /* CRYPTO */
850
851 if (vars->io)
852 {
853 err = IOHibernatePollerIODone(vars, true);
854 if (kIOReturnSuccess != err)
855 break;
856 }
857
858 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
859 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
860
861 err = IOHibernatePollerIO(vars, kIOPolledWrite, vars->bufferHalf, offset, length);
862 if (kIOReturnSuccess != err)
863 break;
864 vars->io = true;
865
866 vars->extentRemaining -= vars->bufferOffset;
867 if (!vars->extentRemaining)
868 {
869 vars->currentExtent++;
870 vars->extentRemaining = vars->currentExtent->length;
871 vars->extentPosition = vars->position;
872 if (!vars->extentRemaining)
873 {
874 err = kIOReturnOverrun;
875 break;
876 }
877 }
878
879 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
880 vars->bufferOffset = 0;
881 if (vars->bufferSize <= vars->extentRemaining)
882 vars->bufferLimit = vars->bufferSize;
883 else
884 vars->bufferLimit = vars->extentRemaining;
885
886 flush = false;
887 }
888 }
889 while (size);
890
891 return (err);
892 }
893
894 static IOReturn
895 IOPolledFileRead(IOPolledFileIOVars * vars,
896 uint8_t * bytes, IOByteCount size,
897 hibernate_cryptvars_t * cryptvars)
898 {
899 IOReturn err = kIOReturnSuccess;
900 IOByteCount copy;
901
902 // bytesWritten += size;
903
904 do
905 {
906 copy = vars->bufferLimit - vars->bufferOffset;
907 if (copy > size)
908 copy = size;
909
910 if (bytes)
911 {
912 bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
913 bytes += copy;
914 }
915 size -= copy;
916 vars->bufferOffset += copy;
917 // vars->position += copy;
918
919 if (vars->bufferOffset == vars->bufferLimit)
920 {
921 if (vars->io)
922 {
923 err = IOHibernatePollerIODone(vars, false);
924 if (kIOReturnSuccess != err)
925 break;
926 }
927 else
928 cryptvars = 0;
929
930 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
931
932 vars->position += vars->lastRead;
933 vars->extentRemaining -= vars->lastRead;
934 vars->bufferLimit = vars->lastRead;
935
936 if (!vars->extentRemaining)
937 {
938 vars->currentExtent++;
939 vars->extentRemaining = vars->currentExtent->length;
940 vars->extentPosition = vars->position;
941 if (!vars->extentRemaining)
942 {
943 err = kIOReturnOverrun;
944 break;
945 }
946 }
947
948 uint64_t length;
949 uint64_t lastReadLength = vars->lastRead;
950 uint64_t offset = (vars->position
951 - vars->extentPosition + vars->currentExtent->start);
952 if (vars->extentRemaining <= vars->bufferSize)
953 length = vars->extentRemaining;
954 else
955 length = vars->bufferSize;
956 vars->lastRead = length;
957
958 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
959
960 err = IOHibernatePollerIO(vars, kIOPolledRead, vars->bufferHalf, offset, length);
961 if (kIOReturnSuccess != err)
962 break;
963 vars->io = true;
964
965 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
966 vars->bufferOffset = 0;
967
968 #if CRYPTO
969 if (cryptvars)
970 {
971 uint8_t thisVector[AES_BLOCK_SIZE];
972 // save initial vector for following decrypts
973 bcopy(&cryptvars->aes_iv[0], &thisVector[0], AES_BLOCK_SIZE);
974 bcopy(vars->buffer + vars->bufferHalf + lastReadLength - AES_BLOCK_SIZE,
975 &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
976 // decrypt the buffer
977 aes_decrypt_cbc(vars->buffer + vars->bufferHalf,
978 &thisVector[0],
979 lastReadLength / AES_BLOCK_SIZE,
980 vars->buffer + vars->bufferHalf,
981 &cryptvars->ctx.decrypt);
982 }
983 #endif /* CRYPTO */
984 }
985 }
986 while (size);
987
988 return (err);
989 }
990
991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
992
993 IOReturn
994 IOHibernateSystemSleep(void)
995 {
996 IOReturn err;
997 OSData * data;
998 OSObject * obj;
999 OSString * str;
1000 bool dsSSD;
1001
1002 IOHibernateVars * vars = &gIOHibernateVars;
1003
1004 if (vars->fileVars && vars->fileVars->fileRef)
1005 // already on the way down
1006 return (kIOReturnSuccess);
1007
1008 gIOHibernateState = kIOHibernateStateInactive;
1009
1010 gIOHibernateDebugFlags = 0;
1011 if (kIOLogHibernate & gIOKitDebug)
1012 gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
1013
1014 if (IOService::getPMRootDomain()->getHibernateSettings(
1015 &gIOHibernateMode, &gIOHibernateFreeRatio, &gIOHibernateFreeTime))
1016 if (kIOHibernateModeSleep & gIOHibernateMode)
1017 // default to discard clean for safe sleep
1018 gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
1019 | kIOHibernateModeDiscardCleanActive);
1020
1021 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey)))
1022 {
1023 if ((str = OSDynamicCast(OSString, obj)))
1024 strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
1025 sizeof(gIOHibernateFilename));
1026 obj->release();
1027 }
1028
1029 if (!gIOHibernateMode || !gIOHibernateFilename[0])
1030 return (kIOReturnUnsupported);
1031
1032 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
1033
1034
1035 do
1036 {
1037 vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1038 4 * page_size, page_size);
1039 vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1040 2 * kDefaultIOSize, page_size);
1041
1042 if (!vars->srcBuffer || !vars->ioBuffer)
1043 {
1044 err = kIOReturnNoMemory;
1045 break;
1046 }
1047
1048 err = IOPolledFileOpen(gIOHibernateFilename, vars->ioBuffer,
1049 &vars->fileVars, &vars->fileExtents, &data);
1050 if (KERN_SUCCESS != err)
1051 {
1052 HIBLOG("IOPolledFileOpen(%x)\n", err);
1053 break;
1054 }
1055 if (vars->fileVars->fileRef)
1056 {
1057 // invalidate the image file
1058 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1059 int err = kern_write_file(vars->fileVars->fileRef, 0,
1060 (caddr_t) gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1061 if (KERN_SUCCESS != err)
1062 HIBLOG("kern_write_file(%d)\n", err);
1063 }
1064
1065 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1066 gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
1067
1068 dsSSD = (vars->fileVars->solid_state
1069 && (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
1070
1071 if (dsSSD)
1072 {
1073 gIOHibernateCurrentHeader->options |=
1074 kIOHibernateOptionSSD
1075 | kIOHibernateOptionColor;
1076 }
1077 else
1078 {
1079 gIOHibernateCurrentHeader->options |= kIOHibernateOptionProgress;
1080 }
1081
1082 boolean_t encryptedswap;
1083 AbsoluteTime startTime, endTime;
1084 uint64_t nsec;
1085
1086 clock_get_uptime(&startTime);
1087 err = hibernate_setup(gIOHibernateCurrentHeader,
1088 gIOHibernateFreeRatio, gIOHibernateFreeTime,
1089 dsSSD,
1090 &vars->page_list, &vars->page_list_wired, &encryptedswap);
1091 clock_get_uptime(&endTime);
1092 SUB_ABSOLUTETIME(&endTime, &startTime);
1093 absolutetime_to_nanoseconds(endTime, &nsec);
1094 HIBLOG("hibernate_setup(%d) took %qd ms\n", err, nsec / 1000000ULL);
1095
1096 if (KERN_SUCCESS != err)
1097 break;
1098
1099 if (encryptedswap)
1100 gIOHibernateMode ^= kIOHibernateModeEncrypt;
1101
1102 if (kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1103 {
1104 vars->videoAllocSize = kVideoMapSize;
1105 if (KERN_SUCCESS != kmem_alloc_pageable(kernel_map, &vars->videoMapping, vars->videoAllocSize))
1106 vars->videoMapping = 0;
1107 }
1108
1109 // generate crypt keys
1110 for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++)
1111 vars->wiredCryptKey[i] = random();
1112 for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++)
1113 vars->cryptKey[i] = random();
1114
1115 // set nvram
1116
1117 IORegistryEntry * regEntry;
1118 if (!gIOOptionsEntry)
1119 {
1120 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1121 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
1122 if (regEntry && !gIOOptionsEntry)
1123 regEntry->release();
1124 }
1125 if (!gIOChosenEntry)
1126 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
1127
1128 if (gIOOptionsEntry)
1129 {
1130 const OSSymbol * sym;
1131
1132 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1133 if (sym)
1134 {
1135 gIOOptionsEntry->setProperty(sym, data);
1136 sym->release();
1137 }
1138 data->release();
1139
1140 #if defined(__ppc__)
1141 size_t len;
1142 char valueString[16];
1143
1144 vars->saveBootDevice = gIOOptionsEntry->copyProperty(kIOSelectedBootDeviceKey);
1145 if (gIOChosenEntry)
1146 {
1147 OSData * bootDevice = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOBootPathKey));
1148 if (bootDevice)
1149 {
1150 sym = OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey);
1151 OSString * str2 = OSString::withCStringNoCopy((const char *) bootDevice->getBytesNoCopy());
1152 if (sym && str2)
1153 gIOOptionsEntry->setProperty(sym, str2);
1154 if (sym)
1155 sym->release();
1156 if (str2)
1157 str2->release();
1158 }
1159 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMemorySignatureKey));
1160 if (data)
1161 {
1162 vars->haveFastBoot = true;
1163
1164 len = snprintf(valueString, sizeof(valueString), "0x%lx", *((UInt32 *)data->getBytesNoCopy()));
1165 data = OSData::withBytes(valueString, len + 1);
1166 sym = OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey);
1167 if (sym && data)
1168 gIOOptionsEntry->setProperty(sym, data);
1169 if (sym)
1170 sym->release();
1171 if (data)
1172 data->release();
1173 }
1174 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
1175 if (data)
1176 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
1177 }
1178 #endif /* __ppc__ */
1179 #if defined(__i386__) || defined(__x86_64__)
1180 struct AppleRTCHibernateVars
1181 {
1182 uint8_t signature[4];
1183 uint32_t revision;
1184 uint8_t booterSignature[20];
1185 uint8_t wiredCryptKey[16];
1186 };
1187 AppleRTCHibernateVars rtcVars;
1188
1189 rtcVars.signature[0] = 'A';
1190 rtcVars.signature[1] = 'A';
1191 rtcVars.signature[2] = 'P';
1192 rtcVars.signature[3] = 'L';
1193 rtcVars.revision = 1;
1194 bcopy(&vars->wiredCryptKey[0], &rtcVars.wiredCryptKey[0], sizeof(rtcVars.wiredCryptKey));
1195 if (gIOHibernateBootSignature[0])
1196 {
1197 char c;
1198 uint8_t value = 0;
1199 for (uint32_t i = 0;
1200 (c = gIOHibernateBootSignature[i]) && (i < (sizeof(rtcVars.booterSignature) << 1));
1201 i++)
1202 {
1203 if (c >= 'a')
1204 c -= 'a' - 10;
1205 else if (c >= 'A')
1206 c -= 'A' - 10;
1207 else if (c >= '0')
1208 c -= '0';
1209 else
1210 continue;
1211 value = (value << 4) | c;
1212 if (i & 1)
1213 rtcVars.booterSignature[i >> 1] = value;
1214 }
1215 }
1216 data = OSData::withBytes(&rtcVars, sizeof(rtcVars));
1217 if (data)
1218 {
1219 if (!gIOHibernateRTCVariablesKey)
1220 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1221 if (gIOHibernateRTCVariablesKey)
1222 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey, data);
1223
1224 if( gIOOptionsEntry )
1225 {
1226 if( gIOHibernateMode & kIOHibernateModeSwitch )
1227 {
1228 const OSSymbol *sym;
1229 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey);
1230 if( sym )
1231 {
1232 gIOOptionsEntry->setProperty(sym, data); /* intentional insecure backup of rtc boot vars */
1233 sym->release();
1234 }
1235 }
1236 }
1237
1238 data->release();
1239 }
1240 if (gIOChosenEntry)
1241 {
1242 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
1243 if (data)
1244 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
1245 {
1246 // set BootNext
1247
1248 if (!gIOHibernateBoot0082Data)
1249 {
1250 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-device-path"));
1251 if (data)
1252 {
1253 // AppleNVRAM_EFI_LOAD_OPTION
1254 struct {
1255 uint32_t Attributes;
1256 uint16_t FilePathLength;
1257 uint16_t Desc;
1258 } loadOptionHeader;
1259 loadOptionHeader.Attributes = 1;
1260 loadOptionHeader.FilePathLength = data->getLength();
1261 loadOptionHeader.Desc = 0;
1262 gIOHibernateBoot0082Data = OSData::withCapacity(sizeof(loadOptionHeader) + loadOptionHeader.FilePathLength);
1263 if (gIOHibernateBoot0082Data)
1264 {
1265 gIOHibernateBoot0082Data->appendBytes(&loadOptionHeader, sizeof(loadOptionHeader));
1266 gIOHibernateBoot0082Data->appendBytes(data);
1267 }
1268 }
1269 }
1270 if (!gIOHibernateBoot0082Key)
1271 gIOHibernateBoot0082Key = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1272 if (!gIOHibernateBootNextKey)
1273 gIOHibernateBootNextKey = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1274 if (!gIOHibernateBootNextData)
1275 {
1276 uint16_t bits = 0x0082;
1277 gIOHibernateBootNextData = OSData::withBytes(&bits, sizeof(bits));
1278 }
1279 if (gIOHibernateBoot0082Key && gIOHibernateBoot0082Data && gIOHibernateBootNextKey && gIOHibernateBootNextData)
1280 {
1281 gIOHibernateBootNextSave = gIOOptionsEntry->copyProperty(gIOHibernateBootNextKey);
1282 gIOOptionsEntry->setProperty(gIOHibernateBoot0082Key, gIOHibernateBoot0082Data);
1283 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextData);
1284 }
1285 }
1286 }
1287 #else /* !i386 && !x86_64 */
1288 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1289 {
1290 data = OSData::withBytes(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1291 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
1292 if (sym && data)
1293 gIOOptionsEntry->setProperty(sym, data);
1294 if (sym)
1295 sym->release();
1296 if (data)
1297 data->release();
1298 if (false && gIOHibernateBootSignature[0])
1299 {
1300 data = OSData::withCapacity(16);
1301 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
1302 if (sym && data)
1303 {
1304 char c;
1305 uint8_t value = 0;
1306 for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++)
1307 {
1308 if (c >= 'a')
1309 c -= 'a' - 10;
1310 else if (c >= 'A')
1311 c -= 'A' - 10;
1312 else if (c >= '0')
1313 c -= '0';
1314 else
1315 continue;
1316 value = (value << 4) | c;
1317 if (i & 1)
1318 data->appendBytes(&value, sizeof(value));
1319 }
1320 gIOOptionsEntry->setProperty(sym, data);
1321 }
1322 if (sym)
1323 sym->release();
1324 if (data)
1325 data->release();
1326 }
1327 }
1328 if (!vars->haveFastBoot)
1329 {
1330 // set boot volume to zero
1331 IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
1332 if (platform && (kIOReturnSuccess == platform->readXPRAM(kXPRamAudioVolume,
1333 &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume))))
1334 {
1335 uint8_t newVolume;
1336 newVolume = vars->saveBootAudioVolume & 0xf8;
1337 platform->writeXPRAM(kXPRamAudioVolume,
1338 &newVolume, sizeof(newVolume));
1339 }
1340 }
1341 #endif /* !i386 && !x86_64 */
1342 }
1343 // --
1344
1345 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderSignature;
1346 gIOHibernateState = kIOHibernateStateHibernating;
1347 }
1348 while (false);
1349
1350 return (err);
1351 }
1352
1353 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1354
1355 DECLARE_IOHIBERNATEPROGRESSALPHA
1356
1357 static void
1358 ProgressInit(hibernate_graphics_t * display, uint8_t * screen, uint8_t * saveunder, uint32_t savelen)
1359 {
1360 uint32_t rowBytes, pixelShift;
1361 uint32_t x, y;
1362 int32_t blob;
1363 uint32_t alpha, in, color, result;
1364 uint8_t * out;
1365 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1366
1367 rowBytes = display->rowBytes;
1368 pixelShift = display->depth >> 4;
1369 if (pixelShift < 1) return;
1370
1371 screen += ((display->width
1372 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1373 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1374
1375 for (y = 0; y < kIOHibernateProgressHeight; y++)
1376 {
1377 out = screen + y * rowBytes;
1378 for (blob = 0; blob < kIOHibernateProgressCount; blob++)
1379 {
1380 color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
1381 for (x = 0; x < kIOHibernateProgressWidth; x++)
1382 {
1383 alpha = gIOHibernateProgressAlpha[y][x];
1384 result = color;
1385 if (alpha)
1386 {
1387 if (0xff != alpha)
1388 {
1389 if (1 == pixelShift)
1390 {
1391 in = *((uint16_t *)out) & 0x1f; // 16
1392 in = (in << 3) | (in >> 2);
1393 }
1394 else
1395 in = *((uint32_t *)out) & 0xff; // 32
1396 saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
1397 result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
1398 }
1399 if (1 == pixelShift)
1400 {
1401 result >>= 3;
1402 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1403 }
1404 else
1405 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1406 }
1407 out += (1 << pixelShift);
1408 }
1409 out += (kIOHibernateProgressSpacing << pixelShift);
1410 }
1411 }
1412 }
1413
1414
1415 static void
1416 ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select)
1417 {
1418 uint32_t rowBytes, pixelShift;
1419 uint32_t x, y;
1420 int32_t blob, lastBlob;
1421 uint32_t alpha, in, color, result;
1422 uint8_t * out;
1423 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1424
1425 pixelShift = display->depth >> 4;
1426 if (pixelShift < 1)
1427 return;
1428
1429 rowBytes = display->rowBytes;
1430
1431 screen += ((display->width
1432 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1433 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1434
1435 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1436
1437 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1438
1439 for (y = 0; y < kIOHibernateProgressHeight; y++)
1440 {
1441 out = screen + y * rowBytes;
1442 for (blob = firstBlob; blob <= lastBlob; blob++)
1443 {
1444 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1445 for (x = 0; x < kIOHibernateProgressWidth; x++)
1446 {
1447 alpha = gIOHibernateProgressAlpha[y][x];
1448 result = color;
1449 if (alpha)
1450 {
1451 if (0xff != alpha)
1452 {
1453 in = display->progressSaveUnder[blob][saveindex[blob]++];
1454 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1455 }
1456 if (1 == pixelShift)
1457 {
1458 result >>= 3;
1459 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1460 }
1461 else
1462 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1463 }
1464 out += (1 << pixelShift);
1465 }
1466 out += (kIOHibernateProgressSpacing << pixelShift);
1467 }
1468 }
1469 }
1470
1471 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1472
1473 IOReturn
1474 IOHibernateSystemHasSlept(void)
1475 {
1476 IOHibernateVars * vars = &gIOHibernateVars;
1477 OSObject * obj;
1478 OSData * data;
1479
1480 obj = IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey);
1481 vars->previewBuffer = OSDynamicCast(IOMemoryDescriptor, obj);
1482 if (obj && !vars->previewBuffer)
1483 obj->release();
1484
1485 vars->consoleMapping = NULL;
1486 if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare()))
1487 {
1488 vars->previewBuffer->release();
1489 vars->previewBuffer = 0;
1490 }
1491
1492 if ((kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1493 && vars->previewBuffer
1494 && (data = OSDynamicCast(OSData,
1495 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey))))
1496 {
1497 UInt32 flags = *((UInt32 *)data->getBytesNoCopy());
1498 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags);
1499
1500 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey);
1501
1502 if (kIOHibernatePreviewUpdates & flags)
1503 {
1504 PE_Video consoleInfo;
1505 hibernate_graphics_t * graphicsInfo = gIOHibernateGraphicsInfo;
1506
1507 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
1508
1509 graphicsInfo->width = consoleInfo.v_width;
1510 graphicsInfo->height = consoleInfo.v_height;
1511 graphicsInfo->rowBytes = consoleInfo.v_rowBytes;
1512 graphicsInfo->depth = consoleInfo.v_depth;
1513 vars->consoleMapping = (uint8_t *) consoleInfo.v_baseAddr;
1514
1515 HIBPRINT("video %p %d %d %d\n",
1516 vars->consoleMapping, graphicsInfo->depth,
1517 graphicsInfo->width, graphicsInfo->height);
1518 if (vars->consoleMapping)
1519 ProgressInit(graphicsInfo, vars->consoleMapping,
1520 &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
1521 }
1522 }
1523
1524 if (gIOOptionsEntry)
1525 gIOOptionsEntry->sync();
1526
1527 return (kIOReturnSuccess);
1528 }
1529
1530 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1531
1532 IOReturn
1533 IOHibernateSystemWake(void)
1534 {
1535 IOHibernateVars * vars = &gIOHibernateVars;
1536
1537 hibernate_teardown(vars->page_list, vars->page_list_wired);
1538
1539 if (vars->videoMapping)
1540 {
1541 if (vars->videoMapSize)
1542 // remove mappings
1543 IOUnmapPages(kernel_map, vars->videoMapping, vars->videoMapSize);
1544 if (vars->videoAllocSize)
1545 // dealloc range
1546 kmem_free(kernel_map, trunc_page(vars->videoMapping), vars->videoAllocSize);
1547 }
1548
1549 if (vars->previewBuffer)
1550 {
1551 vars->previewBuffer->release();
1552 vars->previewBuffer = 0;
1553 }
1554
1555 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState)
1556 {
1557 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey,
1558 gIOHibernateCurrentHeader->options, 32);
1559 }
1560 else
1561 {
1562 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
1563 }
1564
1565 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState)
1566 && (kIOHibernateGfxStatusUnknown != gIOHibernateGraphicsInfo->gfxStatus))
1567 {
1568 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey,
1569 &gIOHibernateGraphicsInfo->gfxStatus,
1570 sizeof(gIOHibernateGraphicsInfo->gfxStatus));
1571 }
1572 else
1573 {
1574 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
1575 }
1576
1577
1578 if (vars->fileVars)
1579 {
1580 IOPolledFileClose(vars->fileVars);
1581 }
1582
1583 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1584
1585 #ifdef __ppc__
1586 OSData * data = OSData::withCapacity(4);
1587 if (gIOOptionsEntry && data)
1588 {
1589 const OSSymbol * sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1590 if (sym)
1591 {
1592 gIOOptionsEntry->setProperty(sym, data);
1593 sym->release();
1594 }
1595 sym = OSSymbol::withCStringNoCopy(kIOSelectedBootDeviceKey);
1596 if (sym)
1597 {
1598 if (vars->saveBootDevice)
1599 {
1600 gIOOptionsEntry->setProperty(sym, vars->saveBootDevice);
1601 vars->saveBootDevice->release();
1602 }
1603 sym->release();
1604 }
1605 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
1606 if (sym)
1607 {
1608 gIOOptionsEntry->setProperty(sym, data);
1609 sym->release();
1610 }
1611 sym = OSSymbol::withCStringNoCopy(kIOHibernateMemorySignatureEnvKey);
1612 if (sym)
1613 {
1614 gIOOptionsEntry->removeProperty(sym);
1615 sym->release();
1616 }
1617 }
1618 if (data)
1619 data->release();
1620
1621 if (gIOOptionsEntry)
1622 {
1623 if (!vars->haveFastBoot)
1624 {
1625 // reset boot audio volume
1626 IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
1627 if (platform)
1628 platform->writeXPRAM(kXPRamAudioVolume,
1629 &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume));
1630 }
1631
1632 // sync now to hardware if the booter has not
1633 if (kIOHibernateStateInactive == gIOHibernateState)
1634 gIOOptionsEntry->sync();
1635 else
1636 // just sync the variables in case a later panic syncs nvram (it won't sync variables)
1637 gIOOptionsEntry->syncOFVariables();
1638 }
1639 #endif
1640
1641 #if defined(__i386__) || defined(__x86_64__)
1642 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey);
1643
1644 /*
1645 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1646 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1647 */
1648 if (gIOOptionsEntry) {
1649
1650 if (gIOHibernateRTCVariablesKey) {
1651 if (gIOOptionsEntry->getProperty(gIOHibernateRTCVariablesKey)) {
1652 gIOOptionsEntry->removeProperty(gIOHibernateRTCVariablesKey);
1653 }
1654 }
1655
1656 if (gIOHibernateBootNextKey)
1657 {
1658 if (gIOHibernateBootNextSave)
1659 {
1660 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextSave);
1661 gIOHibernateBootNextSave->release();
1662 gIOHibernateBootNextSave = NULL;
1663 }
1664 else
1665 gIOOptionsEntry->removeProperty(gIOHibernateBootNextKey);
1666 }
1667 gIOOptionsEntry->sync();
1668 }
1669 #endif
1670
1671 if (vars->srcBuffer)
1672 vars->srcBuffer->release();
1673 if (vars->ioBuffer)
1674 vars->ioBuffer->release();
1675 if (vars->fileExtents)
1676 vars->fileExtents->release();
1677
1678 bzero(vars, sizeof(*vars));
1679
1680 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1681
1682 return (kIOReturnSuccess);
1683 }
1684
1685 IOReturn
1686 IOHibernateSystemPostWake(void)
1687 {
1688 if (gIOHibernateFileRef)
1689 {
1690 // invalidate the image file
1691 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1692 int err = kern_write_file(gIOHibernateFileRef, 0,
1693 (caddr_t) gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1694 if (KERN_SUCCESS != err)
1695 HIBLOG("kern_write_file(%d)\n", err);
1696
1697 kern_close_file_for_direct_io(gIOHibernateFileRef);
1698 gIOHibernateFileRef = 0;
1699 }
1700 return (kIOReturnSuccess);
1701 }
1702
1703 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1704
1705 SYSCTL_STRING(_kern, OID_AUTO, hibernatefile,
1706 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
1707 gIOHibernateFilename, sizeof(gIOHibernateFilename), "");
1708 SYSCTL_STRING(_kern, OID_AUTO, bootsignature,
1709 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
1710 gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), "");
1711 SYSCTL_UINT(_kern, OID_AUTO, hibernatemode,
1712 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN,
1713 &gIOHibernateMode, 0, "");
1714
1715 void
1716 IOHibernateSystemInit(IOPMrootDomain * rootDomain)
1717 {
1718 OSData * data = OSData::withBytesNoCopy(&gIOHibernateState, sizeof(gIOHibernateState));
1719 if (data)
1720 {
1721 rootDomain->setProperty(kIOHibernateStateKey, data);
1722 data->release();
1723 }
1724
1725 if (PE_parse_boot_argn("hfile", gIOHibernateFilename, sizeof(gIOHibernateFilename)))
1726 gIOHibernateMode = kIOHibernateModeOn;
1727 else
1728 gIOHibernateFilename[0] = 0;
1729
1730 sysctl_register_oid(&sysctl__kern_hibernatefile);
1731 sysctl_register_oid(&sysctl__kern_bootsignature);
1732 sysctl_register_oid(&sysctl__kern_hibernatemode);
1733 }
1734
1735
1736 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1737
1738 static void
1739 hibernate_setup_for_wake(void)
1740 {
1741 #if __ppc__
1742 // go slow (state needed for wake)
1743 ml_set_processor_speed(1);
1744 #endif
1745 }
1746
1747 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1748
1749 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
1750
1751 static bool
1752 no_encrypt_page(vm_offset_t ppnum)
1753 {
1754 if (pmap_is_noencrypt((ppnum_t)ppnum) == TRUE)
1755 {
1756 return true;
1757 }
1758 return false;
1759 }
1760
1761 uint32_t wired_pages_encrypted = 0;
1762 uint32_t dirty_pages_encrypted = 0;
1763 uint32_t wired_pages_clear = 0;
1764
1765 extern "C" uint32_t
1766 hibernate_write_image(void)
1767 {
1768 IOHibernateImageHeader * header = gIOHibernateCurrentHeader;
1769 IOHibernateVars * vars = &gIOHibernateVars;
1770 IOPolledFileExtent * fileExtents;
1771
1772 C_ASSERT(sizeof(IOHibernateImageHeader) == 512);
1773
1774 uint32_t pageCount, pagesDone;
1775 IOReturn err;
1776 vm_offset_t ppnum, page;
1777 IOItemCount count;
1778 uint8_t * src;
1779 uint8_t * data;
1780 IOByteCount pageCompressedSize;
1781 uint64_t compressedSize, uncompressedSize;
1782 uint64_t image1Size = 0;
1783 uint32_t bitmap_size;
1784 bool iterDone, pollerOpen, needEncrypt;
1785 uint32_t restore1Sum, sum, sum1, sum2;
1786 uint32_t tag;
1787 uint32_t pageType;
1788 uint32_t pageAndCount[2];
1789
1790 AbsoluteTime startTime, endTime;
1791 AbsoluteTime allTime, compTime, decoTime;
1792 uint64_t compBytes;
1793 uint64_t nsec;
1794 uint32_t lastProgressStamp = 0;
1795 uint32_t progressStamp;
1796 uint32_t blob, lastBlob = (uint32_t) -1L;
1797
1798 hibernate_cryptvars_t _cryptvars;
1799 hibernate_cryptvars_t * cryptvars = 0;
1800
1801 wired_pages_encrypted = 0;
1802 dirty_pages_encrypted = 0;
1803 wired_pages_clear = 0;
1804
1805 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
1806 return (false /* sleep */ );
1807
1808 if (kIOHibernateModeSleep & gIOHibernateMode)
1809 kdebug_enable = save_kdebug_enable;
1810
1811 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_START, 0, 0, 0, 0, 0);
1812
1813 restore1Sum = sum1 = sum2 = 0;
1814
1815 #if CRYPTO
1816 // encryption data. "iv" is the "initial vector".
1817 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1818 {
1819 static const unsigned char first_iv[AES_BLOCK_SIZE]
1820 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1821 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1822
1823 cryptvars = &gIOHibernateCryptWakeContext;
1824 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
1825 aes_encrypt_key(vars->cryptKey,
1826 kIOHibernateAESKeySize,
1827 &cryptvars->ctx.encrypt);
1828 aes_decrypt_key(vars->cryptKey,
1829 kIOHibernateAESKeySize,
1830 &cryptvars->ctx.decrypt);
1831
1832 cryptvars = &_cryptvars;
1833 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
1834 aes_encrypt_key(vars->wiredCryptKey,
1835 kIOHibernateAESKeySize,
1836 &cryptvars->ctx.encrypt);
1837
1838 bcopy(&first_iv[0], &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1839 bzero(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1840 bzero(&vars->cryptKey[0], sizeof(vars->cryptKey));
1841 bzero(gIOHibernateCryptWakeVars, sizeof(hibernate_cryptwakevars_t));
1842 }
1843 #endif /* CRYPTO */
1844
1845 hibernate_setup_for_wake();
1846
1847 hibernate_page_list_setall(vars->page_list,
1848 vars->page_list_wired,
1849 &pageCount);
1850
1851 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount);
1852
1853 fileExtents = (IOPolledFileExtent *) vars->fileExtents->getBytesNoCopy();
1854
1855 #if 0
1856 count = vars->fileExtents->getLength() / sizeof(IOPolledFileExtent);
1857 for (page = 0; page < count; page++)
1858 {
1859 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page,
1860 fileExtents[page].start, fileExtents[page].length,
1861 fileExtents[page].start + fileExtents[page].length);
1862 }
1863 #endif
1864
1865 needEncrypt = (0 != (kIOHibernateModeEncrypt & gIOHibernateMode));
1866
1867 AbsoluteTime_to_scalar(&compTime) = 0;
1868 AbsoluteTime_to_scalar(&decoTime) = 0;
1869
1870 clock_get_uptime(&allTime);
1871 IOService::getPMRootDomain()->pmStatsRecordEvent(
1872 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStartFlag, allTime);
1873
1874 do
1875 {
1876 compressedSize = 0;
1877 uncompressedSize = 0;
1878
1879 IOPolledFileSeek(vars->fileVars, sizeof(IOHibernateImageHeader));
1880
1881 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1882 ml_get_interrupts_enabled());
1883 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledBeforeSleepState, vars->ioBuffer);
1884 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
1885 pollerOpen = (kIOReturnSuccess == err);
1886 if (!pollerOpen)
1887 break;
1888
1889 // copy file block extent list if larger than header
1890
1891 count = vars->fileExtents->getLength();
1892 if (count > sizeof(header->fileExtentMap))
1893 {
1894 count -= sizeof(header->fileExtentMap);
1895 err = IOPolledFileWrite(vars->fileVars,
1896 ((uint8_t *) &fileExtents[0]) + sizeof(header->fileExtentMap), count, cryptvars);
1897 if (kIOReturnSuccess != err)
1898 break;
1899 }
1900
1901 uintptr_t hibernateBase;
1902 uintptr_t hibernateEnd;
1903
1904 #if defined(__i386__) || defined(__x86_64__)
1905 hibernateBase = sectINITPTB;
1906 #else
1907 hibernateBase = sectHIBB;
1908 #endif
1909
1910 hibernateEnd = (sectHIBB + sectSizeHIB);
1911 // copy out restore1 code
1912
1913 page = atop_32(hibernateBase);
1914 count = atop_32(round_page(hibernateEnd)) - page;
1915 header->restore1CodePage = page;
1916 header->restore1PageCount = count;
1917 header->restore1CodeOffset = ((uintptr_t) &hibernate_machine_entrypoint) - hibernateBase;
1918 header->restore1StackOffset = ((uintptr_t) &gIOHibernateRestoreStackEnd[0]) - 64 - hibernateBase;
1919
1920 // sum __HIB sect, with zeros for the stack
1921 src = (uint8_t *) trunc_page(hibernateBase);
1922 for (page = 0; page < count; page++)
1923 {
1924 if ((src < &gIOHibernateRestoreStack[0]) || (src >= &gIOHibernateRestoreStackEnd[0]))
1925 restore1Sum += hibernate_sum_page(src, header->restore1CodePage + page);
1926 else
1927 restore1Sum += 0x00000000;
1928 src += page_size;
1929 }
1930 sum1 = restore1Sum;
1931
1932 // write the __HIB sect, with zeros for the stack
1933
1934 src = (uint8_t *) trunc_page(hibernateBase);
1935 count = ((uintptr_t) &gIOHibernateRestoreStack[0]) - trunc_page(hibernateBase);
1936 if (count)
1937 {
1938 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
1939 if (kIOReturnSuccess != err)
1940 break;
1941 }
1942 err = IOPolledFileWrite(vars->fileVars,
1943 (uint8_t *) 0,
1944 &gIOHibernateRestoreStackEnd[0] - &gIOHibernateRestoreStack[0],
1945 cryptvars);
1946 if (kIOReturnSuccess != err)
1947 break;
1948 src = &gIOHibernateRestoreStackEnd[0];
1949 count = round_page(hibernateEnd) - ((uintptr_t) src);
1950 if (count)
1951 {
1952 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
1953 if (kIOReturnSuccess != err)
1954 break;
1955 }
1956
1957 // write the preview buffer
1958
1959 addr64_t phys64;
1960 IOByteCount segLen;
1961
1962 if (vars->previewBuffer)
1963 {
1964 ppnum = 0;
1965 count = 0;
1966 do
1967 {
1968 phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone);
1969 pageAndCount[0] = atop_64(phys64);
1970 pageAndCount[1] = atop_32(segLen);
1971 err = IOPolledFileWrite(vars->fileVars,
1972 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
1973 cryptvars);
1974 if (kIOReturnSuccess != err)
1975 break;
1976 count += segLen;
1977 ppnum += sizeof(pageAndCount);
1978 }
1979 while (phys64);
1980 if (kIOReturnSuccess != err)
1981 break;
1982
1983 src = (uint8_t *) vars->previewBuffer->getPhysicalSegment(0, NULL, _kIOMemorySourceSegment);
1984 count = vars->previewBuffer->getLength();
1985
1986 header->previewPageListSize = ppnum;
1987 header->previewSize = count + ppnum;
1988
1989 for (page = 0; page < count; page += page_size)
1990 {
1991 phys64 = vars->previewBuffer->getPhysicalSegment(page, NULL, kIOMemoryMapperNone);
1992 sum1 += hibernate_sum_page(src + page, atop_64(phys64));
1993 }
1994 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
1995 if (kIOReturnSuccess != err)
1996 break;
1997 }
1998
1999 // mark areas for no save
2000
2001 for (count = 0;
2002 (phys64 = vars->ioBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2003 count += segLen)
2004 {
2005 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2006 atop_64(phys64), atop_32(segLen),
2007 kIOHibernatePageStateFree);
2008 pageCount -= atop_32(segLen);
2009 }
2010
2011 for (count = 0;
2012 (phys64 = vars->srcBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2013 count += segLen)
2014 {
2015 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2016 atop_64(phys64), atop_32(segLen),
2017 kIOHibernatePageStateFree);
2018 pageCount -= atop_32(segLen);
2019 }
2020
2021 // copy out bitmap of pages available for trashing during restore
2022
2023 bitmap_size = vars->page_list_wired->list_size;
2024 src = (uint8_t *) vars->page_list_wired;
2025 err = IOPolledFileWrite(vars->fileVars, src, bitmap_size, cryptvars);
2026 if (kIOReturnSuccess != err)
2027 break;
2028
2029 // mark more areas for no save, but these are not available
2030 // for trashing during restore
2031
2032 hibernate_page_list_set_volatile(vars->page_list, vars->page_list_wired, &pageCount);
2033
2034 page = atop_32(hibernateBase);
2035 count = atop_32(round_page(hibernateEnd)) - page;
2036 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2037 page, count,
2038 kIOHibernatePageStateFree);
2039 pageCount -= count;
2040
2041 if (vars->previewBuffer) for (count = 0;
2042 (phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2043 count += segLen)
2044 {
2045 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2046 atop_64(phys64), atop_32(segLen),
2047 kIOHibernatePageStateFree);
2048 pageCount -= atop_32(segLen);
2049 }
2050
2051 src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2052
2053 pagesDone = 0;
2054 lastBlob = 0;
2055
2056 HIBLOG("writing %d pages\n", pageCount);
2057
2058 enum
2059 // pageType
2060 {
2061 kWired = 0x02,
2062 kEncrypt = 0x01,
2063 kWiredEncrypt = kWired | kEncrypt,
2064 kWiredClear = kWired,
2065 kUnwiredEncrypt = kEncrypt
2066 };
2067
2068 for (pageType = kWiredEncrypt; pageType >= kUnwiredEncrypt; pageType--)
2069 {
2070 if (needEncrypt && (kEncrypt & pageType))
2071 {
2072 vars->fileVars->encryptStart = (vars->fileVars->position & ~(AES_BLOCK_SIZE - 1));
2073 vars->fileVars->encryptEnd = UINT64_MAX;
2074 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
2075
2076 if (kUnwiredEncrypt == pageType)
2077 {
2078 // start unwired image
2079 bcopy(&cryptvars->aes_iv[0],
2080 &gIOHibernateCryptWakeContext.aes_iv[0],
2081 sizeof(cryptvars->aes_iv));
2082 cryptvars = &gIOHibernateCryptWakeContext;
2083 }
2084 }
2085 for (iterDone = false, ppnum = 0; !iterDone; )
2086 {
2087 count = hibernate_page_list_iterate((kWired & pageType)
2088 ? vars->page_list_wired : vars->page_list,
2089 &ppnum);
2090 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2091 iterDone = !count;
2092
2093 if (count && (kWired & pageType) && needEncrypt)
2094 {
2095 uint32_t checkIndex;
2096 for (checkIndex = 0;
2097 (checkIndex < count)
2098 && (((kEncrypt & pageType) == 0) == no_encrypt_page(ppnum + checkIndex));
2099 checkIndex++)
2100 {}
2101 if (!checkIndex)
2102 {
2103 ppnum++;
2104 continue;
2105 }
2106 count = checkIndex;
2107 }
2108
2109 switch (pageType)
2110 {
2111 case kWiredEncrypt: wired_pages_encrypted += count; break;
2112 case kWiredClear: wired_pages_clear += count; break;
2113 case kUnwiredEncrypt: dirty_pages_encrypted += count; break;
2114 }
2115
2116 if (iterDone && (kWiredEncrypt == pageType)) {/* not yet end of wired list */}
2117 else
2118 {
2119 pageAndCount[0] = ppnum;
2120 pageAndCount[1] = count;
2121 err = IOPolledFileWrite(vars->fileVars,
2122 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
2123 cryptvars);
2124 if (kIOReturnSuccess != err)
2125 break;
2126 }
2127
2128 for (page = ppnum; page < (ppnum + count); page++)
2129 {
2130 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(page), page_size);
2131 if (err)
2132 {
2133 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__, (long)page, err);
2134 break;
2135 }
2136
2137 sum = hibernate_sum_page(src, page);
2138 if (kWired & pageType)
2139 sum1 += sum;
2140 else
2141 sum2 += sum;
2142
2143 clock_get_uptime(&startTime);
2144
2145 pageCompressedSize = WKdm_compress ((WK_word*) src, (WK_word*) (src + page_size), PAGE_SIZE_IN_WORDS);
2146
2147 clock_get_uptime(&endTime);
2148 ADD_ABSOLUTETIME(&compTime, &endTime);
2149 SUB_ABSOLUTETIME(&compTime, &startTime);
2150 compBytes += page_size;
2151
2152 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2153 pageCompressedSize = (pageCompressedSize + AES_BLOCK_SIZE - 1) & ~(AES_BLOCK_SIZE - 1);
2154
2155 if (pageCompressedSize > page_size)
2156 {
2157 // HIBLOG("------------lose: %d\n", pageCompressedSize);
2158 pageCompressedSize = page_size;
2159 }
2160
2161 if (pageCompressedSize != page_size)
2162 data = (src + page_size);
2163 else
2164 data = src;
2165
2166 tag = pageCompressedSize | kIOHibernateTagSignature;
2167 err = IOPolledFileWrite(vars->fileVars, (const uint8_t *) &tag, sizeof(tag), cryptvars);
2168 if (kIOReturnSuccess != err)
2169 break;
2170
2171 err = IOPolledFileWrite(vars->fileVars, data, (pageCompressedSize + 3) & ~3, cryptvars);
2172 if (kIOReturnSuccess != err)
2173 break;
2174
2175 compressedSize += pageCompressedSize;
2176 if (pageCompressedSize)
2177 uncompressedSize += page_size;
2178 pagesDone++;
2179
2180 if (vars->consoleMapping && (0 == (1023 & pagesDone)))
2181 {
2182 blob = ((pagesDone * kIOHibernateProgressCount) / pageCount);
2183 if (blob != lastBlob)
2184 {
2185 ProgressUpdate(gIOHibernateGraphicsInfo, vars->consoleMapping, lastBlob, blob);
2186 lastBlob = blob;
2187 }
2188 }
2189 if (0 == (8191 & pagesDone))
2190 {
2191 clock_get_uptime(&endTime);
2192 SUB_ABSOLUTETIME(&endTime, &allTime);
2193 absolutetime_to_nanoseconds(endTime, &nsec);
2194 progressStamp = nsec / 750000000ULL;
2195 if (progressStamp != lastProgressStamp)
2196 {
2197 lastProgressStamp = progressStamp;
2198 HIBPRINT("pages %d (%d%%)\n", pagesDone, (100 * pagesDone) / pageCount);
2199 }
2200 }
2201 }
2202 if (kIOReturnSuccess != err)
2203 break;
2204 ppnum = page;
2205 }
2206
2207 if (kIOReturnSuccess != err)
2208 break;
2209
2210 if ((kEncrypt & pageType))
2211 {
2212 vars->fileVars->encryptEnd = (vars->fileVars->position + AES_BLOCK_SIZE - 1)
2213 & ~(AES_BLOCK_SIZE - 1);
2214 HIBLOG("encryptEnd %qx\n", vars->fileVars->encryptEnd);
2215 }
2216
2217 if (kWiredEncrypt != pageType)
2218 {
2219 // end of image1/2 - fill to next block
2220 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2221 if (kIOReturnSuccess != err)
2222 break;
2223 }
2224 if (kWiredClear == pageType)
2225 {
2226 // end wired image
2227 header->encryptStart = vars->fileVars->encryptStart;
2228 header->encryptEnd = vars->fileVars->encryptEnd;
2229 image1Size = vars->fileVars->position;
2230 HIBLOG("image1Size %qd, encryptStart1 %qx, End1 %qx\n",
2231 image1Size, header->encryptStart, header->encryptEnd);
2232 }
2233 }
2234 if (kIOReturnSuccess != err)
2235 break;
2236
2237 // Header:
2238
2239 header->imageSize = vars->fileVars->position;
2240 header->image1Size = image1Size;
2241 header->bitmapSize = bitmap_size;
2242 header->pageCount = pageCount;
2243
2244 header->restore1Sum = restore1Sum;
2245 header->image1Sum = sum1;
2246 header->image2Sum = sum2;
2247
2248 count = vars->fileExtents->getLength();
2249 if (count > sizeof(header->fileExtentMap))
2250 {
2251 header->fileExtentMapSize = count;
2252 count = sizeof(header->fileExtentMap);
2253 }
2254 else
2255 header->fileExtentMapSize = sizeof(header->fileExtentMap);
2256 bcopy(&fileExtents[0], &header->fileExtentMap[0], count);
2257
2258 header->deviceBase = vars->fileVars->block0;
2259
2260 IOPolledFileSeek(vars->fileVars, 0);
2261 err = IOPolledFileWrite(vars->fileVars,
2262 (uint8_t *) header, sizeof(IOHibernateImageHeader),
2263 cryptvars);
2264 if (kIOReturnSuccess != err)
2265 break;
2266 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2267 if (kIOReturnSuccess != err)
2268 break;
2269 err = IOHibernatePollerIODone(vars->fileVars, true);
2270 if (kIOReturnSuccess != err)
2271 break;
2272 }
2273 while (false);
2274
2275 clock_get_uptime(&endTime);
2276
2277 IOService::getPMRootDomain()->pmStatsRecordEvent(
2278 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStopFlag, endTime);
2279
2280 SUB_ABSOLUTETIME(&endTime, &allTime);
2281 absolutetime_to_nanoseconds(endTime, &nsec);
2282 HIBLOG("all time: %qd ms, ",
2283 nsec / 1000000ULL);
2284
2285 absolutetime_to_nanoseconds(compTime, &nsec);
2286 HIBLOG("comp time: %qd ms, ",
2287 nsec / 1000000ULL);
2288
2289 absolutetime_to_nanoseconds(decoTime, &nsec);
2290 HIBLOG("deco time: %qd ms, ",
2291 nsec / 1000000ULL);
2292
2293 HIBLOG("\nimage %qd, uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2294 header->imageSize,
2295 uncompressedSize, atop_32(uncompressedSize), compressedSize,
2296 uncompressedSize ? ((int) ((compressedSize * 100ULL) / uncompressedSize)) : 0,
2297 sum1, sum2);
2298
2299 HIBLOG("wired_pages_encrypted %d, wired_pages_clear %d, dirty_pages_encrypted %d\n",
2300 wired_pages_encrypted, wired_pages_clear, dirty_pages_encrypted);
2301
2302 if (vars->fileVars->io)
2303 (void) IOHibernatePollerIODone(vars->fileVars, false);
2304
2305 if (pollerOpen)
2306 IOHibernatePollerClose(vars->fileVars, kIOPolledBeforeSleepState);
2307
2308 if (vars->consoleMapping)
2309 ProgressUpdate(gIOHibernateGraphicsInfo,
2310 vars->consoleMapping, 0, kIOHibernateProgressCount);
2311
2312 HIBLOG("hibernate_write_image done(%x)\n", err);
2313
2314 // should we come back via regular wake, set the state in memory.
2315 gIOHibernateState = kIOHibernateStateInactive;
2316
2317 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_END,
2318 wired_pages_encrypted, wired_pages_clear, dirty_pages_encrypted, 0, 0);
2319
2320 if (kIOReturnSuccess == err)
2321 {
2322 if (kIOHibernateModeSleep & gIOHibernateMode)
2323 {
2324 return (kIOHibernatePostWriteSleep);
2325 }
2326 else if(kIOHibernateModeRestart & gIOHibernateMode)
2327 {
2328 return (kIOHibernatePostWriteRestart);
2329 }
2330 else
2331 {
2332 /* by default, power down */
2333 return (kIOHibernatePostWriteHalt);
2334 }
2335 }
2336 else if (kIOReturnAborted == err)
2337 {
2338 return (kIOHibernatePostWriteWake);
2339 }
2340 else
2341 {
2342 /* on error, sleep */
2343 return (kIOHibernatePostWriteSleep);
2344 }
2345 }
2346
2347 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2348
2349 extern "C" void
2350 hibernate_machine_init(void)
2351 {
2352 IOReturn err;
2353 uint32_t sum;
2354 uint32_t pagesDone;
2355 uint32_t pagesRead = 0;
2356 AbsoluteTime allTime, endTime;
2357 uint64_t nsec;
2358 uint32_t lastProgressStamp = 0;
2359 uint32_t progressStamp;
2360 uint64_t progressZeroPosition = 0;
2361 uint32_t blob, lastBlob = (uint32_t) -1L;
2362 hibernate_cryptvars_t * cryptvars = 0;
2363
2364 IOHibernateVars * vars = &gIOHibernateVars;
2365
2366 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
2367 return;
2368
2369 sum = gIOHibernateCurrentHeader->actualImage1Sum;
2370 pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages;
2371
2372 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, image1Size %qx, conflictCount %d, nextFree %x\n",
2373 gIOHibernateState, pagesDone, sum, gIOHibernateCurrentHeader->image1Size,
2374 gIOHibernateCurrentHeader->conflictCount, gIOHibernateCurrentHeader->nextFree);
2375
2376 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState)
2377 {
2378 HIBLOG("regular wake\n");
2379 return;
2380 }
2381
2382 HIBPRINT("diag %x %x %x %x\n",
2383 gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1],
2384 gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]);
2385
2386 HIBPRINT("video %x %d %d %d status %x\n",
2387 gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth,
2388 gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height, gIOHibernateGraphicsInfo->gfxStatus);
2389
2390 if ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode)
2391 hibernate_page_list_discard(vars->page_list);
2392
2393 boot_args *args = (boot_args *) PE_state.bootArgs;
2394
2395 if (vars->videoMapping
2396 && gIOHibernateGraphicsInfo->physicalAddress
2397 && (args->Video.v_baseAddr == gIOHibernateGraphicsInfo->physicalAddress))
2398 {
2399 vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height
2400 * gIOHibernateGraphicsInfo->rowBytes);
2401 IOMapPages(kernel_map,
2402 vars->videoMapping, gIOHibernateGraphicsInfo->physicalAddress,
2403 vars->videoMapSize, kIOMapInhibitCache );
2404 }
2405
2406 uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2407
2408 if (gIOHibernateWakeMapSize)
2409 {
2410 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(gIOHibernateWakeMap),
2411 gIOHibernateWakeMapSize);
2412 if (kIOReturnSuccess == err)
2413 hibernate_newruntime_map(src, gIOHibernateWakeMapSize,
2414 gIOHibernateCurrentHeader->systemTableOffset);
2415 gIOHibernateWakeMap = 0;
2416 gIOHibernateWakeMapSize = 0;
2417 }
2418
2419 uint32_t decoOffset;
2420
2421 clock_get_uptime(&allTime);
2422
2423 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2424 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledAfterSleepState, 0);
2425 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
2426
2427 if (gIOHibernateCurrentHeader->previewSize)
2428 progressZeroPosition = gIOHibernateCurrentHeader->previewSize
2429 + gIOHibernateCurrentHeader->fileExtentMapSize
2430 - sizeof(gIOHibernateCurrentHeader->fileExtentMap)
2431 + ptoa_64(gIOHibernateCurrentHeader->restore1PageCount);
2432
2433 IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size);
2434
2435 if (vars->videoMapSize)
2436 {
2437 lastBlob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount)
2438 / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition);
2439 ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, 0, lastBlob);
2440 }
2441
2442 cryptvars = (kIOHibernateModeEncrypt & gIOHibernateMode) ? &gIOHibernateCryptWakeContext : 0;
2443 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2444 {
2445 cryptvars = &gIOHibernateCryptWakeContext;
2446 bcopy(&gIOHibernateCryptWakeVars->aes_iv[0],
2447 &cryptvars->aes_iv[0],
2448 sizeof(cryptvars->aes_iv));
2449 }
2450
2451 // kick off the read ahead
2452 vars->fileVars->io = false;
2453 vars->fileVars->bufferHalf = 0;
2454 vars->fileVars->bufferLimit = 0;
2455 vars->fileVars->lastRead = 0;
2456 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2457
2458 IOPolledFileRead(vars->fileVars, 0, 0, cryptvars);
2459 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2460 // --
2461
2462 HIBLOG("hibernate_machine_init reading\n");
2463
2464 uint32_t * header = (uint32_t *) src;
2465 sum = 0;
2466
2467 do
2468 {
2469 unsigned int count;
2470 unsigned int page;
2471 uint32_t tag;
2472 vm_offset_t ppnum, compressedSize;
2473
2474 err = IOPolledFileRead(vars->fileVars, src, 8, cryptvars);
2475 if (kIOReturnSuccess != err)
2476 break;
2477
2478 ppnum = header[0];
2479 count = header[1];
2480
2481 // HIBPRINT("(%x, %x)\n", ppnum, count);
2482
2483 if (!count)
2484 break;
2485
2486 for (page = 0; page < count; page++)
2487 {
2488 err = IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars);
2489 if (kIOReturnSuccess != err)
2490 break;
2491
2492 compressedSize = kIOHibernateTagLength & tag;
2493 if (kIOHibernateTagSignature != (tag & ~kIOHibernateTagLength))
2494 {
2495 err = kIOReturnIPCError;
2496 break;
2497 }
2498
2499 if (!compressedSize)
2500 {
2501 ppnum++;
2502 pagesDone++;
2503 continue;
2504 }
2505
2506 err = IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars);
2507 if (kIOReturnSuccess != err)
2508 break;
2509
2510 if (compressedSize < page_size)
2511 {
2512 decoOffset = page_size;
2513 WKdm_decompress((WK_word*) src, (WK_word*) (src + decoOffset), PAGE_SIZE_IN_WORDS);
2514 }
2515 else
2516 decoOffset = 0;
2517
2518 sum += hibernate_sum_page((src + decoOffset), ppnum);
2519
2520 err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size);
2521 if (err)
2522 {
2523 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum, err);
2524 break;
2525 }
2526
2527 ppnum++;
2528 pagesDone++;
2529 pagesRead++;
2530
2531 if (vars->videoMapSize && (0 == (1023 & pagesDone)))
2532 {
2533 blob = ((vars->fileVars->position - progressZeroPosition) * kIOHibernateProgressCount)
2534 / (gIOHibernateCurrentHeader->imageSize - progressZeroPosition);
2535 if (blob != lastBlob)
2536 {
2537 ProgressUpdate(gIOHibernateGraphicsInfo, (uint8_t *) vars->videoMapping, lastBlob, blob);
2538 lastBlob = blob;
2539 }
2540 }
2541
2542 if (0 == (8191 & pagesDone))
2543 {
2544 clock_get_uptime(&endTime);
2545 SUB_ABSOLUTETIME(&endTime, &allTime);
2546 absolutetime_to_nanoseconds(endTime, &nsec);
2547 progressStamp = nsec / 750000000ULL;
2548 if (progressStamp != lastProgressStamp)
2549 {
2550 lastProgressStamp = progressStamp;
2551 HIBPRINT("pages %d (%d%%)\n", pagesDone,
2552 (100 * pagesDone) / gIOHibernateCurrentHeader->pageCount);
2553 }
2554 }
2555 }
2556 }
2557 while (true);
2558
2559 if (kIOReturnSuccess != err)
2560 panic("Hibernate restore error %x", err);
2561
2562 gIOHibernateCurrentHeader->actualImage2Sum = sum;
2563
2564 if (vars->fileVars->io)
2565 (void) IOHibernatePollerIODone(vars->fileVars, false);
2566
2567 err = IOHibernatePollerClose(vars->fileVars, kIOPolledAfterSleepState);
2568
2569 if (vars->videoMapSize)
2570 ProgressUpdate(gIOHibernateGraphicsInfo,
2571 (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);
2572
2573 clock_get_uptime(&endTime);
2574
2575 IOService::getPMRootDomain()->pmStatsRecordEvent(
2576 kIOPMStatsHibernateImageRead | kIOPMStatsEventStartFlag, allTime);
2577 IOService::getPMRootDomain()->pmStatsRecordEvent(
2578 kIOPMStatsHibernateImageRead | kIOPMStatsEventStopFlag, endTime);
2579
2580 SUB_ABSOLUTETIME(&endTime, &allTime);
2581 absolutetime_to_nanoseconds(endTime, &nsec);
2582
2583 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %qd ms\n",
2584 pagesDone, sum, nsec / 1000000ULL);
2585
2586 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 2) | DBG_FUNC_NONE, pagesRead, pagesDone, 0, 0, 0);
2587 }
2588
2589 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */