]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOHibernateIO.cpp
be2483dbfc2309be0084c94ef16d665bd4804f62
[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/WKdm_new.h>
170 #include <vm/vm_protos.h>
171 #include "IOKitKernelInternal.h"
172 #include <pexpert/device_tree.h>
173
174 #include <machine/pal_routines.h>
175 #include <machine/pal_hibernate.h>
176 #include <i386/tsc.h>
177 #include <i386/cpuid.h>
178 #include <san/kasan.h>
179
180 extern "C" addr64_t kvtophys(vm_offset_t va);
181 extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
182
183 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
184
185 #define DISABLE_TRIM 0
186 #define TRIM_DELAY 25000
187
188 extern unsigned int save_kdebug_enable;
189 extern uint32_t gIOHibernateState;
190 uint32_t gIOHibernateMode;
191 static char gIOHibernateBootSignature[256 + 1];
192 static char gIOHibernateFilename[MAXPATHLEN + 1];
193
194 static uuid_string_t gIOHibernateBridgeBootSessionUUIDString;
195
196 static uint32_t gIOHibernateFreeRatio = 0; // free page target (percent)
197 uint32_t gIOHibernateFreeTime = 0 * 1000; // max time to spend freeing pages (ms)
198 static uint64_t gIOHibernateCompression = 0x80; // default compression 50%
199 boolean_t gIOHibernateStandbyDisabled;
200
201 static IODTNVRAM * gIOOptionsEntry;
202 static IORegistryEntry * gIOChosenEntry;
203
204 static const OSSymbol * gIOHibernateBootImageKey;
205 static const OSSymbol * gIOHibernateBootSignatureKey;
206 static const OSSymbol * gIOBridgeBootSessionUUIDKey;
207
208 #if defined(__i386__) || defined(__x86_64__)
209
210 static const OSSymbol * gIOHibernateRTCVariablesKey;
211 static const OSSymbol * gIOHibernateBoot0082Key;
212 static const OSSymbol * gIOHibernateBootNextKey;
213 static OSData * gIOHibernateBoot0082Data;
214 static OSData * gIOHibernateBootNextData;
215 static OSObject * gIOHibernateBootNextSave;
216
217 #endif /* defined(__i386__) || defined(__x86_64__) */
218
219 static IOLock * gFSLock;
220 uint32_t gFSState;
221 static thread_call_t gIOHibernateTrimCalloutEntry;
222 static IOPolledFileIOVars gFileVars;
223 static IOHibernateVars gIOHibernateVars;
224 static IOPolledFileCryptVars gIOHibernateCryptWakeContext;
225 static hibernate_graphics_t _hibernateGraphics;
226 static hibernate_graphics_t * gIOHibernateGraphicsInfo = &_hibernateGraphics;
227 static hibernate_statistics_t _hibernateStats;
228 static hibernate_statistics_t * gIOHibernateStats = &_hibernateStats;
229
230 enum{
231 kFSIdle = 0,
232 kFSOpening = 2,
233 kFSOpened = 3,
234 kFSTimedOut = 4,
235 kFSTrimDelay = 5
236 };
237
238 static IOReturn IOHibernateDone(IOHibernateVars * vars);
239 static IOReturn IOWriteExtentsToFile(IOPolledFileIOVars * vars, uint32_t signature);
240 static void IOSetBootImageNVRAM(OSData * data);
241 static void IOHibernateSystemPostWakeTrim(void * p1, void * p2);
242
243 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
244
245 enum { kDefaultIOSize = 128 * 1024 };
246 enum { kVideoMapSize = 80 * 1024 * 1024 };
247
248 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
249
250 // copy from phys addr to MD
251
252 static IOReturn
253 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor * md,
254 IOByteCount offset, addr64_t bytes, IOByteCount length)
255 {
256 addr64_t srcAddr = bytes;
257 IOByteCount remaining;
258
259 remaining = length = min(length, md->getLength() - offset);
260 while (remaining) { // (process another target segment?)
261 addr64_t dstAddr64;
262 IOByteCount dstLen;
263
264 dstAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
265 if (!dstAddr64) {
266 break;
267 }
268
269 // Clip segment length to remaining
270 if (dstLen > remaining) {
271 dstLen = remaining;
272 }
273
274 #if 1
275 bcopy_phys(srcAddr, dstAddr64, dstLen);
276 #else
277 copypv(srcAddr, dstAddr64, dstLen,
278 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
279 #endif
280 srcAddr += dstLen;
281 offset += dstLen;
282 remaining -= dstLen;
283 }
284
285 assert(!remaining);
286
287 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
288 }
289
290 // copy from MD to phys addr
291
292 static IOReturn
293 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor * md,
294 IOByteCount offset, addr64_t bytes, IOByteCount length)
295 {
296 addr64_t dstAddr = bytes;
297 IOByteCount remaining;
298
299 remaining = length = min(length, md->getLength() - offset);
300 while (remaining) { // (process another target segment?)
301 addr64_t srcAddr64;
302 IOByteCount dstLen;
303
304 srcAddr64 = md->getPhysicalSegment(offset, &dstLen, kIOMemoryMapperNone);
305 if (!srcAddr64) {
306 break;
307 }
308
309 // Clip segment length to remaining
310 if (dstLen > remaining) {
311 dstLen = remaining;
312 }
313
314 #if 1
315 bcopy_phys(srcAddr64, dstAddr, dstLen);
316 #else
317 copypv(srcAddr, dstAddr64, dstLen,
318 cppvPsnk | cppvFsnk | cppvNoRefSrc | cppvNoModSnk | cppvKmap);
319 #endif
320 dstAddr += dstLen;
321 offset += dstLen;
322 remaining -= dstLen;
323 }
324
325 assert(!remaining);
326
327 return remaining ? kIOReturnUnderrun : kIOReturnSuccess;
328 }
329
330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
331
332 void
333 hibernate_set_page_state(hibernate_page_list_t * page_list, hibernate_page_list_t * page_list_wired,
334 vm_offset_t ppnum, vm_offset_t count, uint32_t kind)
335 {
336 count += ppnum;
337 switch (kind) {
338 case kIOHibernatePageStateUnwiredSave:
339 // unwired save
340 for (; ppnum < count; ppnum++) {
341 hibernate_page_bitset(page_list, FALSE, ppnum);
342 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
343 }
344 break;
345 case kIOHibernatePageStateWiredSave:
346 // wired save
347 for (; ppnum < count; ppnum++) {
348 hibernate_page_bitset(page_list, FALSE, ppnum);
349 hibernate_page_bitset(page_list_wired, FALSE, ppnum);
350 }
351 break;
352 case kIOHibernatePageStateFree:
353 // free page
354 for (; ppnum < count; ppnum++) {
355 hibernate_page_bitset(page_list, TRUE, ppnum);
356 hibernate_page_bitset(page_list_wired, TRUE, ppnum);
357 }
358 break;
359 default:
360 panic("hibernate_set_page_state");
361 }
362 }
363
364 static vm_offset_t
365 hibernate_page_list_iterate(hibernate_page_list_t * list, vm_offset_t * pPage)
366 {
367 uint32_t page = *pPage;
368 uint32_t count;
369 hibernate_bitmap_t * bitmap;
370
371 while ((bitmap = hibernate_page_bitmap_pin(list, &page))) {
372 count = hibernate_page_bitmap_count(bitmap, TRUE, page);
373 if (!count) {
374 break;
375 }
376 page += count;
377 if (page <= bitmap->last_page) {
378 break;
379 }
380 }
381
382 *pPage = page;
383 if (bitmap) {
384 count = hibernate_page_bitmap_count(bitmap, FALSE, page);
385 } else {
386 count = 0;
387 }
388
389 return count;
390 }
391
392 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
393
394 IOReturn
395 IOHibernateSystemSleep(void)
396 {
397 IOReturn err;
398 OSData * nvramData;
399 OSObject * obj;
400 OSString * str;
401 OSNumber * num;
402 bool dsSSD, vmflush, swapPinned;
403 IOHibernateVars * vars;
404 uint64_t setFileSize = 0;
405
406 gIOHibernateState = kIOHibernateStateInactive;
407
408 gIOHibernateDebugFlags = 0;
409 if (kIOLogHibernate & gIOKitDebug) {
410 gIOHibernateDebugFlags |= kIOHibernateDebugRestoreLogs;
411 }
412
413 if (IOService::getPMRootDomain()->getHibernateSettings(
414 &gIOHibernateMode, &gIOHibernateFreeRatio, &gIOHibernateFreeTime)) {
415 if (kIOHibernateModeSleep & gIOHibernateMode) {
416 // default to discard clean for safe sleep
417 gIOHibernateMode ^= (kIOHibernateModeDiscardCleanInactive
418 | kIOHibernateModeDiscardCleanActive);
419 }
420 }
421
422 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey))) {
423 if ((str = OSDynamicCast(OSString, obj))) {
424 strlcpy(gIOHibernateFilename, str->getCStringNoCopy(),
425 sizeof(gIOHibernateFilename));
426 }
427 obj->release();
428 }
429
430 if (!gIOHibernateMode || !gIOHibernateFilename[0]) {
431 return kIOReturnUnsupported;
432 }
433
434 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename);
435
436 vars = IONew(IOHibernateVars, 1);
437 if (!vars) {
438 return kIOReturnNoMemory;
439 }
440 bzero(vars, sizeof(*vars));
441
442 IOLockLock(gFSLock);
443 if (!gIOHibernateTrimCalloutEntry) {
444 gIOHibernateTrimCalloutEntry = thread_call_allocate(&IOHibernateSystemPostWakeTrim, &gFSLock);
445 }
446 IOHibernateSystemPostWakeTrim(NULL, NULL);
447 thread_call_cancel(gIOHibernateTrimCalloutEntry);
448 if (kFSIdle != gFSState) {
449 HIBLOG("hibernate file busy\n");
450 IOLockUnlock(gFSLock);
451 IODelete(vars, IOHibernateVars, 1);
452 return kIOReturnBusy;
453 }
454 gFSState = kFSOpening;
455 IOLockUnlock(gFSLock);
456
457 swapPinned = false;
458 do{
459 vars->srcBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
460 2 * page_size + WKdm_SCRATCH_BUF_SIZE_INTERNAL, page_size);
461
462 vars->handoffBuffer = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn,
463 ptoa_64(gIOHibernateHandoffPageCount), page_size);
464
465 if (!vars->srcBuffer || !vars->handoffBuffer) {
466 err = kIOReturnNoMemory;
467 break;
468 }
469
470 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey))) {
471 if ((num = OSDynamicCast(OSNumber, obj))) {
472 vars->fileMinSize = num->unsigned64BitValue();
473 }
474 obj->release();
475 }
476 if ((obj = IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey))) {
477 if ((num = OSDynamicCast(OSNumber, obj))) {
478 vars->fileMaxSize = num->unsigned64BitValue();
479 }
480 obj->release();
481 }
482
483 boolean_t encryptedswap = true;
484 uint32_t pageCount;
485 AbsoluteTime startTime, endTime;
486 uint64_t nsec;
487
488 bzero(gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader));
489 gIOHibernateCurrentHeader->debugFlags = gIOHibernateDebugFlags;
490 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
491
492 vmflush = ((kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
493 err = hibernate_alloc_page_lists(&vars->page_list,
494 &vars->page_list_wired,
495 &vars->page_list_pal);
496 if (KERN_SUCCESS != err) {
497 break;
498 }
499
500 err = hibernate_pin_swap(TRUE);
501 if (KERN_SUCCESS != err) {
502 break;
503 }
504 swapPinned = true;
505
506 if (vars->fileMinSize || (kIOHibernateModeFileResize & gIOHibernateMode)) {
507 hibernate_page_list_setall(vars->page_list,
508 vars->page_list_wired,
509 vars->page_list_pal,
510 true /* preflight */,
511 vmflush /* discard */,
512 &pageCount);
513 PE_Video consoleInfo;
514 bzero(&consoleInfo, sizeof(consoleInfo));
515 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
516
517 // estimate: 6% increase in pages compressed
518 // screen preview 2 images compressed 0%
519 setFileSize = ((ptoa_64((106 * pageCount) / 100) * gIOHibernateCompression) >> 8)
520 + vars->page_list->list_size
521 + (consoleInfo.v_width * consoleInfo.v_height * 8);
522 enum { setFileRound = 1024 * 1024ULL };
523 setFileSize = ((setFileSize + setFileRound) & ~(setFileRound - 1));
524
525 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
526 pageCount, (100ULL * gIOHibernateCompression) >> 8,
527 setFileSize, vars->fileMinSize);
528
529 if (!(kIOHibernateModeFileResize & gIOHibernateMode)
530 && (setFileSize < vars->fileMinSize)) {
531 setFileSize = vars->fileMinSize;
532 }
533 }
534
535 vars->volumeCryptKeySize = sizeof(vars->volumeCryptKey);
536 err = IOPolledFileOpen(gIOHibernateFilename,
537 (kIOPolledFileCreate | kIOPolledFileHibernate),
538 setFileSize, 0,
539 gIOHibernateCurrentHeader, sizeof(gIOHibernateCurrentHeader),
540 &vars->fileVars, &nvramData,
541 &vars->volumeCryptKey[0], &vars->volumeCryptKeySize);
542
543 if (KERN_SUCCESS != err) {
544 IOLockLock(gFSLock);
545 if (kFSOpening != gFSState) {
546 err = kIOReturnTimeout;
547 }
548 IOLockUnlock(gFSLock);
549 }
550
551 if (KERN_SUCCESS != err) {
552 HIBLOG("IOPolledFileOpen(%x)\n", err);
553 break;
554 }
555
556 // write extents for debug data usage in EFI
557 IOWriteExtentsToFile(vars->fileVars, kIOHibernateHeaderOpenSignature);
558
559 err = IOPolledFilePollersSetup(vars->fileVars, kIOPolledPreflightState);
560 if (KERN_SUCCESS != err) {
561 break;
562 }
563
564 clock_get_uptime(&startTime);
565 err = hibernate_setup(gIOHibernateCurrentHeader,
566 vmflush,
567 vars->page_list, vars->page_list_wired, vars->page_list_pal);
568 clock_get_uptime(&endTime);
569 SUB_ABSOLUTETIME(&endTime, &startTime);
570 absolutetime_to_nanoseconds(endTime, &nsec);
571
572 boolean_t haveSwapPin, hibFileSSD;
573 haveSwapPin = vm_swap_files_pinned();
574
575 hibFileSSD = (kIOPolledFileSSD & vars->fileVars->flags);
576
577 HIBLOG("hibernate_setup(%d) took %qd ms, swapPin(%d) ssd(%d)\n",
578 err, nsec / 1000000ULL,
579 haveSwapPin, hibFileSSD);
580 if (KERN_SUCCESS != err) {
581 break;
582 }
583
584 gIOHibernateStandbyDisabled = ((!haveSwapPin || !hibFileSSD));
585
586 dsSSD = ((0 != (kIOPolledFileSSD & vars->fileVars->flags))
587 && (kOSBooleanTrue == IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey)));
588
589 if (dsSSD) {
590 gIOHibernateCurrentHeader->options |= kIOHibernateOptionSSD | kIOHibernateOptionColor;
591 } else {
592 gIOHibernateCurrentHeader->options |= kIOHibernateOptionProgress;
593 }
594
595
596 #if defined(__i386__) || defined(__x86_64__)
597 if (vars->volumeCryptKeySize &&
598 (kOSBooleanTrue != IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey))) {
599 uintptr_t smcVars[2];
600 smcVars[0] = vars->volumeCryptKeySize;
601 smcVars[1] = (uintptr_t)(void *) &gIOHibernateVars.volumeCryptKey[0];
602
603 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey, smcVars, sizeof(smcVars));
604 bzero(smcVars, sizeof(smcVars));
605 }
606 #endif
607
608
609 if (encryptedswap || vars->volumeCryptKeySize) {
610 gIOHibernateMode ^= kIOHibernateModeEncrypt;
611 }
612
613 if (kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options) {
614 vars->videoAllocSize = kVideoMapSize;
615 if (KERN_SUCCESS != kmem_alloc_pageable(kernel_map, &vars->videoMapping, vars->videoAllocSize, VM_KERN_MEMORY_IOKIT)) {
616 vars->videoMapping = 0;
617 }
618 }
619
620 // generate crypt keys
621 for (uint32_t i = 0; i < sizeof(vars->wiredCryptKey); i++) {
622 vars->wiredCryptKey[i] = random();
623 }
624 for (uint32_t i = 0; i < sizeof(vars->cryptKey); i++) {
625 vars->cryptKey[i] = random();
626 }
627
628 // set nvram
629
630 IOSetBootImageNVRAM(nvramData);
631 nvramData->release();
632
633 #if defined(__i386__) || defined(__x86_64__)
634 {
635 struct AppleRTCHibernateVars {
636 uint8_t signature[4];
637 uint32_t revision;
638 uint8_t booterSignature[20];
639 uint8_t wiredCryptKey[16];
640 };
641 AppleRTCHibernateVars rtcVars;
642 OSData * data;
643
644 rtcVars.signature[0] = 'A';
645 rtcVars.signature[1] = 'A';
646 rtcVars.signature[2] = 'P';
647 rtcVars.signature[3] = 'L';
648 rtcVars.revision = 1;
649 bcopy(&vars->wiredCryptKey[0], &rtcVars.wiredCryptKey[0], sizeof(rtcVars.wiredCryptKey));
650
651 if (gIOChosenEntry
652 && (data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(gIOHibernateBootSignatureKey)))
653 && (sizeof(rtcVars.booterSignature) <= data->getLength())) {
654 bcopy(data->getBytesNoCopy(), &rtcVars.booterSignature[0], sizeof(rtcVars.booterSignature));
655 } else if (gIOHibernateBootSignature[0]) {
656 char c;
657 uint8_t value = 0;
658 uint32_t in, out, digits;
659 for (in = out = digits = 0;
660 (c = gIOHibernateBootSignature[in]) && (in < sizeof(gIOHibernateBootSignature));
661 in++) {
662 if ((c >= 'a') && (c <= 'f')) {
663 c -= 'a' - 10;
664 } else if ((c >= 'A') && (c <= 'F')) {
665 c -= 'A' - 10;
666 } else if ((c >= '0') && (c <= '9')) {
667 c -= '0';
668 } else {
669 if (c == '=') {
670 out = digits = value = 0;
671 }
672 continue;
673 }
674 value = (value << 4) | c;
675 if (digits & 1) {
676 rtcVars.booterSignature[out++] = value;
677 if (out >= sizeof(rtcVars.booterSignature)) {
678 break;
679 }
680 }
681 digits++;
682 }
683 }
684 #if DEBUG || DEVELOPMENT
685 if (kIOLogHibernate & gIOKitDebug) {
686 IOKitKernelLogBuffer("H> rtc:",
687 &rtcVars, sizeof(rtcVars), &kprintf);
688 }
689 #endif /* DEBUG || DEVELOPMENT */
690
691 data = OSData::withBytes(&rtcVars, sizeof(rtcVars));
692 if (data) {
693 if (gIOHibernateRTCVariablesKey) {
694 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey, data);
695 }
696 data->release();
697 }
698 if (gIOChosenEntry && gIOOptionsEntry) {
699 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOHibernateMachineSignatureKey));
700 if (data) {
701 gIOHibernateCurrentHeader->machineSignature = *((UInt32 *)data->getBytesNoCopy());
702 }
703 // set BootNext
704 if (!gIOHibernateBoot0082Data) {
705 OSData * fileData = 0;
706 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-device-path"));
707 if (data && data->getLength() >= 4) {
708 fileData = OSDynamicCast(OSData, gIOChosenEntry->getProperty("boot-file-path"));
709 }
710 if (data) {
711 // AppleNVRAM_EFI_LOAD_OPTION
712 struct {
713 uint32_t Attributes;
714 uint16_t FilePathLength;
715 uint16_t Desc;
716 } loadOptionHeader;
717 loadOptionHeader.Attributes = 1;
718 loadOptionHeader.FilePathLength = data->getLength();
719 loadOptionHeader.Desc = 0;
720 if (fileData) {
721 loadOptionHeader.FilePathLength -= 4;
722 loadOptionHeader.FilePathLength += fileData->getLength();
723 }
724 gIOHibernateBoot0082Data = OSData::withCapacity(sizeof(loadOptionHeader) + loadOptionHeader.FilePathLength);
725 if (gIOHibernateBoot0082Data) {
726 gIOHibernateBoot0082Data->appendBytes(&loadOptionHeader, sizeof(loadOptionHeader));
727 if (fileData) {
728 gIOHibernateBoot0082Data->appendBytes(data->getBytesNoCopy(), data->getLength() - 4);
729 gIOHibernateBoot0082Data->appendBytes(fileData);
730 } else {
731 gIOHibernateBoot0082Data->appendBytes(data);
732 }
733 }
734 }
735 }
736 if (!gIOHibernateBootNextData) {
737 uint16_t bits = 0x0082;
738 gIOHibernateBootNextData = OSData::withBytes(&bits, sizeof(bits));
739 }
740
741 #if DEBUG || DEVELOPMENT
742 if (kIOLogHibernate & gIOKitDebug) {
743 IOKitKernelLogBuffer("H> bootnext:",
744 gIOHibernateBoot0082Data->getBytesNoCopy(), gIOHibernateBoot0082Data->getLength(), &kprintf);
745 }
746 #endif /* DEBUG || DEVELOPMENT */
747 if (gIOHibernateBoot0082Key && gIOHibernateBoot0082Data && gIOHibernateBootNextKey && gIOHibernateBootNextData) {
748 gIOHibernateBootNextSave = gIOOptionsEntry->copyProperty(gIOHibernateBootNextKey);
749 gIOOptionsEntry->setProperty(gIOHibernateBoot0082Key, gIOHibernateBoot0082Data);
750 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextData);
751 }
752 // BootNext
753 }
754 }
755 #endif /* !i386 && !x86_64 */
756 }while (false);
757
758 if (swapPinned) {
759 hibernate_pin_swap(FALSE);
760 }
761
762 IOLockLock(gFSLock);
763 if ((kIOReturnSuccess == err) && (kFSOpening != gFSState)) {
764 HIBLOG("hibernate file close due timeout\n");
765 err = kIOReturnTimeout;
766 }
767 if (kIOReturnSuccess == err) {
768 gFSState = kFSOpened;
769 gIOHibernateVars = *vars;
770 gFileVars = *vars->fileVars;
771 gFileVars.allocated = false;
772 gIOHibernateVars.fileVars = &gFileVars;
773 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderSignature;
774 gIOHibernateState = kIOHibernateStateHibernating;
775
776 #if DEBUG || DEVELOPMENT
777 if (kIOLogHibernate & gIOKitDebug) {
778 OSData * data = OSDynamicCast(OSData, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey));
779 if (data) {
780 uintptr_t * smcVars = (typeof(smcVars))data->getBytesNoCopy();
781 IOKitKernelLogBuffer("H> smc:",
782 (const void *)smcVars[1], smcVars[0], &kprintf);
783 }
784 }
785 #endif /* DEBUG || DEVELOPMENT */
786 } else {
787 IOPolledFileIOVars * fileVars = vars->fileVars;
788 IOHibernateDone(vars);
789 IOPolledFileClose(&fileVars,
790 #if DISABLE_TRIM
791 0, NULL, 0, 0, 0);
792 #else
793 0, NULL, 0, sizeof(IOHibernateImageHeader), setFileSize);
794 #endif
795 gFSState = kFSIdle;
796 }
797 IOLockUnlock(gFSLock);
798
799 if (vars->fileVars) {
800 IODelete(vars->fileVars, IOPolledFileIOVars, 1);
801 }
802 IODelete(vars, IOHibernateVars, 1);
803
804 return err;
805 }
806
807 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
808
809 static void
810 IOSetBootImageNVRAM(OSData * data)
811 {
812 IORegistryEntry * regEntry;
813
814 if (!gIOOptionsEntry) {
815 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
816 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
817 if (regEntry && !gIOOptionsEntry) {
818 regEntry->release();
819 }
820 }
821 if (gIOOptionsEntry && gIOHibernateBootImageKey) {
822 if (data) {
823 gIOOptionsEntry->setProperty(gIOHibernateBootImageKey, data);
824 #if DEBUG || DEVELOPMENT
825 if (kIOLogHibernate & gIOKitDebug) {
826 IOKitKernelLogBuffer("H> boot-image:",
827 data->getBytesNoCopy(), data->getLength(), &kprintf);
828 }
829 #endif /* DEBUG || DEVELOPMENT */
830 } else {
831 gIOOptionsEntry->removeProperty(gIOHibernateBootImageKey);
832 gIOOptionsEntry->sync();
833 }
834 }
835 }
836
837 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
838 /*
839 * Writes header to disk with signature, block size and file extents data.
840 * If there are more than 2 extents, then they are written on second block.
841 */
842 static IOReturn
843 IOWriteExtentsToFile(IOPolledFileIOVars * vars, uint32_t signature)
844 {
845 IOHibernateImageHeader hdr;
846 IOItemCount count;
847 IOReturn err = kIOReturnSuccess;
848 int rc;
849 IOPolledFileExtent * fileExtents;
850
851 fileExtents = (typeof(fileExtents))vars->fileExtents->getBytesNoCopy();
852
853 memset(&hdr, 0, sizeof(IOHibernateImageHeader));
854 count = vars->fileExtents->getLength();
855 if (count > sizeof(hdr.fileExtentMap)) {
856 hdr.fileExtentMapSize = count;
857 count = sizeof(hdr.fileExtentMap);
858 } else {
859 hdr.fileExtentMapSize = sizeof(hdr.fileExtentMap);
860 }
861
862 bcopy(fileExtents, &hdr.fileExtentMap[0], count);
863
864 // copy file block extent list if larger than header
865 if (hdr.fileExtentMapSize > sizeof(hdr.fileExtentMap)) {
866 count = hdr.fileExtentMapSize - sizeof(hdr.fileExtentMap);
867 rc = kern_write_file(vars->fileRef, vars->blockSize,
868 (caddr_t)(((uint8_t *)fileExtents) + sizeof(hdr.fileExtentMap)),
869 count, IO_SKIP_ENCRYPTION);
870 if (rc != 0) {
871 HIBLOG("kern_write_file returned %d\n", rc);
872 err = kIOReturnIOError;
873 goto exit;
874 }
875 }
876 hdr.signature = signature;
877 hdr.deviceBlockSize = vars->blockSize;
878
879 rc = kern_write_file(vars->fileRef, 0, (char *)&hdr, sizeof(hdr), IO_SKIP_ENCRYPTION);
880 if (rc != 0) {
881 HIBLOG("kern_write_file returned %d\n", rc);
882 err = kIOReturnIOError;
883 goto exit;
884 }
885
886 exit:
887 return err;
888 }
889
890 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
891
892 DECLARE_IOHIBERNATEPROGRESSALPHA
893
894 static void
895 ProgressInit(hibernate_graphics_t * display, uint8_t * screen, uint8_t * saveunder, uint32_t savelen)
896 {
897 uint32_t rowBytes, pixelShift;
898 uint32_t x, y;
899 int32_t blob;
900 uint32_t alpha, in, color, result;
901 uint8_t * out;
902 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
903
904 rowBytes = display->rowBytes;
905 pixelShift = display->depth >> 4;
906 if (pixelShift < 1) {
907 return;
908 }
909
910 screen += ((display->width
911 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
912 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
913
914 for (y = 0; y < kIOHibernateProgressHeight; y++) {
915 out = screen + y * rowBytes;
916 for (blob = 0; blob < kIOHibernateProgressCount; blob++) {
917 color = blob ? kIOHibernateProgressDarkGray : kIOHibernateProgressMidGray;
918 for (x = 0; x < kIOHibernateProgressWidth; x++) {
919 alpha = gIOHibernateProgressAlpha[y][x];
920 result = color;
921 if (alpha) {
922 if (0xff != alpha) {
923 if (1 == pixelShift) {
924 in = *((uint16_t *)out) & 0x1f; // 16
925 in = (in << 3) | (in >> 2);
926 } else {
927 in = *((uint32_t *)out) & 0xff; // 32
928 }
929 saveunder[blob * kIOHibernateProgressSaveUnderSize + saveindex[blob]++] = in;
930 result = ((255 - alpha) * in + alpha * result + 0xff) >> 8;
931 }
932 if (1 == pixelShift) {
933 result >>= 3;
934 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
935 } else {
936 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
937 }
938 }
939 out += (1 << pixelShift);
940 }
941 out += (kIOHibernateProgressSpacing << pixelShift);
942 }
943 }
944 }
945
946
947 static void
948 ProgressUpdate(hibernate_graphics_t * display, uint8_t * screen, int32_t firstBlob, int32_t select)
949 {
950 uint32_t rowBytes, pixelShift;
951 uint32_t x, y;
952 int32_t blob, lastBlob;
953 uint32_t alpha, in, color, result;
954 uint8_t * out;
955 uint32_t saveindex[kIOHibernateProgressCount] = { 0 };
956
957 pixelShift = display->depth >> 4;
958 if (pixelShift < 1) {
959 return;
960 }
961
962 rowBytes = display->rowBytes;
963
964 screen += ((display->width
965 - kIOHibernateProgressCount * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << (pixelShift - 1))
966 + (display->height - kIOHibernateProgressOriginY - kIOHibernateProgressHeight) * rowBytes;
967
968 lastBlob = (select < kIOHibernateProgressCount) ? select : (kIOHibernateProgressCount - 1);
969
970 screen += (firstBlob * (kIOHibernateProgressWidth + kIOHibernateProgressSpacing)) << pixelShift;
971
972 for (y = 0; y < kIOHibernateProgressHeight; y++) {
973 out = screen + y * rowBytes;
974 for (blob = firstBlob; blob <= lastBlob; blob++) {
975 color = (blob < select) ? kIOHibernateProgressLightGray : kIOHibernateProgressMidGray;
976 for (x = 0; x < kIOHibernateProgressWidth; x++) {
977 alpha = gIOHibernateProgressAlpha[y][x];
978 result = color;
979 if (alpha) {
980 if (0xff != alpha) {
981 in = display->progressSaveUnder[blob][saveindex[blob]++];
982 result = ((255 - alpha) * in + alpha * result + 0xff) / 255;
983 }
984 if (1 == pixelShift) {
985 result >>= 3;
986 *((uint16_t *)out) = (result << 10) | (result << 5) | result; // 16
987 } else {
988 *((uint32_t *)out) = (result << 16) | (result << 8) | result; // 32
989 }
990 }
991 out += (1 << pixelShift);
992 }
993 out += (kIOHibernateProgressSpacing << pixelShift);
994 }
995 }
996 }
997
998 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
999
1000 IOReturn
1001 IOHibernateIOKitSleep(void)
1002 {
1003 IOReturn ret = kIOReturnSuccess;
1004 IOLockLock(gFSLock);
1005 if (kFSOpening == gFSState) {
1006 gFSState = kFSTimedOut;
1007 HIBLOG("hibernate file open timed out\n");
1008 ret = kIOReturnTimeout;
1009 }
1010 IOLockUnlock(gFSLock);
1011 return ret;
1012 }
1013
1014 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1015
1016 IOReturn
1017 IOHibernateSystemHasSlept(void)
1018 {
1019 IOReturn ret = kIOReturnSuccess;
1020 IOHibernateVars * vars = &gIOHibernateVars;
1021 OSObject * obj = 0;
1022 OSData * data;
1023
1024 IOLockLock(gFSLock);
1025 if ((kFSOpened != gFSState) && gIOHibernateMode) {
1026 ret = kIOReturnTimeout;
1027 }
1028 IOLockUnlock(gFSLock);
1029 if (kIOReturnSuccess != ret) {
1030 return ret;
1031 }
1032
1033 if (gIOHibernateMode) {
1034 obj = IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey);
1035 }
1036 vars->previewBuffer = OSDynamicCast(IOMemoryDescriptor, obj);
1037 if (obj && !vars->previewBuffer) {
1038 obj->release();
1039 }
1040
1041 vars->consoleMapping = NULL;
1042 if (vars->previewBuffer && (kIOReturnSuccess != vars->previewBuffer->prepare())) {
1043 vars->previewBuffer->release();
1044 vars->previewBuffer = 0;
1045 }
1046
1047 if ((kIOHibernateOptionProgress & gIOHibernateCurrentHeader->options)
1048 && vars->previewBuffer
1049 && (data = OSDynamicCast(OSData,
1050 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey)))) {
1051 UInt32 flags = *((UInt32 *)data->getBytesNoCopy());
1052 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags);
1053
1054 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey);
1055
1056 if (kIOHibernatePreviewUpdates & flags) {
1057 PE_Video consoleInfo;
1058 hibernate_graphics_t * graphicsInfo = gIOHibernateGraphicsInfo;
1059
1060 IOService::getPlatform()->getConsoleInfo(&consoleInfo);
1061
1062 graphicsInfo->width = consoleInfo.v_width;
1063 graphicsInfo->height = consoleInfo.v_height;
1064 graphicsInfo->rowBytes = consoleInfo.v_rowBytes;
1065 graphicsInfo->depth = consoleInfo.v_depth;
1066 vars->consoleMapping = (uint8_t *) consoleInfo.v_baseAddr;
1067
1068 HIBPRINT("video %p %d %d %d\n",
1069 vars->consoleMapping, graphicsInfo->depth,
1070 graphicsInfo->width, graphicsInfo->height);
1071 if (vars->consoleMapping) {
1072 ProgressInit(graphicsInfo, vars->consoleMapping,
1073 &graphicsInfo->progressSaveUnder[0][0], sizeof(graphicsInfo->progressSaveUnder));
1074 }
1075 }
1076 }
1077
1078 if (gIOOptionsEntry) {
1079 gIOOptionsEntry->sync();
1080 }
1081
1082 return ret;
1083 }
1084
1085 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1086
1087 static DeviceTreeNode *
1088 MergeDeviceTree(DeviceTreeNode * entry, IORegistryEntry * regEntry)
1089 {
1090 DeviceTreeNodeProperty * prop;
1091 DeviceTreeNode * child;
1092 IORegistryEntry * childRegEntry;
1093 const char * nameProp;
1094 unsigned int propLen, idx;
1095
1096 prop = (DeviceTreeNodeProperty *) (entry + 1);
1097 for (idx = 0; idx < entry->nProperties; idx++) {
1098 if (regEntry && (0 != strcmp("name", prop->name))) {
1099 regEntry->setProperty((const char *) prop->name, (void *) (prop + 1), prop->length);
1100 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1101 }
1102 prop = (DeviceTreeNodeProperty *) (((uintptr_t)(prop + 1)) + ((prop->length + 3) & ~3));
1103 }
1104
1105 child = (DeviceTreeNode *) prop;
1106 for (idx = 0; idx < entry->nChildren; idx++) {
1107 if (kSuccess != DTGetProperty(child, "name", (void **) &nameProp, &propLen)) {
1108 panic("no name");
1109 }
1110 childRegEntry = regEntry ? regEntry->childFromPath(nameProp, gIODTPlane) : NULL;
1111 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1112 child = MergeDeviceTree(child, childRegEntry);
1113 }
1114 return child;
1115 }
1116
1117 IOReturn
1118 IOHibernateSystemWake(void)
1119 {
1120 if (kFSOpened == gFSState) {
1121 IOPolledFilePollersClose(gIOHibernateVars.fileVars, kIOPolledPostflightState);
1122 IOHibernateDone(&gIOHibernateVars);
1123 } else {
1124 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
1125 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
1126 }
1127 return kIOReturnSuccess;
1128 }
1129
1130 static IOReturn
1131 IOHibernateDone(IOHibernateVars * vars)
1132 {
1133 IOReturn err;
1134 OSData * data;
1135
1136 hibernate_teardown(vars->page_list, vars->page_list_wired, vars->page_list_pal);
1137
1138 if (vars->videoMapping) {
1139 if (vars->videoMapSize) {
1140 // remove mappings
1141 IOUnmapPages(kernel_map, vars->videoMapping, vars->videoMapSize);
1142 }
1143 if (vars->videoAllocSize) {
1144 // dealloc range
1145 kmem_free(kernel_map, trunc_page(vars->videoMapping), vars->videoAllocSize);
1146 }
1147 }
1148
1149 if (vars->previewBuffer) {
1150 vars->previewBuffer->release();
1151 vars->previewBuffer = 0;
1152 }
1153
1154 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
1155 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey,
1156 gIOHibernateCurrentHeader->options, 32);
1157 } else {
1158 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey);
1159 }
1160
1161 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState)
1162 && (kIOHibernateGfxStatusUnknown != gIOHibernateGraphicsInfo->gfxStatus)) {
1163 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey,
1164 &gIOHibernateGraphicsInfo->gfxStatus,
1165 sizeof(gIOHibernateGraphicsInfo->gfxStatus));
1166 } else {
1167 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey);
1168 }
1169
1170 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1171
1172 #if defined(__i386__) || defined(__x86_64__)
1173 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey);
1174 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey);
1175
1176 /*
1177 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1178 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1179 */
1180 if (gIOOptionsEntry) {
1181 if (gIOHibernateRTCVariablesKey) {
1182 if (gIOOptionsEntry->getProperty(gIOHibernateRTCVariablesKey)) {
1183 gIOOptionsEntry->removeProperty(gIOHibernateRTCVariablesKey);
1184 }
1185 }
1186
1187 if (gIOHibernateBootNextKey) {
1188 if (gIOHibernateBootNextSave) {
1189 gIOOptionsEntry->setProperty(gIOHibernateBootNextKey, gIOHibernateBootNextSave);
1190 gIOHibernateBootNextSave->release();
1191 gIOHibernateBootNextSave = NULL;
1192 } else {
1193 gIOOptionsEntry->removeProperty(gIOHibernateBootNextKey);
1194 }
1195 }
1196 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState) {
1197 gIOOptionsEntry->sync();
1198 }
1199 }
1200 #endif
1201
1202 if (vars->srcBuffer) {
1203 vars->srcBuffer->release();
1204 }
1205 bzero(&gIOHibernateHandoffPages[0], gIOHibernateHandoffPageCount * sizeof(gIOHibernateHandoffPages[0]));
1206 if (vars->handoffBuffer) {
1207 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
1208 IOHibernateHandoff * handoff;
1209 bool done = false;
1210 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
1211 !done;
1212 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount]) {
1213 HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
1214 uint8_t * data = &handoff->data[0];
1215 switch (handoff->type) {
1216 case kIOHibernateHandoffTypeEnd:
1217 done = true;
1218 break;
1219
1220 case kIOHibernateHandoffTypeDeviceTree:
1221 MergeDeviceTree((DeviceTreeNode *) data, IOService::getServiceRoot());
1222 break;
1223
1224 case kIOHibernateHandoffTypeKeyStore:
1225 #if defined(__i386__) || defined(__x86_64__)
1226 {
1227 IOBufferMemoryDescriptor *
1228 md = IOBufferMemoryDescriptor::withBytes(data, handoff->bytecount, kIODirectionOutIn);
1229 if (md) {
1230 IOSetKeyStoreData(md);
1231 }
1232 }
1233 #endif
1234 break;
1235
1236 default:
1237 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
1238 break;
1239 }
1240 }
1241 #if defined(__i386__) || defined(__x86_64__)
1242 if (vars->volumeCryptKeySize) {
1243 IOBufferMemoryDescriptor *
1244 bmd = IOBufferMemoryDescriptor::withBytes(&vars->volumeCryptKey[0],
1245 vars->volumeCryptKeySize, kIODirectionOutIn);
1246 if (!bmd) {
1247 panic("IOBufferMemoryDescriptor");
1248 }
1249 IOSetAPFSKeyStoreData(bmd);
1250 bzero(&vars->volumeCryptKey[0], sizeof(vars->volumeCryptKey));
1251 }
1252 #endif
1253 }
1254 vars->handoffBuffer->release();
1255 }
1256
1257 if (gIOChosenEntry
1258 && (data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(gIOBridgeBootSessionUUIDKey)))
1259 && (sizeof(gIOHibernateBridgeBootSessionUUIDString) <= data->getLength())) {
1260 bcopy(data->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString[0],
1261 sizeof(gIOHibernateBridgeBootSessionUUIDString));
1262 }
1263
1264 if (vars->hwEncrypt) {
1265 err = IOPolledFilePollersSetEncryptionKey(vars->fileVars, NULL, 0);
1266 HIBLOG("IOPolledFilePollersSetEncryptionKey(0,%x)\n", err);
1267 }
1268
1269 bzero(vars, sizeof(*vars));
1270
1271 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1272
1273 return kIOReturnSuccess;
1274 }
1275
1276 static void
1277 IOHibernateSystemPostWakeTrim(void * p1, void * p2)
1278 {
1279 // invalidate & close the image file
1280 if (p1) {
1281 IOLockLock(gFSLock);
1282 }
1283 if (kFSTrimDelay == gFSState) {
1284 IOPolledFileIOVars * vars = &gFileVars;
1285 IOPolledFileClose(&vars,
1286 #if DISABLE_TRIM
1287 0, NULL, 0, 0, 0);
1288 #else
1289 0, (caddr_t)gIOHibernateCurrentHeader, sizeof(IOHibernateImageHeader),
1290 sizeof(IOHibernateImageHeader), gIOHibernateCurrentHeader->imageSize);
1291 #endif
1292 gFSState = kFSIdle;
1293 }
1294 if (p1) {
1295 IOLockUnlock(gFSLock);
1296 }
1297 }
1298
1299 IOReturn
1300 IOHibernateSystemPostWake(bool now)
1301 {
1302 gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
1303 IOSetBootImageNVRAM(0);
1304
1305 IOLockLock(gFSLock);
1306 if (kFSTrimDelay == gFSState) {
1307 thread_call_cancel(gIOHibernateTrimCalloutEntry);
1308 IOHibernateSystemPostWakeTrim(NULL, NULL);
1309 } else if (kFSOpened != gFSState) {
1310 gFSState = kFSIdle;
1311 } else {
1312 gFSState = kFSTrimDelay;
1313 if (now) {
1314 thread_call_cancel(gIOHibernateTrimCalloutEntry);
1315 IOHibernateSystemPostWakeTrim(NULL, NULL);
1316 } else {
1317 AbsoluteTime deadline;
1318 clock_interval_to_deadline(TRIM_DELAY, kMillisecondScale, &deadline );
1319 thread_call_enter1_delayed(gIOHibernateTrimCalloutEntry, NULL, deadline);
1320 }
1321 }
1322 IOLockUnlock(gFSLock);
1323
1324 return kIOReturnSuccess;
1325 }
1326
1327 uint32_t
1328 IOHibernateWasScreenLocked(void)
1329 {
1330 uint32_t ret = 0;
1331 if ((kIOHibernateStateWakingFromHibernate == gIOHibernateState) && gIOChosenEntry) {
1332 OSData *
1333 data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(kIOScreenLockStateKey));
1334 if (data) {
1335 ret = ((uint32_t *)data->getBytesNoCopy())[0];
1336 gIOChosenEntry->setProperty(kIOBooterScreenLockStateKey, data);
1337 }
1338 } else {
1339 gIOChosenEntry->removeProperty(kIOBooterScreenLockStateKey);
1340 }
1341
1342 return ret;
1343 }
1344
1345 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1346
1347 SYSCTL_STRING(_kern, OID_AUTO, hibernatefile,
1348 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1349 gIOHibernateFilename, sizeof(gIOHibernateFilename), "");
1350 SYSCTL_STRING(_kern, OID_AUTO, bootsignature,
1351 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1352 gIOHibernateBootSignature, sizeof(gIOHibernateBootSignature), "");
1353 SYSCTL_UINT(_kern, OID_AUTO, hibernatemode,
1354 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1355 &gIOHibernateMode, 0, "");
1356 SYSCTL_STRUCT(_kern, OID_AUTO, hibernatestatistics,
1357 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1358 &_hibernateStats, hibernate_statistics_t, "");
1359 SYSCTL_STRING(_kern_bridge, OID_AUTO, bootsessionuuid,
1360 CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1361 gIOHibernateBridgeBootSessionUUIDString, sizeof(gIOHibernateBridgeBootSessionUUIDString), "");
1362
1363 SYSCTL_UINT(_kern, OID_AUTO, hibernategraphicsready,
1364 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1365 &_hibernateStats.graphicsReadyTime, 0, "");
1366 SYSCTL_UINT(_kern, OID_AUTO, hibernatewakenotification,
1367 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1368 &_hibernateStats.wakeNotificationTime, 0, "");
1369 SYSCTL_UINT(_kern, OID_AUTO, hibernatelockscreenready,
1370 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1371 &_hibernateStats.lockScreenReadyTime, 0, "");
1372 SYSCTL_UINT(_kern, OID_AUTO, hibernatehidready,
1373 CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_ANYBODY,
1374 &_hibernateStats.hidReadyTime, 0, "");
1375
1376 void
1377 IOHibernateSystemInit(IOPMrootDomain * rootDomain)
1378 {
1379 gIOHibernateBootImageKey = OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey);
1380 gIOHibernateBootSignatureKey = OSSymbol::withCStringNoCopy(kIOHibernateBootSignatureKey);
1381 gIOBridgeBootSessionUUIDKey = OSSymbol::withCStringNoCopy(kIOBridgeBootSessionUUIDKey);
1382
1383 #if defined(__i386__) || defined(__x86_64__)
1384 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1385 gIOHibernateBoot0082Key = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1386 gIOHibernateBootNextKey = OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1387 gIOHibernateRTCVariablesKey = OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey);
1388 #endif /* defined(__i386__) || defined(__x86_64__) */
1389
1390 OSData * data = OSData::withBytesNoCopy(&gIOHibernateState, sizeof(gIOHibernateState));
1391 if (data) {
1392 rootDomain->setProperty(kIOHibernateStateKey, data);
1393 data->release();
1394 }
1395
1396 if (PE_parse_boot_argn("hfile", gIOHibernateFilename, sizeof(gIOHibernateFilename))) {
1397 gIOHibernateMode = kIOHibernateModeOn;
1398 } else {
1399 gIOHibernateFilename[0] = 0;
1400 }
1401
1402 sysctl_register_oid(&sysctl__kern_hibernatefile);
1403 sysctl_register_oid(&sysctl__kern_bootsignature);
1404 sysctl_register_oid(&sysctl__kern_hibernatemode);
1405 sysctl_register_oid(&sysctl__kern_hibernatestatistics);
1406 sysctl_register_oid(&sysctl__kern_hibernategraphicsready);
1407 sysctl_register_oid(&sysctl__kern_hibernatewakenotification);
1408 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready);
1409 sysctl_register_oid(&sysctl__kern_hibernatehidready);
1410
1411 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
1412
1413 if (gIOChosenEntry
1414 && (data = OSDynamicCast(OSData, gIOChosenEntry->getProperty(gIOBridgeBootSessionUUIDKey)))
1415 && (sizeof(gIOHibernateBridgeBootSessionUUIDString) <= data->getLength())) {
1416 sysctl_register_oid(&sysctl__kern_bridge_bootsessionuuid);
1417 bcopy(data->getBytesNoCopy(), &gIOHibernateBridgeBootSessionUUIDString[0], sizeof(gIOHibernateBridgeBootSessionUUIDString));
1418 }
1419
1420 gFSLock = IOLockAlloc();
1421 }
1422
1423 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1424
1425 static IOReturn
1426 IOHibernatePolledFileWrite(IOPolledFileIOVars * vars,
1427 const uint8_t * bytes, IOByteCount size,
1428 IOPolledFileCryptVars * cryptvars)
1429 {
1430 IOReturn err;
1431
1432 err = IOPolledFileWrite(vars, bytes, size, cryptvars);
1433 if ((kIOReturnSuccess == err) && hibernate_should_abort()) {
1434 err = kIOReturnAborted;
1435 }
1436
1437 return err;
1438 }
1439
1440 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1441
1442 extern "C" uint32_t
1443 hibernate_write_image(void)
1444 {
1445 IOHibernateImageHeader * header = gIOHibernateCurrentHeader;
1446 IOHibernateVars * vars = &gIOHibernateVars;
1447 IOPolledFileExtent * fileExtents;
1448
1449 _static_assert_1_arg(sizeof(IOHibernateImageHeader) == 512);
1450
1451 uint32_t pageCount, pagesDone;
1452 IOReturn err;
1453 vm_offset_t ppnum, page;
1454 IOItemCount count;
1455 uint8_t * src;
1456 uint8_t * data;
1457 uint8_t * compressed;
1458 uint8_t * scratch;
1459 IOByteCount pageCompressedSize;
1460 uint64_t compressedSize, uncompressedSize;
1461 uint64_t image1Size = 0;
1462 uint32_t bitmap_size;
1463 bool iterDone, pollerOpen, needEncrypt;
1464 uint32_t restore1Sum, sum, sum1, sum2;
1465 int wkresult;
1466 uint32_t tag;
1467 uint32_t pageType;
1468 uint32_t pageAndCount[2];
1469 addr64_t phys64;
1470 IOByteCount segLen;
1471 uintptr_t hibernateBase;
1472 uintptr_t hibernateEnd;
1473
1474 AbsoluteTime startTime, endTime;
1475 AbsoluteTime allTime, compTime;
1476 uint64_t compBytes;
1477 uint64_t nsec;
1478 uint32_t lastProgressStamp = 0;
1479 uint32_t progressStamp;
1480 uint32_t blob, lastBlob = (uint32_t) -1L;
1481
1482 uint32_t wiredPagesEncrypted;
1483 uint32_t dirtyPagesEncrypted;
1484 uint32_t wiredPagesClear;
1485 uint32_t svPageCount;
1486 uint32_t zvPageCount;
1487
1488 IOPolledFileCryptVars _cryptvars;
1489 IOPolledFileCryptVars * cryptvars = 0;
1490
1491 wiredPagesEncrypted = 0;
1492 dirtyPagesEncrypted = 0;
1493 wiredPagesClear = 0;
1494 svPageCount = 0;
1495 zvPageCount = 0;
1496
1497 if (!vars->fileVars
1498 || !vars->fileVars->pollers
1499 || !(kIOHibernateModeOn & gIOHibernateMode)) {
1500 return kIOHibernatePostWriteSleep;
1501 }
1502
1503 if (kIOHibernateModeSleep & gIOHibernateMode) {
1504 kdebug_enable = save_kdebug_enable;
1505 }
1506
1507 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_START);
1508 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate);
1509
1510 restore1Sum = sum1 = sum2 = 0;
1511
1512 #if CRYPTO
1513 // encryption data. "iv" is the "initial vector".
1514 if (kIOHibernateModeEncrypt & gIOHibernateMode) {
1515 static const unsigned char first_iv[AES_BLOCK_SIZE]
1516 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1517 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1518
1519 cryptvars = &gIOHibernateCryptWakeContext;
1520 bzero(cryptvars, sizeof(IOPolledFileCryptVars));
1521 aes_encrypt_key(vars->cryptKey,
1522 kIOHibernateAESKeySize,
1523 &cryptvars->ctx.encrypt);
1524 aes_decrypt_key(vars->cryptKey,
1525 kIOHibernateAESKeySize,
1526 &cryptvars->ctx.decrypt);
1527
1528 cryptvars = &_cryptvars;
1529 bzero(cryptvars, sizeof(IOPolledFileCryptVars));
1530 for (pageCount = 0; pageCount < sizeof(vars->wiredCryptKey); pageCount++) {
1531 vars->wiredCryptKey[pageCount] ^= vars->volumeCryptKey[pageCount];
1532 }
1533 aes_encrypt_key(vars->wiredCryptKey,
1534 kIOHibernateAESKeySize,
1535 &cryptvars->ctx.encrypt);
1536
1537 bcopy(&first_iv[0], &cryptvars->aes_iv[0], AES_BLOCK_SIZE);
1538 bzero(&vars->wiredCryptKey[0], sizeof(vars->wiredCryptKey));
1539 bzero(&vars->cryptKey[0], sizeof(vars->cryptKey));
1540 }
1541 #endif /* CRYPTO */
1542
1543 hibernate_page_list_setall(vars->page_list,
1544 vars->page_list_wired,
1545 vars->page_list_pal,
1546 false /* !preflight */,
1547 /* discard_all */
1548 ((0 == (kIOHibernateModeSleep & gIOHibernateMode))
1549 && (0 != ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode))),
1550 &pageCount);
1551
1552 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount);
1553
1554 fileExtents = (IOPolledFileExtent *) vars->fileVars->fileExtents->getBytesNoCopy();
1555
1556 #if 0
1557 count = vars->fileExtents->getLength() / sizeof(IOPolledFileExtent);
1558 for (page = 0; page < count; page++) {
1559 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page,
1560 fileExtents[page].start, fileExtents[page].length,
1561 fileExtents[page].start + fileExtents[page].length);
1562 }
1563 #endif
1564
1565 needEncrypt = (0 != (kIOHibernateModeEncrypt & gIOHibernateMode));
1566 AbsoluteTime_to_scalar(&compTime) = 0;
1567 compBytes = 0;
1568
1569 clock_get_uptime(&allTime);
1570 IOService::getPMRootDomain()->pmStatsRecordEvent(
1571 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStartFlag, allTime);
1572 do{
1573 compressedSize = 0;
1574 uncompressedSize = 0;
1575 svPageCount = 0;
1576 zvPageCount = 0;
1577
1578 IOPolledFileSeek(vars->fileVars, vars->fileVars->blockSize);
1579
1580 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1581 ml_get_interrupts_enabled());
1582 err = IOPolledFilePollersOpen(vars->fileVars, kIOPolledBeforeSleepState,
1583 // abortable if not low battery
1584 !IOService::getPMRootDomain()->mustHibernate());
1585 HIBLOG("IOHibernatePollerOpen(%x)\n", err);
1586 pollerOpen = (kIOReturnSuccess == err);
1587 if (!pollerOpen) {
1588 break;
1589 }
1590
1591 if (vars->volumeCryptKeySize) {
1592 err = IOPolledFilePollersSetEncryptionKey(vars->fileVars, &vars->volumeCryptKey[0], vars->volumeCryptKeySize);
1593 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x)\n", err);
1594 vars->hwEncrypt = (kIOReturnSuccess == err);
1595 bzero(&vars->volumeCryptKey[0], sizeof(vars->volumeCryptKey));
1596 if (vars->hwEncrypt) {
1597 header->options |= kIOHibernateOptionHWEncrypt;
1598 }
1599 }
1600
1601 // copy file block extent list if larger than header
1602
1603 count = vars->fileVars->fileExtents->getLength();
1604 if (count > sizeof(header->fileExtentMap)) {
1605 count -= sizeof(header->fileExtentMap);
1606 err = IOHibernatePolledFileWrite(vars->fileVars,
1607 ((uint8_t *) &fileExtents[0]) + sizeof(header->fileExtentMap), count, cryptvars);
1608 if (kIOReturnSuccess != err) {
1609 break;
1610 }
1611 }
1612
1613 hibernateBase = HIB_BASE; /* Defined in PAL headers */
1614 hibernateEnd = (segHIBB + segSizeHIB);
1615
1616 // copy out restore1 code
1617
1618 for (count = 0;
1619 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
1620 count += segLen) {
1621 for (pagesDone = 0; pagesDone < atop_32(segLen); pagesDone++) {
1622 gIOHibernateHandoffPages[atop_32(count) + pagesDone] = atop_64(phys64) + pagesDone;
1623 }
1624 }
1625
1626 page = atop_32(kvtophys(hibernateBase));
1627 count = atop_32(round_page(hibernateEnd) - hibernateBase);
1628 header->restore1CodePhysPage = page;
1629 header->restore1CodeVirt = hibernateBase;
1630 header->restore1PageCount = count;
1631 header->restore1CodeOffset = ((uintptr_t) &hibernate_machine_entrypoint) - hibernateBase;
1632 header->restore1StackOffset = ((uintptr_t) &gIOHibernateRestoreStackEnd[0]) - 64 - hibernateBase;
1633
1634 if (uuid_parse(&gIOHibernateBridgeBootSessionUUIDString[0], &header->bridgeBootSessionUUID[0])) {
1635 bzero(&header->bridgeBootSessionUUID[0], sizeof(header->bridgeBootSessionUUID));
1636 }
1637
1638 // sum __HIB seg, with zeros for the stack
1639 src = (uint8_t *) trunc_page(hibernateBase);
1640 for (page = 0; page < count; page++) {
1641 if ((src < &gIOHibernateRestoreStack[0]) || (src >= &gIOHibernateRestoreStackEnd[0])) {
1642 restore1Sum += hibernate_sum_page(src, header->restore1CodeVirt + page);
1643 } else {
1644 restore1Sum += 0x00000000;
1645 }
1646 src += page_size;
1647 }
1648 sum1 = restore1Sum;
1649
1650 // write the __HIB seg, with zeros for the stack
1651
1652 src = (uint8_t *) trunc_page(hibernateBase);
1653 count = ((uintptr_t) &gIOHibernateRestoreStack[0]) - trunc_page(hibernateBase);
1654 if (count) {
1655 err = IOHibernatePolledFileWrite(vars->fileVars, src, count, cryptvars);
1656 if (kIOReturnSuccess != err) {
1657 break;
1658 }
1659 }
1660 err = IOHibernatePolledFileWrite(vars->fileVars,
1661 (uint8_t *) 0,
1662 &gIOHibernateRestoreStackEnd[0] - &gIOHibernateRestoreStack[0],
1663 cryptvars);
1664 if (kIOReturnSuccess != err) {
1665 break;
1666 }
1667 src = &gIOHibernateRestoreStackEnd[0];
1668 count = round_page(hibernateEnd) - ((uintptr_t) src);
1669 if (count) {
1670 err = IOHibernatePolledFileWrite(vars->fileVars, src, count, cryptvars);
1671 if (kIOReturnSuccess != err) {
1672 break;
1673 }
1674 }
1675
1676 if (!vars->hwEncrypt && (kIOHibernateModeEncrypt & gIOHibernateMode)) {
1677 vars->fileVars->encryptStart = (vars->fileVars->position & ~(AES_BLOCK_SIZE - 1));
1678 vars->fileVars->encryptEnd = UINT64_MAX;
1679 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
1680 }
1681
1682 // write the preview buffer
1683
1684 if (vars->previewBuffer) {
1685 ppnum = 0;
1686 count = 0;
1687 do{
1688 phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone);
1689 pageAndCount[0] = atop_64(phys64);
1690 pageAndCount[1] = atop_32(segLen);
1691 err = IOHibernatePolledFileWrite(vars->fileVars,
1692 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
1693 cryptvars);
1694 if (kIOReturnSuccess != err) {
1695 break;
1696 }
1697 count += segLen;
1698 ppnum += sizeof(pageAndCount);
1699 }while (phys64);
1700 if (kIOReturnSuccess != err) {
1701 break;
1702 }
1703
1704 src = (uint8_t *) vars->previewBuffer->getPhysicalSegment(0, NULL, _kIOMemorySourceSegment);
1705
1706 ((hibernate_preview_t *)src)->lockTime = gIOConsoleLockTime;
1707
1708 count = vars->previewBuffer->getLength();
1709
1710 header->previewPageListSize = ppnum;
1711 header->previewSize = count + ppnum;
1712
1713 for (page = 0; page < count; page += page_size) {
1714 phys64 = vars->previewBuffer->getPhysicalSegment(page, NULL, kIOMemoryMapperNone);
1715 sum1 += hibernate_sum_page(src + page, atop_64(phys64));
1716 }
1717 err = IOHibernatePolledFileWrite(vars->fileVars, src, count, cryptvars);
1718 if (kIOReturnSuccess != err) {
1719 break;
1720 }
1721 }
1722
1723 // mark areas for no save
1724 IOMemoryDescriptor * ioBuffer;
1725 ioBuffer = IOPolledFileGetIOBuffer(vars->fileVars);
1726 for (count = 0;
1727 (phys64 = ioBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
1728 count += segLen) {
1729 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1730 atop_64(phys64), atop_32(segLen),
1731 kIOHibernatePageStateFree);
1732 pageCount -= atop_32(segLen);
1733 }
1734
1735 for (count = 0;
1736 (phys64 = vars->srcBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
1737 count += segLen) {
1738 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1739 atop_64(phys64), atop_32(segLen),
1740 kIOHibernatePageStateFree);
1741 pageCount -= atop_32(segLen);
1742 }
1743
1744 // copy out bitmap of pages available for trashing during restore
1745
1746 bitmap_size = vars->page_list_wired->list_size;
1747 src = (uint8_t *) vars->page_list_wired;
1748 err = IOHibernatePolledFileWrite(vars->fileVars, src, bitmap_size, cryptvars);
1749 if (kIOReturnSuccess != err) {
1750 break;
1751 }
1752
1753 // mark more areas for no save, but these are not available
1754 // for trashing during restore
1755
1756 hibernate_page_list_set_volatile(vars->page_list, vars->page_list_wired, &pageCount);
1757
1758
1759 page = atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase));
1760 count = atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd))) - page;
1761 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1762 page, count,
1763 kIOHibernatePageStateFree);
1764 pageCount -= count;
1765
1766 if (vars->previewBuffer) {
1767 for (count = 0;
1768 (phys64 = vars->previewBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
1769 count += segLen) {
1770 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1771 atop_64(phys64), atop_32(segLen),
1772 kIOHibernatePageStateFree);
1773 pageCount -= atop_32(segLen);
1774 }
1775 }
1776
1777 for (count = 0;
1778 (phys64 = vars->handoffBuffer->getPhysicalSegment(count, &segLen, kIOMemoryMapperNone));
1779 count += segLen) {
1780 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1781 atop_64(phys64), atop_32(segLen),
1782 kIOHibernatePageStateFree);
1783 pageCount -= atop_32(segLen);
1784 }
1785
1786 #if KASAN
1787 vm_size_t shadow_pages_free = atop_64(shadow_ptop) - atop_64(shadow_pnext);
1788
1789 /* no need to save unused shadow pages */
1790 hibernate_set_page_state(vars->page_list, vars->page_list_wired,
1791 atop_64(shadow_pnext),
1792 shadow_pages_free,
1793 kIOHibernatePageStateFree);
1794 #endif
1795
1796 src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
1797 compressed = src + page_size;
1798 scratch = compressed + page_size;
1799
1800 pagesDone = 0;
1801 lastBlob = 0;
1802
1803 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
1804 bitmap_size, header->previewSize,
1805 pageCount, vars->fileVars->position);
1806
1807 enum
1808 // pageType
1809 {
1810 kWired = 0x02,
1811 kEncrypt = 0x01,
1812 kWiredEncrypt = kWired | kEncrypt,
1813 kWiredClear = kWired,
1814 kUnwiredEncrypt = kEncrypt
1815 };
1816
1817 bool cpuAES = (0 != (CPUID_FEATURE_AES & cpuid_features()));
1818
1819 for (pageType = kWiredEncrypt; pageType >= kUnwiredEncrypt; pageType--) {
1820 if (kUnwiredEncrypt == pageType) {
1821 // start unwired image
1822 if (!vars->hwEncrypt && (kIOHibernateModeEncrypt & gIOHibernateMode)) {
1823 vars->fileVars->encryptStart = (vars->fileVars->position & ~(((uint64_t)AES_BLOCK_SIZE) - 1));
1824 vars->fileVars->encryptEnd = UINT64_MAX;
1825 HIBLOG("encryptStart %qx\n", vars->fileVars->encryptStart);
1826 }
1827 bcopy(&cryptvars->aes_iv[0],
1828 &gIOHibernateCryptWakeContext.aes_iv[0],
1829 sizeof(cryptvars->aes_iv));
1830 cryptvars = &gIOHibernateCryptWakeContext;
1831 }
1832 for (iterDone = false, ppnum = 0; !iterDone;) {
1833 if (cpuAES && (pageType == kWiredClear)) {
1834 count = 0;
1835 } else {
1836 count = hibernate_page_list_iterate((kWired & pageType) ? vars->page_list_wired : vars->page_list,
1837 &ppnum);
1838 }
1839 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1840 iterDone = !count;
1841
1842 if (!cpuAES) {
1843 if (count && (kWired & pageType) && needEncrypt) {
1844 uint32_t checkIndex;
1845 for (checkIndex = 0;
1846 (checkIndex < count)
1847 && (((kEncrypt & pageType) == 0) == pmap_is_noencrypt(ppnum + checkIndex));
1848 checkIndex++) {
1849 }
1850 if (!checkIndex) {
1851 ppnum++;
1852 continue;
1853 }
1854 count = checkIndex;
1855 }
1856 }
1857
1858 switch (pageType) {
1859 case kWiredEncrypt: wiredPagesEncrypted += count; break;
1860 case kWiredClear: wiredPagesClear += count; break;
1861 case kUnwiredEncrypt: dirtyPagesEncrypted += count; break;
1862 }
1863
1864 if (iterDone && (kWiredEncrypt == pageType)) {/* not yet end of wired list */
1865 } else {
1866 pageAndCount[0] = ppnum;
1867 pageAndCount[1] = count;
1868 err = IOHibernatePolledFileWrite(vars->fileVars,
1869 (const uint8_t *) &pageAndCount, sizeof(pageAndCount),
1870 cryptvars);
1871 if (kIOReturnSuccess != err) {
1872 break;
1873 }
1874 }
1875
1876 for (page = ppnum; page < (ppnum + count); page++) {
1877 err = IOMemoryDescriptorWriteFromPhysical(vars->srcBuffer, 0, ptoa_64(page), page_size);
1878 if (err) {
1879 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__, (long)page, err);
1880 break;
1881 }
1882
1883 sum = hibernate_sum_page(src, page);
1884 if (kWired & pageType) {
1885 sum1 += sum;
1886 } else {
1887 sum2 += sum;
1888 }
1889
1890 clock_get_uptime(&startTime);
1891 wkresult = WKdm_compress_new((const WK_word*) src,
1892 (WK_word*) compressed,
1893 (WK_word*) scratch,
1894 page_size - 4);
1895
1896 clock_get_uptime(&endTime);
1897 ADD_ABSOLUTETIME(&compTime, &endTime);
1898 SUB_ABSOLUTETIME(&compTime, &startTime);
1899
1900 compBytes += page_size;
1901 pageCompressedSize = (-1 == wkresult) ? page_size : wkresult;
1902
1903 if (pageCompressedSize == 0) {
1904 pageCompressedSize = 4;
1905 data = src;
1906
1907 if (*(uint32_t *)src) {
1908 svPageCount++;
1909 } else {
1910 zvPageCount++;
1911 }
1912 } else {
1913 if (pageCompressedSize != page_size) {
1914 data = compressed;
1915 } else {
1916 data = src;
1917 }
1918 }
1919
1920 tag = pageCompressedSize | kIOHibernateTagSignature;
1921 err = IOHibernatePolledFileWrite(vars->fileVars, (const uint8_t *) &tag, sizeof(tag), cryptvars);
1922 if (kIOReturnSuccess != err) {
1923 break;
1924 }
1925
1926 err = IOHibernatePolledFileWrite(vars->fileVars, data, (pageCompressedSize + 3) & ~3, cryptvars);
1927 if (kIOReturnSuccess != err) {
1928 break;
1929 }
1930
1931 compressedSize += pageCompressedSize;
1932 uncompressedSize += page_size;
1933 pagesDone++;
1934
1935 if (vars->consoleMapping && (0 == (1023 & pagesDone))) {
1936 blob = ((pagesDone * kIOHibernateProgressCount) / pageCount);
1937 if (blob != lastBlob) {
1938 ProgressUpdate(gIOHibernateGraphicsInfo, vars->consoleMapping, lastBlob, blob);
1939 lastBlob = blob;
1940 }
1941 }
1942 if (0 == (8191 & pagesDone)) {
1943 clock_get_uptime(&endTime);
1944 SUB_ABSOLUTETIME(&endTime, &allTime);
1945 absolutetime_to_nanoseconds(endTime, &nsec);
1946 progressStamp = nsec / 750000000ULL;
1947 if (progressStamp != lastProgressStamp) {
1948 lastProgressStamp = progressStamp;
1949 HIBPRINT("pages %d (%d%%)\n", pagesDone, (100 * pagesDone) / pageCount);
1950 }
1951 }
1952 }
1953 if (kIOReturnSuccess != err) {
1954 break;
1955 }
1956 ppnum = page;
1957 }
1958
1959 if (kIOReturnSuccess != err) {
1960 break;
1961 }
1962
1963 if ((kEncrypt & pageType) && vars->fileVars->encryptStart) {
1964 vars->fileVars->encryptEnd = ((vars->fileVars->position + 511) & ~511ULL);
1965 HIBLOG("encryptEnd %qx\n", vars->fileVars->encryptEnd);
1966 }
1967
1968 if (kWiredEncrypt != pageType) {
1969 // end of image1/2 - fill to next block
1970 err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0, cryptvars);
1971 if (kIOReturnSuccess != err) {
1972 break;
1973 }
1974 }
1975 if (kWiredClear == pageType) {
1976 // enlarge wired image for test
1977 // err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
1978
1979 // end wired image
1980 header->encryptStart = vars->fileVars->encryptStart;
1981 header->encryptEnd = vars->fileVars->encryptEnd;
1982 image1Size = vars->fileVars->position;
1983 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
1984 image1Size, header->encryptStart, header->encryptEnd);
1985 }
1986 }
1987 if (kIOReturnSuccess != err) {
1988 if (kIOReturnOverrun == err) {
1989 // update actual compression ratio on not enough space (for retry)
1990 gIOHibernateCompression = (compressedSize << 8) / uncompressedSize;
1991 }
1992
1993 // update partial amount written (for IOPolledFileClose cleanup/unmap)
1994 header->imageSize = vars->fileVars->position;
1995 break;
1996 }
1997
1998 // Header:
1999
2000 header->imageSize = vars->fileVars->position;
2001 header->image1Size = image1Size;
2002 header->bitmapSize = bitmap_size;
2003 header->pageCount = pageCount;
2004
2005 header->restore1Sum = restore1Sum;
2006 header->image1Sum = sum1;
2007 header->image2Sum = sum2;
2008 header->sleepTime = gIOLastSleepTime.tv_sec;
2009
2010 header->compression = (compressedSize << 8) / uncompressedSize;
2011 gIOHibernateCompression = header->compression;
2012
2013 count = vars->fileVars->fileExtents->getLength();
2014 if (count > sizeof(header->fileExtentMap)) {
2015 header->fileExtentMapSize = count;
2016 count = sizeof(header->fileExtentMap);
2017 } else {
2018 header->fileExtentMapSize = sizeof(header->fileExtentMap);
2019 }
2020 bcopy(&fileExtents[0], &header->fileExtentMap[0], count);
2021
2022 header->deviceBase = vars->fileVars->block0;
2023 header->deviceBlockSize = vars->fileVars->blockSize;
2024
2025 IOPolledFileSeek(vars->fileVars, 0);
2026 err = IOHibernatePolledFileWrite(vars->fileVars,
2027 (uint8_t *) header, sizeof(IOHibernateImageHeader),
2028 cryptvars);
2029 if (kIOReturnSuccess != err) {
2030 break;
2031 }
2032 err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0, cryptvars);
2033 }while (false);
2034
2035 clock_get_uptime(&endTime);
2036
2037 IOService::getPMRootDomain()->pmStatsRecordEvent(
2038 kIOPMStatsHibernateImageWrite | kIOPMStatsEventStopFlag, endTime);
2039
2040 SUB_ABSOLUTETIME(&endTime, &allTime);
2041 absolutetime_to_nanoseconds(endTime, &nsec);
2042 HIBLOG("all time: %qd ms, ", nsec / 1000000ULL);
2043
2044 absolutetime_to_nanoseconds(compTime, &nsec);
2045 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2046 compBytes,
2047 nsec / 1000000ULL,
2048 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2049
2050 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2051 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2052 vars->fileVars->cryptBytes,
2053 nsec / 1000000ULL,
2054 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2055
2056 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2057 header->imageSize, (header->imageSize * 100) / vars->fileVars->fileSize,
2058 uncompressedSize, atop_32(uncompressedSize), compressedSize,
2059 uncompressedSize ? ((int) ((compressedSize * 100ULL) / uncompressedSize)) : 0,
2060 sum1, sum2);
2061
2062 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2063 svPageCount, zvPageCount, wiredPagesEncrypted, wiredPagesClear, dirtyPagesEncrypted);
2064
2065 if (pollerOpen) {
2066 IOPolledFilePollersClose(vars->fileVars, (kIOReturnSuccess == err) ? kIOPolledBeforeSleepState : kIOPolledBeforeSleepStateAborted );
2067 }
2068
2069 if (vars->consoleMapping) {
2070 ProgressUpdate(gIOHibernateGraphicsInfo,
2071 vars->consoleMapping, 0, kIOHibernateProgressCount);
2072 }
2073
2074 HIBLOG("hibernate_write_image done(%x)\n", err);
2075
2076 // should we come back via regular wake, set the state in memory.
2077 gIOHibernateState = kIOHibernateStateInactive;
2078
2079 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 1) | DBG_FUNC_END, wiredPagesEncrypted,
2080 wiredPagesClear, dirtyPagesEncrypted);
2081
2082 if (kIOReturnSuccess == err) {
2083 if (kIOHibernateModeSleep & gIOHibernateMode) {
2084 return kIOHibernatePostWriteSleep;
2085 } else if (kIOHibernateModeRestart & gIOHibernateMode) {
2086 return kIOHibernatePostWriteRestart;
2087 } else {
2088 /* by default, power down */
2089 return kIOHibernatePostWriteHalt;
2090 }
2091 } else if (kIOReturnAborted == err) {
2092 return kIOHibernatePostWriteWake;
2093 } else {
2094 /* on error, sleep */
2095 return kIOHibernatePostWriteSleep;
2096 }
2097 }
2098
2099 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2100
2101 extern "C" void
2102 hibernate_machine_init(void)
2103 {
2104 IOReturn err;
2105 uint32_t sum;
2106 uint32_t pagesDone;
2107 uint32_t pagesRead = 0;
2108 AbsoluteTime startTime, compTime;
2109 AbsoluteTime allTime, endTime;
2110 AbsoluteTime startIOTime, endIOTime;
2111 uint64_t nsec, nsecIO;
2112 uint64_t compBytes;
2113 uint32_t lastProgressStamp = 0;
2114 uint32_t progressStamp;
2115 IOPolledFileCryptVars * cryptvars = 0;
2116
2117 IOHibernateVars * vars = &gIOHibernateVars;
2118 bzero(gIOHibernateStats, sizeof(hibernate_statistics_t));
2119
2120 if (!vars->fileVars || !vars->fileVars->pollers) {
2121 return;
2122 }
2123
2124 sum = gIOHibernateCurrentHeader->actualImage1Sum;
2125 pagesDone = gIOHibernateCurrentHeader->actualUncompressedPages;
2126
2127 if (kIOHibernateStateWakingFromHibernate != gIOHibernateState) {
2128 HIBLOG("regular wake\n");
2129 return;
2130 }
2131
2132 HIBPRINT("diag %x %x %x %x\n",
2133 gIOHibernateCurrentHeader->diag[0], gIOHibernateCurrentHeader->diag[1],
2134 gIOHibernateCurrentHeader->diag[2], gIOHibernateCurrentHeader->diag[3]);
2135
2136 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
2137 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2138 tStat(booterStart, booterStart);
2139 gIOHibernateStats->smcStart = gIOHibernateCurrentHeader->smcStart;
2140 tStat(booterDuration0, booterTime0);
2141 tStat(booterDuration1, booterTime1);
2142 tStat(booterDuration2, booterTime2);
2143 tStat(booterDuration, booterTime);
2144 tStat(booterConnectDisplayDuration, connectDisplayTime);
2145 tStat(booterSplashDuration, splashTime);
2146 tStat(trampolineDuration, trampolineTime);
2147
2148 gIOHibernateStats->image1Size = gIOHibernateCurrentHeader->image1Size;
2149 gIOHibernateStats->imageSize = gIOHibernateCurrentHeader->imageSize;
2150 gIOHibernateStats->image1Pages = pagesDone;
2151
2152 /* HIBERNATE_stats */
2153 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 14), gIOHibernateStats->smcStart,
2154 gIOHibernateStats->booterStart, gIOHibernateStats->booterDuration,
2155 gIOHibernateStats->trampolineDuration);
2156
2157 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2158 gIOHibernateStats->booterStart,
2159 gIOHibernateStats->smcStart,
2160 gIOHibernateStats->booterDuration0,
2161 gIOHibernateStats->booterDuration1,
2162 gIOHibernateStats->booterDuration2,
2163 gIOHibernateStats->booterDuration,
2164 gIOHibernateStats->booterConnectDisplayDuration,
2165 gIOHibernateStats->booterSplashDuration,
2166 gIOHibernateStats->trampolineDuration);
2167
2168 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2169 gIOHibernateState, pagesDone, sum, gIOHibernateStats->imageSize, gIOHibernateStats->image1Size,
2170 gIOHibernateCurrentHeader->conflictCount, gIOHibernateCurrentHeader->nextFree);
2171
2172 if ((0 != (kIOHibernateModeSleep & gIOHibernateMode))
2173 && (0 != ((kIOHibernateModeDiscardCleanActive | kIOHibernateModeDiscardCleanInactive) & gIOHibernateMode))) {
2174 hibernate_page_list_discard(vars->page_list);
2175 }
2176
2177 cryptvars = (kIOHibernateModeEncrypt & gIOHibernateMode) ? &gIOHibernateCryptWakeContext : 0;
2178
2179 if (gIOHibernateCurrentHeader->handoffPageCount > gIOHibernateHandoffPageCount) {
2180 panic("handoff overflow");
2181 }
2182
2183 IOHibernateHandoff * handoff;
2184 bool done = false;
2185 bool foundCryptData = false;
2186 bool foundVolumeEncryptData = false;
2187
2188 for (handoff = (IOHibernateHandoff *) vars->handoffBuffer->getBytesNoCopy();
2189 !done;
2190 handoff = (IOHibernateHandoff *) &handoff->data[handoff->bytecount]) {
2191 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2192 uint8_t * data = &handoff->data[0];
2193 switch (handoff->type) {
2194 case kIOHibernateHandoffTypeEnd:
2195 done = true;
2196 break;
2197
2198 case kIOHibernateHandoffTypeGraphicsInfo:
2199 if (handoff->bytecount == sizeof(*gIOHibernateGraphicsInfo)) {
2200 bcopy(data, gIOHibernateGraphicsInfo, sizeof(*gIOHibernateGraphicsInfo));
2201 }
2202 break;
2203
2204 case kIOHibernateHandoffTypeCryptVars:
2205 if (cryptvars) {
2206 hibernate_cryptwakevars_t *
2207 wakevars = (hibernate_cryptwakevars_t *) &handoff->data[0];
2208 bcopy(&wakevars->aes_iv[0], &cryptvars->aes_iv[0], sizeof(cryptvars->aes_iv));
2209 }
2210 foundCryptData = true;
2211 bzero(data, handoff->bytecount);
2212 break;
2213
2214 case kIOHibernateHandoffTypeVolumeCryptKey:
2215 if (handoff->bytecount == vars->volumeCryptKeySize) {
2216 bcopy(data, &vars->volumeCryptKey[0], vars->volumeCryptKeySize);
2217 foundVolumeEncryptData = true;
2218 } else {
2219 panic("kIOHibernateHandoffTypeVolumeCryptKey(%d)", handoff->bytecount);
2220 }
2221 break;
2222
2223 case kIOHibernateHandoffTypeMemoryMap:
2224
2225 clock_get_uptime(&allTime);
2226
2227 hibernate_newruntime_map(data, handoff->bytecount,
2228 gIOHibernateCurrentHeader->systemTableOffset);
2229
2230 clock_get_uptime(&endTime);
2231
2232 SUB_ABSOLUTETIME(&endTime, &allTime);
2233 absolutetime_to_nanoseconds(endTime, &nsec);
2234
2235 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec / 1000000ULL);
2236
2237 break;
2238
2239 case kIOHibernateHandoffTypeDeviceTree:
2240 {
2241 // DTEntry chosen = NULL;
2242 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2243 }
2244 break;
2245
2246 default:
2247 done = (kIOHibernateHandoffType != (handoff->type & 0xFFFF0000));
2248 break;
2249 }
2250 }
2251
2252 if (vars->hwEncrypt && !foundVolumeEncryptData) {
2253 panic("no volumeCryptKey");
2254 } else if (cryptvars && !foundCryptData) {
2255 panic("hibernate handoff");
2256 }
2257
2258 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2259 gIOHibernateGraphicsInfo->physicalAddress, gIOHibernateGraphicsInfo->depth,
2260 gIOHibernateGraphicsInfo->width, gIOHibernateGraphicsInfo->height, gIOHibernateGraphicsInfo->gfxStatus);
2261
2262 if (vars->videoMapping && gIOHibernateGraphicsInfo->physicalAddress) {
2263 vars->videoMapSize = round_page(gIOHibernateGraphicsInfo->height
2264 * gIOHibernateGraphicsInfo->rowBytes);
2265 if (vars->videoMapSize > vars->videoAllocSize) {
2266 vars->videoMapSize = 0;
2267 } else {
2268 IOMapPages(kernel_map,
2269 vars->videoMapping, gIOHibernateGraphicsInfo->physicalAddress,
2270 vars->videoMapSize, kIOMapInhibitCache );
2271 }
2272 }
2273
2274 if (vars->videoMapSize) {
2275 ProgressUpdate(gIOHibernateGraphicsInfo,
2276 (uint8_t *) vars->videoMapping, 0, kIOHibernateProgressCount);
2277 }
2278
2279 uint8_t * src = (uint8_t *) vars->srcBuffer->getBytesNoCopy();
2280 uint8_t * compressed = src + page_size;
2281 uint8_t * scratch = compressed + page_size;
2282 uint32_t decoOffset;
2283
2284 clock_get_uptime(&allTime);
2285 AbsoluteTime_to_scalar(&compTime) = 0;
2286 compBytes = 0;
2287
2288 HIBLOG("IOPolledFilePollersOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2289 err = IOPolledFilePollersOpen(vars->fileVars, kIOPolledAfterSleepState, false);
2290 clock_get_uptime(&startIOTime);
2291 endTime = startIOTime;
2292 SUB_ABSOLUTETIME(&endTime, &allTime);
2293 absolutetime_to_nanoseconds(endTime, &nsec);
2294 HIBLOG("IOPolledFilePollersOpen(%x) %qd ms\n", err, nsec / 1000000ULL);
2295
2296 if (vars->hwEncrypt) {
2297 err = IOPolledFilePollersSetEncryptionKey(vars->fileVars,
2298 &vars->volumeCryptKey[0], vars->volumeCryptKeySize);
2299 HIBLOG("IOPolledFilePollersSetEncryptionKey(%x) %ld\n", err, vars->volumeCryptKeySize);
2300 if (kIOReturnSuccess != err) {
2301 panic("IOPolledFilePollersSetEncryptionKey(0x%x)", err);
2302 }
2303 cryptvars = 0;
2304 }
2305
2306 IOPolledFileSeek(vars->fileVars, gIOHibernateCurrentHeader->image1Size);
2307
2308 // kick off the read ahead
2309 vars->fileVars->bufferHalf = 0;
2310 vars->fileVars->bufferLimit = 0;
2311 vars->fileVars->lastRead = 0;
2312 vars->fileVars->readEnd = gIOHibernateCurrentHeader->imageSize;
2313 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2314 vars->fileVars->cryptBytes = 0;
2315 AbsoluteTime_to_scalar(&vars->fileVars->cryptTime) = 0;
2316
2317 err = IOPolledFileRead(vars->fileVars, 0, 0, cryptvars);
2318 vars->fileVars->bufferOffset = vars->fileVars->bufferLimit;
2319 // --
2320
2321 HIBLOG("hibernate_machine_init reading\n");
2322
2323 uint32_t * header = (uint32_t *) src;
2324 sum = 0;
2325
2326 while (kIOReturnSuccess == err) {
2327 unsigned int count;
2328 unsigned int page;
2329 uint32_t tag;
2330 vm_offset_t ppnum, compressedSize;
2331
2332 err = IOPolledFileRead(vars->fileVars, src, 8, cryptvars);
2333 if (kIOReturnSuccess != err) {
2334 break;
2335 }
2336
2337 ppnum = header[0];
2338 count = header[1];
2339
2340 // HIBPRINT("(%x, %x)\n", ppnum, count);
2341
2342 if (!count) {
2343 break;
2344 }
2345
2346 for (page = 0; page < count; page++) {
2347 err = IOPolledFileRead(vars->fileVars, (uint8_t *) &tag, 4, cryptvars);
2348 if (kIOReturnSuccess != err) {
2349 break;
2350 }
2351
2352 compressedSize = kIOHibernateTagLength & tag;
2353 if (kIOHibernateTagSignature != (tag & ~kIOHibernateTagLength)) {
2354 err = kIOReturnIPCError;
2355 break;
2356 }
2357
2358 err = IOPolledFileRead(vars->fileVars, src, (compressedSize + 3) & ~3, cryptvars);
2359 if (kIOReturnSuccess != err) {
2360 break;
2361 }
2362
2363 if (compressedSize < page_size) {
2364 decoOffset = page_size;
2365 clock_get_uptime(&startTime);
2366
2367 if (compressedSize == 4) {
2368 int i;
2369 uint32_t *s, *d;
2370
2371 s = (uint32_t *)src;
2372 d = (uint32_t *)(uintptr_t)compressed;
2373
2374 for (i = 0; i < (int)(PAGE_SIZE / sizeof(int32_t)); i++) {
2375 *d++ = *s;
2376 }
2377 } else {
2378 WKdm_decompress_new((WK_word*) src, (WK_word*) compressed, (WK_word*) scratch, compressedSize);
2379 }
2380 clock_get_uptime(&endTime);
2381 ADD_ABSOLUTETIME(&compTime, &endTime);
2382 SUB_ABSOLUTETIME(&compTime, &startTime);
2383 compBytes += page_size;
2384 } else {
2385 decoOffset = 0;
2386 }
2387
2388 sum += hibernate_sum_page((src + decoOffset), ppnum);
2389 err = IOMemoryDescriptorReadToPhysical(vars->srcBuffer, decoOffset, ptoa_64(ppnum), page_size);
2390 if (err) {
2391 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum, err);
2392 break;
2393 }
2394
2395 ppnum++;
2396 pagesDone++;
2397 pagesRead++;
2398
2399 if (0 == (8191 & pagesDone)) {
2400 clock_get_uptime(&endTime);
2401 SUB_ABSOLUTETIME(&endTime, &allTime);
2402 absolutetime_to_nanoseconds(endTime, &nsec);
2403 progressStamp = nsec / 750000000ULL;
2404 if (progressStamp != lastProgressStamp) {
2405 lastProgressStamp = progressStamp;
2406 HIBPRINT("pages %d (%d%%)\n", pagesDone,
2407 (100 * pagesDone) / gIOHibernateCurrentHeader->pageCount);
2408 }
2409 }
2410 }
2411 }
2412 if ((kIOReturnSuccess == err) && (pagesDone == gIOHibernateCurrentHeader->actualUncompressedPages)) {
2413 err = kIOReturnLockedRead;
2414 }
2415
2416 if (kIOReturnSuccess != err) {
2417 panic("Hibernate restore error %x", err);
2418 }
2419
2420 gIOHibernateCurrentHeader->actualImage2Sum = sum;
2421 gIOHibernateCompression = gIOHibernateCurrentHeader->compression;
2422
2423 clock_get_uptime(&endIOTime);
2424
2425 err = IOPolledFilePollersClose(vars->fileVars, kIOPolledAfterSleepState);
2426
2427 clock_get_uptime(&endTime);
2428
2429 IOService::getPMRootDomain()->pmStatsRecordEvent(
2430 kIOPMStatsHibernateImageRead | kIOPMStatsEventStartFlag, allTime);
2431 IOService::getPMRootDomain()->pmStatsRecordEvent(
2432 kIOPMStatsHibernateImageRead | kIOPMStatsEventStopFlag, endTime);
2433
2434 SUB_ABSOLUTETIME(&endTime, &allTime);
2435 absolutetime_to_nanoseconds(endTime, &nsec);
2436
2437 SUB_ABSOLUTETIME(&endIOTime, &startIOTime);
2438 absolutetime_to_nanoseconds(endIOTime, &nsecIO);
2439
2440 gIOHibernateStats->kernelImageReadDuration = nsec / 1000000ULL;
2441 gIOHibernateStats->imagePages = pagesDone;
2442
2443 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
2444 pagesDone, sum, gIOHibernateStats->kernelImageReadDuration, kDefaultIOSize,
2445 nsecIO ? ((((gIOHibernateCurrentHeader->imageSize - gIOHibernateCurrentHeader->image1Size) * 1000000000ULL) / 1024 / 1024) / nsecIO) : 0);
2446
2447 absolutetime_to_nanoseconds(compTime, &nsec);
2448 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2449 compBytes,
2450 nsec / 1000000ULL,
2451 nsec ? (((compBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2452
2453 absolutetime_to_nanoseconds(vars->fileVars->cryptTime, &nsec);
2454 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2455 vars->fileVars->cryptBytes,
2456 nsec / 1000000ULL,
2457 nsec ? (((vars->fileVars->cryptBytes * 1000000000ULL) / 1024 / 1024) / nsec) : 0);
2458
2459 KDBG(IOKDBG_CODE(DBG_HIBERNATE, 2), pagesRead, pagesDone);
2460 }
2461
2462 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2463
2464 void
2465 IOHibernateSetWakeCapabilities(uint32_t capability)
2466 {
2467 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2468 gIOHibernateStats->wakeCapability = capability;
2469
2470 if (kIOPMSystemCapabilityGraphics & capability) {
2471 vm_compressor_do_warmup();
2472 }
2473 }
2474 }
2475
2476 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2477
2478 void
2479 IOHibernateSystemRestart(void)
2480 {
2481 static uint8_t noteStore[32] __attribute__((aligned(32)));
2482 IORegistryEntry * regEntry;
2483 const OSSymbol * sym;
2484 OSData * noteProp;
2485 OSData * data;
2486 uintptr_t * smcVars;
2487 uint8_t * smcBytes;
2488 size_t len;
2489 addr64_t element;
2490
2491 data = OSDynamicCast(OSData, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey));
2492 if (!data) {
2493 return;
2494 }
2495
2496 smcVars = (typeof(smcVars))data->getBytesNoCopy();
2497 smcBytes = (typeof(smcBytes))smcVars[1];
2498 len = smcVars[0];
2499 if (len > sizeof(noteStore)) {
2500 len = sizeof(noteStore);
2501 }
2502 noteProp = OSData::withCapacity(3 * sizeof(element));
2503 if (!noteProp) {
2504 return;
2505 }
2506 element = len;
2507 noteProp->appendBytes(&element, sizeof(element));
2508 element = crc32(0, smcBytes, len);
2509 noteProp->appendBytes(&element, sizeof(element));
2510
2511 bcopy(smcBytes, noteStore, len);
2512 element = (addr64_t) &noteStore[0];
2513 element = (element & page_mask) | ptoa_64(pmap_find_phys(kernel_pmap, element));
2514 noteProp->appendBytes(&element, sizeof(element));
2515
2516 if (!gIOOptionsEntry) {
2517 regEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
2518 gIOOptionsEntry = OSDynamicCast(IODTNVRAM, regEntry);
2519 if (regEntry && !gIOOptionsEntry) {
2520 regEntry->release();
2521 }
2522 }
2523
2524 sym = OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey);
2525 if (gIOOptionsEntry && sym) {
2526 gIOOptionsEntry->setProperty(sym, noteProp);
2527 }
2528 if (noteProp) {
2529 noteProp->release();
2530 }
2531 if (sym) {
2532 sym->release();
2533 }
2534 }