]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOHibernateIO.cpp
xnu-2782.1.97.tar.gz
[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 segment "__HIB" is written uncompressed to the image. This segment 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 segment "__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 <IOKit/AppleKeyStoreInterface.h>
155 #include <libkern/crypto/aes.h>
156
157 #include <sys/uio.h>
158 #include <sys/conf.h>
159 #include <sys/stat.h>
160 #include <sys/fcntl.h> // (FWRITE, ...)
161 #include <sys/sysctl.h>
162 #include <sys/kdebug.h>
163 #include <stdint.h>
164
165 #include <IOKit/IOHibernatePrivate.h>
166 #include <IOKit/IOPolledInterface.h>
167 #include <IOKit/IONVRAM.h>
168 #include "IOHibernateInternal.h"
169 #include <vm/WKdm_new.h>
170 #include "IOKitKernelInternal.h"
171 #include <pexpert/device_tree.h>
172
173 #include <machine/pal_routines.h>
174 #include <machine/pal_hibernate.h>
175 #include <i386/tsc.h>
176
177 extern "C" addr64_t kvtophys(vm_offset_t va);
178 extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
179
180 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
181
182 #define DISABLE_TRIM 0
183 #define TRIM_DELAY 5000
184
185 extern unsigned int save_kdebug_enable;
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 static uint64_t gIOHibernateCompression = 0x80; // default compression 50%
193
194 static IODTNVRAM * gIOOptionsEntry;
195 static IORegistryEntry * gIOChosenEntry;
196 #if defined(__i386__) || defined(__x86_64__)
197 static const OSSymbol * gIOCreateEFIDevicePathSymbol;
198 static const OSSymbol * gIOHibernateRTCVariablesKey;
199 static const OSSymbol * gIOHibernateBoot0082Key;
200 static const OSSymbol * gIOHibernateBootNextKey;
201 static OSData * gIOHibernateBoot0082Data;
202 static OSData * gIOHibernateBootNextData;
203 static OSObject * gIOHibernateBootNextSave;
204 static struct kern_direct_file_io_ref_t * gDebugImageFileRef;
205 #endif
206
207 static IOLock * gFSLock;
208 static uint32_t gFSState;
209 static IOPolledFileIOVars gFileVars;
210 static IOHibernateVars gIOHibernateVars;
211 static struct kern_direct_file_io_ref_t * gIOHibernateFileRef;
212 static hibernate_cryptvars_t gIOHibernateCryptWakeContext;
213 static hibernate_graphics_t _hibernateGraphics;
214 static hibernate_graphics_t * gIOHibernateGraphicsInfo = &_hibernateGraphics;
215 static hibernate_statistics_t _hibernateStats;
216 static hibernate_statistics_t * gIOHibernateStats = &_hibernateStats;
217
218 enum
219 {
220 kFSIdle = 0,
221 kFSOpening = 2,
222 kFSOpened = 3,
223 kFSTimedOut = 4,
224 };
225
226 static IOReturn IOHibernateDone(IOHibernateVars * vars);
227
228 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
229
230 enum { kXPRamAudioVolume = 8 };
231 enum { kDefaultIOSize = 128 * 1024 };
232 enum { kVideoMapSize = 80 * 1024 * 1024 };
233
234 #ifndef kIOMediaPreferredBlockSizeKey
235 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
236 #endif
237
238 #ifndef kIOBootPathKey
239 #define kIOBootPathKey "bootpath"
240 #endif
241 #ifndef kIOSelectedBootDeviceKey
242 #define kIOSelectedBootDeviceKey "boot-device"
243 #endif
244
245 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
246
247 // copy from phys addr to MD
248
249 static IOReturn
250 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,
251 IOByteCount offset, addr64_t bytes, IOByteCount length)
252 {
253 addr64_t srcAddr = bytes;
254 IOByteCount remaining;
255
256 remaining = length = min(length, md->getLength() - offset);
257 while (remaining) { // (process another target segment?)
258 addr64_t dstAddr64;
259 IOByteCount dstLen;
260
261 dstAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
262 if (!dstAddr64)
263 break;
264
265 // Clip segment length to remaining
266 if (dstLen > remaining)
267 dstLen = remaining;
268
269 #if 1
270 bcopy_phys(srcAddr, dstAddr64, dstLen);
271 #else
272 copypv(srcAddr, dstAddr64, dstLen,
273 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
274 #endif
275 srcAddr += dstLen;
276 offset += dstLen;
277 remaining -= dstLen;
278 }
279
280 assert(!remaining);
281
282 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
283 }
284
285 // copy from MD to phys addr
286
287 static IOReturn
288 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,
289 IOByteCount offset, addr64_t bytes, IOByteCount length)
290 {
291 addr64_t dstAddr = bytes;
292 IOByteCount remaining;
293
294 remaining = length = min(length, md->getLength() - offset);
295 while (remaining) { // (process another target segment?)
296 addr64_t srcAddr64;
297 IOByteCount dstLen;
298
299 srcAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
300 if (!srcAddr64)
301 break;
302
303 // Clip segment length to remaining
304 if (dstLen > remaining)
305 dstLen = remaining;
306
307 #if 1
308 bcopy_phys(srcAddr64, dstAddr, dstLen);
309 #else
310 copypv(srcAddr, dstAddr64, dstLen,
311 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
312 #endif
313 dstAddr += dstLen;
314 offset += dstLen;
315 remaining -= dstLen;
316 }
317
318 assert(!remaining);
319
320 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
321 }
322
323 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
324
325 void
326 hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_t * page_list_wired,
327 vm_offset_t ppnum, vm_offset_t count, uint32_t kind)
328 {
329 count += ppnum;
330 switch (kind)
331 {
332 case kIOHibernatePageStateUnwiredSave:
333 // unwired save
334 for (; ppnum < count; ppnum++)
335 {
336 hibernate_page_bitset(page_list, FALSE, ppnum);
337 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
338 }
339 break;
340 case kIOHibernatePageStateWiredSave:
341 // wired save
342 for (; ppnum < count; ppnum++)
343 {
344 hibernate_page_bitset(page_list, FALSE, ppnum);
345 hibernate_page_bitset(page_list_wired, FALSE, ppnum);
346 }
347 break;
348 case kIOHibernatePageStateFree:
349 // free page
350 for (; ppnum < count; ppnum++)
351 {
352 hibernate_page_bitset(page_list, TRUE, ppnum);
353 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
354 }
355 break;
356 default:
357 panic("hibernate_set_page_state");
358 }
359 }
360
361 static vm_offset_t
362 hibernate_page_list_iterate(hibernate_page_list_t * list, vm_offset_t * pPage)
363 {
364 uint32_t page = *pPage;
365 uint32_t count;
366 hibernate_bitmap_t * bitmap;
367
368 while ((bitmap = hibernate_page_bitmap_pin(list, &page)))
369 {
370 count = hibernate_page_bitmap_count(bitmap, TRUE, page);
371 if (!count)
372 break;
373 page += count;
374 if (page <= bitmap->last_page)
375 break;
376 }
377
378 *pPage = page;
379 if (bitmap)
380 count = hibernate_page_bitmap_count(bitmap, FALSE, page);
381 else
382 count = 0;
383
384 return (count);
385 }
386
387 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
388
389 static IOReturn
390 IOHibernatePollerProbe(IOPolledFileIOVars * vars, IOService * target)
391 {
392 IOReturn err = kIOReturnError;
393 int32_t idx;
394 IOPolledInterface * poller;
395
396 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
397 {
398 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
399 err = poller->probe(target);
400 if (err)
401 {
402 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx, err);
403 break;
404 }
405 }
406
407 return (err);
408 }
409
410 static IOReturn
411 IOHibernatePollerOpen(IOPolledFileIOVars * vars, uint32_t state, IOMemoryDescriptor * md)
412 {
413 IOReturn err = kIOReturnError;
414 int32_t idx;
415 IOPolledInterface * poller;
416
417 for (idx = vars->pollers->getCount() - 1; idx >= 0; idx--)
418 {
419 poller = (IOPolledInterface *) vars->pollers->getObject(idx);
420 err = poller->open(state, md);
421 if (err)
422 {
423 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx, err);
424 break;
425 }
426 }
427
428 return (err);
429 }
430
431 static IOReturn
432 IOHibernatePollerClose(IOPolledFileIOVars * vars, uint32_t state)
433 {
434 IOReturn err = kIOReturnError;
435 int32_t idx;
436 IOPolledInterface * poller;
437
438 for (idx = 0;
439 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
440 idx++)
441 {
442 err = poller->close(state);
443 if (err)
444 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx, err);
445 }
446
447 return (err);
448 }
449
450 static void
451 IOHibernatePollerIOComplete(void * target,
452 void * parameter,
453 IOReturn status,
454 UInt64 actualByteCount)
455 {
456 IOPolledFileIOVars * vars = (IOPolledFileIOVars *) parameter;
457
458 vars->ioStatus = status;
459 }
460
461 static IOReturn
462 IOHibernatePollerIO(IOPolledFileIOVars * vars,
463 uint32_t operation, uint32_t bufferOffset,
464 uint64_t deviceOffset, uint64_t length)
465 {
466
467 IOReturn err = kIOReturnError;
468 IOPolledInterface * poller;
469 IOPolledCompletion completion;
470
471 completion.target = 0;
472 completion.action = &IOHibernatePollerIOComplete;
473 completion.parameter = vars;
474
475 vars->ioStatus = -1;
476
477 poller = (IOPolledInterface *) vars->pollers->getObject(0);
478 err = poller->startIO(operation, bufferOffset, deviceOffset + vars->block0, length, completion);
479 if (err)
480 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err);
481
482 return (err);
483 }
484
485 static IOReturn
486 IOHibernatePollerIODone(IOPolledFileIOVars * vars, bool abortable)
487 {
488 IOReturn err = kIOReturnSuccess;
489 int32_t idx = 0;
490 IOPolledInterface * poller;
491
492 while (-1 == vars->ioStatus)
493 {
494 for (idx = 0;
495 (poller = (IOPolledInterface *) vars->pollers->getObject(idx));
496 idx++)
497 {
498 IOReturn newErr;
499 newErr = poller->checkForWork();
500 if ((newErr == kIOReturnAborted) && !abortable)
501 newErr = kIOReturnSuccess;
502 if (kIOReturnSuccess == err)
503 err = newErr;
504 }
505 }
506
507 if ((kIOReturnSuccess == err) && abortable && hibernate_should_abort())
508 {
509 err = kIOReturnAborted;
510 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
511 }
512
513 if (err)
514 {
515 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx, err);
516 }
517 else
518 {
519 err = vars->ioStatus;
520 if (kIOReturnSuccess != err)
521 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err);
522 }
523
524 return (err);
525 }
526
527 IOReturn
528 IOPolledInterface::checkAllForWork(void)
529 {
530 IOReturn err = kIOReturnNotReady;
531 int32_t idx;
532 IOPolledInterface * poller;
533
534 IOHibernateVars * vars = &gIOHibernateVars;
535
536 if (!vars->fileVars || !vars->fileVars->pollers)
537 return (err);
538
539 for (idx = 0;
540 (poller = (IOPolledInterface *) vars->fileVars->pollers->getObject(idx));
541 idx++)
542 {
543 err = poller->checkForWork();
544 if (err)
545 HIBLOG("IOPolledInterface::checkAllForWork[%d] 0x%x\n", idx, err);
546 }
547
548 return (err);
549 }
550
551 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
552
553 struct _OpenFileContext
554 {
555 OSData * extents;
556 uint64_t size;
557 };
558
559 static void
560 file_extent_callback(void * ref, uint64_t start, uint64_t length)
561 {
562 _OpenFileContext * ctx = (_OpenFileContext *) ref;
563 IOPolledFileExtent extent;
564
565 extent.start = start;
566 extent.length = length;
567
568 HIBLOG("[0x%qx, 0x%qx]\n", start, length);
569
570 ctx->extents->appendBytes(&extent, sizeof(extent));
571 ctx->size += length;
572 }
573
574 static IOService *
575 IOCopyMediaForDev(dev_t device)
576 {
577 OSDictionary * matching;
578 OSNumber * num;
579 OSIterator * iter;
580 IOService * result = 0;
581
582 matching = IOService::serviceMatching("IOMedia");
583 if (!matching)
584 return (0);
585 do
586 {
587 num = OSNumber::withNumber(major(device), 32);
588 if (!num)
589 break;
590 matching->setObject(kIOBSDMajorKey, num);
591 num->release();
592 num = OSNumber::withNumber(minor(device), 32);
593 if (!num)
594 break;
595 matching->setObject(kIOBSDMinorKey, num);
596 num->release();
597 if (!num)
598 break;
599 iter = IOService::getMatchingServices(matching);
600 if (iter)
601 {
602 result = (IOService *) iter->getNextObject();
603 result->retain();
604 iter->release();
605 }
606 }
607 while (false);
608 matching->release();
609
610 return (result);
611 }
612
613 /*
614 * Writes header to disk with signature, block size and file extents data.
615 * If there are more than 2 extents, then they are written on second block.
616 */
617 static IOReturn
618 WriteExtentsToFile(struct kern_direct_file_io_ref_t * fileRef,
619 uint32_t signature, uint32_t blockSize,
620 IOPolledFileExtent *fileExtents,
621 IOByteCount size)
622 {
623 IOHibernateImageHeader hdr;
624 IOItemCount count;
625 IOReturn err = kIOReturnSuccess;
626 int rc;
627
628 memset(&hdr, 0, sizeof(IOHibernateImageHeader));
629 count = size;
630 if (count > sizeof(hdr.fileExtentMap))
631 {
632 hdr.fileExtentMapSize = count;
633 count = sizeof(hdr.fileExtentMap);
634 }
635 else
636 hdr.fileExtentMapSize = sizeof(hdr.fileExtentMap);
637
638 bcopy(fileExtents, &hdr.fileExtentMap[0], count);
639
640 // copy file block extent list if larger than header
641 if (hdr.fileExtentMapSize > sizeof(hdr.fileExtentMap))
642 {
643 count = hdr.fileExtentMapSize - sizeof(hdr.fileExtentMap);
644 rc = kern_write_file(fileRef, blockSize,
645 (caddr_t)(((uint8_t *)fileExtents) + sizeof(hdr.fileExtentMap)),
646 count, IO_SKIP_ENCRYPTION);
647 if (rc != 0) {
648 HIBLOG("kern_write_file returned %d\n", rc);
649 err = kIOReturnIOError;
650 goto exit;
651 }
652 }
653 hdr.signature = signature;
654 hdr.deviceBlockSize = blockSize;
655
656 rc = kern_write_file(fileRef, 0, (char *)&hdr, sizeof(hdr), IO_SKIP_ENCRYPTION);
657 if (rc != 0) {
658 HIBLOG("kern_write_file returned %d\n", rc);
659 err = kIOReturnIOError;
660 goto exit;
661 }
662
663 exit:
664 return err;
665 }
666
667 static IOReturn
668 GetImageBlockSize(IOService *part, OSArray *pollers, IOByteCount *blockSize)
669 {
670 IOService * service;
671 IORegistryEntry * next;
672 IORegistryEntry * child;
673
674 IOReturn err = kIOReturnSuccess;
675
676
677 next = part;
678 do
679 {
680 IOPolledInterface * poller;
681 OSObject * obj;
682 OSNumber * num;
683
684 obj = next->getProperty(kIOPolledInterfaceSupportKey);
685 if (kOSBooleanFalse == obj)
686 {
687 pollers->flushCollection();
688 break;
689 }
690 else if ((poller = OSDynamicCast(IOPolledInterface, obj)))
691 pollers->setObject(poller);
692
693 if ((service = OSDynamicCast(IOService, next))
694 && service->getDeviceMemory()
695 && !pollers->getCount()) break;
696
697 if ((num = OSDynamicCast(OSNumber, next->getProperty(kIOMediaPreferredBlockSizeKey))))
698 *blockSize = num->unsigned32BitValue();
699 child = next;
700 }
701 while ((next = child->getParentEntry(gIOServicePlane))
702 && child->isParent(next, gIOServicePlane, true));
703
704 if (*blockSize < 4096) *blockSize = 4096;
705
706 if (!pollers->getCount())
707 err = kIOReturnUnsupported;
708
709 return err;
710 }
711
712 IOReturn
713 IOPolledFileOpen( const char * filename, uint64_t setFileSize,
714 IOBufferMemoryDescriptor * ioBuffer,
715 IOPolledFileIOVars ** fileVars, OSData ** fileExtents,
716 OSData ** imagePath, uint8_t * volumeCryptKey)
717 {
718 IOReturn err = kIOReturnSuccess;
719 IOPolledFileIOVars * vars;
720 _OpenFileContext ctx;
721 OSData * extentsData;
722 IOService * part = 0;
723 OSString * keyUUID = 0;
724 OSString * keyStoreUUID = 0;
725 dev_t block_dev;
726 dev_t hibernate_image_dev;
727 uint64_t maxiobytes;
728 AbsoluteTime startTime, endTime;
729 uint64_t nsec;
730 caddr_t write_file_addr = NULL;
731 vm_size_t write_file_len = 0;
732
733 vars = IONew(IOPolledFileIOVars, 1);
734 if (!vars) return (kIOReturnNoMemory);
735 bzero(vars, sizeof(*vars));
736
737 do
738 {
739 vars->io = false;
740 vars->buffer = (uint8_t *) ioBuffer->getBytesNoCopy();
741 vars->bufferHalf = 0;
742 vars->bufferOffset = 0;
743 vars->bufferSize = ioBuffer->getLength() >> 1;
744
745 extentsData = OSData::withCapacity(32);
746 ctx.extents = extentsData;
747 ctx.size = 0;
748 clock_get_uptime(&startTime);
749 if (!gDebugImageFileRef)
750 {
751 // Avoid writing the header if it is written when file is prep'd for debug data
752 // Image is locked during prep for debug data. So, write may fail.
753 write_file_addr = (caddr_t)gIOHibernateCurrentHeader;
754 write_file_len = sizeof(IOHibernateImageHeader);
755 }
756 vars->fileRef = kern_open_file_for_direct_io(filename,
757 true,
758 &file_extent_callback, &ctx,
759 setFileSize,
760 // write file:
761 0, write_file_addr,
762 write_file_len,
763 // results
764 &block_dev,
765 &hibernate_image_dev,
766 &vars->block0,
767 &maxiobytes,
768 &vars->flags);
769 #if 0
770 uint32_t msDelay = (131071 & random());
771 HIBLOG("sleep %d\n", msDelay);
772 IOSleep(msDelay);
773 #endif
774 clock_get_uptime(&endTime);
775 SUB_ABSOLUTETIME(&endTime, &startTime);
776 absolutetime_to_nanoseconds(endTime, &nsec);
777
778 if (!vars->fileRef) err = kIOReturnNoSpace;
779
780 IOLockLock(gFSLock);
781 if (kFSOpening != gFSState) err = kIOReturnTimeout;
782 IOLockUnlock(gFSLock);
783
784 HIBLOG("kern_open_file_for_direct_io(%d) took %qd ms\n", err, nsec / 1000000ULL);
785 if (kIOReturnSuccess != err) break;
786
787 if (kIOHibernateModeSSDInvert & gIOHibernateMode)
788 vars->flags ^= kIOHibernateOptionSSD;
789
790 HIBLOG("Opened file %s, size %qd, partition base 0x%qx, maxio %qx ssd %d\n", filename, ctx.size,
791 vars->block0, maxiobytes, kIOHibernateOptionSSD & vars->flags);
792 if (ctx.size < 1*1024*1024) // check against image size estimate!
793 {
794 err = kIOReturnNoSpace;
795 break;
796 }
797
798 vars->fileSize = ctx.size;
799 if (maxiobytes < vars->bufferSize) vars->bufferSize = maxiobytes;
800
801 vars->extentMap = (IOPolledFileExtent *) extentsData->getBytesNoCopy();
802
803 part = IOCopyMediaForDev(block_dev);
804 if (!part)
805 {
806 err = kIOReturnNotFound;
807 break;
808 }
809 err = part->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID, false,
810 (void *) &keyUUID, (void *) &keyStoreUUID, NULL, NULL);
811 if ((kIOReturnSuccess == err) && keyUUID && keyStoreUUID)
812 {
813 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
814 uuid_t volumeKeyUUID;
815 aks_volume_key_t vek;
816 static IOService * sKeyStore;
817 static const OSSymbol * sAKSGetKey;
818
819 if (!sAKSGetKey)
820 sAKSGetKey = OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY);
821 if (!sKeyStore)
822 sKeyStore = (IOService *) IORegistryEntry::fromPath(AKS_SERVICE_PATH, gIOServicePlane);
823 if (sKeyStore)
824 err = uuid_parse(keyStoreUUID->getCStringNoCopy(), volumeKeyUUID);
825 else
826 err = kIOReturnNoResources;
827 if (kIOReturnSuccess == err)
828 err = sKeyStore->callPlatformFunction(sAKSGetKey, true, volumeKeyUUID, &vek, NULL, NULL);
829 if (kIOReturnSuccess != err)
830 IOLog("volume key err 0x%x\n", err);
831 else
832 {
833 size_t bytes = (kIOHibernateAESKeySize / 8);
834 if (vek.key.keybytecount < bytes)
835 bytes = vek.key.keybytecount;
836 bcopy(&vek.key.keybytes[0], volumeCryptKey, bytes);
837 }
838 bzero(&vek, sizeof(vek));
839 }
840 part->release();
841
842 part = IOCopyMediaForDev(hibernate_image_dev);
843 if (!part)
844 {
845 err = kIOReturnNotFound;
846 break;
847 }
848
849 vars->pollers = OSArray::withCapacity(4);
850 if (!vars->pollers)
851 {
852 err = kIOReturnNoMemory;
853 break;
854 }
855
856 err = GetImageBlockSize(part, vars->pollers, &vars->blockSize);
857
858 HIBLOG("hibernate image major %d, minor %d, blocksize %ld, pollers %d\n",
859 major(hibernate_image_dev), minor(hibernate_image_dev), (long)vars->blockSize,
860 vars->pollers->getCount());
861
862 if (err != kIOReturnSuccess)
863 break;
864
865 IORegistryEntry * next;
866 OSData * data;
867 if (vars->blockSize < sizeof(IOHibernateImageHeader))
868 {
869 err = kIOReturnError;
870 continue;
871 }
872
873 err = IOHibernatePollerProbe(vars, (IOService *) part);
874 if (kIOReturnSuccess != err) break;
875
876 err = IOHibernatePollerOpen(vars, kIOPolledPreflightState, ioBuffer);
877 if (kIOReturnSuccess != err) break;
878
879 vars->media = part;
880 next = part;
881 while (next)
882 {
883 next->setProperty(kIOPolledInterfaceActiveKey, kOSBooleanTrue);
884 next = next->getParentEntry(gIOServicePlane);
885 }
886
887 *fileVars = vars;
888 *fileExtents = extentsData;
889
890 // make imagePath
891
892 if ((extentsData->getLength() >= sizeof(IOPolledFileExtent)))
893 {
894 char str2[24 + sizeof(uuid_string_t) + 2];
895
896 #if defined(__i386__) || defined(__x86_64__)
897 if (!gIOCreateEFIDevicePathSymbol)
898 gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath");
899
900 if (keyUUID)
901 snprintf(str2, sizeof(str2), "%qx:%s",
902 vars->extentMap[0].start, keyUUID->getCStringNoCopy());
903 else
904 snprintf(str2, sizeof(str2), "%qx", vars->extentMap[0].start);
905
906 err = IOService::getPlatform()->callPlatformFunction(
907 gIOCreateEFIDevicePathSymbol, false,
908 (void *) part, (void *) str2,
909 (void *) (uintptr_t) true, (void *) &data);
910 #else
911 char str1[256];
912 int len = sizeof(str1);
913
914 if (!part->getPath(str1, &len, gIODTPlane))
915 err = kIOReturnNotFound;
916 else
917 {
918 snprintf(str2, sizeof(str2), ",%qx", vars->extentMap[0].start);
919 // (strip the plane name)
920 char * tail = strchr(str1, ':');
921 if (!tail)
922 tail = str1 - 1;
923 data = OSData::withBytes(tail + 1, strlen(tail + 1));
924 data->appendBytes(str2, strlen(str2));
925 }
926 #endif
927 if (kIOReturnSuccess == err)
928 *imagePath = data;
929 else
930 HIBLOG("error 0x%x getting path\n", err);
931 }
932 }
933 while (false);
934
935 if (kIOReturnSuccess != err)
936 {
937 HIBLOG("error 0x%x opening hibernation file\n", err);
938 if (vars->fileRef)
939 {
940 kern_close_file_for_direct_io(vars->fileRef, 0, 0, 0, 0, 0);
941 vars->fileRef = NULL;
942 }
943 }
944 else
945 {
946 WriteExtentsToFile(vars->fileRef, kIOHibernateHeaderOpenSignature, vars->blockSize,
947 (IOPolledFileExtent *)extentsData->getBytesNoCopy(),
948 extentsData->getLength());
949 }
950
951 if (part)
952 part->release();
953
954 return (err);
955 }
956
957 IOReturn
958 IOPolledFileClose( IOPolledFileIOVars * vars )
959 {
960 if (vars->pollers)
961 {
962 IOHibernatePollerClose(vars, kIOPolledPostflightState);
963 vars->pollers->release();
964 }
965
966 bzero(vars, sizeof(IOPolledFileIOVars));
967
968 return (kIOReturnSuccess);
969 }
970
971 static IOReturn
972 IOPolledFileSeek(IOPolledFileIOVars * vars, uint64_t position)
973 {
974 IOPolledFileExtent * extentMap;
975
976 extentMap = vars->extentMap;
977
978 vars->position = position;
979
980 while (position >= extentMap->length)
981 {
982 position -= extentMap->length;
983 extentMap++;
984 }
985
986 vars->currentExtent = extentMap;
987 vars->extentRemaining = extentMap->length - position;
988 vars->extentPosition = vars->position - position;
989
990 if (vars->bufferSize <= vars->extentRemaining)
991 vars->bufferLimit = vars->bufferSize;
992 else
993 vars->bufferLimit = vars->extentRemaining;
994
995 return (kIOReturnSuccess);
996 }
997
998 static IOReturn
999 IOPolledFileWrite(IOPolledFileIOVars * vars,
1000 const uint8_t * bytes, IOByteCount size,
1001 hibernate_cryptvars_t * cryptvars)
1002 {
1003 IOReturn err = kIOReturnSuccess;
1004 IOByteCount copy;
1005 bool flush = false;
1006
1007 do
1008 {
1009 if (!bytes && !size)
1010 {
1011 // seek to end of block & flush
1012 size = vars->position & (vars->blockSize - 1);
1013 if (size)
1014 size = vars->blockSize - size;
1015 flush = true;
1016 // use some garbage for the fill
1017 bytes = vars->buffer + vars->bufferOffset;
1018 }
1019
1020 copy = vars->bufferLimit - vars->bufferOffset;
1021 if (copy > size)
1022 copy = size;
1023 else
1024 flush = true;
1025
1026 if (bytes)
1027 {
1028 bcopy(bytes, vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
1029 bytes += copy;
1030 }
1031 else
1032 bzero(vars->buffer + vars->bufferHalf + vars->bufferOffset, copy);
1033
1034 size -= copy;
1035 vars->bufferOffset += copy;
1036 vars->position += copy;
1037
1038 if (flush && vars->bufferOffset)
1039 {
1040 uint64_t offset = (vars->position - vars->bufferOffset
1041 - vars->extentPosition + vars->currentExtent->start);
1042 uint32_t length = (vars->bufferOffset);
1043
1044 #if CRYPTO
1045 if (cryptvars && vars->encryptStart
1046 && (vars->position > vars->encryptStart)
1047 && ((vars->position - length) < vars->encryptEnd))
1048 {
1049 AbsoluteTime startTime, endTime;
1050
1051 uint64_t encryptLen, encryptStart;
1052 encryptLen = vars->position - vars->encryptStart;
1053 if (encryptLen > length)
1054 encryptLen = length;
1055 encryptStart = length - encryptLen;
1056 if (vars->position > vars->encryptEnd)
1057 encryptLen -= (vars->position - vars->encryptEnd);
1058
1059 clock_get_uptime(&startTime);
1060
1061 // encrypt the buffer
1062 aes_encrypt_cbc(vars->buffer + vars->bufferHalf + encryptStart,
1063 &cryptvars->aes_iv[0],
1064 encryptLen / AES_BLOCK_SIZE,
1065 vars->buffer + vars->bufferHalf + encryptStart,
1066 &cryptvars->ctx.encrypt);
1067
1068 clock_get_uptime(&endTime);
1069 ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
1070 SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
1071 vars->cryptBytes += encryptLen;
1072
1073 // save initial vector for following encrypts
1074 bcopy(vars->buffer + vars->bufferHalf + encryptStart + encryptLen - AES_BLOCK_SIZE,
1075 &cryptvars->aes_iv[0],
1076 AES_BLOCK_SIZE);
1077 }
1078 #endif /* CRYPTO */
1079
1080 if (vars->io)
1081 {
1082 err = IOHibernatePollerIODone(vars, true);
1083 if (kIOReturnSuccess != err)
1084 break;
1085 }
1086
1087 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
1088 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
1089
1090 err = IOHibernatePollerIO(vars, kIOPolledWrite, vars->bufferHalf, offset, length);
1091 if (kIOReturnSuccess != err)
1092 break;
1093 vars->io = true;
1094
1095 vars->extentRemaining -= vars->bufferOffset;
1096 if (!vars->extentRemaining)
1097 {
1098 vars->currentExtent++;
1099 vars->extentRemaining = vars->currentExtent->length;
1100 vars->extentPosition = vars->position;
1101 if (!vars->extentRemaining)
1102 {
1103 err = kIOReturnOverrun;
1104 break;
1105 }
1106 }
1107
1108 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
1109 vars->bufferOffset = 0;
1110 if (vars->bufferSize <= vars->extentRemaining)
1111 vars->bufferLimit = vars->bufferSize;
1112 else
1113 vars->bufferLimit = vars->extentRemaining;
1114
1115 flush = false;
1116 }
1117 }
1118 while (size);
1119
1120 return (err);
1121 }
1122
1123 static IOReturn
1124 IOPolledFileRead(IOPolledFileIOVars * vars,
1125 uint8_t * bytes, IOByteCount size,
1126 hibernate_cryptvars_t * cryptvars)
1127 {
1128 IOReturn err = kIOReturnSuccess;
1129 IOByteCount copy;
1130
1131 // bytesWritten += size;
1132
1133 do
1134 {
1135 copy = vars->bufferLimit - vars->bufferOffset;
1136 if (copy > size)
1137 copy = size;
1138
1139 if (bytes)
1140 {
1141 bcopy(vars->buffer + vars->bufferHalf + vars->bufferOffset, bytes, copy);
1142 bytes += copy;
1143 }
1144 size -= copy;
1145 vars->bufferOffset += copy;
1146 // vars->position += copy;
1147
1148 if ((vars->bufferOffset == vars->bufferLimit) && (vars->position < vars->readEnd))
1149 {
1150 if (vars->io)
1151 {
1152 err = IOHibernatePollerIODone(vars, false);
1153 if (kIOReturnSuccess != err)
1154 break;
1155 }
1156 else
1157 cryptvars = 0;
1158
1159 if (vars->position & (vars->blockSize - 1)) HIBLOG("misaligned file pos %qx\n", vars->position);
1160
1161 vars->position += vars->lastRead;
1162 vars->extentRemaining -= vars->lastRead;
1163 vars->bufferLimit = vars->lastRead;
1164
1165 if (!vars->extentRemaining)
1166 {
1167 vars->currentExtent++;
1168 vars->extentRemaining = vars->currentExtent->length;
1169 vars->extentPosition = vars->position;
1170 if (!vars->extentRemaining)
1171 {
1172 err = kIOReturnOverrun;
1173 break;
1174 }
1175 }
1176
1177 uint64_t length;
1178 uint64_t lastReadLength = vars->lastRead;
1179 uint64_t offset = (vars->position
1180 - vars->extentPosition + vars->currentExtent->start);
1181 if (vars->extentRemaining <= vars->bufferSize)
1182 length = vars->extentRemaining;
1183 else
1184 length = vars->bufferSize;
1185 if ((length + vars->position) > vars->readEnd)
1186 length = vars->readEnd - vars->position;
1187
1188 vars->lastRead = length;
1189 if (length)
1190 {
1191 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1192 err = IOHibernatePollerIO(vars, kIOPolledRead, vars->bufferHalf, offset, length);
1193 if (kIOReturnSuccess != err)
1194 break;
1195 vars->io = true;
1196 }
1197
1198 vars->bufferHalf = vars->bufferHalf ? 0 : vars->bufferSize;
1199 vars->bufferOffset = 0;
1200
1201 #if CRYPTO
1202 if (cryptvars)
1203 {
1204 uint8_t thisVector[AES_BLOCK_SIZE];
1205 AbsoluteTime startTime, endTime;
1206
1207 // save initial vector for following decrypts
1208 bcopy(&cryptvars->aes_iv[0], &thisVector[0], AES_BLOCK_SIZE);
1209 bcopy(vars->buffer + vars->bufferHalf + lastReadLength - AES_BLOCK_SIZE,
1210 &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1211
1212 // decrypt the buffer
1213 clock_get_uptime(&startTime);
1214
1215 aes_decrypt_cbc(vars->buffer + vars->bufferHalf,
1216 &thisVector[0],
1217 lastReadLength / AES_BLOCK_SIZE,
1218 vars->buffer + vars->bufferHalf,
1219 &cryptvars->ctx.decrypt);
1220
1221 clock_get_uptime(&endTime);
1222 ADD_ABSOLUTETIME(&vars->cryptTime, &endTime);
1223 SUB_ABSOLUTETIME(&vars->cryptTime, &startTime);
1224 vars->cryptBytes += lastReadLength;
1225 }
1226 #endif /* CRYPTO */
1227 }
1228 }
1229 while (size);
1230
1231 return (err);
1232 }
1233
1234 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1235
1236 #if HIBERNATION
1237 IOReturn
1238 IOHibernateOpenForDebugData( )
1239 {
1240 dev_t image_dev;
1241 OSData *extentsData = NULL;
1242 OSObject *obj;
1243 OSString *str;
1244 IOByteCount blockSize = 0;
1245 IOByteCount size;
1246 IOService * part = 0;
1247 OSData * data = NULL;
1248
1249 IOPolledFileExtent * fileExtents;
1250 IOReturn err = kIOReturnSuccess;
1251 IORegistryEntry * regEntry;
1252 OSArray * pollers = NULL;
1253
1254 _OpenFileContext ctx;
1255
1256 if (gDebugImageFileRef != NULL)
1257 return kIOReturnError;
1258
1259 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey)))
1260 {
1261 if ((str = OSDynamicCast(OSString, obj)))
1262 strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
1263 sizeof(gIOHibernateFilename));
1264 obj->release();
1265 }
1266
1267 if (!gIOHibernateFilename[0]) {
1268 HIBLOG("Failed to get hibernate image filename\n");
1269 return (kIOReturnUnsupported);
1270 }
1271
1272 extentsData = OSData::withCapacity(32);
1273 ctx.extents = extentsData;
1274 ctx.size = 0;
1275
1276 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1277 gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
1278 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1279
1280 gDebugImageFileRef = kern_open_file_for_direct_io(gIOHibernateFilename,
1281 false,
1282 &file_extent_callback, &ctx,
1283 0, 0,
1284 (caddr_t)gIOHibernateCurrentHeader,
1285 sizeof(IOHibernateImageHeader),
1286 NULL, &image_dev, NULL, NULL, NULL);
1287
1288 if (gDebugImageFileRef == NULL)
1289 {
1290 HIBLOG("Failed to open the file \n");
1291 err = kIOReturnError;
1292 goto exit;
1293 }
1294 fileExtents = (IOPolledFileExtent *)extentsData->getBytesNoCopy();
1295 size = extentsData->getLength();
1296
1297 part = IOCopyMediaForDev(image_dev);
1298 if (!part)
1299 {
1300 HIBLOG("Failed to get the media device\n");
1301 err = kIOReturnNotFound;
1302 goto exit;
1303 }
1304
1305
1306 pollers = OSArray::withCapacity(4);
1307 if (!pollers)
1308 {
1309 err = kIOReturnNoMemory;
1310 goto exit;
1311 }
1312
1313 err = GetImageBlockSize(part, pollers, &blockSize);
1314 if (err != kIOReturnSuccess)
1315 {
1316 HIBLOG("Failed to get block size\n");
1317 goto exit;
1318 }
1319 if (blockSize < sizeof(IOHibernateImageHeader))
1320 {
1321 HIBLOG("block size %llu is less than the size of the header\n", blockSize);
1322 err = kIOReturnError;
1323 goto exit;
1324 }
1325
1326 WriteExtentsToFile(gDebugImageFileRef, kIOHibernateHeaderOpenSignature,
1327 blockSize, fileExtents, size);
1328
1329 char str2[24 + sizeof(uuid_string_t) + 2];
1330
1331 if (!gIOCreateEFIDevicePathSymbol)
1332 gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath");
1333
1334 snprintf(str2, sizeof(str2), "%qx", fileExtents[0].start);
1335
1336 err = IOService::getPlatform()->callPlatformFunction(
1337 gIOCreateEFIDevicePathSymbol, false,
1338 (void *) part, (void *) str2,
1339 (void *) (uintptr_t) true, (void *) &data);
1340
1341 if (!gIOOptionsEntry)
1342 {
1343 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1344 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
1345 if (regEntry && !gIOOptionsEntry)
1346 regEntry->release();
1347 }
1348 if (gIOOptionsEntry)
1349 {
1350 const OSSymbol * sym;
1351
1352 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1353 if (sym)
1354 {
1355 gIOOptionsEntry->setProperty(sym, data);
1356 sym->release();
1357 }
1358 }
1359
1360
1361 exit:
1362
1363 if ( (err != kIOReturnSuccess) && gDebugImageFileRef) {
1364 kern_close_file_for_direct_io(gDebugImageFileRef, 0, 0, 0, 0, 0);
1365 gDebugImageFileRef = NULL;
1366 }
1367 if (extentsData) extentsData->release();
1368 if (part) part->release();
1369 if (pollers) pollers->release();
1370 if (data) data->release();
1371
1372 return err;
1373 }
1374 #endif
1375
1376 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1377
1378 IOReturn
1379 IOHibernateSystemSleep(void)
1380 {
1381 IOReturn err;
1382 OSData * data;
1383 OSObject * obj;
1384 OSString * str;
1385 OSNumber * num;
1386 bool dsSSD, vmflush;
1387 IOHibernateVars * vars;
1388
1389 gIOHibernateState = kIOHibernateStateInactive;
1390
1391 if (!gIOChosenEntry)
1392 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
1393
1394 gIOHibernateDebugFlags = 0;
1395 if (kIOLogHibernate & gIOKitDebug)
1396 gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
1397
1398 if (IOService::getPMRootDomain()->getHibernateSettings(
1399 &gIOHibernateMode, &gIOHibernateFreeRatio, &gIOHibernateFreeTime))
1400 {
1401 if (kIOHibernateModeSleep & gIOHibernateMode)
1402 // default to discard clean for safe sleep
1403 gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
1404 | kIOHibernateModeDiscardCleanActive);
1405 }
1406
1407 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey)))
1408 {
1409 if ((str = OSDynamicCast(OSString, obj)))
1410 strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
1411 sizeof(gIOHibernateFilename));
1412 obj->release();
1413 }
1414
1415 if (!gIOHibernateMode || !gIOHibernateFilename[0])
1416 return (kIOReturnUnsupported);
1417
1418 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
1419
1420 vars = IONew(IOHibernateVars, 1);
1421 if (!vars) return (kIOReturnNoMemory);
1422 bzero(vars, sizeof(*vars));
1423
1424 IOLockLock(gFSLock);
1425 if (kFSIdle != gFSState)
1426 {
1427 HIBLOG("hibernate file busy\n");
1428 IOLockUnlock(gFSLock);
1429 IODelete(vars, IOHibernateVars, 1);
1430 return (kIOReturnBusy);
1431 }
1432 gFSState = kFSOpening;
1433 IOLockUnlock(gFSLock);
1434
1435 do
1436 {
1437 vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1438 2 * page_size + WKdm_SCRATCH_BUF_SIZE, page_size);
1439 vars->ioBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1440 2 * kDefaultIOSize, page_size);
1441
1442 vars->handoffBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
1443 ptoa_64(gIOHibernateHandoffPageCount), page_size);
1444
1445 if (!vars->srcBuffer || !vars->ioBuffer || !vars->handoffBuffer)
1446 {
1447 err = kIOReturnNoMemory;
1448 break;
1449 }
1450
1451 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey)))
1452 {
1453 if ((num = OSDynamicCast(OSNumber, obj))) vars->fileMinSize = num->unsigned64BitValue();
1454 obj->release();
1455 }
1456 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey)))
1457 {
1458 if ((num = OSDynamicCast(OSNumber, obj))) vars->fileMaxSize = num->unsigned64BitValue();
1459 obj->release();
1460 }
1461
1462 boolean_t encryptedswap = true;
1463 uint32_t pageCount;
1464 AbsoluteTime startTime, endTime;
1465 uint64_t nsec;
1466
1467 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
1468 gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
1469 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1470
1471 vmflush = (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey));
1472 uint64_t setFileSize = 0;
1473 err = hibernate_alloc_page_lists(&vars->page_list,
1474 &vars->page_list_wired,
1475 &vars->page_list_pal);
1476 if (KERN_SUCCESS != err)
1477 break;
1478
1479 if (vars->fileMinSize || (kIOHibernateModeFileResize & gIOHibernateMode))
1480 {
1481 hibernate_page_list_setall(vars->page_list,
1482 vars->page_list_wired,
1483 vars->page_list_pal,
1484 true /* preflight */,
1485 vmflush /* discard */,
1486 &pageCount);
1487 PE_Video consoleInfo;
1488 bzero(&consoleInfo, sizeof(consoleInfo));
1489 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
1490
1491 // estimate: 6% increase in pages compressed
1492 // screen preview 2 images compressed 0%
1493 setFileSize = ((ptoa_64((106 * pageCount) / 100) * gIOHibernateCompression) >> 8)
1494 + vars->page_list->list_size
1495 + (consoleInfo.v_width * consoleInfo.v_height * 8);
1496 enum { setFileRound = 1024*1024ULL };
1497 setFileSize = ((setFileSize + setFileRound) & ~(setFileRound - 1));
1498
1499 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
1500 pageCount, (100ULL * gIOHibernateCompression) >> 8,
1501 setFileSize, vars->fileMinSize);
1502
1503 if (!(kIOHibernateModeFileResize & gIOHibernateMode)
1504 && (setFileSize < vars->fileMinSize))
1505 {
1506 setFileSize = vars->fileMinSize;
1507 }
1508 }
1509
1510 // open & invalidate the image file
1511
1512 if (gDebugImageFileRef) {
1513 kern_close_file_for_direct_io(gDebugImageFileRef, 0, 0, 0, 0, 0);
1514 gDebugImageFileRef = NULL;
1515 }
1516
1517 err = IOPolledFileOpen(gIOHibernateFilename, setFileSize, vars->ioBuffer,
1518 &vars->fileVars, &vars->fileExtents, &data,
1519 &vars->volumeCryptKey[0]);
1520
1521 if (KERN_SUCCESS != err)
1522 {
1523 HIBLOG("IOPolledFileOpen(%x)\n", err);
1524 break;
1525 }
1526
1527 clock_get_uptime(&startTime);
1528 err = hibernate_setup(gIOHibernateCurrentHeader,
1529 gIOHibernateFreeRatio, gIOHibernateFreeTime,
1530 vmflush,
1531 vars->page_list, vars->page_list_wired, vars->page_list_pal);
1532 clock_get_uptime(&endTime);
1533 SUB_ABSOLUTETIME(&endTime, &startTime);
1534 absolutetime_to_nanoseconds(endTime, &nsec);
1535 HIBLOG("hibernate_setup(%d) took %qd ms\n", err, nsec / 1000000ULL);
1536
1537 dsSSD = ((0 != (kIOHibernateOptionSSD & vars->fileVars->flags))
1538 && (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
1539 if (dsSSD)
1540 {
1541 gIOHibernateCurrentHeader->options |=
1542 kIOHibernateOptionSSD
1543 | kIOHibernateOptionColor;
1544
1545 #if defined(__i386__) || defined(__x86_64__)
1546 if (!uuid_is_null(vars->volumeCryptKey) &&
1547 (kOSBooleanTrue != IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey)))
1548 {
1549 uintptr_t smcVars[2];
1550 smcVars[0] = sizeof(vars->volumeCryptKey);
1551 smcVars[1] = (uintptr_t)(void *) &gIOHibernateVars.volumeCryptKey[0];
1552
1553 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey, smcVars, sizeof(smcVars));
1554 bzero(smcVars, sizeof(smcVars));
1555 }
1556 #endif
1557 }
1558 else
1559 {
1560 gIOHibernateCurrentHeader->options |= kIOHibernateOptionProgress;
1561 }
1562
1563
1564 if (KERN_SUCCESS != err)
1565 break;
1566
1567 if (encryptedswap || !uuid_is_null(vars->volumeCryptKey))
1568 gIOHibernateMode ^= kIOHibernateModeEncrypt;
1569
1570 if (kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1571 {
1572 vars->videoAllocSize = kVideoMapSize;
1573 if (KERN_SUCCESS != kmem_alloc_pageable(kernel_map, &vars->videoMapping, vars->videoAllocSize))
1574 vars->videoMapping = 0;
1575 }
1576
1577 // generate crypt keys
1578 for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++)
1579 vars->wiredCryptKey[i] = random();
1580 for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++)
1581 vars->cryptKey[i] = random();
1582
1583 // set nvram
1584
1585 IORegistryEntry * regEntry;
1586 if (!gIOOptionsEntry)
1587 {
1588 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1589 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
1590 if (regEntry && !gIOOptionsEntry)
1591 regEntry->release();
1592 }
1593
1594 if (gIOOptionsEntry)
1595 {
1596 const OSSymbol * sym;
1597
1598 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1599 if (sym)
1600 {
1601 gIOOptionsEntry->setProperty(sym, data);
1602 sym->release();
1603 }
1604 data->release();
1605
1606 #if defined(__i386__) || defined(__x86_64__)
1607 struct AppleRTCHibernateVars
1608 {
1609 uint8_t signature[4];
1610 uint32_t revision;
1611 uint8_t booterSignature[20];
1612 uint8_t wiredCryptKey[16];
1613 };
1614 AppleRTCHibernateVars rtcVars;
1615
1616 rtcVars.signature[0] = 'A';
1617 rtcVars.signature[1] = 'A';
1618 rtcVars.signature[2] = 'P';
1619 rtcVars.signature[3] = 'L';
1620 rtcVars.revision = 1;
1621 bcopy(&vars->wiredCryptKey[0], &rtcVars.wiredCryptKey[0], sizeof(rtcVars.wiredCryptKey));
1622 if (gIOHibernateBootSignature[0])
1623 {
1624 char c;
1625 uint8_t value = 0;
1626 for (uint32_t i = 0;
1627 (c = gIOHibernateBootSignature[i]) && (i < (sizeof(rtcVars.booterSignature) << 1));
1628 i++)
1629 {
1630 if (c >= 'a')
1631 c -= 'a' - 10;
1632 else if (c >= 'A')
1633 c -= 'A' - 10;
1634 else if (c >= '0')
1635 c -= '0';
1636 else
1637 continue;
1638 value = (value << 4) | c;
1639 if (i & 1)
1640 rtcVars.booterSignature[i >> 1] = value;
1641 }
1642 }
1643 data = OSData::withBytes(&rtcVars, sizeof(rtcVars));
1644 if (data)
1645 {
1646 if (!gIOHibernateRTCVariablesKey)
1647 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1648 if (gIOHibernateRTCVariablesKey)
1649 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey, data);
1650
1651 if( gIOOptionsEntry )
1652 {
1653 if( gIOHibernateMode & kIOHibernateModeSwitch )
1654 {
1655 const OSSymbol *sym;
1656 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSwitchVarsKey);
1657 if( sym )
1658 {
1659 gIOOptionsEntry->setProperty(sym, data); /* intentional insecure backup of rtc boot vars */
1660 sym->release();
1661 }
1662 }
1663 }
1664
1665 data->release();
1666 }
1667 if (gIOChosenEntry)
1668 {
1669 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
1670 if (data)
1671 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
1672 {
1673 // set BootNext
1674
1675 if (!gIOHibernateBoot0082Data)
1676 {
1677 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-device-path"));
1678 if (data)
1679 {
1680 // AppleNVRAM_EFI_LOAD_OPTION
1681 struct {
1682 uint32_t Attributes;
1683 uint16_t FilePathLength;
1684 uint16_t Desc;
1685 } loadOptionHeader;
1686 loadOptionHeader.Attributes = 1;
1687 loadOptionHeader.FilePathLength = data->getLength();
1688 loadOptionHeader.Desc = 0;
1689 gIOHibernateBoot0082Data = OSData::withCapacity(sizeof(loadOptionHeader) + loadOptionHeader.FilePathLength);
1690 if (gIOHibernateBoot0082Data)
1691 {
1692 gIOHibernateBoot0082Data->appendBytes(&loadOptionHeader, sizeof(loadOptionHeader));
1693 gIOHibernateBoot0082Data->appendBytes(data);
1694 }
1695 }
1696 }
1697 if (!gIOHibernateBoot0082Key)
1698 gIOHibernateBoot0082Key = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1699 if (!gIOHibernateBootNextKey)
1700 gIOHibernateBootNextKey = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1701 if (!gIOHibernateBootNextData)
1702 {
1703 uint16_t bits = 0x0082;
1704 gIOHibernateBootNextData = OSData::withBytes(&bits, sizeof(bits));
1705 }
1706 if (gIOHibernateBoot0082Key && gIOHibernateBoot0082Data && gIOHibernateBootNextKey && gIOHibernateBootNextData)
1707 {
1708 gIOHibernateBootNextSave = gIOOptionsEntry->copyProperty(gIOHibernateBootNextKey);
1709 gIOOptionsEntry->setProperty(gIOHibernateBoot0082Key, gIOHibernateBoot0082Data);
1710 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextData);
1711 }
1712 }
1713 }
1714 #else /* !i386 && !x86_64 */
1715 if (kIOHibernateModeEncrypt & gIOHibernateMode)
1716 {
1717 data = OSData::withBytes(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1718 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKeyKey);
1719 if (sym && data)
1720 gIOOptionsEntry->setProperty(sym, data);
1721 if (sym)
1722 sym->release();
1723 if (data)
1724 data->release();
1725 if (false && gIOHibernateBootSignature[0])
1726 {
1727 data = OSData::withCapacity(16);
1728 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
1729 if (sym && data)
1730 {
1731 char c;
1732 uint8_t value = 0;
1733 for (uint32_t i = 0; (c = gIOHibernateBootSignature[i]); i++)
1734 {
1735 if (c >= 'a')
1736 c -= 'a' - 10;
1737 else if (c >= 'A')
1738 c -= 'A' - 10;
1739 else if (c >= '0')
1740 c -= '0';
1741 else
1742 continue;
1743 value = (value << 4) | c;
1744 if (i & 1)
1745 data->appendBytes(&value, sizeof(value));
1746 }
1747 gIOOptionsEntry->setProperty(sym, data);
1748 }
1749 if (sym)
1750 sym->release();
1751 if (data)
1752 data->release();
1753 }
1754 }
1755 if (!vars->haveFastBoot)
1756 {
1757 // set boot volume to zero
1758 IODTPlatformExpert * platform = OSDynamicCast(IODTPlatformExpert, IOService::getPlatform());
1759 if (platform && (kIOReturnSuccess == platform->readXPRAM(kXPRamAudioVolume,
1760 &vars->saveBootAudioVolume, sizeof(vars->saveBootAudioVolume))))
1761 {
1762 uint8_t newVolume;
1763 newVolume = vars->saveBootAudioVolume & 0xf8;
1764 platform->writeXPRAM(kXPRamAudioVolume,
1765 &newVolume, sizeof(newVolume));
1766 }
1767 }
1768 #endif /* !i386 && !x86_64 */
1769 }
1770 // --
1771
1772 }
1773 while (false);
1774
1775 IOLockLock(gFSLock);
1776 if ((kIOReturnSuccess == err) && (kFSOpening == gFSState))
1777 {
1778 gFSState = kFSOpened;
1779 gIOHibernateVars = *vars;
1780 gFileVars = *vars->fileVars;
1781 gIOHibernateVars.fileVars = &gFileVars;
1782 gIOHibernateFileRef = gFileVars.fileRef;
1783 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderSignature;
1784 gIOHibernateState = kIOHibernateStateHibernating;
1785 }
1786 else
1787 {
1788 HIBLOG("hibernate file close due timeout\n");
1789 if (vars->fileVars && vars->fileVars->fileRef) kern_close_file_for_direct_io(vars->fileVars->fileRef, 0, 0, 0, 0, 0);
1790 IOHibernateDone(vars);
1791 gFSState = kFSIdle;
1792 }
1793 IOLockUnlock(gFSLock);
1794
1795 if (vars->fileVars) IODelete(vars->fileVars, IOPolledFileIOVars, 1);
1796 IODelete(vars, IOHibernateVars, 1);
1797
1798 return (err);
1799 }
1800
1801 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1802
1803 DECLARE_IOHIBERNATEPROGRESSALPHA
1804
1805 static void
1806 ProgressInit(hibernate_graphics_t * display, uint8_t * screen, uint8_t * saveunder, uint32_t savelen)
1807 {
1808 uint32_t rowBytes, pixelShift;
1809 uint32_t x, y;
1810 int32_t blob;
1811 uint32_t alpha, in, color, result;
1812 uint8_t * out;
1813 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1814
1815 rowBytes = display->rowBytes;
1816 pixelShift = display->depth >> 4;
1817 if (pixelShift < 1) return;
1818
1819 screen += ((display->width
1820 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1821 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1822
1823 for (y = 0; y < kIOHibernateProgressHeight; y++)
1824 {
1825 out = screen + y * rowBytes;
1826 for (blob = 0; blob < kIOHibernateProgressCount; blob++)
1827 {
1828 color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
1829 for (x = 0; x < kIOHibernateProgressWidth; x++)
1830 {
1831 alpha = gIOHibernateProgressAlpha[y][x];
1832 result = color;
1833 if (alpha)
1834 {
1835 if (0xff != alpha)
1836 {
1837 if (1 == pixelShift)
1838 {
1839 in = *((uint16_t *)out) & 0x1f; // 16
1840 in = (in << 3) | (in >> 2);
1841 }
1842 else
1843 in = *((uint32_t *)out) & 0xff; // 32
1844 saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
1845 result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
1846 }
1847 if (1 == pixelShift)
1848 {
1849 result >>= 3;
1850 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1851 }
1852 else
1853 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1854 }
1855 out += (1 << pixelShift);
1856 }
1857 out += (kIOHibernateProgressSpacing << pixelShift);
1858 }
1859 }
1860 }
1861
1862
1863 static void
1864 ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select)
1865 {
1866 uint32_t rowBytes, pixelShift;
1867 uint32_t x, y;
1868 int32_t blob, lastBlob;
1869 uint32_t alpha, in, color, result;
1870 uint8_t * out;
1871 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1872
1873 pixelShift = display->depth >> 4;
1874 if (pixelShift < 1)
1875 return;
1876
1877 rowBytes = display->rowBytes;
1878
1879 screen += ((display->width
1880 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1881 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1882
1883 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1884
1885 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1886
1887 for (y = 0; y < kIOHibernateProgressHeight; y++)
1888 {
1889 out = screen + y * rowBytes;
1890 for (blob = firstBlob; blob <= lastBlob; blob++)
1891 {
1892 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1893 for (x = 0; x < kIOHibernateProgressWidth; x++)
1894 {
1895 alpha = gIOHibernateProgressAlpha[y][x];
1896 result = color;
1897 if (alpha)
1898 {
1899 if (0xff != alpha)
1900 {
1901 in = display->progressSaveUnder[blob][saveindex[blob]++];
1902 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1903 }
1904 if (1 == pixelShift)
1905 {
1906 result >>= 3;
1907 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
1908 }
1909 else
1910 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1911 }
1912 out += (1 << pixelShift);
1913 }
1914 out += (kIOHibernateProgressSpacing << pixelShift);
1915 }
1916 }
1917 }
1918
1919 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1920
1921 IOReturn
1922 IOHibernateIOKitSleep(void)
1923 {
1924 IOReturn ret = kIOReturnSuccess;
1925 IOLockLock(gFSLock);
1926 if (kFSOpening == gFSState)
1927 {
1928 gFSState = kFSTimedOut;
1929 HIBLOG("hibernate file open timed out\n");
1930 ret = kIOReturnTimeout;
1931 }
1932 IOLockUnlock(gFSLock);
1933 return (ret);
1934 }
1935
1936 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1937
1938 IOReturn
1939 IOHibernateSystemHasSlept(void)
1940 {
1941 IOReturn ret = kIOReturnSuccess;
1942 IOHibernateVars * vars = &gIOHibernateVars;
1943 OSObject * obj = 0;
1944 OSData * data;
1945
1946 IOLockLock(gFSLock);
1947 if ((kFSOpened != gFSState) && gIOHibernateMode)
1948 {
1949 ret = kIOReturnTimeout;
1950 }
1951 IOLockUnlock(gFSLock);
1952 if (kIOReturnSuccess != ret) return (ret);
1953
1954 if (gIOHibernateMode) obj = IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey);
1955 vars->previewBuffer = OSDynamicCast(IOMemoryDescriptor, obj);
1956 if (obj && !vars->previewBuffer)
1957 obj->release();
1958
1959 vars->consoleMapping = NULL;
1960 if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare()))
1961 {
1962 vars->previewBuffer->release();
1963 vars->previewBuffer = 0;
1964 }
1965
1966 if ((kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1967 && vars->previewBuffer
1968 && (data = OSDynamicCast(OSData,
1969 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey))))
1970 {
1971 UInt32 flags = *((UInt32 *)data->getBytesNoCopy());
1972 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags);
1973
1974 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey);
1975
1976 if (kIOHibernatePreviewUpdates & flags)
1977 {
1978 PE_Video consoleInfo;
1979 hibernate_graphics_t * graphicsInfo = gIOHibernateGraphicsInfo;
1980
1981 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
1982
1983 graphicsInfo->width = consoleInfo.v_width;
1984 graphicsInfo->height = consoleInfo.v_height;
1985 graphicsInfo->rowBytes = consoleInfo.v_rowBytes;
1986 graphicsInfo->depth = consoleInfo.v_depth;
1987 vars->consoleMapping = (uint8_t *) consoleInfo.v_baseAddr;
1988
1989 HIBPRINT("video %p %d %d %d\n",
1990 vars->consoleMapping, graphicsInfo->depth,
1991 graphicsInfo->width, graphicsInfo->height);
1992 if (vars->consoleMapping)
1993 ProgressInit(graphicsInfo, vars->consoleMapping,
1994 &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
1995 }
1996 }
1997
1998 if (gIOOptionsEntry)
1999 gIOOptionsEntry->sync();
2000
2001 return (ret);
2002 }
2003
2004 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005
2006 static DeviceTreeNode *
2007 MergeDeviceTree(DeviceTreeNode * entry, IORegistryEntry * regEntry)
2008 {
2009 DeviceTreeNodeProperty * prop;
2010 DeviceTreeNode * child;
2011 IORegistryEntry * childRegEntry;
2012 const char * nameProp;
2013 unsigned int propLen, idx;
2014
2015 prop = (DeviceTreeNodeProperty *) (entry + 1);
2016 for (idx = 0; idx < entry->nProperties; idx++)
2017 {
2018 if (regEntry && (0 != strcmp("name", prop->name)))
2019 {
2020 regEntry->setProperty((const char *) prop->name, (void *) (prop + 1), prop->length);
2021 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
2022 }
2023 prop = (DeviceTreeNodeProperty *) (((uintptr_t)(prop + 1)) + ((prop->length + 3) & ~3));
2024 }
2025
2026 child = (DeviceTreeNode *) prop;
2027 for (idx = 0; idx < entry->nChildren; idx++)
2028 {
2029 if (kSuccess != DTGetProperty(child, "name", (void **) &nameProp, &propLen))
2030 panic("no name");
2031 childRegEntry = regEntry ? regEntry->childFromPath(nameProp, gIODTPlane) : NULL;
2032 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
2033 child = MergeDeviceTree(child, childRegEntry);
2034 }
2035 return (child);
2036 }
2037
2038 IOReturn
2039 IOHibernateSystemWake(void)
2040 {
2041 if (kFSOpened == gFSState)
2042 {
2043 IOHibernateDone(&gIOHibernateVars);
2044 }
2045 else
2046 {
2047 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
2048 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
2049 }
2050 return (kIOReturnSuccess);
2051 }
2052
2053 static IOReturn
2054 IOHibernateDone(IOHibernateVars * vars)
2055 {
2056 IORegistryEntry * next;
2057
2058 hibernate_teardown(vars->page_list, vars->page_list_wired, vars->page_list_pal);
2059
2060 if (vars->videoMapping)
2061 {
2062 if (vars->videoMapSize)
2063 // remove mappings
2064 IOUnmapPages(kernel_map, vars->videoMapping, vars->videoMapSize);
2065 if (vars->videoAllocSize)
2066 // dealloc range
2067 kmem_free(kernel_map, trunc_page(vars->videoMapping), vars->videoAllocSize);
2068 }
2069
2070 if (vars->previewBuffer)
2071 {
2072 vars->previewBuffer->release();
2073 vars->previewBuffer = 0;
2074 }
2075
2076 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState)
2077 {
2078 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey,
2079 gIOHibernateCurrentHeader->options, 32);
2080 }
2081 else
2082 {
2083 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
2084 }
2085
2086 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState)
2087 && (kIOHibernateGfxStatusUnknown != gIOHibernateGraphicsInfo->gfxStatus))
2088 {
2089 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey,
2090 &gIOHibernateGraphicsInfo->gfxStatus,
2091 sizeof(gIOHibernateGraphicsInfo->gfxStatus));
2092 }
2093 else
2094 {
2095 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
2096 }
2097
2098 if (vars->fileVars)
2099 {
2100 if ((next = vars->fileVars->media)) do
2101 {
2102 next->removeProperty(kIOPolledInterfaceActiveKey);
2103 next = next->getParentEntry(gIOServicePlane);
2104 }
2105 while (next);
2106 IOPolledFileClose(vars->fileVars);
2107 }
2108
2109 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
2110
2111 #if defined(__i386__) || defined(__x86_64__)
2112 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey);
2113 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey);
2114
2115 /*
2116 * Hibernate variable is written to NVRAM on platforms in which RtcRam
2117 * is not backed by coin cell. Remove Hibernate data from NVRAM.
2118 */
2119 if (gIOOptionsEntry) {
2120
2121 if (gIOHibernateRTCVariablesKey) {
2122 if (gIOOptionsEntry->getProperty(gIOHibernateRTCVariablesKey)) {
2123 gIOOptionsEntry->removeProperty(gIOHibernateRTCVariablesKey);
2124 }
2125 }
2126
2127 if (gIOHibernateBootNextKey)
2128 {
2129 if (gIOHibernateBootNextSave)
2130 {
2131 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextSave);
2132 gIOHibernateBootNextSave->release();
2133 gIOHibernateBootNextSave = NULL;
2134 }
2135 else
2136 gIOOptionsEntry->removeProperty(gIOHibernateBootNextKey);
2137 }
2138 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState) gIOOptionsEntry->sync();
2139 }
2140 #endif
2141
2142 if (vars->srcBuffer)
2143 vars->srcBuffer->release();
2144 if (vars->ioBuffer)
2145 vars->ioBuffer->release();
2146 bzero(&gIOHibernateHandoffPages[0], gIOHibernateHandoffPageCount * sizeof(gIOHibernateHandoffPages[0]));
2147 if (vars->handoffBuffer)
2148 {
2149 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState)
2150 {
2151 IOHibernateHandoff * handoff;
2152 bool done = false;
2153 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
2154 !done;
2155 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount])
2156 {
2157 HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2158 uint8_t * data = &handoff->data[0];
2159 switch (handoff->type)
2160 {
2161 case kIOHibernateHandoffTypeEnd:
2162 done = true;
2163 break;
2164
2165 case kIOHibernateHandoffTypeDeviceTree:
2166 MergeDeviceTree((DeviceTreeNode *) data, IOService::getServiceRoot());
2167 break;
2168
2169 case kIOHibernateHandoffTypeKeyStore:
2170 #if defined(__i386__) || defined(__x86_64__)
2171 {
2172 IOBufferMemoryDescriptor *
2173 md = IOBufferMemoryDescriptor::withBytes(data, handoff->bytecount, kIODirectionOutIn);
2174 if (md)
2175 {
2176 IOSetKeyStoreData(md);
2177 }
2178 }
2179 #endif
2180 break;
2181
2182 default:
2183 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
2184 break;
2185 }
2186 }
2187 }
2188 vars->handoffBuffer->release();
2189 }
2190 if (vars->fileExtents)
2191 vars->fileExtents->release();
2192
2193 bzero(vars, sizeof(*vars));
2194
2195 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
2196
2197 return (kIOReturnSuccess);
2198 }
2199
2200 IOReturn
2201 IOHibernateSystemPostWake(void)
2202 {
2203 struct kern_direct_file_io_ref_t * fileRef;
2204
2205 if (kFSOpened == gFSState)
2206 {
2207 // invalidate & close the image file
2208 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
2209 if ((fileRef = gIOHibernateFileRef))
2210 {
2211 gIOHibernateFileRef = 0;
2212 IOSleep(TRIM_DELAY);
2213 kern_close_file_for_direct_io(fileRef,
2214 #if DISABLE_TRIM
2215 0, 0, 0, 0, 0);
2216 #else
2217 0, (caddr_t) gIOHibernateCurrentHeader,
2218 sizeof(IOHibernateImageHeader),
2219 0,
2220 gIOHibernateCurrentHeader->imageSize);
2221 #endif
2222 }
2223 gFSState = kFSIdle;
2224 }
2225
2226 if (gDebugImageFileRef) {
2227 kern_close_file_for_direct_io(gDebugImageFileRef, 0, 0, 0, 0, 0);
2228 gDebugImageFileRef = NULL;
2229 }
2230
2231 if (!gIOOptionsEntry)
2232 {
2233 IORegistryEntry * regEntry;
2234 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
2235 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
2236 if (regEntry && !gIOOptionsEntry)
2237 regEntry->release();
2238 }
2239 if (gIOOptionsEntry)
2240 {
2241 const OSSymbol * sym;
2242
2243 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
2244 if (sym)
2245 {
2246 gIOOptionsEntry->removeProperty(sym);
2247 gIOOptionsEntry->sync();
2248 sym->release();
2249 }
2250 }
2251
2252 return (kIOReturnSuccess);
2253 }
2254
2255 bool IOHibernateWasScreenLocked(void)
2256 {
2257 bool ret = false;
2258 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState) && gIOChosenEntry)
2259 {
2260 OSData *
2261 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOScreenLockStateKey));
2262 if (data) switch (*((uint32_t *)data->getBytesNoCopy()))
2263 {
2264 case kIOScreenLockLocked:
2265 case kIOScreenLockFileVaultDialog:
2266 ret = true;
2267 break;
2268 case kIOScreenLockNoLock:
2269 case kIOScreenLockUnlocked:
2270 default:
2271 ret = false;
2272 break;
2273 }
2274 }
2275 return (ret);
2276 }
2277
2278 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2279
2280 SYSCTL_STRING(_kern, OID_AUTO, hibernatefile,
2281 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
2282 gIOHibernateFilename, sizeof(gIOHibernateFilename), "");
2283 SYSCTL_STRING(_kern, OID_AUTO, bootsignature,
2284 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
2285 gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), "");
2286 SYSCTL_UINT(_kern, OID_AUTO, hibernatemode,
2287 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
2288 &gIOHibernateMode, 0, "");
2289 SYSCTL_STRUCT(_kern, OID_AUTO, hibernatestatistics,
2290 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
2291 gIOHibernateStats, hibernate_statistics_t, "");
2292
2293 SYSCTL_UINT(_kern, OID_AUTO, hibernategraphicsready,
2294 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
2295 &gIOHibernateStats->graphicsReadyTime, 0, "");
2296 SYSCTL_UINT(_kern, OID_AUTO, hibernatewakenotification,
2297 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
2298 &gIOHibernateStats->wakeNotificationTime, 0, "");
2299 SYSCTL_UINT(_kern, OID_AUTO, hibernatelockscreenready,
2300 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
2301 &gIOHibernateStats->lockScreenReadyTime, 0, "");
2302 SYSCTL_UINT(_kern, OID_AUTO, hibernatehidready,
2303 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
2304 &gIOHibernateStats->hidReadyTime, 0, "");
2305
2306
2307 void
2308 IOHibernateSystemInit(IOPMrootDomain * rootDomain)
2309 {
2310 OSData * data = OSData::withBytesNoCopy(&gIOHibernateState, sizeof(gIOHibernateState));
2311 if (data)
2312 {
2313 rootDomain->setProperty(kIOHibernateStateKey, data);
2314 data->release();
2315 }
2316
2317 if (PE_parse_boot_argn("hfile", gIOHibernateFilename, sizeof(gIOHibernateFilename)))
2318 gIOHibernateMode = kIOHibernateModeOn;
2319 else
2320 gIOHibernateFilename[0] = 0;
2321
2322 sysctl_register_oid(&sysctl__kern_hibernatefile);
2323 sysctl_register_oid(&sysctl__kern_bootsignature);
2324 sysctl_register_oid(&sysctl__kern_hibernatemode);
2325 sysctl_register_oid(&sysctl__kern_hibernatestatistics);
2326 sysctl_register_oid(&sysctl__kern_hibernategraphicsready);
2327 sysctl_register_oid(&sysctl__kern_hibernatewakenotification);
2328 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready);
2329 sysctl_register_oid(&sysctl__kern_hibernatehidready);
2330
2331 gFSLock = IOLockAlloc();
2332 }
2333
2334
2335 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2336
2337 static void
2338 hibernate_setup_for_wake(void)
2339 {
2340 }
2341
2342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2343
2344 #define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
2345
2346 static bool
2347 no_encrypt_page(vm_offset_t ppnum)
2348 {
2349 if (pmap_is_noencrypt((ppnum_t)ppnum) == TRUE)
2350 {
2351 return true;
2352 }
2353 return false;
2354 }
2355
2356 static void
2357 hibernate_pal_callback(void *vars_arg, vm_offset_t addr)
2358 {
2359 IOHibernateVars *vars = (IOHibernateVars *)vars_arg;
2360 /* Make sure it's not in either of the save lists */
2361 hibernate_set_page_state(vars->page_list, vars->page_list_wired, atop_64(addr), 1, kIOHibernatePageStateFree);
2362
2363 /* Set it in the bitmap of pages owned by the PAL */
2364 hibernate_page_bitset(vars->page_list_pal, TRUE, atop_64(addr));
2365 }
2366
2367 static struct hibernate_cryptvars_t *local_cryptvars;
2368
2369 extern "C" int
2370 hibernate_pal_write(void *buffer, size_t size)
2371 {
2372 IOHibernateVars * vars = &gIOHibernateVars;
2373
2374 IOReturn err = IOPolledFileWrite(vars->fileVars, (const uint8_t *)buffer, size, local_cryptvars);
2375 if (kIOReturnSuccess != err) {
2376 kprintf("epic hibernate fail! %d\n", err);
2377 return err;
2378 }
2379
2380 return 0;
2381 }
2382
2383
2384 extern "C" uint32_t
2385 hibernate_write_image(void)
2386 {
2387 IOHibernateImageHeader * header = gIOHibernateCurrentHeader;
2388 IOHibernateVars * vars = &gIOHibernateVars;
2389 IOPolledFileExtent * fileExtents;
2390
2391 C_ASSERT(sizeof(IOHibernateImageHeader) == 512);
2392
2393 uint32_t pageCount, pagesDone;
2394 IOReturn err;
2395 vm_offset_t ppnum, page;
2396 IOItemCount count;
2397 uint8_t * src;
2398 uint8_t * data;
2399 uint8_t * compressed;
2400 uint8_t * scratch;
2401 void * zerosCompressed;
2402 IOByteCount pageCompressedSize, zerosCompressedLen;
2403 uint64_t compressedSize, uncompressedSize;
2404 uint64_t image1Size = 0;
2405 uint32_t bitmap_size;
2406 bool iterDone, pollerOpen, needEncrypt;
2407 uint32_t restore1Sum, sum, sum1, sum2;
2408 int wkresult;
2409 uint32_t tag;
2410 uint32_t pageType;
2411 uint32_t pageAndCount[2];
2412 addr64_t phys64;
2413 IOByteCount segLen;
2414
2415 AbsoluteTime startTime, endTime;
2416 AbsoluteTime allTime, compTime;
2417 uint64_t compBytes;
2418 uint64_t nsec;
2419 uint32_t lastProgressStamp = 0;
2420 uint32_t progressStamp;
2421 uint32_t blob, lastBlob = (uint32_t) -1L;
2422
2423 uint32_t wiredPagesEncrypted;
2424 uint32_t dirtyPagesEncrypted;
2425 uint32_t wiredPagesClear;
2426 uint32_t zeroPageCount;
2427
2428 hibernate_cryptvars_t _cryptvars;
2429 hibernate_cryptvars_t * cryptvars = 0;
2430
2431 wiredPagesEncrypted = 0;
2432 dirtyPagesEncrypted = 0;
2433 wiredPagesClear = 0;
2434 zeroPageCount = 0;
2435
2436 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
2437 return (false /* sleep */ );
2438
2439 if (kIOHibernateModeSleep & gIOHibernateMode)
2440 kdebug_enable = save_kdebug_enable;
2441
2442 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_START, 0, 0, 0, 0, 0);
2443 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate);
2444
2445 restore1Sum = sum1 = sum2 = 0;
2446
2447 hibernate_pal_prepare();
2448
2449 #if CRYPTO
2450 // encryption data. "iv" is the "initial vector".
2451 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2452 {
2453 static const unsigned char first_iv[AES_BLOCK_SIZE]
2454 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
2455 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
2456
2457 cryptvars = &gIOHibernateCryptWakeContext;
2458 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
2459 aes_encrypt_key(vars->cryptKey,
2460 kIOHibernateAESKeySize,
2461 &cryptvars->ctx.encrypt);
2462 aes_decrypt_key(vars->cryptKey,
2463 kIOHibernateAESKeySize,
2464 &cryptvars->ctx.decrypt);
2465
2466 cryptvars = &_cryptvars;
2467 bzero(cryptvars, sizeof(hibernate_cryptvars_t));
2468 for (pageCount = 0; pageCount < sizeof(vars->wiredCryptKey); pageCount++)
2469 vars->wiredCryptKey[pageCount] ^= vars->volumeCryptKey[pageCount];
2470 bzero(&vars->volumeCryptKey[0], sizeof(vars->volumeCryptKey));
2471 aes_encrypt_key(vars->wiredCryptKey,
2472 kIOHibernateAESKeySize,
2473 &cryptvars->ctx.encrypt);
2474
2475 bcopy(&first_iv[0], &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
2476 bzero(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
2477 bzero(&vars->cryptKey[0], sizeof(vars->cryptKey));
2478
2479 local_cryptvars = cryptvars;
2480 }
2481 #endif /* CRYPTO */
2482
2483 hibernate_setup_for_wake();
2484
2485 hibernate_page_list_setall(vars->page_list,
2486 vars->page_list_wired,
2487 vars->page_list_pal,
2488 false /* !preflight */,
2489 /* discard_all */
2490 ((0 == (kIOHibernateModeSleep & gIOHibernateMode))
2491 && (0 != ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode))),
2492 &pageCount);
2493
2494 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount);
2495
2496 fileExtents = (IOPolledFileExtent *) vars->fileExtents->getBytesNoCopy();
2497
2498 #if 0
2499 count = vars->fileExtents->getLength() / sizeof(IOPolledFileExtent);
2500 for (page = 0; page < count; page++)
2501 {
2502 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page,
2503 fileExtents[page].start, fileExtents[page].length,
2504 fileExtents[page].start + fileExtents[page].length);
2505 }
2506 #endif
2507
2508 needEncrypt = (0 != (kIOHibernateModeEncrypt & gIOHibernateMode));
2509 AbsoluteTime_to_scalar(&compTime) = 0;
2510 compBytes = 0;
2511
2512 clock_get_uptime(&allTime);
2513 IOService::getPMRootDomain()->pmStatsRecordEvent(
2514 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStartFlag, allTime);
2515 do
2516 {
2517 compressedSize = 0;
2518 uncompressedSize = 0;
2519 zeroPageCount = 0;
2520
2521 IOPolledFileSeek(vars->fileVars, vars->fileVars->blockSize);
2522
2523 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
2524 ml_get_interrupts_enabled());
2525 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledBeforeSleepState, vars->ioBuffer);
2526 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
2527 pollerOpen = (kIOReturnSuccess == err);
2528 if (!pollerOpen)
2529 break;
2530
2531 // copy file block extent list if larger than header
2532
2533 count = vars->fileExtents->getLength();
2534 if (count > sizeof(header->fileExtentMap))
2535 {
2536 count -= sizeof(header->fileExtentMap);
2537 err = IOPolledFileWrite(vars->fileVars,
2538 ((uint8_t *) &fileExtents[0]) + sizeof(header->fileExtentMap), count, cryptvars);
2539 if (kIOReturnSuccess != err)
2540 break;
2541 }
2542
2543 uintptr_t hibernateBase;
2544 uintptr_t hibernateEnd;
2545
2546 hibernateBase = HIB_BASE; /* Defined in PAL headers */
2547
2548 hibernateEnd = (segHIBB + segSizeHIB);
2549
2550 // copy out restore1 code
2551
2552 for (count = 0;
2553 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2554 count += segLen)
2555 {
2556 for (pagesDone = 0; pagesDone < atop_32(segLen); pagesDone++)
2557 {
2558 gIOHibernateHandoffPages[atop_32(count) + pagesDone] = atop_64(phys64) + pagesDone;
2559 }
2560 }
2561
2562 page = atop_32(kvtophys(hibernateBase));
2563 count = atop_32(round_page(hibernateEnd) - hibernateBase);
2564 header->restore1CodePhysPage = page;
2565 header->restore1CodeVirt = hibernateBase;
2566 header->restore1PageCount = count;
2567 header->restore1CodeOffset = ((uintptr_t) &hibernate_machine_entrypoint) - hibernateBase;
2568 header->restore1StackOffset = ((uintptr_t) &gIOHibernateRestoreStackEnd[0]) - 64 - hibernateBase;
2569
2570 // sum __HIB seg, with zeros for the stack
2571 src = (uint8_t *) trunc_page(hibernateBase);
2572 for (page = 0; page < count; page++)
2573 {
2574 if ((src < &gIOHibernateRestoreStack[0]) || (src >= &gIOHibernateRestoreStackEnd[0]))
2575 restore1Sum += hibernate_sum_page(src, header->restore1CodeVirt + page);
2576 else
2577 restore1Sum += 0x00000000;
2578 src += page_size;
2579 }
2580 sum1 = restore1Sum;
2581
2582 // write the __HIB seg, with zeros for the stack
2583
2584 src = (uint8_t *) trunc_page(hibernateBase);
2585 count = ((uintptr_t) &gIOHibernateRestoreStack[0]) - trunc_page(hibernateBase);
2586 if (count)
2587 {
2588 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
2589 if (kIOReturnSuccess != err)
2590 break;
2591 }
2592 err = IOPolledFileWrite(vars->fileVars,
2593 (uint8_t *) 0,
2594 &gIOHibernateRestoreStackEnd[0] - &gIOHibernateRestoreStack[0],
2595 cryptvars);
2596 if (kIOReturnSuccess != err)
2597 break;
2598 src = &gIOHibernateRestoreStackEnd[0];
2599 count = round_page(hibernateEnd) - ((uintptr_t) src);
2600 if (count)
2601 {
2602 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
2603 if (kIOReturnSuccess != err)
2604 break;
2605 }
2606
2607 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2608 {
2609 vars->fileVars->encryptStart = (vars->fileVars->position & ~(AES_BLOCK_SIZE - 1));
2610 vars->fileVars->encryptEnd = UINT64_MAX;
2611 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
2612 }
2613
2614 // write the preview buffer
2615
2616 if (vars->previewBuffer)
2617 {
2618 ppnum = 0;
2619 count = 0;
2620 do
2621 {
2622 phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone);
2623 pageAndCount[0] = atop_64(phys64);
2624 pageAndCount[1] = atop_32(segLen);
2625 err = IOPolledFileWrite(vars->fileVars,
2626 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
2627 cryptvars);
2628 if (kIOReturnSuccess != err)
2629 break;
2630 count += segLen;
2631 ppnum += sizeof(pageAndCount);
2632 }
2633 while (phys64);
2634 if (kIOReturnSuccess != err)
2635 break;
2636
2637 src = (uint8_t *) vars->previewBuffer->getPhysicalSegment(0, NULL, _kIOMemorySourceSegment);
2638
2639 ((hibernate_preview_t *)src)->lockTime = gIOConsoleLockTime;
2640
2641 count = vars->previewBuffer->getLength();
2642
2643 header->previewPageListSize = ppnum;
2644 header->previewSize = count + ppnum;
2645
2646 for (page = 0; page < count; page += page_size)
2647 {
2648 phys64 = vars->previewBuffer->getPhysicalSegment(page, NULL, kIOMemoryMapperNone);
2649 sum1 += hibernate_sum_page(src + page, atop_64(phys64));
2650 }
2651 err = IOPolledFileWrite(vars->fileVars, src, count, cryptvars);
2652 if (kIOReturnSuccess != err)
2653 break;
2654 }
2655
2656 // mark areas for no save
2657
2658 for (count = 0;
2659 (phys64 = vars->ioBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2660 count += segLen)
2661 {
2662 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2663 atop_64(phys64), atop_32(segLen),
2664 kIOHibernatePageStateFree);
2665 pageCount -= atop_32(segLen);
2666 }
2667
2668 for (count = 0;
2669 (phys64 = vars->srcBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2670 count += segLen)
2671 {
2672 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2673 atop_64(phys64), atop_32(segLen),
2674 kIOHibernatePageStateFree);
2675 pageCount -= atop_32(segLen);
2676 }
2677
2678 // copy out bitmap of pages available for trashing during restore
2679
2680 bitmap_size = vars->page_list_wired->list_size;
2681 src = (uint8_t *) vars->page_list_wired;
2682 err = IOPolledFileWrite(vars->fileVars, src, bitmap_size, cryptvars);
2683 if (kIOReturnSuccess != err)
2684 break;
2685
2686 // mark more areas for no save, but these are not available
2687 // for trashing during restore
2688
2689 hibernate_page_list_set_volatile(vars->page_list, vars->page_list_wired, &pageCount);
2690
2691
2692 page = atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase));
2693 count = atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd))) - page;
2694 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2695 page, count,
2696 kIOHibernatePageStateFree);
2697 pageCount -= count;
2698
2699 if (vars->previewBuffer) for (count = 0;
2700 (phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2701 count += segLen)
2702 {
2703 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2704 atop_64(phys64), atop_32(segLen),
2705 kIOHibernatePageStateFree);
2706 pageCount -= atop_32(segLen);
2707 }
2708
2709 for (count = 0;
2710 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
2711 count += segLen)
2712 {
2713 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
2714 atop_64(phys64), atop_32(segLen),
2715 kIOHibernatePageStateFree);
2716 pageCount -= atop_32(segLen);
2717 }
2718
2719 (void)hibernate_pal_callback;
2720
2721 src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2722 compressed = src + page_size;
2723 scratch = compressed + page_size;
2724
2725 // compress a zero page
2726 bzero(src, page_size);
2727 zerosCompressed = vars->handoffBuffer->getBytesNoCopy();
2728 zerosCompressedLen = WKdm_compress_new((WK_word*) src,
2729 (WK_word*) zerosCompressed,
2730 (WK_word*) scratch,
2731 page_size - 4);
2732
2733 pagesDone = 0;
2734 lastBlob = 0;
2735
2736 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
2737 bitmap_size, header->previewSize,
2738 pageCount, vars->fileVars->position);
2739
2740 enum
2741 // pageType
2742 {
2743 kWired = 0x02,
2744 kEncrypt = 0x01,
2745 kWiredEncrypt = kWired | kEncrypt,
2746 kWiredClear = kWired,
2747 kUnwiredEncrypt = kEncrypt
2748 };
2749
2750 for (pageType = kWiredEncrypt; pageType >= kUnwiredEncrypt; pageType--)
2751 {
2752 if (kUnwiredEncrypt == pageType)
2753 {
2754 // start unwired image
2755 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2756 {
2757 vars->fileVars->encryptStart = (vars->fileVars->position & ~(((uint64_t)AES_BLOCK_SIZE) - 1));
2758 vars->fileVars->encryptEnd = UINT64_MAX;
2759 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
2760 }
2761 bcopy(&cryptvars->aes_iv[0],
2762 &gIOHibernateCryptWakeContext.aes_iv[0],
2763 sizeof(cryptvars->aes_iv));
2764 cryptvars = &gIOHibernateCryptWakeContext;
2765 }
2766 for (iterDone = false, ppnum = 0; !iterDone; )
2767 {
2768 count = hibernate_page_list_iterate((kWired & pageType)
2769 ? vars->page_list_wired : vars->page_list,
2770 &ppnum);
2771 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2772 iterDone = !count;
2773
2774 if (count && (kWired & pageType) && needEncrypt)
2775 {
2776 uint32_t checkIndex;
2777 for (checkIndex = 0;
2778 (checkIndex < count)
2779 && (((kEncrypt & pageType) == 0) == no_encrypt_page(ppnum + checkIndex));
2780 checkIndex++)
2781 {}
2782 if (!checkIndex)
2783 {
2784 ppnum++;
2785 continue;
2786 }
2787 count = checkIndex;
2788 }
2789
2790 switch (pageType)
2791 {
2792 case kWiredEncrypt: wiredPagesEncrypted += count; break;
2793 case kWiredClear: wiredPagesClear += count; break;
2794 case kUnwiredEncrypt: dirtyPagesEncrypted += count; break;
2795 }
2796
2797 if (iterDone && (kWiredEncrypt == pageType)) {/* not yet end of wired list */}
2798 else
2799 {
2800 pageAndCount[0] = ppnum;
2801 pageAndCount[1] = count;
2802 err = IOPolledFileWrite(vars->fileVars,
2803 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
2804 cryptvars);
2805 if (kIOReturnSuccess != err)
2806 break;
2807 }
2808
2809 for (page = ppnum; page < (ppnum + count); page++)
2810 {
2811 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(page), page_size);
2812 if (err)
2813 {
2814 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__, (long)page, err);
2815 break;
2816 }
2817
2818 sum = hibernate_sum_page(src, page);
2819 if (kWired & pageType)
2820 sum1 += sum;
2821 else
2822 sum2 += sum;
2823
2824 clock_get_uptime(&startTime);
2825 wkresult = WKdm_compress_new((WK_word*) src,
2826 (WK_word*) compressed,
2827 (WK_word*) scratch,
2828 page_size - 4);
2829
2830 clock_get_uptime(&endTime);
2831 ADD_ABSOLUTETIME(&compTime, &endTime);
2832 SUB_ABSOLUTETIME(&compTime, &startTime);
2833
2834 compBytes += page_size;
2835 pageCompressedSize = (-1 == wkresult) ? page_size : wkresult;
2836
2837 if ((pageCompressedSize == zerosCompressedLen)
2838 && !bcmp(compressed, zerosCompressed, zerosCompressedLen))
2839 {
2840 pageCompressedSize = 0;
2841 zeroPageCount++;
2842 }
2843
2844 if (kIOHibernateModeEncrypt & gIOHibernateMode)
2845 pageCompressedSize = (pageCompressedSize + AES_BLOCK_SIZE - 1) & ~(AES_BLOCK_SIZE - 1);
2846
2847 if (pageCompressedSize != page_size)
2848 data = compressed;
2849 else
2850 data = src;
2851
2852 tag = pageCompressedSize | kIOHibernateTagSignature;
2853 err = IOPolledFileWrite(vars->fileVars, (const uint8_t *) &tag, sizeof(tag), cryptvars);
2854 if (kIOReturnSuccess != err)
2855 break;
2856
2857 err = IOPolledFileWrite(vars->fileVars, data, (pageCompressedSize + 3) & ~3, cryptvars);
2858 if (kIOReturnSuccess != err)
2859 break;
2860
2861 compressedSize += pageCompressedSize;
2862 uncompressedSize += page_size;
2863 pagesDone++;
2864
2865 if (vars->consoleMapping && (0 == (1023 & pagesDone)))
2866 {
2867 blob = ((pagesDone * kIOHibernateProgressCount) / pageCount);
2868 if (blob != lastBlob)
2869 {
2870 ProgressUpdate(gIOHibernateGraphicsInfo, vars->consoleMapping, lastBlob, blob);
2871 lastBlob = blob;
2872 }
2873 }
2874 if (0 == (8191 & pagesDone))
2875 {
2876 clock_get_uptime(&endTime);
2877 SUB_ABSOLUTETIME(&endTime, &allTime);
2878 absolutetime_to_nanoseconds(endTime, &nsec);
2879 progressStamp = nsec / 750000000ULL;
2880 if (progressStamp != lastProgressStamp)
2881 {
2882 lastProgressStamp = progressStamp;
2883 HIBPRINT("pages %d (%d%%)\n", pagesDone, (100 * pagesDone) / pageCount);
2884 }
2885 }
2886 }
2887 if (kIOReturnSuccess != err)
2888 break;
2889 ppnum = page;
2890 }
2891
2892 if (kIOReturnSuccess != err)
2893 break;
2894
2895 if ((kEncrypt & pageType) && vars->fileVars->encryptStart)
2896 {
2897 vars->fileVars->encryptEnd = ((vars->fileVars->position + 511) & ~511ULL);
2898 HIBLOG("encryptEnd %qx\n", vars->fileVars->encryptEnd);
2899 }
2900
2901 if (kWiredEncrypt != pageType)
2902 {
2903 // end of image1/2 - fill to next block
2904 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2905 if (kIOReturnSuccess != err)
2906 break;
2907 }
2908 if (kWiredClear == pageType)
2909 {
2910 // enlarge wired image for test
2911 // err = IOPolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
2912
2913 // end wired image
2914 header->encryptStart = vars->fileVars->encryptStart;
2915 header->encryptEnd = vars->fileVars->encryptEnd;
2916 image1Size = vars->fileVars->position;
2917 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2918 image1Size, header->encryptStart, header->encryptEnd);
2919 }
2920 }
2921 if (kIOReturnSuccess != err)
2922 {
2923 if (kIOReturnOverrun == err)
2924 {
2925 // update actual compression ratio on not enough space
2926 gIOHibernateCompression = (compressedSize << 8) / uncompressedSize;
2927 }
2928 break;
2929 }
2930
2931 // Header:
2932
2933 header->imageSize = vars->fileVars->position;
2934 header->image1Size = image1Size;
2935 header->bitmapSize = bitmap_size;
2936 header->pageCount = pageCount;
2937
2938 header->restore1Sum = restore1Sum;
2939 header->image1Sum = sum1;
2940 header->image2Sum = sum2;
2941 header->sleepTime = gIOLastSleepTime.tv_sec;
2942
2943 header->compression = (compressedSize << 8) / uncompressedSize;
2944 gIOHibernateCompression = header->compression;
2945
2946 count = vars->fileExtents->getLength();
2947 if (count > sizeof(header->fileExtentMap))
2948 {
2949 header->fileExtentMapSize = count;
2950 count = sizeof(header->fileExtentMap);
2951 }
2952 else
2953 header->fileExtentMapSize = sizeof(header->fileExtentMap);
2954 bcopy(&fileExtents[0], &header->fileExtentMap[0], count);
2955
2956 header->deviceBase = vars->fileVars->block0;
2957 header->deviceBlockSize = vars->fileVars->blockSize;
2958
2959 IOPolledFileSeek(vars->fileVars, 0);
2960 err = IOPolledFileWrite(vars->fileVars,
2961 (uint8_t *) header, sizeof(IOHibernateImageHeader),
2962 cryptvars);
2963 if (kIOReturnSuccess != err)
2964 break;
2965 err = IOPolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2966 if (kIOReturnSuccess != err)
2967 break;
2968 err = IOHibernatePollerIODone(vars->fileVars, true);
2969 if (kIOReturnSuccess != err)
2970 break;
2971 }
2972 while (false);
2973
2974 clock_get_uptime(&endTime);
2975
2976 IOService::getPMRootDomain()->pmStatsRecordEvent(
2977 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStopFlag, endTime);
2978
2979 SUB_ABSOLUTETIME(&endTime, &allTime);
2980 absolutetime_to_nanoseconds(endTime, &nsec);
2981 HIBLOG("all time: %qd ms, ", nsec / 1000000ULL);
2982
2983 absolutetime_to_nanoseconds(compTime, &nsec);
2984 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2985 compBytes,
2986 nsec / 1000000ULL,
2987 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2988
2989 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2990 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2991 vars->fileVars->cryptBytes,
2992 nsec / 1000000ULL,
2993 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2994
2995 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2996 header->imageSize, (header->imageSize * 100) / vars->fileVars->fileSize,
2997 uncompressedSize, atop_32(uncompressedSize), compressedSize,
2998 uncompressedSize ? ((int) ((compressedSize * 100ULL) / uncompressedSize)) : 0,
2999 sum1, sum2);
3000
3001 HIBLOG("zeroPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
3002 zeroPageCount, wiredPagesEncrypted, wiredPagesClear, dirtyPagesEncrypted);
3003
3004 if (vars->fileVars->io)
3005 (void) IOHibernatePollerIODone(vars->fileVars, false);
3006
3007 if (pollerOpen)
3008 IOHibernatePollerClose(vars->fileVars, kIOPolledBeforeSleepState);
3009
3010 if (vars->consoleMapping)
3011 ProgressUpdate(gIOHibernateGraphicsInfo,
3012 vars->consoleMapping, 0, kIOHibernateProgressCount);
3013
3014 HIBLOG("hibernate_write_image done(%x)\n", err);
3015
3016 // should we come back via regular wake, set the state in memory.
3017 gIOHibernateState = kIOHibernateStateInactive;
3018
3019 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_END,
3020 wiredPagesEncrypted, wiredPagesClear, dirtyPagesEncrypted, 0, 0);
3021
3022 if (kIOReturnSuccess == err)
3023 {
3024 if (kIOHibernateModeSleep & gIOHibernateMode)
3025 {
3026 return (kIOHibernatePostWriteSleep);
3027 }
3028 else if(kIOHibernateModeRestart & gIOHibernateMode)
3029 {
3030 return (kIOHibernatePostWriteRestart);
3031 }
3032 else
3033 {
3034 /* by default, power down */
3035 return (kIOHibernatePostWriteHalt);
3036 }
3037 }
3038 else if (kIOReturnAborted == err)
3039 {
3040 return (kIOHibernatePostWriteWake);
3041 }
3042 else
3043 {
3044 /* on error, sleep */
3045 return (kIOHibernatePostWriteSleep);
3046 }
3047 }
3048
3049 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3050
3051 extern "C" void
3052 hibernate_machine_init(void)
3053 {
3054 IOReturn err;
3055 uint32_t sum;
3056 uint32_t pagesDone;
3057 uint32_t pagesRead = 0;
3058 AbsoluteTime startTime, compTime;
3059 AbsoluteTime allTime, endTime;
3060 AbsoluteTime startIOTime, endIOTime;
3061 uint64_t nsec, nsecIO;
3062 uint64_t compBytes;
3063 uint32_t lastProgressStamp = 0;
3064 uint32_t progressStamp;
3065 hibernate_cryptvars_t * cryptvars = 0;
3066
3067 IOHibernateVars * vars = &gIOHibernateVars;
3068 bzero(gIOHibernateStats, sizeof(hibernate_statistics_t));
3069
3070 if (!vars->fileVars || !vars->fileVars->pollers || !vars->fileExtents)
3071 return;
3072
3073 sum = gIOHibernateCurrentHeader->actualImage1Sum;
3074 pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages;
3075
3076 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState)
3077 {
3078 HIBLOG("regular wake\n");
3079 return;
3080 }
3081
3082 HIBPRINT("diag %x %x %x %x\n",
3083 gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1],
3084 gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]);
3085
3086 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
3087 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
3088 tStat(booterStart, booterStart);
3089 gIOHibernateStats->smcStart = gIOHibernateCurrentHeader->smcStart,
3090 tStat(booterDuration0, booterTime0);
3091 tStat(booterDuration1, booterTime1);
3092 tStat(booterDuration2, booterTime2);
3093 tStat(booterDuration, booterTime);
3094 tStat(booterConnectDisplayDuration, connectDisplayTime);
3095 tStat(booterSplashDuration, splashTime);
3096 tStat(trampolineDuration, trampolineTime);
3097
3098 gIOHibernateStats->image1Size = gIOHibernateCurrentHeader->image1Size;
3099 gIOHibernateStats->imageSize = gIOHibernateCurrentHeader->imageSize;
3100 gIOHibernateStats->image1Pages = pagesDone;
3101
3102 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
3103 gIOHibernateStats->booterStart,
3104 gIOHibernateStats->smcStart,
3105 gIOHibernateStats->booterDuration0,
3106 gIOHibernateStats->booterDuration1,
3107 gIOHibernateStats->booterDuration2,
3108 gIOHibernateStats->booterDuration,
3109 gIOHibernateStats->booterConnectDisplayDuration,
3110 gIOHibernateStats->booterSplashDuration,
3111 gIOHibernateStats->trampolineDuration);
3112
3113 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
3114 gIOHibernateState, pagesDone, sum, gIOHibernateStats->imageSize, gIOHibernateStats->image1Size,
3115 gIOHibernateCurrentHeader->conflictCount, gIOHibernateCurrentHeader->nextFree);
3116
3117 if ((0 != (kIOHibernateModeSleep & gIOHibernateMode))
3118 && (0 != ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode)))
3119 {
3120 hibernate_page_list_discard(vars->page_list);
3121 }
3122
3123 cryptvars = (kIOHibernateModeEncrypt & gIOHibernateMode) ? &gIOHibernateCryptWakeContext : 0;
3124
3125 if (gIOHibernateCurrentHeader->handoffPageCount > gIOHibernateHandoffPageCount)
3126 panic("handoff overflow");
3127
3128 IOHibernateHandoff * handoff;
3129 bool done = false;
3130 bool foundCryptData = false;
3131
3132 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
3133 !done;
3134 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount])
3135 {
3136 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
3137 uint8_t * data = &handoff->data[0];
3138 switch (handoff->type)
3139 {
3140 case kIOHibernateHandoffTypeEnd:
3141 done = true;
3142 break;
3143
3144 case kIOHibernateHandoffTypeGraphicsInfo:
3145 bcopy(data, gIOHibernateGraphicsInfo, sizeof(*gIOHibernateGraphicsInfo));
3146 break;
3147
3148 case kIOHibernateHandoffTypeCryptVars:
3149 if (cryptvars)
3150 {
3151 hibernate_cryptwakevars_t *
3152 wakevars = (hibernate_cryptwakevars_t *) &handoff->data[0];
3153 bcopy(&wakevars->aes_iv[0], &cryptvars->aes_iv[0], sizeof(cryptvars->aes_iv));
3154 }
3155 foundCryptData = true;
3156 bzero(data, handoff->bytecount);
3157 break;
3158
3159 case kIOHibernateHandoffTypeMemoryMap:
3160
3161 clock_get_uptime(&allTime);
3162
3163 hibernate_newruntime_map(data, handoff->bytecount,
3164 gIOHibernateCurrentHeader->systemTableOffset);
3165
3166 clock_get_uptime(&endTime);
3167
3168 SUB_ABSOLUTETIME(&endTime, &allTime);
3169 absolutetime_to_nanoseconds(endTime, &nsec);
3170
3171 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec / 1000000ULL);
3172
3173 break;
3174
3175 case kIOHibernateHandoffTypeDeviceTree:
3176 {
3177 // DTEntry chosen = NULL;
3178 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
3179 }
3180 break;
3181
3182 default:
3183 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
3184 break;
3185 }
3186 }
3187 if (cryptvars && !foundCryptData)
3188 panic("hibernate handoff");
3189
3190 HIBPRINT("video %x %d %d %d status %x\n",
3191 gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth,
3192 gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height, gIOHibernateGraphicsInfo->gfxStatus);
3193
3194 if (vars->videoMapping && gIOHibernateGraphicsInfo->physicalAddress)
3195 {
3196 vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height
3197 * gIOHibernateGraphicsInfo->rowBytes);
3198 if (vars->videoMapSize > vars->videoAllocSize) vars->videoMapSize = 0;
3199 else
3200 {
3201 IOMapPages(kernel_map,
3202 vars->videoMapping, gIOHibernateGraphicsInfo->physicalAddress,
3203 vars->videoMapSize, kIOMapInhibitCache );
3204 }
3205 }
3206
3207 if (vars->videoMapSize)
3208 ProgressUpdate(gIOHibernateGraphicsInfo,
3209 (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);
3210
3211 uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
3212 uint8_t * compressed = src + page_size;
3213 uint8_t * scratch = compressed + page_size;
3214 uint32_t decoOffset;
3215
3216 clock_get_uptime(&allTime);
3217 AbsoluteTime_to_scalar(&compTime) = 0;
3218 compBytes = 0;
3219
3220 HIBLOG("IOHibernatePollerOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
3221 err = IOHibernatePollerOpen(vars->fileVars, kIOPolledAfterSleepState, 0);
3222 clock_get_uptime(&startIOTime);
3223 endTime = startIOTime;
3224 SUB_ABSOLUTETIME(&endTime, &allTime);
3225 absolutetime_to_nanoseconds(endTime, &nsec);
3226 HIBLOG("IOHibernatePollerOpen(%x) %qd ms\n", err, nsec / 1000000ULL);
3227
3228 IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size);
3229
3230 // kick off the read ahead
3231 vars->fileVars->io = false;
3232 vars->fileVars->bufferHalf = 0;
3233 vars->fileVars->bufferLimit = 0;
3234 vars->fileVars->lastRead = 0;
3235 vars->fileVars->readEnd = gIOHibernateCurrentHeader->imageSize;
3236 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
3237 vars->fileVars->cryptBytes = 0;
3238 AbsoluteTime_to_scalar(&vars->fileVars->cryptTime) = 0;
3239
3240 err = IOPolledFileRead(vars->fileVars, 0, 0, cryptvars);
3241 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
3242 // --
3243
3244 HIBLOG("hibernate_machine_init reading\n");
3245
3246 uint32_t * header = (uint32_t *) src;
3247 sum = 0;
3248
3249 while (kIOReturnSuccess == err)
3250 {
3251 unsigned int count;
3252 unsigned int page;
3253 uint32_t tag;
3254 vm_offset_t ppnum, compressedSize;
3255
3256 err = IOPolledFileRead(vars->fileVars, src, 8, cryptvars);
3257 if (kIOReturnSuccess != err)
3258 break;
3259
3260 ppnum = header[0];
3261 count = header[1];
3262
3263 // HIBPRINT("(%x, %x)\n", ppnum, count);
3264
3265 if (!count)
3266 break;
3267
3268 for (page = 0; page < count; page++)
3269 {
3270 err = IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars);
3271 if (kIOReturnSuccess != err)
3272 break;
3273
3274 compressedSize = kIOHibernateTagLength & tag;
3275 if (kIOHibernateTagSignature != (tag & ~kIOHibernateTagLength))
3276 {
3277 err = kIOReturnIPCError;
3278 break;
3279 }
3280
3281 if (!compressedSize) bzero_phys(ptoa_64(ppnum), page_size);
3282 else
3283 {
3284 err = IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars);
3285 if (kIOReturnSuccess != err) break;
3286 if (compressedSize < page_size)
3287 {
3288 decoOffset = page_size;
3289 clock_get_uptime(&startTime);
3290 WKdm_decompress_new((WK_word*) src, (WK_word*) compressed, (WK_word*) scratch, page_size);
3291 clock_get_uptime(&endTime);
3292 ADD_ABSOLUTETIME(&compTime, &endTime);
3293 SUB_ABSOLUTETIME(&compTime, &startTime);
3294 compBytes += page_size;
3295 }
3296 else decoOffset = 0;
3297
3298 sum += hibernate_sum_page((src + decoOffset), ppnum);
3299 err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size);
3300 if (err)
3301 {
3302 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum, err);
3303 break;
3304 }
3305 }
3306
3307 ppnum++;
3308 pagesDone++;
3309 pagesRead++;
3310
3311 if (0 == (8191 & pagesDone))
3312 {
3313 clock_get_uptime(&endTime);
3314 SUB_ABSOLUTETIME(&endTime, &allTime);
3315 absolutetime_to_nanoseconds(endTime, &nsec);
3316 progressStamp = nsec / 750000000ULL;
3317 if (progressStamp != lastProgressStamp)
3318 {
3319 lastProgressStamp = progressStamp;
3320 HIBPRINT("pages %d (%d%%)\n", pagesDone,
3321 (100 * pagesDone) / gIOHibernateCurrentHeader->pageCount);
3322 }
3323 }
3324 }
3325 }
3326 if ((kIOReturnSuccess == err) && (pagesDone == gIOHibernateCurrentHeader->actualUncompressedPages))
3327 err = kIOReturnLockedRead;
3328
3329 if (kIOReturnSuccess != err)
3330 panic("Hibernate restore error %x", err);
3331
3332 gIOHibernateCurrentHeader->actualImage2Sum = sum;
3333 gIOHibernateCompression = gIOHibernateCurrentHeader->compression;
3334
3335 if (vars->fileVars->io)
3336 (void) IOHibernatePollerIODone(vars->fileVars, false);
3337
3338 clock_get_uptime(&endIOTime);
3339
3340 err = IOHibernatePollerClose(vars->fileVars, kIOPolledAfterSleepState);
3341
3342 clock_get_uptime(&endTime);
3343
3344 IOService::getPMRootDomain()->pmStatsRecordEvent(
3345 kIOPMStatsHibernateImageRead | kIOPMStatsEventStartFlag, allTime);
3346 IOService::getPMRootDomain()->pmStatsRecordEvent(
3347 kIOPMStatsHibernateImageRead | kIOPMStatsEventStopFlag, endTime);
3348
3349 SUB_ABSOLUTETIME(&endTime, &allTime);
3350 absolutetime_to_nanoseconds(endTime, &nsec);
3351
3352 SUB_ABSOLUTETIME(&endIOTime, &startIOTime);
3353 absolutetime_to_nanoseconds(endIOTime, &nsecIO);
3354
3355 gIOHibernateStats->kernelImageReadDuration = nsec / 1000000ULL;
3356 gIOHibernateStats->imagePages = pagesDone;
3357
3358 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
3359 pagesDone, sum, gIOHibernateStats->kernelImageReadDuration, kDefaultIOSize,
3360 nsecIO ? ((((gIOHibernateCurrentHeader->imageSize - gIOHibernateCurrentHeader->image1Size) * 1000000000ULL) / 1024 / 1024) / nsecIO) : 0);
3361
3362 absolutetime_to_nanoseconds(compTime, &nsec);
3363 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
3364 compBytes,
3365 nsec / 1000000ULL,
3366 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
3367
3368 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
3369 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
3370 vars->fileVars->cryptBytes,
3371 nsec / 1000000ULL,
3372 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
3373
3374 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE, 2) | DBG_FUNC_NONE, pagesRead, pagesDone, 0, 0, 0);
3375 }
3376
3377 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3378
3379 void IOHibernateSetWakeCapabilities(uint32_t capability)
3380 {
3381 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState)
3382 {
3383 gIOHibernateStats->wakeCapability = capability;
3384
3385 if (kIOPMSystemCapabilityGraphics & capability)
3386 {
3387 vm_compressor_do_warmup();
3388 }
3389 }
3390 }
3391
3392 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3393
3394 void IOHibernateSystemRestart(void)
3395 {
3396 static uint8_t noteStore[32] __attribute__((aligned(32)));
3397 IORegistryEntry * regEntry;
3398 const OSSymbol * sym;
3399 OSData * noteProp;
3400 OSData * data;
3401 uintptr_t * smcVars;
3402 uint8_t * smcBytes;
3403 size_t len;
3404 addr64_t element;
3405
3406 data = OSDynamicCast(OSData, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey));
3407 if (!data) return;
3408
3409 smcVars = (typeof(smcVars)) data->getBytesNoCopy();
3410 smcBytes = (typeof(smcBytes)) smcVars[1];
3411 len = smcVars[0];
3412 if (len > sizeof(noteStore)) len = sizeof(noteStore);
3413 noteProp = OSData::withCapacity(3 * sizeof(element));
3414 if (!noteProp) return;
3415 element = len;
3416 noteProp->appendBytes(&element, sizeof(element));
3417 element = crc32(0, smcBytes, len);
3418 noteProp->appendBytes(&element, sizeof(element));
3419
3420 bcopy(smcBytes, noteStore, len);
3421 element = (addr64_t) &noteStore[0];
3422 element = (element & page_mask) | ptoa_64(pmap_find_phys(kernel_pmap, element));
3423 noteProp->appendBytes(&element, sizeof(element));
3424
3425 if (!gIOOptionsEntry)
3426 {
3427 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
3428 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
3429 if (regEntry && !gIOOptionsEntry)
3430 regEntry->release();
3431 }
3432
3433 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey);
3434 if (gIOOptionsEntry && sym) gIOOptionsEntry->setProperty(sym, noteProp);
3435 if (noteProp) noteProp->release();
3436 if (sym) sym->release();
3437 }
3438
3439
3440