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