xref: /xnu-11215/iokit/Kernel/IOHibernateIO.cpp (revision 4f1223e8)
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(&copyDest[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) &noteStore[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