1 /*
2 * Copyright (c) 2004-2016 Apple 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 * Sleep:
32 *
33 * - PMRootDomain calls IOHibernateSystemSleep() before system sleep
34 * (devices awake, normal execution context)
35 * - IOHibernateSystemSleep opens the hibernation file (or partition) at the bsd level,
36 * grabs its extents and searches for a polling driver willing to work with that IOMedia.
37 * The BSD code makes an ioctl to the storage driver to get the partition base offset to
38 * the disk, and other ioctls to get the transfer constraints
39 * If successful, the file is written to make sure its initially not bootable (in case of
40 * later failure) and nvram set to point to the first block of the file. (Has to be done
41 * here so blocking is possible in nvram support).
42 * hibernate_setup() in osfmk is called to allocate page bitmaps for all dram, and
43 * page out any pages it wants to (currently zero, but probably some percentage of memory).
44 * Its assumed just allocating pages will cause the VM system to naturally select the best
45 * pages for eviction. It also copies processor flags needed for the restore path and sets
46 * a flag in the boot processor proc info.
47 * gIOHibernateState = kIOHibernateStateHibernating.
48 * - Regular sleep progresses - some drivers may inspect the root domain property
49 * kIOHibernateStateKey to modify behavior. The platform driver saves state to memory
50 * as usual but leaves motherboard I/O on.
51 * - Eventually the platform calls ml_ppc_sleep() in the shutdown context on the last cpu,
52 * at which point memory is ready to be saved. mapping_hibernate_flush() is called to get
53 * all ppc RC bits out of the hash table and caches into the mapping structures.
54 * - hibernate_write_image() is called (still in shutdown context, no blocking or preemption).
55 * hibernate_page_list_setall() is called to get a bitmap of dram pages that need to be saved.
56 * All pages are assumed to be saved (as part of the wired image) unless explicitly subtracted
57 * by hibernate_page_list_setall(), avoiding having to find arch dependent low level bits.
58 * The image header and block list are written. The header includes the second file extent so
59 * only the header block is needed to read the file, regardless of filesystem.
60 * The kernel segment "__HIB" is written uncompressed to the image. This segment of code and data
61 * (only) is used to decompress the image during wake/boot.
62 * Some additional pages are removed from the bitmaps - the buffers used for hibernation.
63 * The bitmaps are written to the image.
64 * More areas are removed from the bitmaps (after they have been written to the image) - the
65 * segment "__HIB" pages and interrupt stack.
66 * Each wired page is compressed and written and then each non-wired page. Compression and
67 * disk writes are in parallel.
68 * The image header is written to the start of the file and the polling driver closed.
69 * The machine powers down (or sleeps).
70 *
71 * Boot/Wake:
72 *
73 * - BootX sees the boot-image nvram variable containing the device and block number of the image,
74 * reads the header and if the signature is correct proceeds. The boot-image variable is cleared.
75 * - BootX reads the portion of the image used for wired pages, to memory. Its assumed this will fit
76 * in the OF memory environment, and the image is decrypted. There is no decompression in BootX,
77 * that is in the kernel's __HIB section.
78 * - BootX copies the "__HIB" section to its correct position in memory, quiesces and calls its entry
79 * hibernate_kernel_entrypoint(), passing the location of the image in memory. Translation is off,
80 * only code & data in that section is safe to call since all the other wired pages are still
81 * compressed in the image.
82 * - hibernate_kernel_entrypoint() removes pages occupied by the raw image from the page bitmaps.
83 * It uses the bitmaps to work out which pages can be uncompressed from the image to their final
84 * location directly, and copies those that can't to interim free pages. When the image has been
85 * completed, the copies are uncompressed, overwriting the wired image pages.
86 * hibernate_restore_phys_page() (in osfmk since its arch dependent, but part of the "__HIB" section)
87 * is used to get pages into place for 64bit.
88 * - the reset vector is called (at least on ppc), the kernel proceeds on a normal wake, with some
89 * changes conditional on the per proc flag - before VM is turned on the boot cpu, all mappings
90 * are removed from the software strutures, and the hash table is reinitialized.
91 * - After the platform CPU init code is called, hibernate_machine_init() is called to restore the rest
92 * of memory, using the polled mode driver, before other threads can run or any devices are turned on.
93 * This reduces the memory usage for BootX and allows decompression in parallel with disk reads,
94 * for the remaining non wired pages.
95 * - The polling driver is closed down and regular wake proceeds. When the kernel calls iokit to wake
96 * (normal execution context) hibernate_teardown() in osmfk is called to release any memory, the file
97 * is closed via bsd.
98 *
99 * Polled Mode I/O:
100 *
101 * IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
102 * registry, specifying an object of calls IOPolledInterface.
103 *
104 * Before the system goes to sleep it searches from the IOMedia object (could be a filesystem or
105 * partition) that the image is going to live, looking for polled interface properties. If it finds
106 * one the IOMedia object is passed to a "probe" call for the interface to accept or reject. All the
107 * interfaces found are kept in an ordered list.
108 *
109 * There is an Open/Close pair of calls made to each of the interfaces at various stages since there are
110 * few different contexts things happen in:
111 *
112 * - there is an Open/Close (Preflight) made before any part of the system has slept (I/O is all
113 * up and running) and after wake - this is safe to allocate memory and do anything. The device
114 * ignores sleep requests from that point since its a waste of time if it goes to sleep and
115 * immediately wakes back up for the image write.
116 *
117 * - there is an Open/Close (BeforeSleep) pair made around the image write operations that happen
118 * immediately before sleep. These can't block or allocate memory - the I/O system is asleep apart
119 * from the low level bits (motherboard I/O etc). There is only one thread running. The close can be
120 * used to flush and set the disk to sleep.
121 *
122 * - there is an Open/Close (AfterSleep) pair made around the image read operations that happen
123 * immediately after sleep. These can't block or allocate memory. This is happening after the platform
124 * expert has woken the low level bits of the system, but most of the I/O system has not. There is only
125 * one thread running.
126 *
127 * For the actual I/O, all the ops are with respect to a single IOMemoryDescriptor that was passed
128 * (prepared) to the Preflight Open() call. There is a read/write op, buffer offset to the IOMD for
129 * the data, an offset to the disk and length (block aligned 64 bit numbers), and completion callback.
130 * Each I/O is async but only one is ever outstanding. The polled interface has a checkForWork call
131 * that is called for the hardware to check for events, and complete the I/O via the callback.
132 * The hibernate path uses the same transfer constraints the regular cluster I/O path in BSD uses
133 * to restrict I/O ops.
134 */
135
136 #include <sys/systm.h>
137
138 #include <IOKit/IOWorkLoop.h>
139 #include <IOKit/IOCommandGate.h>
140 #include <IOKit/IOTimerEventSource.h>
141 #include <IOKit/IOPlatformExpert.h>
142 #include <IOKit/IOKitDebug.h>
143 #include <IOKit/IOTimeStamp.h>
144 #include <IOKit/pwr_mgt/RootDomain.h>
145 #include <IOKit/pwr_mgt/IOPMPrivate.h>
146 #include <IOKit/IOMessage.h>
147 #include <IOKit/IODeviceTreeSupport.h>
148 #include <IOKit/IOBSD.h>
149 #include <IOKit/IOKitKeysPrivate.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/vm_protos.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 #if defined(__i386__) || defined(__x86_64__)
176 #include <i386/tsc.h>
177 #include <i386/cpuid.h>
178 #include <vm/WKdm_new.h>
179 #elif defined(__arm64__)
180 #include <arm64/amcc_rorgn.h>
181 #include <kern/ecc.h>
182 #endif /* defined(__i386__) || defined(__x86_64__) */
183 #include <san/kasan.h>
184
185
186 extern "C" addr64_t kvtophys(vm_offset_t va);
187 extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
188
189 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
190
191 #define DISABLE_TRIM 0
192 #define TRIM_DELAY 25000
193
194 extern unsigned int save_kdebug_enable;
195 extern uint32_t gIOHibernateState;
196 uint32_t gIOHibernateMode;
197 static char gIOHibernateBootSignature[256 + 1];
198 static char gIOHibernateFilename[MAXPATHLEN + 1];
199 uint32_t gIOHibernateCount;
200
201 static uuid_string_t gIOHibernateBridgeBootSessionUUIDString;
202
203 static uint32_t gIOHibernateFreeRatio = 0; // free page target (percent)
204 uint32_t gIOHibernateFreeTime = 0 * 1000; // max time to spend freeing pages (ms)
205
206 enum {
207 HIB_COMPR_RATIO_ARM64 = (0xa5), // compression ~65%. Since we don't support retries we start higher.
208 HIB_COMPR_RATIO_INTEL = (0x80) // compression 50%
209 };
210
211 #if defined(__arm64__)
212 static uint64_t gIOHibernateCompression = HIB_COMPR_RATIO_ARM64;
213 #else
214 static uint64_t gIOHibernateCompression = HIB_COMPR_RATIO_INTEL;
215 #endif /* __arm64__ */
216 boolean_t gIOHibernateStandbyDisabled;
217
218 static IODTNVRAM * gIOOptionsEntry;
219 static IORegistryEntry * gIOChosenEntry;
220
221 static const OSSymbol * gIOHibernateBootImageKey;
222 static const OSSymbol * gIOHibernateBootSignatureKey;
223 static const OSSymbol * gIOBridgeBootSessionUUIDKey;
224
225 #if defined(__i386__) || defined(__x86_64__)
226
227 static const OSSymbol * gIOHibernateRTCVariablesKey;
228 static const OSSymbol * gIOHibernateBoot0082Key;
229 static const OSSymbol * gIOHibernateBootNextKey;
230 static OSData * gIOHibernateBoot0082Data;
231 static OSData * gIOHibernateBootNextData;
232 static OSObject * gIOHibernateBootNextSave;
233
234 #endif /* defined(__i386__) || defined(__x86_64__) */
235
236 static IOLock * gFSLock;
237 uint32_t gFSState;
238 static thread_call_t gIOHibernateTrimCalloutEntry;
239 static IOPolledFileIOVars gFileVars;
240 static IOHibernateVars gIOHibernateVars;
241 static IOPolledFileCryptVars gIOHibernateCryptWakeContext;
242 static hibernate_graphics_t _hibernateGraphics;
243 static hibernate_graphics_t * gIOHibernateGraphicsInfo = &_hibernateGraphics;
244 static hibernate_statistics_t _hibernateStats;
245 static hibernate_statistics_t * gIOHibernateStats = &_hibernateStats;
246
247 enum{
248 kFSIdle = 0,
249 kFSOpening = 2,
250 kFSOpened = 3,
251 kFSTimedOut = 4,
252 kFSTrimDelay = 5
253 };
254
255 static IOReturn IOHibernateDone(IOHibernateVars * vars);
256 static IOReturn IOWriteExtentsToFile(IOPolledFileIOVars * vars, uint32_t signature);
257 static void IOSetBootImageNVRAM(OSData * data);
258 static void IOHibernateSystemPostWakeTrim(void * p1, void * p2);
259
260 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
261
262 enum { kDefaultIOSize = 128 * 1024 };
263 enum { kVideoMapSize = 80 * 1024 * 1024 };
264
265 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
266
267 // copy from phys addr to MD
268
269 static IOReturn
IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,IOByteCount offset,addr64_t bytes,IOByteCount length)270 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,
271 IOByteCount offset, addr64_t bytes, IOByteCount length)
272 {
273 addr64_t srcAddr = bytes;
274 IOByteCount remaining;
275
276 remaining = length = min(length, md->getLength() - offset);
277 while (remaining) { // (process another target segment?)
278 addr64_t dstAddr64;
279 IOByteCount dstLen;
280
281 dstAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
282 if (!dstAddr64) {
283 break;
284 }
285
286 // Clip segment length to remaining
287 if (dstLen > remaining) {
288 dstLen = remaining;
289 }
290
291 #if 1
292 bcopy_phys(srcAddr, dstAddr64, dstLen);
293 #else
294 copypv(srcAddr, dstAddr64, dstLen,
295 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
296 #endif
297 srcAddr += dstLen;
298 offset += dstLen;
299 remaining -= dstLen;
300 }
301
302 assert(!remaining);
303
304 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
305 }
306
307 // copy from MD to phys addr
308
309 static IOReturn
IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,IOByteCount offset,addr64_t bytes,IOByteCount length)310 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,
311 IOByteCount offset, addr64_t bytes, IOByteCount length)
312 {
313 addr64_t dstAddr = bytes;
314 IOByteCount remaining;
315
316 remaining = length = min(length, md->getLength() - offset);
317 while (remaining) { // (process another target segment?)
318 addr64_t srcAddr64;
319 IOByteCount dstLen;
320
321 srcAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
322 if (!srcAddr64) {
323 break;
324 }
325
326 // Clip segment length to remaining
327 if (dstLen > remaining) {
328 dstLen = remaining;
329 }
330
331 #if 1
332 bcopy_phys(srcAddr64, dstAddr, dstLen);
333 #else
334 copypv(srcAddr, dstAddr64, dstLen,
335 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
336 #endif
337 dstAddr += dstLen;
338 offset += dstLen;
339 remaining -= dstLen;
340 }
341
342 assert(!remaining);
343
344 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
345 }
346
347 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
348
349 void
hibernate_set_page_state(hibernate_page_list_t * page_list,hibernate_page_list_t * page_list_wired,vm_offset_t ppnum,vm_offset_t count,uint32_t kind)350 hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_t * page_list_wired,
351 vm_offset_t ppnum, vm_offset_t count, uint32_t kind)
352 {
353 count += ppnum;
354
355 if (count > UINT_MAX) {
356 panic("hibernate_set_page_state ppnum");
357 }
358
359 switch (kind) {
360 case kIOHibernatePageStateUnwiredSave:
361 // unwired save
362 for (; ppnum < count; ppnum++) {
363 hibernate_page_bitset(page_list, FALSE, (uint32_t) ppnum);
364 hibernate_page_bitset(page_list_wired, TRUE, (uint32_t) ppnum);
365 }
366 break;
367 case kIOHibernatePageStateWiredSave:
368 // wired save
369 for (; ppnum < count; ppnum++) {
370 hibernate_page_bitset(page_list, FALSE, (uint32_t) ppnum);
371 hibernate_page_bitset(page_list_wired, FALSE, (uint32_t) ppnum);
372 }
373 break;
374 case kIOHibernatePageStateFree:
375 // free page
376 for (; ppnum < count; ppnum++) {
377 hibernate_page_bitset(page_list, TRUE, (uint32_t) ppnum);
378 hibernate_page_bitset(page_list_wired, TRUE, (uint32_t) ppnum);
379 }
380 break;
381 default:
382 panic("hibernate_set_page_state");
383 }
384 }
385
386 static void
hibernate_set_descriptor_page_state(IOHibernateVars * vars,IOMemoryDescriptor * descriptor,uint32_t kind,uint32_t * pageCount)387 hibernate_set_descriptor_page_state(IOHibernateVars *vars,
388 IOMemoryDescriptor *descriptor,
389 uint32_t kind,
390 uint32_t *pageCount)
391 {
392 IOItemCount count;
393 addr64_t phys64;
394 IOByteCount segLen;
395 if (descriptor) {
396 for (count = 0;
397 (phys64 = descriptor->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
398 count += segLen) {
399 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
400 atop_64(phys64), atop_32(segLen),
401 kind);
402 *pageCount -= atop_32(segLen);
403 }
404 }
405 }
406
407 static vm_offset_t
hibernate_page_list_iterate(hibernate_page_list_t * list,ppnum_t * pPage)408 hibernate_page_list_iterate(hibernate_page_list_t * list, ppnum_t * pPage)
409 {
410 uint32_t page = ((typeof(page)) * pPage);
411 uint32_t count;
412 hibernate_bitmap_t * bitmap;
413
414 while ((bitmap = hibernate_page_bitmap_pin(list, &page))) {
415 count = hibernate_page_bitmap_count(bitmap, TRUE, page);
416 if (!count) {
417 break;
418 }
419 page += count;
420 if (page <= bitmap->last_page) {
421 break;
422 }
423 }
424
425 *pPage = page;
426 if (bitmap) {
427 count = hibernate_page_bitmap_count(bitmap, FALSE, page);
428 } else {
429 count = 0;
430 }
431
432 return count;
433 }
434
435 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
436
437 IOReturn
IOHibernateSystemSleep(void)438 IOHibernateSystemSleep(void)
439 {
440 IOReturn err;
441 OSData * nvramData;
442 OSObject * obj;
443 OSString * str;
444 OSNumber * num;
445 bool dsSSD, vmflush, swapPinned;
446 IOHibernateVars * vars;
447 uint64_t setFileSize = 0;
448
449 gIOHibernateState = kIOHibernateStateInactive;
450
451 #if defined(__arm64__)
452 #endif /* __arm64__ */
453
454 gIOHibernateDebugFlags = 0;
455 if (kIOLogHibernate & gIOKitDebug) {
456 gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
457 }
458
459 if (IOService::getPMRootDomain()->getHibernateSettings(
460 &gIOHibernateMode, &gIOHibernateFreeRatio, &gIOHibernateFreeTime)) {
461 if (kIOHibernateModeSleep & gIOHibernateMode) {
462 // default to discard clean for safe sleep
463 gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
464 | kIOHibernateModeDiscardCleanActive);
465 }
466 }
467
468 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey))) {
469 if ((str = OSDynamicCast(OSString, obj))) {
470 strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
471 sizeof(gIOHibernateFilename));
472 }
473 obj->release();
474 }
475
476 if (!gIOHibernateMode || !gIOHibernateFilename[0]) {
477 return kIOReturnUnsupported;
478 }
479
480 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
481
482 vars = IOMallocType(IOHibernateVars);
483
484 IOLockLock(gFSLock);
485 if (!gIOHibernateTrimCalloutEntry) {
486 gIOHibernateTrimCalloutEntry = thread_call_allocate(&IOHibernateSystemPostWakeTrim, &gFSLock);
487 }
488 IOHibernateSystemPostWakeTrim(NULL, NULL);
489 thread_call_cancel(gIOHibernateTrimCalloutEntry);
490 if (kFSIdle != gFSState) {
491 HIBLOG("hibernate file busy\n");
492 IOLockUnlock(gFSLock);
493 IOFreeType(vars, IOHibernateVars);
494 return kIOReturnBusy;
495 }
496 gFSState = kFSOpening;
497 IOLockUnlock(gFSLock);
498
499 swapPinned = false;
500 do{
501 vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
502 HIBERNATION_SRC_BUFFER_SIZE, page_size);
503
504 vars->handoffBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
505 ptoa_64(gIOHibernateHandoffPageCount), page_size);
506
507 if (!vars->srcBuffer || !vars->handoffBuffer) {
508 err = kIOReturnNoMemory;
509 break;
510 }
511
512 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey))) {
513 if ((num = OSDynamicCast(OSNumber, obj))) {
514 vars->fileMinSize = num->unsigned64BitValue();
515 }
516 obj->release();
517 }
518 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey))) {
519 if ((num = OSDynamicCast(OSNumber, obj))) {
520 vars->fileMaxSize = num->unsigned64BitValue();
521 }
522 obj->release();
523 }
524
525 boolean_t encryptedswap = true;
526 uint32_t pageCount;
527 AbsoluteTime startTime, endTime;
528 uint64_t nsec;
529
530 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
531 gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
532 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
533
534 vmflush = ((kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
535 err = hibernate_alloc_page_lists(&vars->page_list,
536 &vars->page_list_wired,
537 &vars->page_list_pal);
538 if (KERN_SUCCESS != err) {
539 HIBLOG("%s err, hibernate_alloc_page_lists return 0x%x\n", __FUNCTION__, err);
540 break;
541 }
542
543 err = hibernate_pin_swap(TRUE);
544 if (KERN_SUCCESS != err) {
545 HIBLOG("%s error, hibernate_pin_swap return 0x%x\n", __FUNCTION__, err);
546 break;
547 }
548 swapPinned = true;
549
550 if (vars->fileMinSize || (kIOHibernateModeFileResize & gIOHibernateMode)) {
551 hibernate_page_list_setall(vars->page_list,
552 vars->page_list_wired,
553 vars->page_list_pal,
554 true /* preflight */,
555 vmflush /* discard */,
556 &pageCount);
557 PE_Video consoleInfo;
558 bzero(&consoleInfo, sizeof(consoleInfo));
559 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
560
561 // estimate: 6% increase in pages compressed
562 // screen preview 2 images compressed 0%
563 setFileSize = ((ptoa_64((106 * pageCount) / 100) * gIOHibernateCompression) >> 8)
564 + vars->page_list->list_size
565 + (consoleInfo.v_width * consoleInfo.v_height * 8);
566 enum { setFileRound = 1024 * 1024ULL };
567 setFileSize = ((setFileSize + setFileRound) & ~(setFileRound - 1));
568
569 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
570 pageCount, (100ULL * gIOHibernateCompression) >> 8,
571 setFileSize, vars->fileMinSize);
572
573 if (!(kIOHibernateModeFileResize & gIOHibernateMode)
574 && (setFileSize < vars->fileMinSize)) {
575 setFileSize = vars->fileMinSize;
576 }
577 }
578
579 vars->volumeCryptKeySize = sizeof(vars->volumeCryptKey);
580 err = IOPolledFileOpen(gIOHibernateFilename,
581 (kIOPolledFileCreate | kIOPolledFileHibernate),
582 setFileSize, 0,
583 gIOHibernateCurrentHeader, sizeof(gIOHibernateCurrentHeader),
584 &vars->fileVars, &nvramData,
585 &vars->volumeCryptKey[0], &vars->volumeCryptKeySize);
586
587 if (KERN_SUCCESS != err) {
588 IOLockLock(gFSLock);
589 if (kFSOpening != gFSState) {
590 err = kIOReturnTimeout;
591 }
592 IOLockUnlock(gFSLock);
593 }
594
595 if (KERN_SUCCESS != err) {
596 HIBLOG("IOPolledFileOpen(%x)\n", err);
597 OSSafeReleaseNULL(nvramData);
598 break;
599 }
600
601 // write extents for debug data usage in EFI
602 IOWriteExtentsToFile(vars->fileVars, kIOHibernateHeaderOpenSignature);
603
604 err = IOPolledFilePollersSetup(vars->fileVars, kIOPolledPreflightState);
605 if (KERN_SUCCESS != err) {
606 OSSafeReleaseNULL(nvramData);
607 break;
608 }
609
610 clock_get_uptime(&startTime);
611 err = hibernate_setup(gIOHibernateCurrentHeader,
612 vmflush,
613 vars->page_list, vars->page_list_wired, vars->page_list_pal);
614 clock_get_uptime(&endTime);
615 SUB_ABSOLUTETIME(&endTime, &startTime);
616 absolutetime_to_nanoseconds(endTime, &nsec);
617
618 boolean_t haveSwapPin, hibFileSSD;
619 haveSwapPin = vm_swap_files_pinned();
620
621 hibFileSSD = (kIOPolledFileSSD & vars->fileVars->flags);
622
623 HIBLOG("hibernate_setup(%d) took %qd ms, swapPin(%d) ssd(%d)\n",
624 err, nsec / 1000000ULL,
625 haveSwapPin, hibFileSSD);
626 if (KERN_SUCCESS != err) {
627 OSSafeReleaseNULL(nvramData);
628 break;
629 }
630
631 gIOHibernateStandbyDisabled = ((!haveSwapPin || !hibFileSSD));
632
633 dsSSD = ((0 != (kIOPolledFileSSD & vars->fileVars->flags))
634 && (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
635
636 if (dsSSD) {
637 gIOHibernateCurrentHeader->options |= kIOHibernateOptionSSD | kIOHibernateOptionColor;
638 } else {
639 gIOHibernateCurrentHeader->options |= kIOHibernateOptionProgress;
640 }
641
642
643 #if defined(__i386__) || defined(__x86_64__)
644 if (vars->volumeCryptKeySize &&
645 (kOSBooleanTrue != IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey))) {
646 OSData * smcData;
647 smcData = OSData::withBytesNoCopy(&gIOHibernateVars.volumeCryptKey[0], (unsigned int)vars->volumeCryptKeySize);
648 if (smcData) {
649 smcData->setSerializable(false);
650 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey, smcData);
651 smcData->release();
652 }
653 }
654 #endif /* defined(__i386__) || defined(__x86_64__) */
655
656 if (encryptedswap || vars->volumeCryptKeySize) {
657 gIOHibernateMode ^= kIOHibernateModeEncrypt;
658 }
659
660 if (kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options) {
661 vars->videoAllocSize = kVideoMapSize;
662 if (KERN_SUCCESS != kmem_alloc(kernel_map, &vars->videoMapping, vars->videoAllocSize,
663 (kma_flags_t)(KMA_PAGEABLE | KMA_DATA), VM_KERN_MEMORY_IOKIT)) {
664 vars->videoMapping = 0;
665 }
666 }
667
668 // generate crypt keys
669 for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++) {
670 vars->wiredCryptKey[i] = ((uint8_t) random());
671 }
672 for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++) {
673 vars->cryptKey[i] = ((uint8_t) random());
674 }
675
676 // set nvram
677
678 IOSetBootImageNVRAM(nvramData);
679 OSSafeReleaseNULL(nvramData);
680
681 #if defined(__i386__) || defined(__x86_64__)
682 {
683 struct AppleRTCHibernateVars {
684 uint8_t signature[4];
685 uint32_t revision;
686 uint8_t booterSignature[20];
687 uint8_t wiredCryptKey[16];
688 };
689 AppleRTCHibernateVars rtcVars;
690 OSData * data;
691
692 rtcVars.signature[0] = 'A';
693 rtcVars.signature[1] = 'A';
694 rtcVars.signature[2] = 'P';
695 rtcVars.signature[3] = 'L';
696 rtcVars.revision = 1;
697 bcopy(&vars->wiredCryptKey[0], &rtcVars.wiredCryptKey[0], sizeof(rtcVars.wiredCryptKey));
698
699 if (gIOChosenEntry
700 && (data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(gIOHibernateBootSignatureKey)))
701 && (sizeof(rtcVars.booterSignature) <= data->getLength())) {
702 bcopy(data->getBytesNoCopy(), &rtcVars.booterSignature[0], sizeof(rtcVars.booterSignature));
703 } else if (gIOHibernateBootSignature[0]) {
704 char c;
705 uint8_t value = 0;
706 uint32_t in, out, digits;
707 for (in = out = digits = 0;
708 (c = gIOHibernateBootSignature[in]) && (in < sizeof(gIOHibernateBootSignature));
709 in++) {
710 if ((c >= 'a') && (c <= 'f')) {
711 c -= 'a' - 10;
712 } else if ((c >= 'A') && (c <= 'F')) {
713 c -= 'A' - 10;
714 } else if ((c >= '0') && (c <= '9')) {
715 c -= '0';
716 } else {
717 if (c == '=') {
718 out = digits = value = 0;
719 }
720 continue;
721 }
722 value = ((uint8_t) ((value << 4) | c));
723 if (digits & 1) {
724 rtcVars.booterSignature[out++] = value;
725 if (out >= sizeof(rtcVars.booterSignature)) {
726 break;
727 }
728 }
729 digits++;
730 }
731 }
732 #if DEBUG || DEVELOPMENT
733 if (kIOLogHibernate & gIOKitDebug) {
734 IOKitKernelLogBuffer("H> rtc:",
735 &rtcVars, sizeof(rtcVars), &kprintf);
736 }
737 #endif /* DEBUG || DEVELOPMENT */
738
739 data = OSData::withValue(rtcVars);
740 if (data) {
741 if (gIOHibernateRTCVariablesKey) {
742 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey, data);
743 }
744 data->release();
745 }
746 if (gIOChosenEntry && gIOOptionsEntry) {
747 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
748 if (data) {
749 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
750 }
751 // set BootNext
752 if (!gIOHibernateBoot0082Data) {
753 OSData * fileData = NULL;
754 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-device-path"));
755 if (data && data->getLength() >= 4) {
756 fileData = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-file-path"));
757 }
758 if (data && (data->getLength() <= UINT16_MAX)) {
759 // AppleNVRAM_EFI_LOAD_OPTION
760 struct {
761 uint32_t Attributes;
762 uint16_t FilePathLength;
763 uint16_t Desc;
764 } loadOptionHeader;
765 loadOptionHeader.Attributes = 1;
766 loadOptionHeader.FilePathLength = ((uint16_t) data->getLength());
767 loadOptionHeader.Desc = 0;
768 if (fileData) {
769 loadOptionHeader.FilePathLength -= 4;
770 loadOptionHeader.FilePathLength += fileData->getLength();
771 }
772 gIOHibernateBoot0082Data = OSData::withCapacity(sizeof(loadOptionHeader) + loadOptionHeader.FilePathLength);
773 if (gIOHibernateBoot0082Data) {
774 gIOHibernateBoot0082Data->appendValue(loadOptionHeader);
775 if (fileData) {
776 gIOHibernateBoot0082Data->appendBytes(data->getBytesNoCopy(), data->getLength() - 4);
777 gIOHibernateBoot0082Data->appendBytes(fileData);
778 } else {
779 gIOHibernateBoot0082Data->appendBytes(data);
780 }
781 }
782 }
783 }
784 if (!gIOHibernateBootNextData) {
785 uint16_t bits = 0x0082;
786 gIOHibernateBootNextData = OSData::withValue(bits);
787 }
788
789 #if DEBUG || DEVELOPMENT
790 if (kIOLogHibernate & gIOKitDebug) {
791 IOKitKernelLogBuffer("H> bootnext:",
792 gIOHibernateBoot0082Data->getBytesNoCopy(), gIOHibernateBoot0082Data->getLength(), &kprintf);
793 }
794 #endif /* DEBUG || DEVELOPMENT */
795 if (gIOHibernateBoot0082Key && gIOHibernateBoot0082Data && gIOHibernateBootNextKey && gIOHibernateBootNextData) {
796 gIOHibernateBootNextSave = gIOOptionsEntry->copyProperty(gIOHibernateBootNextKey);
797 gIOOptionsEntry->setProperty(gIOHibernateBoot0082Key, gIOHibernateBoot0082Data);
798 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextData);
799 }
800 // BootNext
801 }
802 }
803 #endif /* !i386 && !x86_64 */
804 }while (false);
805
806 if (swapPinned) {
807 hibernate_pin_swap(FALSE);
808 }
809
810 IOLockLock(gFSLock);
811 if ((kIOReturnSuccess == err) && (kFSOpening != gFSState)) {
812 HIBLOG("hibernate file close due timeout\n");
813 err = kIOReturnTimeout;
814 }
815 if (kIOReturnSuccess == err) {
816 gFSState = kFSOpened;
817 gIOHibernateVars = *vars;
818 gFileVars = *vars->fileVars;
819 gFileVars.allocated = false;
820 gIOHibernateVars.fileVars = &gFileVars;
821 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderSignature;
822 gIOHibernateCurrentHeader->kernVirtSlide = vm_kernel_slide;
823 gIOHibernateState = kIOHibernateStateHibernating;
824
825 #if DEBUG || DEVELOPMENT
826 #if defined(__i386__) || defined(__x86_64__)
827 if (kIOLogHibernate & gIOKitDebug) {
828 OSData * data = OSDynamicCast(OSData, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey));
829 if (data) {
830 IOKitKernelLogBuffer("H> smc:",
831 data->getBytesNoCopy(), data->getLength(), &kprintf);
832 }
833 }
834 #endif /* defined(__i386__) || defined(__x86_64__) */
835 #endif /* DEBUG || DEVELOPMENT */
836 } else {
837 IOPolledFileIOVars * fileVars = vars->fileVars;
838 IOHibernateDone(vars);
839 IOPolledFileClose(&fileVars,
840 #if DISABLE_TRIM
841 0, NULL, 0, 0, 0, false);
842 #else
843 0, NULL, 0, sizeof(IOHibernateImageHeader), setFileSize, false);
844 #endif
845 gFSState = kFSIdle;
846 }
847 IOLockUnlock(gFSLock);
848
849 if (vars->fileVars) {
850 IOFreeType(vars->fileVars, IOPolledFileIOVars);
851 }
852 IOFreeType(vars, IOHibernateVars);
853
854 return err;
855 }
856
857 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
858
859 static void
IOSetBootImageNVRAM(OSData * data)860 IOSetBootImageNVRAM(OSData * data)
861 {
862 IORegistryEntry * regEntry;
863
864 if (!gIOOptionsEntry) {
865 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
866 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
867 if (regEntry && !gIOOptionsEntry) {
868 regEntry->release();
869 }
870 }
871 if (gIOOptionsEntry && gIOHibernateBootImageKey) {
872 if (data) {
873 gIOOptionsEntry->setProperty(gIOHibernateBootImageKey, data);
874 #if DEBUG || DEVELOPMENT
875 if (kIOLogHibernate & gIOKitDebug) {
876 IOKitKernelLogBuffer("H> boot-image:",
877 data->getBytesNoCopy(), data->getLength(), &kprintf);
878 }
879 #endif /* DEBUG || DEVELOPMENT */
880 } else {
881 gIOOptionsEntry->removeProperty(gIOHibernateBootImageKey);
882 #if __x86_64__
883 gIOOptionsEntry->sync();
884 #else
885 if (gIOHibernateState == kIOHibernateStateWakingFromHibernate) {
886 // if we woke from hibernation, the booter may have changed the state of NVRAM, so force a sync
887 gIOOptionsEntry->sync();
888 }
889 #endif
890 }
891 }
892 }
893
894 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
895 /*
896 * Writes header to disk with signature, block size and file extents data.
897 * If there are more than 2 extents, then they are written on second block.
898 */
899 static IOReturn
IOWriteExtentsToFile(IOPolledFileIOVars * vars,uint32_t signature)900 IOWriteExtentsToFile(IOPolledFileIOVars * vars, uint32_t signature)
901 {
902 IOHibernateImageHeader hdr;
903 IOItemCount count;
904 IOReturn err = kIOReturnSuccess;
905 int rc;
906 IOPolledFileExtent * fileExtents;
907
908 fileExtents = (typeof(fileExtents))vars->fileExtents->getBytesNoCopy();
909
910 memset(&hdr, 0, sizeof(IOHibernateImageHeader));
911 count = vars->fileExtents->getLength();
912 if (count > sizeof(hdr.fileExtentMap)) {
913 hdr.fileExtentMapSize = count;
914 count = sizeof(hdr.fileExtentMap);
915 } else {
916 hdr.fileExtentMapSize = sizeof(hdr.fileExtentMap);
917 }
918
919 bcopy(fileExtents, &hdr.fileExtentMap[0], count);
920
921 // copy file block extent list if larger than header
922 if (hdr.fileExtentMapSize > sizeof(hdr.fileExtentMap)) {
923 count = hdr.fileExtentMapSize - sizeof(hdr.fileExtentMap);
924 rc = kern_write_file(vars->fileRef, vars->blockSize,
925 (caddr_t)(((uint8_t *)fileExtents) + sizeof(hdr.fileExtentMap)),
926 count, IO_SKIP_ENCRYPTION);
927 if (rc != 0) {
928 HIBLOG("kern_write_file returned %d\n", rc);
929 err = kIOReturnIOError;
930 goto exit;
931 }
932 }
933 hdr.signature = signature;
934 hdr.deviceBlockSize = vars->blockSize;
935
936 rc = kern_write_file(vars->fileRef, 0, (char *)&hdr, sizeof(hdr), IO_SKIP_ENCRYPTION);
937 if (rc != 0) {
938 HIBLOG("kern_write_file returned %d\n", rc);
939 err = kIOReturnIOError;
940 goto exit;
941 }
942
943 exit:
944 return err;
945 }
946
947 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
948
949 DECLARE_IOHIBERNATEPROGRESSALPHA
950
951 static void
ProgressInit(hibernate_graphics_t * display,uint8_t * screen,uint8_t * saveunder,uint32_t savelen)952 ProgressInit(hibernate_graphics_t * display, uint8_t * screen, uint8_t * saveunder, uint32_t savelen)
953 {
954 uint32_t rowBytes, pixelShift;
955 uint32_t x, y;
956 int32_t blob;
957 uint32_t alpha, color, result;
958 uint8_t * out, in;
959 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
960
961 rowBytes = display->rowBytes;
962 pixelShift = display->depth >> 4;
963 if (pixelShift < 1) {
964 return;
965 }
966
967 screen += ((display->width
968 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
969 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
970
971 for (y = 0; y < kIOHibernateProgressHeight; y++) {
972 out = screen + y * rowBytes;
973 for (blob = 0; blob < kIOHibernateProgressCount; blob++) {
974 color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
975 for (x = 0; x < kIOHibernateProgressWidth; x++) {
976 alpha = gIOHibernateProgressAlpha[y][x];
977 result = color;
978 if (alpha) {
979 if (0xff != alpha) {
980 if (1 == pixelShift) {
981 in = *((uint16_t *)out) & 0x1f; // 16
982 in = ((uint8_t)(in << 3)) | ((uint8_t)(in >> 2));
983 } else {
984 in = *((uint32_t *)out) & 0xff; // 32
985 }
986 saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
987 result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
988 }
989 if (1 == pixelShift) {
990 result >>= 3;
991 *((uint16_t *)out) = ((uint16_t)((result << 10) | (result << 5) | result)); // 16
992 } else {
993 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
994 }
995 }
996 out += (1 << pixelShift);
997 }
998 out += (kIOHibernateProgressSpacing << pixelShift);
999 }
1000 }
1001 }
1002
1003
1004 static void
ProgressUpdate(hibernate_graphics_t * display,uint8_t * screen,int32_t firstBlob,int32_t select)1005 ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select)
1006 {
1007 uint32_t rowBytes, pixelShift;
1008 uint32_t x, y;
1009 int32_t blob, lastBlob;
1010 uint32_t alpha, in, color, result;
1011 uint8_t * out;
1012 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
1013
1014 pixelShift = display->depth >> 4;
1015 if (pixelShift < 1) {
1016 return;
1017 }
1018
1019 rowBytes = display->rowBytes;
1020
1021 screen += ((display->width
1022 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
1023 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
1024
1025 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
1026
1027 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
1028
1029 for (y = 0; y < kIOHibernateProgressHeight; y++) {
1030 out = screen + y * rowBytes;
1031 for (blob = firstBlob; blob <= lastBlob; blob++) {
1032 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
1033 for (x = 0; x < kIOHibernateProgressWidth; x++) {
1034 alpha = gIOHibernateProgressAlpha[y][x];
1035 result = color;
1036 if (alpha) {
1037 if (0xff != alpha) {
1038 in = display->progressSaveUnder[blob][saveindex[blob]++];
1039 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
1040 }
1041 if (1 == pixelShift) {
1042 result >>= 3;
1043 *((uint16_t *)out) = ((uint16_t)((result << 10) | (result << 5) | result)); // 16
1044 } else {
1045 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
1046 }
1047 }
1048 out += (1 << pixelShift);
1049 }
1050 out += (kIOHibernateProgressSpacing << pixelShift);
1051 }
1052 }
1053 }
1054
1055 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1056
1057 IOReturn
IOHibernateIOKitSleep(void)1058 IOHibernateIOKitSleep(void)
1059 {
1060 IOReturn ret = kIOReturnSuccess;
1061 IOLockLock(gFSLock);
1062 if (kFSOpening == gFSState) {
1063 gFSState = kFSTimedOut;
1064 HIBLOG("hibernate file open timed out\n");
1065 ret = kIOReturnTimeout;
1066 }
1067 IOLockUnlock(gFSLock);
1068 return ret;
1069 }
1070
1071 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1072
1073 IOReturn
IOHibernateSystemHasSlept(void)1074 IOHibernateSystemHasSlept(void)
1075 {
1076 IOReturn ret = kIOReturnSuccess;
1077 IOHibernateVars * vars = &gIOHibernateVars;
1078 OSObject * obj = NULL;
1079 OSData * data;
1080
1081 IOLockLock(gFSLock);
1082 if ((kFSOpened != gFSState) && gIOHibernateMode) {
1083 ret = kIOReturnTimeout;
1084 }
1085 IOLockUnlock(gFSLock);
1086 if (kIOReturnSuccess != ret) {
1087 return ret;
1088 }
1089
1090 if (gIOHibernateMode) {
1091 obj = IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey);
1092 }
1093 vars->previewBuffer = OSDynamicCast(IOMemoryDescriptor, obj);
1094 if (obj && !vars->previewBuffer) {
1095 obj->release();
1096 }
1097 if (vars->previewBuffer && (vars->previewBuffer->getLength() > UINT_MAX)) {
1098 OSSafeReleaseNULL(vars->previewBuffer);
1099 }
1100
1101 vars->consoleMapping = NULL;
1102 if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare())) {
1103 vars->previewBuffer->release();
1104 vars->previewBuffer = NULL;
1105 }
1106
1107 if ((kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1108 && vars->previewBuffer
1109 && (data = OSDynamicCast(OSData,
1110 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey)))) {
1111 UInt32 flags = *((UInt32 *)data->getBytesNoCopy());
1112 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags);
1113
1114 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey);
1115
1116 if (kIOHibernatePreviewUpdates & flags) {
1117 PE_Video consoleInfo;
1118 hibernate_graphics_t * graphicsInfo = gIOHibernateGraphicsInfo;
1119
1120 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
1121
1122 graphicsInfo->width = (uint32_t) consoleInfo.v_width;
1123 graphicsInfo->height = (uint32_t) consoleInfo.v_height;
1124 graphicsInfo->rowBytes = (uint32_t) consoleInfo.v_rowBytes;
1125 graphicsInfo->depth = (uint32_t) consoleInfo.v_depth;
1126 vars->consoleMapping = (uint8_t *) consoleInfo.v_baseAddr;
1127
1128 HIBPRINT("video %p %d %d %d\n",
1129 vars->consoleMapping, graphicsInfo->depth,
1130 graphicsInfo->width, graphicsInfo->height);
1131 if (vars->consoleMapping) {
1132 ProgressInit(graphicsInfo, vars->consoleMapping,
1133 &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
1134 }
1135 }
1136 }
1137
1138 if (gIOOptionsEntry) {
1139 #if __x86_64__
1140 gIOOptionsEntry->sync();
1141 #else
1142 if (gIOHibernateMode) {
1143 gIOOptionsEntry->sync();
1144 }
1145 #endif
1146 }
1147
1148 return ret;
1149 }
1150
1151 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1152
1153 static const DeviceTreeNode *
MergeDeviceTree(const DeviceTreeNode * entry,IORegistryEntry * regEntry,OSSet * entriesToUpdate,vm_offset_t region_start,vm_size_t region_size)1154 MergeDeviceTree(const DeviceTreeNode * entry, IORegistryEntry * regEntry, OSSet * entriesToUpdate, vm_offset_t region_start, vm_size_t region_size)
1155 {
1156 DeviceTreeNodeProperty * prop;
1157 const DeviceTreeNode * child;
1158 IORegistryEntry * childRegEntry;
1159 const char * nameProp;
1160 unsigned int propLen, idx;
1161
1162 bool updateEntry = true;
1163 if (!regEntry) {
1164 updateEntry = false;
1165 } else if (entriesToUpdate && !entriesToUpdate->containsObject(regEntry)) {
1166 updateEntry = false;
1167 }
1168
1169 prop = (DeviceTreeNodeProperty *) (entry + 1);
1170 for (idx = 0; idx < entry->nProperties; idx++) {
1171 if (updateEntry && (0 != strcmp("name", prop->name))) {
1172 regEntry->setProperty((const char *) prop->name, (void *) (prop + 1), prop->length);
1173 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1174 }
1175 prop = (DeviceTreeNodeProperty *) (((uintptr_t)(prop + 1)) + ((prop->length + 3) & ~3));
1176 }
1177
1178 if (entriesToUpdate) {
1179 entriesToUpdate->removeObject(regEntry);
1180 if (entriesToUpdate->getCount() == 0) {
1181 // we've updated all the entries we care about so we can stop
1182 return NULL;
1183 }
1184 }
1185
1186 child = (const DeviceTreeNode *) prop;
1187 for (idx = 0; idx < entry->nChildren; idx++) {
1188 if (kSuccess != SecureDTGetPropertyRegion(child, "name", (void const **) &nameProp, &propLen,
1189 region_start, region_size)) {
1190 panic("no name");
1191 }
1192 childRegEntry = regEntry ? regEntry->childFromPath(nameProp, gIODTPlane) : NULL;
1193 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1194 child = MergeDeviceTree(child, childRegEntry, entriesToUpdate, region_start, region_size);
1195 OSSafeReleaseNULL(childRegEntry);
1196 if (!child) {
1197 // the recursive call updated the last entry we cared about, so we can stop
1198 break;
1199 }
1200 }
1201 return child;
1202 }
1203
1204 IOReturn
IOHibernateSystemWake(void)1205 IOHibernateSystemWake(void)
1206 {
1207 if (kFSOpened == gFSState) {
1208 IOPolledFilePollersClose(gIOHibernateVars.fileVars, kIOPolledPostflightState);
1209 IOHibernateDone(&gIOHibernateVars);
1210 } else {
1211 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
1212 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
1213 }
1214
1215 if (gIOOptionsEntry && gIOHibernateBootImageKey) {
1216 // if we got this far, clear boot-image
1217 // we don't need to sync immediately; the booter should have already removed this entry
1218 // we just want to make sure that if anyone syncs nvram after this point, we don't re-write
1219 // a stale boot-image value
1220 gIOOptionsEntry->removeProperty(gIOHibernateBootImageKey);
1221 }
1222
1223 return kIOReturnSuccess;
1224 }
1225
1226 static IOReturn
IOHibernateDone(IOHibernateVars * vars)1227 IOHibernateDone(IOHibernateVars * vars)
1228 {
1229 IOReturn err;
1230 OSData * data;
1231
1232 hibernate_teardown(vars->page_list, vars->page_list_wired, vars->page_list_pal);
1233
1234 if (vars->videoMapping) {
1235 if (vars->videoMapSize) {
1236 // remove mappings
1237 IOUnmapPages(kernel_map, vars->videoMapping, vars->videoMapSize);
1238 }
1239 if (vars->videoAllocSize) {
1240 // dealloc range
1241 kmem_free(kernel_map, trunc_page(vars->videoMapping), vars->videoAllocSize);
1242 }
1243 }
1244
1245 if (vars->previewBuffer) {
1246 vars->previewBuffer->release();
1247 vars->previewBuffer = NULL;
1248 }
1249
1250 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
1251 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey,
1252 gIOHibernateCurrentHeader->options, 32);
1253 } else {
1254 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
1255 }
1256
1257 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState)
1258 && (kIOHibernateGfxStatusUnknown != gIOHibernateGraphicsInfo->gfxStatus)) {
1259 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey,
1260 &gIOHibernateGraphicsInfo->gfxStatus,
1261 sizeof(gIOHibernateGraphicsInfo->gfxStatus));
1262 } else {
1263 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
1264 }
1265
1266 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1267
1268 #if defined(__i386__) || defined(__x86_64__)
1269 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey);
1270 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey);
1271
1272 /*
1273 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1274 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1275 */
1276 if (gIOOptionsEntry) {
1277 if (gIOHibernateRTCVariablesKey) {
1278 if (gIOOptionsEntry->getProperty(gIOHibernateRTCVariablesKey)) {
1279 gIOOptionsEntry->removeProperty(gIOHibernateRTCVariablesKey);
1280 }
1281 }
1282
1283 if (gIOHibernateBootNextKey) {
1284 if (gIOHibernateBootNextSave) {
1285 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextSave);
1286 gIOHibernateBootNextSave->release();
1287 gIOHibernateBootNextSave = NULL;
1288 } else {
1289 gIOOptionsEntry->removeProperty(gIOHibernateBootNextKey);
1290 }
1291 }
1292 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState) {
1293 gIOOptionsEntry->sync();
1294 }
1295 }
1296 #endif
1297
1298 if (vars->srcBuffer) {
1299 vars->srcBuffer->release();
1300 }
1301
1302
1303 bzero(&gIOHibernateHandoffPages[0], gIOHibernateHandoffPageCount * sizeof(gIOHibernateHandoffPages[0]));
1304 if (vars->handoffBuffer) {
1305 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
1306 IOHibernateHandoff * handoff;
1307 bool done = false;
1308 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
1309 !done;
1310 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount]) {
1311 HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
1312 uint8_t * __unused data = &handoff->data[0];
1313 switch (handoff->type) {
1314 case kIOHibernateHandoffTypeEnd:
1315 done = true;
1316 break;
1317
1318 case kIOHibernateHandoffTypeDeviceTree:
1319 {
1320 #if defined(__i386__) || defined(__x86_64__)
1321 // On Intel, process the entirety of the passed in device tree
1322 OSSet * entriesToUpdate = NULL;
1323 #elif defined(__arm64__)
1324 // On ARM, only allow hibernation to update specific entries
1325 const char *mergePaths[] = {
1326 kIODeviceTreePlane ":/chosen/boot-object-manifests",
1327 kIODeviceTreePlane ":/chosen/secure-boot-hashes",
1328 };
1329 const size_t mergePathCount = sizeof(mergePaths) / sizeof(mergePaths[0]);
1330 OSSet * entriesToUpdate = OSSet::withCapacity(mergePathCount);
1331 for (size_t i = 0; i < mergePathCount; i++) {
1332 IORegistryEntry *entry = IORegistryEntry::fromPath(mergePaths[i]);
1333 if (!entry) {
1334 panic("failed to find %s in IORegistry", mergePaths[i]);
1335 }
1336 entriesToUpdate->setObject(entry);
1337 OSSafeReleaseNULL(entry);
1338 }
1339 #endif
1340 MergeDeviceTree((DeviceTreeNode *) data, IOService::getServiceRoot(), entriesToUpdate,
1341 (vm_offset_t)data, (vm_size_t)handoff->bytecount);
1342 OSSafeReleaseNULL(entriesToUpdate);
1343 break;
1344 }
1345
1346 case kIOHibernateHandoffTypeKeyStore:
1347 #if defined(__i386__) || defined(__x86_64__)
1348 {
1349 IOBufferMemoryDescriptor *
1350 md = IOBufferMemoryDescriptor::withBytes(data, handoff->bytecount, kIODirectionOutIn);
1351 if (md) {
1352 IOSetKeyStoreData(md);
1353 }
1354 }
1355 #endif
1356 break;
1357
1358 default:
1359 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
1360 break;
1361 }
1362 }
1363 #if defined(__i386__) || defined(__x86_64__)
1364 if (vars->volumeCryptKeySize) {
1365 IOBufferMemoryDescriptor *
1366 bmd = IOBufferMemoryDescriptor::withBytes(&vars->volumeCryptKey[0],
1367 vars->volumeCryptKeySize, kIODirectionOutIn);
1368 if (!bmd) {
1369 panic("IOBufferMemoryDescriptor");
1370 }
1371 IOSetAPFSKeyStoreData(bmd);
1372 bzero(&vars->volumeCryptKey[0], sizeof(vars->volumeCryptKey));
1373 }
1374 #endif
1375 }
1376 vars->handoffBuffer->release();
1377 }
1378
1379 if (gIOChosenEntry
1380 && (data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(gIOBridgeBootSessionUUIDKey)))
1381 && (sizeof(gIOHibernateBridgeBootSessionUUIDString) <= data->getLength())) {
1382 bcopy(data->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString[0],
1383 sizeof(gIOHibernateBridgeBootSessionUUIDString));
1384 }
1385
1386 if (vars->hwEncrypt) {
1387 err = IOPolledFilePollersSetEncryptionKey(vars->fileVars, NULL, 0);
1388 HIBLOG("IOPolledFilePollersSetEncryptionKey(0,%x)\n", err);
1389 }
1390
1391 bzero(vars, sizeof(*vars));
1392
1393 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1394 gIOHibernateCount++;
1395
1396 return kIOReturnSuccess;
1397 }
1398
1399 static void
IOHibernateSystemPostWakeTrim(void * p1,void * p2)1400 IOHibernateSystemPostWakeTrim(void * p1, void * p2)
1401 {
1402 // invalidate & close the image file
1403 if (p1) {
1404 IOLockLock(gFSLock);
1405 }
1406 if (kFSTrimDelay == gFSState) {
1407 IOPolledFileIOVars * vars = &gFileVars;
1408 IOPolledFileClose(&vars,
1409 #if DISABLE_TRIM
1410 0, NULL, 0, 0, 0, false);
1411 #else
1412 0, (caddr_t)gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader),
1413 sizeof(IOHibernateImageHeader), gIOHibernateCurrentHeader->imageSize, false);
1414 #endif
1415 gFSState = kFSIdle;
1416 }
1417 if (p1) {
1418 IOLockUnlock(gFSLock);
1419 }
1420 }
1421
1422 IOReturn
IOHibernateSystemPostWake(bool now)1423 IOHibernateSystemPostWake(bool now)
1424 {
1425 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1426 IOSetBootImageNVRAM(NULL);
1427
1428 IOLockLock(gFSLock);
1429 if (kFSTrimDelay == gFSState) {
1430 thread_call_cancel(gIOHibernateTrimCalloutEntry);
1431 IOHibernateSystemPostWakeTrim(NULL, NULL);
1432 } else if (kFSOpened != gFSState) {
1433 gFSState = kFSIdle;
1434 } else {
1435 gFSState = kFSTrimDelay;
1436 if (now) {
1437 thread_call_cancel(gIOHibernateTrimCalloutEntry);
1438 IOHibernateSystemPostWakeTrim(NULL, NULL);
1439 } else {
1440 AbsoluteTime deadline;
1441 clock_interval_to_deadline(TRIM_DELAY, kMillisecondScale, &deadline );
1442 thread_call_enter1_delayed(gIOHibernateTrimCalloutEntry, NULL, deadline);
1443 }
1444 }
1445 IOLockUnlock(gFSLock);
1446
1447 return kIOReturnSuccess;
1448 }
1449
1450 uint32_t
IOHibernateWasScreenLocked(void)1451 IOHibernateWasScreenLocked(void)
1452 {
1453 uint32_t ret = 0;
1454 if (gIOChosenEntry) {
1455 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
1456 OSData *
1457 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOScreenLockStateKey));
1458 if (data) {
1459 ret = ((uint32_t *)data->getBytesNoCopy())[0];
1460 gIOChosenEntry->setProperty(kIOBooterScreenLockStateKey, data);
1461 }
1462 } else {
1463 gIOChosenEntry->removeProperty(kIOBooterScreenLockStateKey);
1464 }
1465 }
1466
1467 return ret;
1468 }
1469
1470 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1471
1472 SYSCTL_STRING(_kern, OID_AUTO, hibernatefile,
1473 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1474 gIOHibernateFilename, sizeof(gIOHibernateFilename), "");
1475 SYSCTL_STRING(_kern, OID_AUTO, bootsignature,
1476 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1477 gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), "");
1478 SYSCTL_UINT(_kern, OID_AUTO, hibernatemode,
1479 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
1480 &gIOHibernateMode, 0, "");
1481 SYSCTL_STRUCT(_kern, OID_AUTO, hibernatestatistics,
1482 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
1483 &_hibernateStats, hibernate_statistics_t, "");
1484 SYSCTL_OID_MANUAL(_kern_bridge, OID_AUTO, bootsessionuuid,
1485 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1486 gIOHibernateBridgeBootSessionUUIDString, sizeof(gIOHibernateBridgeBootSessionUUIDString),
1487 sysctl_handle_string, "A", "");
1488
1489 SYSCTL_UINT(_kern, OID_AUTO, hibernategraphicsready,
1490 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1491 &_hibernateStats.graphicsReadyTime, 0, "");
1492 SYSCTL_UINT(_kern, OID_AUTO, hibernatewakenotification,
1493 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1494 &_hibernateStats.wakeNotificationTime, 0, "");
1495 SYSCTL_UINT(_kern, OID_AUTO, hibernatelockscreenready,
1496 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1497 &_hibernateStats.lockScreenReadyTime, 0, "");
1498 SYSCTL_UINT(_kern, OID_AUTO, hibernatehidready,
1499 CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1500 &_hibernateStats.hidReadyTime, 0, "");
1501
1502 SYSCTL_UINT(_kern, OID_AUTO, hibernatecount,
1503 CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1504 &gIOHibernateCount, 0, "");
1505
1506 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1507
1508 static int
1509 hibernate_set_preview SYSCTL_HANDLER_ARGS
1510 {
1511 #pragma unused(oidp, arg1, arg2)
1512
1513 if (!IOCurrentTaskHasEntitlement(kIOHibernateSetPreviewEntitlementKey)) {
1514 return EPERM;
1515 }
1516
1517 if ((req->newptr == USER_ADDR_NULL) || (!req->newlen)) {
1518 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewBufferKey);
1519 return 0;
1520 }
1521 size_t rounded_size;
1522 if (round_page_overflow(req->newlen, &rounded_size)) {
1523 return ENOMEM;
1524 }
1525 IOBufferMemoryDescriptor *md = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn, rounded_size, page_size);
1526 if (!md) {
1527 return ENOMEM;
1528 }
1529
1530 uint8_t *bytes = (uint8_t *)md->getBytesNoCopy();
1531 int error = SYSCTL_IN(req, bytes, req->newlen);
1532 if (error) {
1533 md->release();
1534 return error;
1535 }
1536
1537 IOService::getPMRootDomain()->setProperty(kIOHibernatePreviewBufferKey, md);
1538 md->release();
1539
1540 return 0;
1541 }
1542
1543 SYSCTL_PROC(_kern, OID_AUTO, hibernatepreview,
1544 CTLTYPE_OPAQUE | CTLFLAG_WR | CTLFLAG_LOCKED | CTLFLAG_ANYBODY, NULL, 0,
1545 hibernate_set_preview, "S", "");
1546
1547 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1548
1549 void
IOHibernateSystemInit(IOPMrootDomain * rootDomain)1550 IOHibernateSystemInit(IOPMrootDomain * rootDomain)
1551 {
1552 gIOHibernateBootImageKey = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1553 gIOHibernateBootSignatureKey = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
1554 gIOBridgeBootSessionUUIDKey = OSSymbol::withCStringNoCopy(kIOBridgeBootSessionUUIDKey);
1555
1556 #if defined(__i386__) || defined(__x86_64__)
1557 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1558 gIOHibernateBoot0082Key = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1559 gIOHibernateBootNextKey = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1560 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1561 #endif /* defined(__i386__) || defined(__x86_64__) */
1562
1563 OSData * data = OSData::withValueNoCopy(gIOHibernateState);
1564 if (data) {
1565 rootDomain->setProperty(kIOHibernateStateKey, data);
1566 data->release();
1567 }
1568
1569 if (PE_parse_boot_argn("hfile", gIOHibernateFilename, sizeof(gIOHibernateFilename))) {
1570 gIOHibernateMode = kIOHibernateModeOn;
1571 } else {
1572 gIOHibernateFilename[0] = 0;
1573 }
1574
1575 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
1576
1577 if (gIOChosenEntry
1578 && (data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(gIOBridgeBootSessionUUIDKey)))
1579 && (sizeof(gIOHibernateBridgeBootSessionUUIDString) <= data->getLength())) {
1580 sysctl_register_oid(&sysctl__kern_bridge_bootsessionuuid);
1581 bcopy(data->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString[0], sizeof(gIOHibernateBridgeBootSessionUUIDString));
1582 }
1583
1584 gFSLock = IOLockAlloc();
1585 gIOHibernateCount = 0;
1586 }
1587
1588 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1589
1590 static IOReturn
IOHibernatePolledFileWrite(IOHibernateVars * vars,const uint8_t * bytes,IOByteCount size,IOPolledFileCryptVars * cryptvars)1591 IOHibernatePolledFileWrite(IOHibernateVars * vars,
1592 const uint8_t * bytes, IOByteCount size,
1593 IOPolledFileCryptVars * cryptvars)
1594 {
1595 IOReturn err;
1596
1597
1598 err = IOPolledFileWrite(vars->fileVars, bytes, size, cryptvars);
1599 if ((kIOReturnSuccess == err) && hibernate_should_abort()) {
1600 err = kIOReturnAborted;
1601 }
1602
1603
1604 return err;
1605 }
1606
1607 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1608
1609 extern "C" uint32_t
hibernate_write_image(void)1610 hibernate_write_image(void)
1611 {
1612 IOHibernateImageHeader * header = gIOHibernateCurrentHeader;
1613 IOHibernateVars * vars = &gIOHibernateVars;
1614 IOPolledFileExtent * fileExtents;
1615
1616 #if !defined(__arm64__)
1617 _static_assert_1_arg(sizeof(IOHibernateImageHeader) == 512);
1618 #endif /* !defined(__arm64__) */
1619
1620 uint32_t pageCount, pagesDone;
1621 IOReturn err;
1622 ppnum_t ppnum, page;
1623 vm_offset_t count;
1624 uint8_t * src;
1625 uint8_t * data;
1626 uint8_t * compressed;
1627 uint8_t * scratch;
1628 IOByteCount pageCompressedSize;
1629 uint64_t compressedSize, uncompressedSize;
1630 uint64_t image1Size = 0;
1631 uint32_t bitmap_size;
1632 bool iterDone, pollerOpen, needEncrypt;
1633 int wkresult;
1634 uint32_t tag;
1635 uint32_t pageType;
1636 uint32_t pageAndCount[2];
1637 addr64_t phys64;
1638 IOByteCount segLen;
1639 uint32_t restore1Sum = 0, sum = 0, sum1 = 0, sum2 = 0;
1640 uintptr_t hibernateBase;
1641 uintptr_t hibernateEnd;
1642
1643 AbsoluteTime startTime, endTime;
1644 AbsoluteTime allTime, compTime;
1645 uint64_t compBytes;
1646 uint64_t nsec;
1647 uint64_t lastProgressStamp = 0;
1648 uint64_t progressStamp;
1649 uint32_t blob, lastBlob = (uint32_t) -1L;
1650
1651 uint32_t wiredPagesEncrypted;
1652 uint32_t dirtyPagesEncrypted;
1653 uint32_t wiredPagesClear;
1654 uint32_t svPageCount;
1655 uint32_t zvPageCount;
1656
1657 IOPolledFileCryptVars _cryptvars;
1658 IOPolledFileCryptVars * cryptvars = NULL;
1659
1660 wiredPagesEncrypted = 0;
1661 dirtyPagesEncrypted = 0;
1662 wiredPagesClear = 0;
1663 svPageCount = 0;
1664 zvPageCount = 0;
1665
1666 if (!vars->fileVars
1667 || !vars->fileVars->pollers
1668 || !(kIOHibernateModeOn & gIOHibernateMode)) {
1669 return kIOHibernatePostWriteSleep;
1670 }
1671
1672
1673 #if !defined(__arm64__)
1674 if (kIOHibernateModeSleep & gIOHibernateMode) {
1675 kdebug_enable = save_kdebug_enable;
1676 }
1677 #endif /* !defined(__arm64__) */
1678
1679 pal_hib_write_hook();
1680
1681 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_START);
1682 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate);
1683
1684 #if CRYPTO
1685 // encryption data. "iv" is the "initial vector".
1686 if (kIOHibernateModeEncrypt & gIOHibernateMode) {
1687 static const unsigned char first_iv[AES_BLOCK_SIZE]
1688 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1689 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1690
1691 cryptvars = &gIOHibernateCryptWakeContext;
1692 bzero(cryptvars, sizeof(IOPolledFileCryptVars));
1693 aes_encrypt_key(vars->cryptKey,
1694 kIOHibernateAESKeySize,
1695 &cryptvars->ctx.encrypt);
1696 aes_decrypt_key(vars->cryptKey,
1697 kIOHibernateAESKeySize,
1698 &cryptvars->ctx.decrypt);
1699
1700 cryptvars = &_cryptvars;
1701 bzero(cryptvars, sizeof(IOPolledFileCryptVars));
1702 for (pageCount = 0; pageCount < sizeof(vars->wiredCryptKey); pageCount++) {
1703 vars->wiredCryptKey[pageCount] ^= vars->volumeCryptKey[pageCount];
1704 }
1705 aes_encrypt_key(vars->wiredCryptKey,
1706 kIOHibernateAESKeySize,
1707 &cryptvars->ctx.encrypt);
1708
1709 bcopy(&first_iv[0], &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1710 bzero(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1711 bzero(&vars->cryptKey[0], sizeof(vars->cryptKey));
1712 }
1713 #endif /* CRYPTO */
1714
1715 hibernate_page_list_setall(vars->page_list,
1716 vars->page_list_wired,
1717 vars->page_list_pal,
1718 false /* !preflight */,
1719 /* discard_all */
1720 ((0 == (kIOHibernateModeSleep & gIOHibernateMode))
1721 && (0 != ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode))),
1722 &pageCount);
1723
1724 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount);
1725
1726 fileExtents = (IOPolledFileExtent *) vars->fileVars->fileExtents->getBytesNoCopy();
1727
1728 #if 0
1729 count = vars->fileExtents->getLength() / sizeof(IOPolledFileExtent);
1730 for (page = 0; page < count; page++) {
1731 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page,
1732 fileExtents[page].start, fileExtents[page].length,
1733 fileExtents[page].start + fileExtents[page].length);
1734 }
1735 #endif
1736
1737 needEncrypt = (0 != (kIOHibernateModeEncrypt & gIOHibernateMode));
1738 AbsoluteTime_to_scalar(&compTime) = 0;
1739 compBytes = 0;
1740
1741 clock_get_uptime(&allTime);
1742 IOService::getPMRootDomain()->pmStatsRecordEvent(
1743 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStartFlag, allTime);
1744 do{
1745 compressedSize = 0;
1746 uncompressedSize = 0;
1747 svPageCount = 0;
1748 zvPageCount = 0;
1749
1750 IOPolledFileSeek(vars->fileVars, vars->fileVars->blockSize);
1751
1752 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1753 ml_get_interrupts_enabled());
1754 err = IOPolledFilePollersOpen(vars->fileVars, kIOPolledBeforeSleepState,
1755 // abortable if not low battery
1756 !IOService::getPMRootDomain()->mustHibernate());
1757 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
1758 pollerOpen = (kIOReturnSuccess == err);
1759 if (!pollerOpen) {
1760 break;
1761 }
1762
1763 if (vars->volumeCryptKeySize) {
1764 err = IOPolledFilePollersSetEncryptionKey(vars->fileVars, &vars->volumeCryptKey[0], vars->volumeCryptKeySize);
1765 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x)\n", err);
1766 vars->hwEncrypt = (kIOReturnSuccess == err);
1767 bzero(&vars->volumeCryptKey[0], sizeof(vars->volumeCryptKey));
1768 if (vars->hwEncrypt) {
1769 header->options |= kIOHibernateOptionHWEncrypt;
1770 }
1771 }
1772
1773 // copy file block extent list if larger than header
1774
1775 count = vars->fileVars->fileExtents->getLength();
1776 if (count > sizeof(header->fileExtentMap)) {
1777 count -= sizeof(header->fileExtentMap);
1778 err = IOHibernatePolledFileWrite(vars,
1779 ((uint8_t *) &fileExtents[0]) + sizeof(header->fileExtentMap), count, cryptvars);
1780 if (kIOReturnSuccess != err) {
1781 break;
1782 }
1783 }
1784
1785 // copy out restore1 code
1786
1787 for (count = 0;
1788 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
1789 count += segLen) {
1790 for (pagesDone = 0; pagesDone < atop_32(segLen); pagesDone++) {
1791 gIOHibernateHandoffPages[atop_32(count) + pagesDone] = atop_64_ppnum(phys64) + pagesDone;
1792 }
1793 }
1794
1795 hibernateBase = HIB_BASE; /* Defined in PAL headers */
1796 hibernateEnd = (segHIBB + segSizeHIB);
1797
1798 page = atop_32(kvtophys(hibernateBase));
1799 count = atop_32(round_page(hibernateEnd) - hibernateBase);
1800 uintptr_t entrypoint = ((uintptr_t) &hibernate_machine_entrypoint) - hibernateBase;
1801 uintptr_t stack = ((uintptr_t) &gIOHibernateRestoreStackEnd[0]) - 64 - hibernateBase;
1802 if ((count > UINT_MAX) || (entrypoint > UINT_MAX) || (stack > UINT_MAX)) {
1803 panic("malformed kernel layout");
1804 }
1805 header->restore1CodePhysPage = (ppnum_t) page;
1806 header->restore1CodeVirt = hibernateBase;
1807 header->restore1PageCount = (uint32_t) count;
1808 header->restore1CodeOffset = (uint32_t) entrypoint;
1809 header->restore1StackOffset = (uint32_t) stack;
1810
1811 if (uuid_parse(&gIOHibernateBridgeBootSessionUUIDString[0], &header->bridgeBootSessionUUID[0])) {
1812 bzero(&header->bridgeBootSessionUUID[0], sizeof(header->bridgeBootSessionUUID));
1813 }
1814
1815 // sum __HIB seg, with zeros for the stack
1816 src = (uint8_t *) trunc_page(hibernateBase);
1817 for (page = 0; page < count; page++) {
1818 if ((src < &gIOHibernateRestoreStack[0]) || (src >= &gIOHibernateRestoreStackEnd[0])) {
1819 restore1Sum += hibernate_sum_page(src, (uint32_t) (header->restore1CodeVirt + page));
1820 } else {
1821 restore1Sum += 0x00000000;
1822 }
1823 src += page_size;
1824 }
1825 sum1 = restore1Sum;
1826
1827 // write the __HIB seg, with zeros for the stack
1828
1829 src = (uint8_t *) trunc_page(hibernateBase);
1830 count = ((uintptr_t) &gIOHibernateRestoreStack[0]) - trunc_page(hibernateBase);
1831 if (count) {
1832 err = IOHibernatePolledFileWrite(vars, src, count, cryptvars);
1833 if (kIOReturnSuccess != err) {
1834 break;
1835 }
1836 }
1837 err = IOHibernatePolledFileWrite(vars,
1838 (uint8_t *) NULL,
1839 &gIOHibernateRestoreStackEnd[0] - &gIOHibernateRestoreStack[0],
1840 cryptvars);
1841 if (kIOReturnSuccess != err) {
1842 break;
1843 }
1844 src = &gIOHibernateRestoreStackEnd[0];
1845 count = round_page(hibernateEnd) - ((uintptr_t) src);
1846 if (count) {
1847 err = IOHibernatePolledFileWrite(vars, src, count, cryptvars);
1848 if (kIOReturnSuccess != err) {
1849 break;
1850 }
1851 }
1852
1853 if (!vars->hwEncrypt && (kIOHibernateModeEncrypt & gIOHibernateMode)) {
1854 vars->fileVars->encryptStart = (vars->fileVars->position & ~(AES_BLOCK_SIZE - 1));
1855 vars->fileVars->encryptEnd = UINT64_MAX;
1856 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
1857 }
1858
1859 // write the preview buffer
1860
1861 if (vars->previewBuffer) {
1862 ppnum = 0;
1863 count = 0;
1864 do{
1865 phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone);
1866 pageAndCount[0] = atop_64_ppnum(phys64);
1867 pageAndCount[1] = atop_64_ppnum(segLen);
1868 err = IOHibernatePolledFileWrite(vars,
1869 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
1870 cryptvars);
1871 if (kIOReturnSuccess != err) {
1872 break;
1873 }
1874 count += segLen;
1875 ppnum += sizeof(pageAndCount);
1876 }while (phys64);
1877 if (kIOReturnSuccess != err) {
1878 break;
1879 }
1880
1881 src = (uint8_t *) vars->previewBuffer->getPhysicalSegment(0, NULL, _kIOMemorySourceSegment);
1882
1883 ((hibernate_preview_t *)src)->lockTime = gIOConsoleLockTime;
1884
1885 count = (uint32_t) vars->previewBuffer->getLength();
1886
1887 header->previewPageListSize = ((uint32_t) ppnum);
1888 header->previewSize = ((uint32_t) (count + ppnum));
1889
1890 for (page = 0; page < count; page += page_size) {
1891 phys64 = vars->previewBuffer->getPhysicalSegment(page, NULL, kIOMemoryMapperNone);
1892 sum1 += hibernate_sum_page(src + page, atop_64_ppnum(phys64));
1893 }
1894 if (kIOReturnSuccess != err) {
1895 break;
1896 }
1897 err = IOHibernatePolledFileWrite(vars, src, count, cryptvars);
1898 if (kIOReturnSuccess != err) {
1899 break;
1900 }
1901 }
1902
1903 // mark areas for no save
1904 hibernate_set_descriptor_page_state(vars, IOPolledFileGetIOBuffer(vars->fileVars),
1905 kIOHibernatePageStateFree, &pageCount);
1906 hibernate_set_descriptor_page_state(vars, vars->srcBuffer,
1907 kIOHibernatePageStateFree, &pageCount);
1908
1909 // copy out bitmap of pages available for trashing during restore
1910
1911 bitmap_size = vars->page_list_wired->list_size;
1912 src = (uint8_t *) vars->page_list_wired;
1913 err = IOHibernatePolledFileWrite(vars, src, bitmap_size, cryptvars);
1914 if (kIOReturnSuccess != err) {
1915 break;
1916 }
1917
1918 // mark more areas for no save, but these are not available
1919 // for trashing during restore
1920
1921 hibernate_page_list_set_volatile(vars->page_list, vars->page_list_wired, &pageCount);
1922
1923 #if defined(__i386__) || defined(__x86_64__)
1924 // __HIB is explicitly saved above so we don't have to save it again
1925 page = atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase));
1926 count = atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd))) - page;
1927 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1928 page, count,
1929 kIOHibernatePageStateFree);
1930 pageCount -= count;
1931 #elif defined(__arm64__)
1932 // the segments described in IOHibernateHibSegInfo are stored directly in the
1933 // hibernation file, so they don't need to be saved again
1934 extern unsigned long gPhysBase, gPhysSize;
1935 for (size_t i = 0; i < NUM_HIBSEGINFO_SEGMENTS; i++) {
1936 page = segInfo->segments[i].physPage;
1937 count = segInfo->segments[i].pageCount;
1938 uint64_t physAddr = ptoa_64(page);
1939 uint64_t size = ptoa_64(count);
1940 if (size &&
1941 (physAddr >= gPhysBase) &&
1942 (physAddr + size <= gPhysBase + gPhysSize)) {
1943 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1944 page, count,
1945 kIOHibernatePageStateFree);
1946 pageCount -= count;
1947 }
1948 }
1949 #else
1950 #error unimplemented
1951 #endif
1952
1953 hibernate_set_descriptor_page_state(vars, vars->previewBuffer,
1954 kIOHibernatePageStateFree, &pageCount);
1955 hibernate_set_descriptor_page_state(vars, vars->handoffBuffer,
1956 kIOHibernatePageStateFree, &pageCount);
1957
1958 #if KASAN
1959 vm_size_t shadow_pages_free = atop_64(shadow_ptop) - atop_64(shadow_pnext);
1960
1961 /* no need to save unused shadow pages */
1962 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1963 atop_64(shadow_pnext),
1964 shadow_pages_free,
1965 kIOHibernatePageStateFree);
1966 #endif
1967
1968 src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
1969 compressed = src + page_size;
1970 scratch = compressed + page_size;
1971
1972 pagesDone = 0;
1973 lastBlob = 0;
1974
1975 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
1976 bitmap_size, header->previewSize,
1977 pageCount, vars->fileVars->position);
1978
1979
1980 enum
1981 // pageType
1982 {
1983 kWired = 0x02,
1984 kEncrypt = 0x01,
1985 kWiredEncrypt = kWired | kEncrypt,
1986 kWiredClear = kWired,
1987 kUnwiredEncrypt = kEncrypt
1988 };
1989
1990 #if defined(__i386__) || defined(__x86_64__)
1991 bool cpuAES = (0 != (CPUID_FEATURE_AES & cpuid_features()));
1992 #else /* defined(__i386__) || defined(__x86_64__) */
1993 static const bool cpuAES = true;
1994 #endif /* defined(__i386__) || defined(__x86_64__) */
1995
1996 for (pageType = kWiredEncrypt; pageType >= kUnwiredEncrypt; pageType--) {
1997 if (kUnwiredEncrypt == pageType) {
1998 // start unwired image
1999 if (!vars->hwEncrypt && (kIOHibernateModeEncrypt & gIOHibernateMode)) {
2000 vars->fileVars->encryptStart = (vars->fileVars->position & ~(((uint64_t)AES_BLOCK_SIZE) - 1));
2001 vars->fileVars->encryptEnd = UINT64_MAX;
2002 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
2003 }
2004 bcopy(&cryptvars->aes_iv[0],
2005 &gIOHibernateCryptWakeContext.aes_iv[0],
2006 sizeof(cryptvars->aes_iv));
2007 cryptvars = &gIOHibernateCryptWakeContext;
2008 }
2009 for (iterDone = false, ppnum = 0; !iterDone;) {
2010 if (cpuAES && (pageType == kWiredClear)) {
2011 count = 0;
2012 } else {
2013 count = hibernate_page_list_iterate((kWired & pageType) ? vars->page_list_wired : vars->page_list,
2014 &ppnum);
2015 if (count > UINT_MAX) {
2016 count = UINT_MAX;
2017 }
2018 }
2019 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
2020 iterDone = !count;
2021
2022 if (!cpuAES) {
2023 if (count && (kWired & pageType) && needEncrypt) {
2024 uint32_t checkIndex;
2025 for (checkIndex = 0;
2026 (checkIndex < count)
2027 && (((kEncrypt & pageType) == 0) == pmap_is_noencrypt(((ppnum_t)(ppnum + checkIndex))));
2028 checkIndex++) {
2029 }
2030 if (!checkIndex) {
2031 ppnum++;
2032 continue;
2033 }
2034 count = checkIndex;
2035 }
2036 }
2037
2038 switch (pageType) {
2039 case kWiredEncrypt: wiredPagesEncrypted += count; break;
2040 case kWiredClear: wiredPagesClear += count; break;
2041 case kUnwiredEncrypt: dirtyPagesEncrypted += count; break;
2042 }
2043
2044 if (iterDone && (kWiredEncrypt == pageType)) {/* not yet end of wired list */
2045 } else {
2046 pageAndCount[0] = (uint32_t) ppnum;
2047 pageAndCount[1] = (uint32_t) count;
2048 err = IOHibernatePolledFileWrite(vars,
2049 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
2050 cryptvars);
2051 if (kIOReturnSuccess != err) {
2052 break;
2053 }
2054 }
2055
2056 for (page = ppnum; page < (ppnum + count); page++) {
2057 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(page), page_size);
2058 if (err) {
2059 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__, (long)page, err);
2060 break;
2061 }
2062
2063 sum = hibernate_sum_page(src, (uint32_t) page);
2064 if (kWired & pageType) {
2065 sum1 += sum;
2066 } else {
2067 sum2 += sum;
2068 }
2069
2070 clock_get_uptime(&startTime);
2071 wkresult = WKdm_compress_new((const WK_word*) src,
2072 (WK_word*) compressed,
2073 (WK_word*) scratch,
2074 (uint32_t) (page_size - 4));
2075
2076 clock_get_uptime(&endTime);
2077 ADD_ABSOLUTETIME(&compTime, &endTime);
2078 SUB_ABSOLUTETIME(&compTime, &startTime);
2079
2080 compBytes += page_size;
2081 pageCompressedSize = (-1 == wkresult) ? page_size : wkresult;
2082
2083 if (pageCompressedSize == 0) {
2084 pageCompressedSize = 4;
2085 data = src;
2086
2087 if (*(uint32_t *)src) {
2088 svPageCount++;
2089 } else {
2090 zvPageCount++;
2091 }
2092 } else {
2093 if (pageCompressedSize != page_size) {
2094 data = compressed;
2095 } else {
2096 data = src;
2097 }
2098 }
2099
2100 assert(pageCompressedSize <= page_size);
2101 tag = ((uint32_t) pageCompressedSize) | kIOHibernateTagSignature;
2102 err = IOHibernatePolledFileWrite(vars, (const uint8_t *) &tag, sizeof(tag), cryptvars);
2103 if (kIOReturnSuccess != err) {
2104 break;
2105 }
2106
2107 err = IOHibernatePolledFileWrite(vars, data, (pageCompressedSize + 3) & ~3, cryptvars);
2108 if (kIOReturnSuccess != err) {
2109 break;
2110 }
2111
2112 compressedSize += pageCompressedSize;
2113 uncompressedSize += page_size;
2114 pagesDone++;
2115
2116 if (vars->consoleMapping && (0 == (1023 & pagesDone))) {
2117 blob = ((pagesDone * kIOHibernateProgressCount) / pageCount);
2118 if (blob != lastBlob) {
2119 ProgressUpdate(gIOHibernateGraphicsInfo, vars->consoleMapping, lastBlob, blob);
2120 lastBlob = blob;
2121 }
2122 }
2123 if (0 == (8191 & pagesDone)) {
2124 clock_get_uptime(&endTime);
2125 SUB_ABSOLUTETIME(&endTime, &allTime);
2126 absolutetime_to_nanoseconds(endTime, &nsec);
2127 progressStamp = nsec / 750000000ULL;
2128 if (progressStamp != lastProgressStamp) {
2129 lastProgressStamp = progressStamp;
2130 HIBPRINT("pages %d (%d%%)\n", pagesDone, (100 * pagesDone) / pageCount);
2131 }
2132 }
2133 }
2134 if (kIOReturnSuccess != err) {
2135 break;
2136 }
2137 ppnum = page;
2138 }
2139
2140 if (kIOReturnSuccess != err) {
2141 break;
2142 }
2143
2144 if ((kEncrypt & pageType) && vars->fileVars->encryptStart) {
2145 vars->fileVars->encryptEnd = ((vars->fileVars->position + 511) & ~511ULL);
2146 HIBLOG("encryptEnd %qx\n", vars->fileVars->encryptEnd);
2147 }
2148
2149 if (kWiredEncrypt != pageType) {
2150 // end of image1/2 - fill to next block
2151 err = IOHibernatePolledFileWrite(vars, NULL, 0, cryptvars);
2152 if (kIOReturnSuccess != err) {
2153 break;
2154 }
2155 }
2156 if (kWiredClear == pageType) {
2157 // enlarge wired image for test
2158 // err = IOHibernatePolledFileWrite(vars, 0, 0x60000000, cryptvars);
2159
2160 // end wired image
2161 header->encryptStart = vars->fileVars->encryptStart;
2162 header->encryptEnd = vars->fileVars->encryptEnd;
2163 image1Size = vars->fileVars->position;
2164 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
2165 image1Size, header->encryptStart, header->encryptEnd);
2166 }
2167 }
2168 if (kIOReturnSuccess != err) {
2169 if (kIOReturnOverrun == err) {
2170 // update actual compression ratio on not enough space (for retry)
2171 gIOHibernateCompression = (compressedSize << 8) / uncompressedSize;
2172 }
2173
2174 // update partial amount written (for IOPolledFileClose cleanup/unmap)
2175 header->imageSize = vars->fileVars->position;
2176 break;
2177 }
2178
2179
2180 // Header:
2181
2182 header->imageSize = vars->fileVars->position;
2183 header->image1Size = image1Size;
2184 header->bitmapSize = bitmap_size;
2185 header->pageCount = pageCount;
2186
2187 header->restore1Sum = restore1Sum;
2188 header->image1Sum = sum1;
2189 header->image2Sum = sum2;
2190 header->sleepTime = gIOLastSleepTime.tv_sec;
2191
2192 header->compression = ((uint32_t)((compressedSize << 8) / uncompressedSize));
2193 #if defined(__arm64__)
2194 /*
2195 * We don't support retry on hibernation failure and so
2196 * we don't want to set this value to anything smaller
2197 * just because we may have been lucky this time around.
2198 * Though we'll let it go higher.
2199 */
2200 if (header->compression < HIB_COMPR_RATIO_ARM64) {
2201 header->compression = HIB_COMPR_RATIO_ARM64;
2202 }
2203 #endif /* __arm64__ */
2204
2205 gIOHibernateCompression = header->compression;
2206
2207 count = vars->fileVars->fileExtents->getLength();
2208 if (count > sizeof(header->fileExtentMap)) {
2209 header->fileExtentMapSize = ((uint32_t) count);
2210 count = sizeof(header->fileExtentMap);
2211 } else {
2212 header->fileExtentMapSize = sizeof(header->fileExtentMap);
2213 }
2214 bcopy(&fileExtents[0], &header->fileExtentMap[0], count);
2215
2216 header->deviceBase = vars->fileVars->block0;
2217 header->deviceBlockSize = vars->fileVars->blockSize;
2218 header->lastHibAbsTime = mach_absolute_time();
2219 header->lastHibContTime = mach_continuous_time();
2220
2221
2222 IOPolledFileSeek(vars->fileVars, 0);
2223 err = IOHibernatePolledFileWrite(vars,
2224 (uint8_t *) header, sizeof(IOHibernateImageHeader),
2225 cryptvars);
2226 if (kIOReturnSuccess != err) {
2227 break;
2228 }
2229
2230 err = IOHibernatePolledFileWrite(vars, NULL, 0, cryptvars);
2231 }while (false);
2232
2233 clock_get_uptime(&endTime);
2234
2235 IOService::getPMRootDomain()->pmStatsRecordEvent(
2236 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStopFlag, endTime);
2237
2238 SUB_ABSOLUTETIME(&endTime, &allTime);
2239 absolutetime_to_nanoseconds(endTime, &nsec);
2240 HIBLOG("all time: %qd ms, ", nsec / 1000000ULL);
2241
2242 absolutetime_to_nanoseconds(compTime, &nsec);
2243 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2244 compBytes,
2245 nsec / 1000000ULL,
2246 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2247
2248 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2249 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2250 vars->fileVars->cryptBytes,
2251 nsec / 1000000ULL,
2252 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2253
2254 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%)\n",
2255 header->imageSize, (header->imageSize * 100) / vars->fileVars->fileSize,
2256 uncompressedSize, atop_32(uncompressedSize), compressedSize,
2257 uncompressedSize ? ((int) ((compressedSize * 100ULL) / uncompressedSize)) : 0);
2258
2259 HIBLOG("\nsum1 %x, sum2 %x\n", sum1, sum2);
2260
2261 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2262 svPageCount, zvPageCount, wiredPagesEncrypted, wiredPagesClear, dirtyPagesEncrypted);
2263
2264 if (pollerOpen) {
2265 IOPolledFilePollersClose(vars->fileVars, (kIOReturnSuccess == err) ? kIOPolledBeforeSleepState : kIOPolledBeforeSleepStateAborted );
2266 }
2267
2268 if (vars->consoleMapping) {
2269 ProgressUpdate(gIOHibernateGraphicsInfo,
2270 vars->consoleMapping, 0, kIOHibernateProgressCount);
2271 }
2272
2273 HIBLOG("hibernate_write_image done(%x)\n", err);
2274
2275 // should we come back via regular wake, set the state in memory.
2276 gIOHibernateState = kIOHibernateStateInactive;
2277
2278 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_END, wiredPagesEncrypted,
2279 wiredPagesClear, dirtyPagesEncrypted);
2280
2281 #if defined(__arm64__)
2282 if (kIOReturnSuccess == err) {
2283 return kIOHibernatePostWriteHalt;
2284 } else {
2285 // on ARM, once ApplePMGR decides we're hibernating, we can't turn back
2286 // see: <rdar://problem/63848862> Tonga ApplePMGR diff quiesce path support
2287 vm_panic_hibernate_write_image_failed(err);
2288 return err; //not coming here post panic
2289 }
2290 #else
2291 if (kIOReturnSuccess == err) {
2292 if (kIOHibernateModeSleep & gIOHibernateMode) {
2293 return kIOHibernatePostWriteSleep;
2294 } else if (kIOHibernateModeRestart & gIOHibernateMode) {
2295 return kIOHibernatePostWriteRestart;
2296 } else {
2297 /* by default, power down */
2298 return kIOHibernatePostWriteHalt;
2299 }
2300 } else if (kIOReturnAborted == err) {
2301 return kIOHibernatePostWriteWake;
2302 } else {
2303 /* on error, sleep */
2304 return kIOHibernatePostWriteSleep;
2305 }
2306 #endif
2307 }
2308
2309 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2310
2311 extern "C" void
hibernate_machine_init(void)2312 hibernate_machine_init(void)
2313 {
2314 IOReturn err;
2315 uint32_t sum;
2316 uint32_t pagesDone;
2317 uint32_t pagesRead = 0;
2318 AbsoluteTime startTime, compTime;
2319 AbsoluteTime allTime, endTime;
2320 AbsoluteTime startIOTime, endIOTime;
2321 uint64_t nsec, nsecIO;
2322 uint64_t compBytes;
2323 uint64_t lastProgressStamp = 0;
2324 uint64_t progressStamp;
2325 IOPolledFileCryptVars * cryptvars = NULL;
2326
2327 IOHibernateVars * vars = &gIOHibernateVars;
2328 bzero(gIOHibernateStats, sizeof(hibernate_statistics_t));
2329
2330 if (!vars->fileVars || !vars->fileVars->pollers) {
2331 return;
2332 }
2333
2334 sum = gIOHibernateCurrentHeader->actualImage1Sum;
2335 pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages;
2336
2337 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState) {
2338 HIBLOG("regular wake\n");
2339 return;
2340 }
2341
2342 HIBPRINT("diag %x %x %x %x\n",
2343 gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1],
2344 gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]);
2345
2346 #if defined(__i386__) || defined(__x86_64__)
2347 #define t40ms(x) ((uint32_t)((tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)))
2348 #else /* defined(__i386__) || defined(__x86_64__) */
2349 #define t40ms(x) x
2350 #endif /* defined(__i386__) || defined(__x86_64__) */
2351 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2352 tStat(booterStart, booterStart);
2353 gIOHibernateStats->smcStart = gIOHibernateCurrentHeader->smcStart;
2354 tStat(booterDuration0, booterTime0);
2355 tStat(booterDuration1, booterTime1);
2356 tStat(booterDuration2, booterTime2);
2357 tStat(booterDuration, booterTime);
2358 tStat(booterConnectDisplayDuration, connectDisplayTime);
2359 tStat(booterSplashDuration, splashTime);
2360 tStat(trampolineDuration, trampolineTime);
2361
2362 gIOHibernateStats->image1Size = gIOHibernateCurrentHeader->image1Size;
2363 gIOHibernateStats->imageSize = gIOHibernateCurrentHeader->imageSize;
2364 gIOHibernateStats->image1Pages = pagesDone;
2365
2366 /* HIBERNATE_stats */
2367 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 14), gIOHibernateStats->smcStart,
2368 gIOHibernateStats->booterStart, gIOHibernateStats->booterDuration,
2369 gIOHibernateStats->trampolineDuration);
2370
2371 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2372 gIOHibernateStats->booterStart,
2373 gIOHibernateStats->smcStart,
2374 gIOHibernateStats->booterDuration0,
2375 gIOHibernateStats->booterDuration1,
2376 gIOHibernateStats->booterDuration2,
2377 gIOHibernateStats->booterDuration,
2378 gIOHibernateStats->booterConnectDisplayDuration,
2379 gIOHibernateStats->booterSplashDuration,
2380 gIOHibernateStats->trampolineDuration);
2381
2382 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2383 gIOHibernateState, pagesDone, sum, gIOHibernateStats->imageSize, gIOHibernateStats->image1Size,
2384 gIOHibernateCurrentHeader->conflictCount, gIOHibernateCurrentHeader->nextFree);
2385
2386 if ((0 != (kIOHibernateModeSleep & gIOHibernateMode))
2387 && (0 != ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode))) {
2388 hibernate_page_list_discard(vars->page_list);
2389 }
2390
2391 if (vars->hwEncrypt) {
2392 // if vars->hwEncrypt is true, we don't need cryptvars since we supply the
2393 // decryption key via IOPolledFilePollersSetEncryptionKey
2394 cryptvars = NULL;
2395 } else {
2396 cryptvars = (kIOHibernateModeEncrypt & gIOHibernateMode) ? &gIOHibernateCryptWakeContext : NULL;
2397 }
2398
2399 if (gIOHibernateCurrentHeader->handoffPageCount > gIOHibernateHandoffPageCount) {
2400 panic("handoff overflow");
2401 }
2402
2403 IOHibernateHandoff * handoff;
2404 bool done = false;
2405 bool foundCryptData = false;
2406 bool foundVolumeEncryptData = false;
2407 const uint8_t * handoffStart = (const uint8_t*)vars->handoffBuffer->getBytesNoCopy();
2408 const uint8_t * handoffEnd = handoffStart + vars->handoffBuffer->getLength();
2409
2410 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
2411 !done;
2412 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount]) {
2413 if (((uint8_t*)handoff < handoffStart) ||
2414 (&handoff->data[handoff->bytecount] > handoffEnd)) {
2415 panic("handoff out of range");
2416 }
2417 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2418 uint8_t * data = &handoff->data[0];
2419 switch (handoff->type) {
2420 case kIOHibernateHandoffTypeEnd:
2421 done = true;
2422 break;
2423
2424 case kIOHibernateHandoffTypeGraphicsInfo:
2425 if (handoff->bytecount == sizeof(*gIOHibernateGraphicsInfo)) {
2426 bcopy(data, gIOHibernateGraphicsInfo, sizeof(*gIOHibernateGraphicsInfo));
2427 }
2428 break;
2429
2430 case kIOHibernateHandoffTypeCryptVars:
2431 if (cryptvars) {
2432 hibernate_cryptwakevars_t *
2433 wakevars = (hibernate_cryptwakevars_t *) &handoff->data[0];
2434 if (handoff->bytecount == sizeof(*wakevars)) {
2435 bcopy(&wakevars->aes_iv[0], &cryptvars->aes_iv[0], sizeof(cryptvars->aes_iv));
2436 } else {
2437 panic("kIOHibernateHandoffTypeCryptVars(%d)", handoff->bytecount);
2438 }
2439 }
2440 foundCryptData = true;
2441 bzero(data, handoff->bytecount);
2442 break;
2443
2444 case kIOHibernateHandoffTypeVolumeCryptKey:
2445 if (handoff->bytecount == vars->volumeCryptKeySize) {
2446 bcopy(data, &vars->volumeCryptKey[0], vars->volumeCryptKeySize);
2447 foundVolumeEncryptData = true;
2448 } else {
2449 panic("kIOHibernateHandoffTypeVolumeCryptKey(%d)", handoff->bytecount);
2450 }
2451 break;
2452
2453 #if defined(__i386__) || defined(__x86_64__)
2454 case kIOHibernateHandoffTypeMemoryMap:
2455
2456 clock_get_uptime(&allTime);
2457
2458 hibernate_newruntime_map(data, handoff->bytecount,
2459 gIOHibernateCurrentHeader->systemTableOffset);
2460
2461 clock_get_uptime(&endTime);
2462
2463 SUB_ABSOLUTETIME(&endTime, &allTime);
2464 absolutetime_to_nanoseconds(endTime, &nsec);
2465
2466 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec / 1000000ULL);
2467
2468 break;
2469
2470 case kIOHibernateHandoffTypeDeviceTree:
2471 {
2472 // DTEntry chosen = NULL;
2473 // HIBPRINT("SecureDTLookupEntry %d\n", SecureDTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2474 }
2475 break;
2476 #endif /* defined(__i386__) || defined(__x86_64__) */
2477
2478 default:
2479 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
2480 break;
2481 }
2482 }
2483
2484 if (vars->hwEncrypt && !foundVolumeEncryptData) {
2485 panic("no volumeCryptKey");
2486 } else if (cryptvars && !foundCryptData) {
2487 panic("hibernate handoff");
2488 }
2489
2490 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2491 gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth,
2492 gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height, gIOHibernateGraphicsInfo->gfxStatus);
2493
2494 if (vars->videoMapping && gIOHibernateGraphicsInfo->physicalAddress) {
2495 vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height
2496 * gIOHibernateGraphicsInfo->rowBytes);
2497 if (vars->videoMapSize > vars->videoAllocSize) {
2498 vars->videoMapSize = 0;
2499 } else {
2500 IOMapPages(kernel_map,
2501 vars->videoMapping, gIOHibernateGraphicsInfo->physicalAddress,
2502 vars->videoMapSize, kIOMapInhibitCache );
2503 }
2504 }
2505
2506 if (vars->videoMapSize) {
2507 ProgressUpdate(gIOHibernateGraphicsInfo,
2508 (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);
2509 }
2510
2511 uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2512 uint8_t * compressed = src + page_size;
2513 uint8_t * scratch = compressed + page_size;
2514 uint32_t decoOffset;
2515
2516 clock_get_uptime(&allTime);
2517 AbsoluteTime_to_scalar(&compTime) = 0;
2518 compBytes = 0;
2519
2520 HIBLOG("IOPolledFilePollersOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2521 err = IOPolledFilePollersOpen(vars->fileVars, kIOPolledAfterSleepState, false);
2522 clock_get_uptime(&startIOTime);
2523 endTime = startIOTime;
2524 SUB_ABSOLUTETIME(&endTime, &allTime);
2525 absolutetime_to_nanoseconds(endTime, &nsec);
2526 HIBLOG("IOPolledFilePollersOpen(%x) %qd ms\n", err, nsec / 1000000ULL);
2527
2528 if (vars->hwEncrypt) {
2529 err = IOPolledFilePollersSetEncryptionKey(vars->fileVars,
2530 &vars->volumeCryptKey[0], vars->volumeCryptKeySize);
2531 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x) %ld\n", err, vars->volumeCryptKeySize);
2532 if (kIOReturnSuccess != err) {
2533 panic("IOPolledFilePollersSetEncryptionKey(0x%x)", err);
2534 }
2535 cryptvars = NULL;
2536 }
2537
2538 IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size);
2539
2540 // kick off the read ahead
2541 vars->fileVars->bufferHalf = 0;
2542 vars->fileVars->bufferLimit = 0;
2543 vars->fileVars->lastRead = 0;
2544 vars->fileVars->readEnd = gIOHibernateCurrentHeader->imageSize;
2545 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2546 vars->fileVars->cryptBytes = 0;
2547 AbsoluteTime_to_scalar(&vars->fileVars->cryptTime) = 0;
2548
2549 err = IOPolledFileRead(vars->fileVars, NULL, 0, cryptvars);
2550 if (kIOReturnSuccess != err) {
2551 panic("Hibernate restore error %x", err);
2552 }
2553 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2554 // --
2555
2556 HIBLOG("hibernate_machine_init reading\n");
2557
2558
2559 uint32_t * header = (uint32_t *) src;
2560 sum = 0;
2561
2562 while (kIOReturnSuccess == err) {
2563 unsigned int count;
2564 unsigned int page;
2565 uint32_t tag;
2566 vm_offset_t compressedSize;
2567 ppnum_t ppnum;
2568
2569 err = IOPolledFileRead(vars->fileVars, src, 8, cryptvars);
2570 if (kIOReturnSuccess != err) {
2571 panic("Hibernate restore error %x", err);
2572 }
2573
2574 ppnum = header[0];
2575 count = header[1];
2576
2577 // HIBPRINT("(%x, %x)\n", ppnum, count);
2578
2579 if (!count) {
2580 break;
2581 }
2582
2583 for (page = 0; page < count; page++) {
2584 err = IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars);
2585 if (kIOReturnSuccess != err) {
2586 panic("Hibernate restore error %x", err);
2587 }
2588
2589 compressedSize = kIOHibernateTagLength & tag;
2590 if (kIOHibernateTagSignature != (tag & ~kIOHibernateTagLength)) {
2591 err = kIOReturnIPCError;
2592 panic("Hibernate restore error %x", err);
2593 }
2594
2595 err = IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars);
2596 if (kIOReturnSuccess != err) {
2597 panic("Hibernate restore error %x", err);
2598 }
2599
2600 if (compressedSize < page_size) {
2601 decoOffset = ((uint32_t) page_size);
2602 clock_get_uptime(&startTime);
2603
2604 if (compressedSize == 4) {
2605 int i;
2606 uint32_t *s, *d;
2607
2608 s = (uint32_t *)src;
2609 d = (uint32_t *)(uintptr_t)compressed;
2610
2611 for (i = 0; i < (int)(PAGE_SIZE / sizeof(int32_t)); i++) {
2612 *d++ = *s;
2613 }
2614 } else {
2615 pal_hib_decompress_page(src, compressed, scratch, ((unsigned int) compressedSize));
2616 }
2617 clock_get_uptime(&endTime);
2618 ADD_ABSOLUTETIME(&compTime, &endTime);
2619 SUB_ABSOLUTETIME(&compTime, &startTime);
2620 compBytes += page_size;
2621 } else {
2622 decoOffset = 0;
2623 }
2624
2625 sum += hibernate_sum_page((src + decoOffset), ((uint32_t) ppnum));
2626 err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size);
2627 if (err) {
2628 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum, err);
2629 panic("Hibernate restore error %x", err);
2630 }
2631
2632
2633 ppnum++;
2634 pagesDone++;
2635 pagesRead++;
2636
2637 if (0 == (8191 & pagesDone)) {
2638 clock_get_uptime(&endTime);
2639 SUB_ABSOLUTETIME(&endTime, &allTime);
2640 absolutetime_to_nanoseconds(endTime, &nsec);
2641 progressStamp = nsec / 750000000ULL;
2642 if (progressStamp != lastProgressStamp) {
2643 lastProgressStamp = progressStamp;
2644 HIBPRINT("pages %d (%d%%)\n", pagesDone,
2645 (100 * pagesDone) / gIOHibernateCurrentHeader->pageCount);
2646 }
2647 }
2648 }
2649 }
2650 if ((kIOReturnSuccess == err) && (pagesDone == gIOHibernateCurrentHeader->actualUncompressedPages)) {
2651 err = kIOReturnLockedRead;
2652 }
2653
2654 if (kIOReturnSuccess != err) {
2655 panic("Hibernate restore error %x", err);
2656 }
2657
2658
2659 gIOHibernateCurrentHeader->actualImage2Sum = sum;
2660 gIOHibernateCompression = gIOHibernateCurrentHeader->compression;
2661
2662 clock_get_uptime(&endIOTime);
2663
2664 err = IOPolledFilePollersClose(vars->fileVars, kIOPolledAfterSleepState);
2665
2666 clock_get_uptime(&endTime);
2667
2668 IOService::getPMRootDomain()->pmStatsRecordEvent(
2669 kIOPMStatsHibernateImageRead | kIOPMStatsEventStartFlag, allTime);
2670 IOService::getPMRootDomain()->pmStatsRecordEvent(
2671 kIOPMStatsHibernateImageRead | kIOPMStatsEventStopFlag, endTime);
2672
2673 SUB_ABSOLUTETIME(&endTime, &allTime);
2674 absolutetime_to_nanoseconds(endTime, &nsec);
2675
2676 SUB_ABSOLUTETIME(&endIOTime, &startIOTime);
2677 absolutetime_to_nanoseconds(endIOTime, &nsecIO);
2678
2679 gIOHibernateStats->kernelImageReadDuration = ((uint32_t) (nsec / 1000000ULL));
2680 gIOHibernateStats->imagePages = pagesDone;
2681
2682 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
2683 pagesDone, sum, gIOHibernateStats->kernelImageReadDuration, kDefaultIOSize,
2684 nsecIO ? ((((gIOHibernateCurrentHeader->imageSize - gIOHibernateCurrentHeader->image1Size) * 1000000000ULL) / 1024 / 1024) / nsecIO) : 0);
2685
2686 absolutetime_to_nanoseconds(compTime, &nsec);
2687 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2688 compBytes,
2689 nsec / 1000000ULL,
2690 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2691
2692 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2693 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2694 vars->fileVars->cryptBytes,
2695 nsec / 1000000ULL,
2696 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2697
2698 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 2), pagesRead, pagesDone);
2699 }
2700
2701 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2702
2703 void
IOHibernateSetWakeCapabilities(uint32_t capability)2704 IOHibernateSetWakeCapabilities(uint32_t capability)
2705 {
2706 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2707 gIOHibernateStats->wakeCapability = capability;
2708
2709 if (kIOPMSystemCapabilityGraphics & capability) {
2710 vm_compressor_do_warmup();
2711 }
2712 }
2713 }
2714
2715 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2716
2717 void
IOHibernateSystemRestart(void)2718 IOHibernateSystemRestart(void)
2719 {
2720 #if defined(__i386__) || defined(__x86_64__)
2721 static uint8_t noteStore[32] __attribute__((aligned(32)));
2722 IORegistryEntry * regEntry;
2723 const OSSymbol * sym;
2724 OSData * noteProp;
2725 OSData * data;
2726 uint8_t * smcBytes;
2727 size_t len;
2728 addr64_t element;
2729
2730 data = OSDynamicCast(OSData, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey));
2731 if (!data) {
2732 return;
2733 }
2734
2735 smcBytes = (typeof(smcBytes))data->getBytesNoCopy();
2736 len = data->getLength();
2737 if (len > sizeof(noteStore)) {
2738 len = sizeof(noteStore);
2739 }
2740 noteProp = OSData::withCapacity(3 * sizeof(element));
2741 if (!noteProp) {
2742 return;
2743 }
2744 element = len;
2745 noteProp->appendValue(element);
2746 element = crc32(0, smcBytes, len);
2747 noteProp->appendValue(element);
2748
2749 bcopy(smcBytes, noteStore, len);
2750 element = (addr64_t) ¬eStore[0];
2751 element = (element & page_mask) | ptoa_64(pmap_find_phys(kernel_pmap, element));
2752 noteProp->appendValue(element);
2753
2754 if (!gIOOptionsEntry) {
2755 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
2756 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
2757 if (regEntry && !gIOOptionsEntry) {
2758 regEntry->release();
2759 }
2760 }
2761
2762 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey);
2763 if (gIOOptionsEntry && sym) {
2764 gIOOptionsEntry->setProperty(sym, noteProp);
2765 }
2766 if (noteProp) {
2767 noteProp->release();
2768 }
2769 if (sym) {
2770 sym->release();
2771 }
2772 #endif /* defined(__i386__) || defined(__x86_64__) */
2773 }
2774