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