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