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