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