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