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