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