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