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