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