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