2 * Copyright (c) 2004-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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).
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
101 IOHibernateSystemSleep() finds a polled mode interface to the ATA controller via a property in the
102 registry, specifying an object of calls IOPolledInterface.
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.
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:
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.
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.
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
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
136 #include <sys/systm.h>
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>
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>
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>
173 #include <machine/pal_routines.h>
174 #include <machine/pal_hibernate.h>
175 #include <i386/tsc.h>
176 #include <i386/cpuid.h>
178 extern "C" addr64_t
kvtophys(vm_offset_t va
);
179 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
181 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
183 #define DISABLE_TRIM 0
184 #define TRIM_DELAY 25000
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
;
196 static IODTNVRAM
* gIOOptionsEntry
;
197 static IORegistryEntry
* gIOChosenEntry
;
199 static const OSSymbol
* gIOHibernateBootImageKey
;
201 #if defined(__i386__) || defined(__x86_64__)
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
;
210 static IOPolledFileIOVars
* gDebugImageFileVars
;
211 static IOLock
* gDebugImageLock
;
213 #endif /* defined(__i386__) || defined(__x86_64__) */
215 static IOLock
* gFSLock
;
216 static uint32_t gFSState
;
217 static IOPolledFileIOVars gFileVars
;
218 static IOHibernateVars gIOHibernateVars
;
219 static IOPolledFileCryptVars gIOHibernateCryptWakeContext
;
220 static hibernate_graphics_t _hibernateGraphics
;
221 static hibernate_graphics_t
* gIOHibernateGraphicsInfo
= &_hibernateGraphics
;
222 static hibernate_statistics_t _hibernateStats
;
223 static hibernate_statistics_t
* gIOHibernateStats
= &_hibernateStats
;
233 static IOReturn
IOHibernateDone(IOHibernateVars
* vars
);
234 static IOReturn
IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
);
235 static void IOSetBootImageNVRAM(OSData
* data
);
237 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
239 enum { kDefaultIOSize
= 128 * 1024 };
240 enum { kVideoMapSize
= 80 * 1024 * 1024 };
242 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
244 // copy from phys addr to MD
247 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
248 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
250 addr64_t srcAddr
= bytes
;
251 IOByteCount remaining
;
253 remaining
= length
= min(length
, md
->getLength() - offset
);
254 while (remaining
) { // (process another target segment?)
258 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
262 // Clip segment length to remaining
263 if (dstLen
> remaining
)
267 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
269 copypv(srcAddr
, dstAddr64
, dstLen
,
270 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
279 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
282 // copy from MD to phys addr
285 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
286 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
288 addr64_t dstAddr
= bytes
;
289 IOByteCount remaining
;
291 remaining
= length
= min(length
, md
->getLength() - offset
);
292 while (remaining
) { // (process another target segment?)
296 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
300 // Clip segment length to remaining
301 if (dstLen
> remaining
)
305 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
307 copypv(srcAddr
, dstAddr64
, dstLen
,
308 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
317 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
320 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
323 hibernate_set_page_state(hibernate_page_list_t
* page_list
, hibernate_page_list_t
* page_list_wired
,
324 vm_offset_t ppnum
, vm_offset_t count
, uint32_t kind
)
329 case kIOHibernatePageStateUnwiredSave
:
331 for (; ppnum
< count
; ppnum
++)
333 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
334 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
337 case kIOHibernatePageStateWiredSave
:
339 for (; ppnum
< count
; ppnum
++)
341 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
342 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
345 case kIOHibernatePageStateFree
:
347 for (; ppnum
< count
; ppnum
++)
349 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
350 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
354 panic("hibernate_set_page_state");
359 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
361 uint32_t page
= *pPage
;
363 hibernate_bitmap_t
* bitmap
;
365 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
367 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
371 if (page
<= bitmap
->last_page
)
377 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
384 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
387 IOHibernateSystemSleep(void)
394 bool dsSSD
, vmflush
, swapPinned
;
395 IOHibernateVars
* vars
;
396 uint64_t setFileSize
= 0;
398 gIOHibernateState
= kIOHibernateStateInactive
;
400 gIOHibernateDebugFlags
= 0;
401 if (kIOLogHibernate
& gIOKitDebug
)
402 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
404 if (IOService::getPMRootDomain()->getHibernateSettings(
405 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
407 if (kIOHibernateModeSleep
& gIOHibernateMode
)
408 // default to discard clean for safe sleep
409 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
410 | kIOHibernateModeDiscardCleanActive
);
413 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
415 if ((str
= OSDynamicCast(OSString
, obj
)))
416 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
417 sizeof(gIOHibernateFilename
));
421 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
422 return (kIOReturnUnsupported
);
424 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
426 vars
= IONew(IOHibernateVars
, 1);
427 if (!vars
) return (kIOReturnNoMemory
);
428 bzero(vars
, sizeof(*vars
));
431 if (kFSIdle
!= gFSState
)
433 HIBLOG("hibernate file busy\n");
434 IOLockUnlock(gFSLock
);
435 IODelete(vars
, IOHibernateVars
, 1);
436 return (kIOReturnBusy
);
438 gFSState
= kFSOpening
;
439 IOLockUnlock(gFSLock
);
444 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
445 2 * page_size
+ WKdm_SCRATCH_BUF_SIZE_INTERNAL
, page_size
);
447 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
448 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
450 if (!vars
->srcBuffer
|| !vars
->handoffBuffer
)
452 err
= kIOReturnNoMemory
;
456 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey
)))
458 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMinSize
= num
->unsigned64BitValue();
461 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey
)))
463 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMaxSize
= num
->unsigned64BitValue();
467 boolean_t encryptedswap
= true;
469 AbsoluteTime startTime
, endTime
;
472 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
473 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
474 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
476 vmflush
= ((kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
477 err
= hibernate_alloc_page_lists(&vars
->page_list
,
478 &vars
->page_list_wired
,
479 &vars
->page_list_pal
);
480 if (KERN_SUCCESS
!= err
) break;
482 err
= hibernate_pin_swap(TRUE
);
483 if (KERN_SUCCESS
!= err
) break;
486 if (vars
->fileMinSize
|| (kIOHibernateModeFileResize
& gIOHibernateMode
))
488 hibernate_page_list_setall(vars
->page_list
,
489 vars
->page_list_wired
,
491 true /* preflight */,
492 vmflush
/* discard */,
494 PE_Video consoleInfo
;
495 bzero(&consoleInfo
, sizeof(consoleInfo
));
496 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
498 // estimate: 6% increase in pages compressed
499 // screen preview 2 images compressed 0%
500 setFileSize
= ((ptoa_64((106 * pageCount
) / 100) * gIOHibernateCompression
) >> 8)
501 + vars
->page_list
->list_size
502 + (consoleInfo
.v_width
* consoleInfo
.v_height
* 8);
503 enum { setFileRound
= 1024*1024ULL };
504 setFileSize
= ((setFileSize
+ setFileRound
) & ~(setFileRound
- 1));
506 HIBLOG("hibernate_page_list_setall preflight pageCount %d est comp %qd setfile %qd min %qd\n",
507 pageCount
, (100ULL * gIOHibernateCompression
) >> 8,
508 setFileSize
, vars
->fileMinSize
);
510 if (!(kIOHibernateModeFileResize
& gIOHibernateMode
)
511 && (setFileSize
< vars
->fileMinSize
))
513 setFileSize
= vars
->fileMinSize
;
517 // Invalidate the image file
518 if (gDebugImageLock
) {
519 IOLockLock(gDebugImageLock
);
520 if (gDebugImageFileVars
!= 0) {
521 kprintf("IOHIBSystemSleep: Closing debugdata file\n");
522 IOSetBootImageNVRAM(0);
523 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
525 IOLockUnlock(gDebugImageLock
);
528 err
= IOPolledFileOpen(gIOHibernateFilename
, setFileSize
, 0,
529 gIOHibernateCurrentHeader
, sizeof(gIOHibernateCurrentHeader
),
530 &vars
->fileVars
, &nvramData
,
531 &vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
533 if (KERN_SUCCESS
!= err
)
536 if (kFSOpening
!= gFSState
) err
= kIOReturnTimeout
;
537 IOLockUnlock(gFSLock
);
540 if (KERN_SUCCESS
!= err
)
542 HIBLOG("IOPolledFileOpen(%x)\n", err
);
546 // write extents for debug data usage in EFI
547 IOWriteExtentsToFile(vars
->fileVars
, kIOHibernateHeaderOpenSignature
);
549 err
= IOPolledFilePollersSetup(vars
->fileVars
, kIOPolledPreflightState
);
550 if (KERN_SUCCESS
!= err
) break;
552 clock_get_uptime(&startTime
);
553 err
= hibernate_setup(gIOHibernateCurrentHeader
,
555 vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
556 clock_get_uptime(&endTime
);
557 SUB_ABSOLUTETIME(&endTime
, &startTime
);
558 absolutetime_to_nanoseconds(endTime
, &nsec
);
560 boolean_t haveSwapPin
, hibFileSSD
;
561 haveSwapPin
= vm_swap_files_pinned();
563 hibFileSSD
= (kIOPolledFileSSD
& vars
->fileVars
->flags
);
565 HIBLOG("hibernate_setup(%d) took %qd ms, swapPin(%d) ssd(%d)\n",
566 err
, nsec
/ 1000000ULL,
567 haveSwapPin
, hibFileSSD
);
568 if (KERN_SUCCESS
!= err
) break;
570 gIOHibernateStandbyDisabled
= ((!haveSwapPin
|| !hibFileSSD
));
572 dsSSD
= ((0 != (kIOPolledFileSSD
& vars
->fileVars
->flags
))
573 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
575 if (dsSSD
) gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionSSD
| kIOHibernateOptionColor
;
576 else gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
579 #if defined(__i386__) || defined(__x86_64__)
580 if (!uuid_is_null(vars
->volumeCryptKey
) &&
581 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
)))
583 uintptr_t smcVars
[2];
584 smcVars
[0] = sizeof(vars
->volumeCryptKey
);
585 smcVars
[1] = (uintptr_t)(void *) &gIOHibernateVars
.volumeCryptKey
[0];
587 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
588 bzero(smcVars
, sizeof(smcVars
));
593 if (encryptedswap
|| !uuid_is_null(vars
->volumeCryptKey
))
594 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
596 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
598 vars
->videoAllocSize
= kVideoMapSize
;
599 if (KERN_SUCCESS
!= kmem_alloc_pageable(kernel_map
, &vars
->videoMapping
, vars
->videoAllocSize
, VM_KERN_MEMORY_IOKIT
))
600 vars
->videoMapping
= 0;
603 // generate crypt keys
604 for (uint32_t i
= 0; i
< sizeof(vars
->wiredCryptKey
); i
++)
605 vars
->wiredCryptKey
[i
] = random();
606 for (uint32_t i
= 0; i
< sizeof(vars
->cryptKey
); i
++)
607 vars
->cryptKey
[i
] = random();
611 IOSetBootImageNVRAM(nvramData
);
612 nvramData
->release();
614 #if defined(__i386__) || defined(__x86_64__)
616 struct AppleRTCHibernateVars
618 uint8_t signature
[4];
620 uint8_t booterSignature
[20];
621 uint8_t wiredCryptKey
[16];
623 AppleRTCHibernateVars rtcVars
;
626 rtcVars
.signature
[0] = 'A';
627 rtcVars
.signature
[1] = 'A';
628 rtcVars
.signature
[2] = 'P';
629 rtcVars
.signature
[3] = 'L';
630 rtcVars
.revision
= 1;
631 bcopy(&vars
->wiredCryptKey
[0], &rtcVars
.wiredCryptKey
[0], sizeof(rtcVars
.wiredCryptKey
));
632 if (gIOHibernateBootSignature
[0])
637 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
640 if (c
>= 'a') c
-= 'a' - 10;
641 else if (c
>= 'A') c
-= 'A' - 10;
642 else if (c
>= '0') c
-= '0';
644 value
= (value
<< 4) | c
;
645 if (i
& 1) rtcVars
.booterSignature
[i
>> 1] = value
;
648 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
651 if (gIOHibernateRTCVariablesKey
)
652 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
657 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
658 if (data
) gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
660 if (!gIOHibernateBoot0082Data
)
662 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
665 // AppleNVRAM_EFI_LOAD_OPTION
668 uint16_t FilePathLength
;
671 loadOptionHeader
.Attributes
= 1;
672 loadOptionHeader
.FilePathLength
= data
->getLength();
673 loadOptionHeader
.Desc
= 0;
674 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
675 if (gIOHibernateBoot0082Data
)
677 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
678 gIOHibernateBoot0082Data
->appendBytes(data
);
682 if (!gIOHibernateBootNextData
)
684 uint16_t bits
= 0x0082;
685 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
687 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
689 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
690 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
691 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
696 #endif /* !i386 && !x86_64 */
700 if (swapPinned
) hibernate_pin_swap(FALSE
);
703 if ((kIOReturnSuccess
== err
) && (kFSOpening
!= gFSState
))
705 HIBLOG("hibernate file close due timeout\n");
706 err
= kIOReturnTimeout
;
708 if (kIOReturnSuccess
== err
)
710 gFSState
= kFSOpened
;
711 gIOHibernateVars
= *vars
;
712 gFileVars
= *vars
->fileVars
;
713 gFileVars
.allocated
= false;
714 gIOHibernateVars
.fileVars
= &gFileVars
;
715 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderSignature
;
716 gIOHibernateState
= kIOHibernateStateHibernating
;
720 IOPolledFileIOVars
* fileVars
= vars
->fileVars
;
721 IOHibernateDone(vars
);
722 IOPolledFileClose(&fileVars
,
726 0, NULL
, 0, sizeof(IOHibernateImageHeader
), setFileSize
);
730 IOLockUnlock(gFSLock
);
732 if (vars
->fileVars
) IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
733 IODelete(vars
, IOHibernateVars
, 1);
738 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
741 IOSetBootImageNVRAM(OSData
* data
)
743 IORegistryEntry
* regEntry
;
745 if (!gIOOptionsEntry
)
747 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
748 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
749 if (regEntry
&& !gIOOptionsEntry
)
752 if (gIOOptionsEntry
&& gIOHibernateBootImageKey
)
754 if (data
) gIOOptionsEntry
->setProperty(gIOHibernateBootImageKey
, data
);
757 gIOOptionsEntry
->removeProperty(gIOHibernateBootImageKey
);
758 gIOOptionsEntry
->sync();
763 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
765 * Writes header to disk with signature, block size and file extents data.
766 * If there are more than 2 extents, then they are written on second block.
769 IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
)
771 IOHibernateImageHeader hdr
;
773 IOReturn err
= kIOReturnSuccess
;
775 IOPolledFileExtent
* fileExtents
;
777 fileExtents
= (typeof(fileExtents
)) vars
->fileExtents
->getBytesNoCopy();
779 memset(&hdr
, 0, sizeof(IOHibernateImageHeader
));
780 count
= vars
->fileExtents
->getLength();
781 if (count
> sizeof(hdr
.fileExtentMap
))
783 hdr
.fileExtentMapSize
= count
;
784 count
= sizeof(hdr
.fileExtentMap
);
787 hdr
.fileExtentMapSize
= sizeof(hdr
.fileExtentMap
);
789 bcopy(fileExtents
, &hdr
.fileExtentMap
[0], count
);
791 // copy file block extent list if larger than header
792 if (hdr
.fileExtentMapSize
> sizeof(hdr
.fileExtentMap
))
794 count
= hdr
.fileExtentMapSize
- sizeof(hdr
.fileExtentMap
);
795 rc
= kern_write_file(vars
->fileRef
, vars
->blockSize
,
796 (caddr_t
)(((uint8_t *)fileExtents
) + sizeof(hdr
.fileExtentMap
)),
797 count
, IO_SKIP_ENCRYPTION
);
799 HIBLOG("kern_write_file returned %d\n", rc
);
800 err
= kIOReturnIOError
;
804 hdr
.signature
= signature
;
805 hdr
.deviceBlockSize
= vars
->blockSize
;
807 rc
= kern_write_file(vars
->fileRef
, 0, (char *)&hdr
, sizeof(hdr
), IO_SKIP_ENCRYPTION
);
809 HIBLOG("kern_write_file returned %d\n", rc
);
810 err
= kIOReturnIOError
;
818 extern "C" boolean_t root_is_CF_drive
;
821 IOOpenDebugDataFile(const char *fname
, uint64_t size
)
824 OSData
* imagePath
= NULL
;
827 if (!gDebugImageLock
) {
828 gDebugImageLock
= IOLockAlloc();
831 if (root_is_CF_drive
) return;
833 // Try to get a lock, but don't block for getting lock
834 if (!IOLockTryLock(gDebugImageLock
)) {
835 HIBLOG("IOOpenDebugDataFile: Failed to get lock\n");
839 if (gDebugImageFileVars
|| !fname
|| !size
) {
840 HIBLOG("IOOpenDebugDataFile: conditions failed\n");
844 padding
= (PAGE_SIZE
*2); // allocate couple more pages for header and fileextents
845 err
= IOPolledFileOpen(fname
, size
+padding
, 32ULL*1024*1024*1024,
847 &gDebugImageFileVars
, &imagePath
, NULL
, 0);
849 if ((kIOReturnSuccess
== err
) && imagePath
)
851 if ((gDebugImageFileVars
->fileSize
< (size
+padding
)) ||
852 (gDebugImageFileVars
->fileExtents
->getLength() > PAGE_SIZE
)) {
853 // Can't use the file
854 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
855 HIBLOG("IOOpenDebugDataFile: too many file extents\n");
859 // write extents for debug data usage in EFI
860 IOWriteExtentsToFile(gDebugImageFileVars
, kIOHibernateHeaderOpenSignature
);
861 IOSetBootImageNVRAM(imagePath
);
862 kprintf("IOOpenDebugDataFile: opened debugdata file\n");
866 IOLockUnlock(gDebugImageLock
);
868 if (imagePath
) imagePath
->release();
873 IOCloseDebugDataFile()
875 IOSetBootImageNVRAM(0);
877 if (gDebugImageLock
) {
878 IOLockLock(gDebugImageLock
);
879 if (gDebugImageFileVars
!= 0) {
880 kprintf("IOHibernateSystemPostWake: Closing debugdata file\n");
881 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
883 IOLockUnlock(gDebugImageLock
);
889 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
891 DECLARE_IOHIBERNATEPROGRESSALPHA
894 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
896 uint32_t rowBytes
, pixelShift
;
899 uint32_t alpha
, in
, color
, result
;
901 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
903 rowBytes
= display
->rowBytes
;
904 pixelShift
= display
->depth
>> 4;
905 if (pixelShift
< 1) return;
907 screen
+= ((display
->width
908 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
909 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
911 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
913 out
= screen
+ y
* rowBytes
;
914 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
916 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
917 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
919 alpha
= gIOHibernateProgressAlpha
[y
][x
];
927 in
= *((uint16_t *)out
) & 0x1f; // 16
928 in
= (in
<< 3) | (in
>> 2);
931 in
= *((uint32_t *)out
) & 0xff; // 32
932 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
933 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
938 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
941 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
943 out
+= (1 << pixelShift
);
945 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
952 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
954 uint32_t rowBytes
, pixelShift
;
956 int32_t blob
, lastBlob
;
957 uint32_t alpha
, in
, color
, result
;
959 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
961 pixelShift
= display
->depth
>> 4;
965 rowBytes
= display
->rowBytes
;
967 screen
+= ((display
->width
968 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
969 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
971 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
973 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
975 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
977 out
= screen
+ y
* rowBytes
;
978 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
980 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
981 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
983 alpha
= gIOHibernateProgressAlpha
[y
][x
];
989 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
990 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
995 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
998 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1000 out
+= (1 << pixelShift
);
1002 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1007 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1010 IOHibernateIOKitSleep(void)
1012 IOReturn ret
= kIOReturnSuccess
;
1013 IOLockLock(gFSLock
);
1014 if (kFSOpening
== gFSState
)
1016 gFSState
= kFSTimedOut
;
1017 HIBLOG("hibernate file open timed out\n");
1018 ret
= kIOReturnTimeout
;
1020 IOLockUnlock(gFSLock
);
1024 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1027 IOHibernateSystemHasSlept(void)
1029 IOReturn ret
= kIOReturnSuccess
;
1030 IOHibernateVars
* vars
= &gIOHibernateVars
;
1034 IOLockLock(gFSLock
);
1035 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
)
1037 ret
= kIOReturnTimeout
;
1039 IOLockUnlock(gFSLock
);
1040 if (kIOReturnSuccess
!= ret
) return (ret
);
1042 if (gIOHibernateMode
) obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1043 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1044 if (obj
&& !vars
->previewBuffer
)
1047 vars
->consoleMapping
= NULL
;
1048 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1050 vars
->previewBuffer
->release();
1051 vars
->previewBuffer
= 0;
1054 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1055 && vars
->previewBuffer
1056 && (data
= OSDynamicCast(OSData
,
1057 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1059 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1060 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1062 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1064 if (kIOHibernatePreviewUpdates
& flags
)
1066 PE_Video consoleInfo
;
1067 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1069 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
1071 graphicsInfo
->width
= consoleInfo
.v_width
;
1072 graphicsInfo
->height
= consoleInfo
.v_height
;
1073 graphicsInfo
->rowBytes
= consoleInfo
.v_rowBytes
;
1074 graphicsInfo
->depth
= consoleInfo
.v_depth
;
1075 vars
->consoleMapping
= (uint8_t *) consoleInfo
.v_baseAddr
;
1077 HIBPRINT("video %p %d %d %d\n",
1078 vars
->consoleMapping
, graphicsInfo
->depth
,
1079 graphicsInfo
->width
, graphicsInfo
->height
);
1080 if (vars
->consoleMapping
)
1081 ProgressInit(graphicsInfo
, vars
->consoleMapping
,
1082 &graphicsInfo
->progressSaveUnder
[0][0], sizeof(graphicsInfo
->progressSaveUnder
));
1086 if (gIOOptionsEntry
)
1087 gIOOptionsEntry
->sync();
1092 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1094 static DeviceTreeNode
*
1095 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
1097 DeviceTreeNodeProperty
* prop
;
1098 DeviceTreeNode
* child
;
1099 IORegistryEntry
* childRegEntry
;
1100 const char * nameProp
;
1101 unsigned int propLen
, idx
;
1103 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1104 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
1106 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
1108 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1109 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1111 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1114 child
= (DeviceTreeNode
*) prop
;
1115 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
1117 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
1119 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1120 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1121 child
= MergeDeviceTree(child
, childRegEntry
);
1127 IOHibernateSystemWake(void)
1129 if (kFSOpened
== gFSState
)
1131 IOPolledFilePollersClose(gIOHibernateVars
.fileVars
, kIOPolledPostflightState
);
1132 IOHibernateDone(&gIOHibernateVars
);
1136 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1137 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1139 return (kIOReturnSuccess
);
1143 IOHibernateDone(IOHibernateVars
* vars
)
1145 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1147 if (vars
->videoMapping
)
1149 if (vars
->videoMapSize
)
1151 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1152 if (vars
->videoAllocSize
)
1154 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1157 if (vars
->previewBuffer
)
1159 vars
->previewBuffer
->release();
1160 vars
->previewBuffer
= 0;
1163 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1165 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1166 gIOHibernateCurrentHeader
->options
, 32);
1170 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1173 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1174 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1176 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1177 &gIOHibernateGraphicsInfo
->gfxStatus
,
1178 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1182 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1185 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1187 #if defined(__i386__) || defined(__x86_64__)
1188 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1189 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1192 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1193 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1195 if (gIOOptionsEntry
) {
1197 if (gIOHibernateRTCVariablesKey
) {
1198 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1199 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1203 if (gIOHibernateBootNextKey
)
1205 if (gIOHibernateBootNextSave
)
1207 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1208 gIOHibernateBootNextSave
->release();
1209 gIOHibernateBootNextSave
= NULL
;
1212 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1214 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) gIOOptionsEntry
->sync();
1218 if (vars
->srcBuffer
) vars
->srcBuffer
->release();
1219 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1220 if (vars
->handoffBuffer
)
1222 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1224 IOHibernateHandoff
* handoff
;
1226 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1228 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
1230 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1231 uint8_t * data
= &handoff
->data
[0];
1232 switch (handoff
->type
)
1234 case kIOHibernateHandoffTypeEnd
:
1238 case kIOHibernateHandoffTypeDeviceTree
:
1239 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
1242 case kIOHibernateHandoffTypeKeyStore
:
1243 #if defined(__i386__) || defined(__x86_64__)
1245 IOBufferMemoryDescriptor
*
1246 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1249 IOSetKeyStoreData(md
);
1256 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1261 vars
->handoffBuffer
->release();
1264 bzero(vars
, sizeof(*vars
));
1266 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1268 return (kIOReturnSuccess
);
1272 IOHibernateSystemPostWake(void)
1274 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1275 IOLockLock(gFSLock
);
1276 if (kFSOpened
== gFSState
)
1278 // invalidate & close the image file
1279 IOSleep(TRIM_DELAY
);
1280 IOPolledFileIOVars
* vars
= &gFileVars
;
1281 IOPolledFileClose(&vars
,
1285 0, (caddr_t
)gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
),
1286 sizeof(IOHibernateImageHeader
), gIOHibernateCurrentHeader
->imageSize
);
1291 IOLockUnlock(gFSLock
);
1293 // IOCloseDebugDataFile() calls IOSetBootImageNVRAM() unconditionally
1294 IOCloseDebugDataFile( );
1295 return (kIOReturnSuccess
);
1298 uint32_t IOHibernateWasScreenLocked(void)
1301 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
)
1304 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
1307 ret
= ((uint32_t *)data
->getBytesNoCopy())[0];
1308 gIOChosenEntry
->setProperty(kIOBooterScreenLockStateKey
, data
);
1311 else gIOChosenEntry
->removeProperty(kIOBooterScreenLockStateKey
);
1316 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1318 SYSCTL_STRING(_kern
, OID_AUTO
, hibernatefile
,
1319 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1320 gIOHibernateFilename
, sizeof(gIOHibernateFilename
), "");
1321 SYSCTL_STRING(_kern
, OID_AUTO
, bootsignature
,
1322 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1323 gIOHibernateBootSignature
, sizeof(gIOHibernateBootSignature
), "");
1324 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatemode
,
1325 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1326 &gIOHibernateMode
, 0, "");
1327 SYSCTL_STRUCT(_kern
, OID_AUTO
, hibernatestatistics
,
1328 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1329 &_hibernateStats
, hibernate_statistics_t
, "");
1331 SYSCTL_UINT(_kern
, OID_AUTO
, hibernategraphicsready
,
1332 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1333 &_hibernateStats
.graphicsReadyTime
, 0, "");
1334 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatewakenotification
,
1335 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1336 &_hibernateStats
.wakeNotificationTime
, 0, "");
1337 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatelockscreenready
,
1338 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1339 &_hibernateStats
.lockScreenReadyTime
, 0, "");
1340 SYSCTL_UINT(_kern
, OID_AUTO
, hibernatehidready
,
1341 CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_ANYBODY
,
1342 &_hibernateStats
.hidReadyTime
, 0, "");
1346 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1348 gIOHibernateBootImageKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
1350 #if defined(__i386__) || defined(__x86_64__)
1351 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1352 gIOHibernateBoot0082Key
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:Boot0082");
1353 gIOHibernateBootNextKey
= OSSymbol::withCString("8BE4DF61-93CA-11D2-AA0D-00E098032B8C:BootNext");
1354 gIOHibernateRTCVariablesKey
= OSSymbol::withCStringNoCopy(kIOHibernateRTCVariablesKey
);
1355 #endif /* defined(__i386__) || defined(__x86_64__) */
1357 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1360 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1364 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1365 gIOHibernateMode
= kIOHibernateModeOn
;
1367 gIOHibernateFilename
[0] = 0;
1369 sysctl_register_oid(&sysctl__kern_hibernatefile
);
1370 sysctl_register_oid(&sysctl__kern_bootsignature
);
1371 sysctl_register_oid(&sysctl__kern_hibernatemode
);
1372 sysctl_register_oid(&sysctl__kern_hibernatestatistics
);
1373 sysctl_register_oid(&sysctl__kern_hibernategraphicsready
);
1374 sysctl_register_oid(&sysctl__kern_hibernatewakenotification
);
1375 sysctl_register_oid(&sysctl__kern_hibernatelockscreenready
);
1376 sysctl_register_oid(&sysctl__kern_hibernatehidready
);
1378 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1380 gFSLock
= IOLockAlloc();
1383 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1386 IOHibernatePolledFileWrite(IOPolledFileIOVars
* vars
,
1387 const uint8_t * bytes
, IOByteCount size
,
1388 IOPolledFileCryptVars
* cryptvars
)
1392 err
= IOPolledFileWrite(vars
, bytes
, size
, cryptvars
);
1393 if ((kIOReturnSuccess
== err
) && hibernate_should_abort()) err
= kIOReturnAborted
;
1398 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1401 hibernate_write_image(void)
1403 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1404 IOHibernateVars
* vars
= &gIOHibernateVars
;
1405 IOPolledFileExtent
* fileExtents
;
1407 _static_assert_1_arg(sizeof(IOHibernateImageHeader
) == 512);
1409 uint32_t pageCount
, pagesDone
;
1411 vm_offset_t ppnum
, page
;
1415 uint8_t * compressed
;
1417 IOByteCount pageCompressedSize
;
1418 uint64_t compressedSize
, uncompressedSize
;
1419 uint64_t image1Size
= 0;
1420 uint32_t bitmap_size
;
1421 bool iterDone
, pollerOpen
, needEncrypt
;
1422 uint32_t restore1Sum
, sum
, sum1
, sum2
;
1426 uint32_t pageAndCount
[2];
1429 uintptr_t hibernateBase
;
1430 uintptr_t hibernateEnd
;
1432 AbsoluteTime startTime
, endTime
;
1433 AbsoluteTime allTime
, compTime
;
1436 uint32_t lastProgressStamp
= 0;
1437 uint32_t progressStamp
;
1438 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1440 uint32_t wiredPagesEncrypted
;
1441 uint32_t dirtyPagesEncrypted
;
1442 uint32_t wiredPagesClear
;
1443 uint32_t svPageCount
;
1444 uint32_t zvPageCount
;
1446 IOPolledFileCryptVars _cryptvars
;
1447 IOPolledFileCryptVars
* cryptvars
= 0;
1449 wiredPagesEncrypted
= 0;
1450 dirtyPagesEncrypted
= 0;
1451 wiredPagesClear
= 0;
1456 || !vars
->fileVars
->pollers
1457 || !(kIOHibernateModeOn
& gIOHibernateMode
)) return (kIOHibernatePostWriteSleep
);
1459 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1460 kdebug_enable
= save_kdebug_enable
;
1462 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
, 0, 0, 0, 0, 0);
1463 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
1465 restore1Sum
= sum1
= sum2
= 0;
1468 // encryption data. "iv" is the "initial vector".
1469 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1471 static const unsigned char first_iv
[AES_BLOCK_SIZE
]
1472 = { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
1473 0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
1475 cryptvars
= &gIOHibernateCryptWakeContext
;
1476 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1477 aes_encrypt_key(vars
->cryptKey
,
1478 kIOHibernateAESKeySize
,
1479 &cryptvars
->ctx
.encrypt
);
1480 aes_decrypt_key(vars
->cryptKey
,
1481 kIOHibernateAESKeySize
,
1482 &cryptvars
->ctx
.decrypt
);
1484 cryptvars
= &_cryptvars
;
1485 bzero(cryptvars
, sizeof(IOPolledFileCryptVars
));
1486 for (pageCount
= 0; pageCount
< sizeof(vars
->wiredCryptKey
); pageCount
++)
1487 vars
->wiredCryptKey
[pageCount
] ^= vars
->volumeCryptKey
[pageCount
];
1488 bzero(&vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
1489 aes_encrypt_key(vars
->wiredCryptKey
,
1490 kIOHibernateAESKeySize
,
1491 &cryptvars
->ctx
.encrypt
);
1493 bcopy(&first_iv
[0], &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1494 bzero(&vars
->wiredCryptKey
[0], sizeof(vars
->wiredCryptKey
));
1495 bzero(&vars
->cryptKey
[0], sizeof(vars
->cryptKey
));
1499 hibernate_page_list_setall(vars
->page_list
,
1500 vars
->page_list_wired
,
1501 vars
->page_list_pal
,
1502 false /* !preflight */,
1504 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
1505 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
1508 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1510 fileExtents
= (IOPolledFileExtent
*) vars
->fileVars
->fileExtents
->getBytesNoCopy();
1513 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1514 for (page
= 0; page
< count
; page
++)
1516 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1517 fileExtents
[page
].start
, fileExtents
[page
].length
,
1518 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1522 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1523 AbsoluteTime_to_scalar(&compTime
) = 0;
1526 clock_get_uptime(&allTime
);
1527 IOService::getPMRootDomain()->pmStatsRecordEvent(
1528 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1532 uncompressedSize
= 0;
1536 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
1538 HIBLOG("IOHibernatePollerOpen, ml_get_interrupts_enabled %d\n",
1539 ml_get_interrupts_enabled());
1540 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledBeforeSleepState
, true);
1541 HIBLOG("IOHibernatePollerOpen(%x)\n", err
);
1542 pollerOpen
= (kIOReturnSuccess
== err
);
1546 // copy file block extent list if larger than header
1548 count
= vars
->fileVars
->fileExtents
->getLength();
1549 if (count
> sizeof(header
->fileExtentMap
))
1551 count
-= sizeof(header
->fileExtentMap
);
1552 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1553 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1554 if (kIOReturnSuccess
!= err
)
1558 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
1559 hibernateEnd
= (segHIBB
+ segSizeHIB
);
1561 // copy out restore1 code
1564 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1567 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
1569 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
1573 page
= atop_32(kvtophys(hibernateBase
));
1574 count
= atop_32(round_page(hibernateEnd
) - hibernateBase
);
1575 header
->restore1CodePhysPage
= page
;
1576 header
->restore1CodeVirt
= hibernateBase
;
1577 header
->restore1PageCount
= count
;
1578 header
->restore1CodeOffset
= ((uintptr_t) &hibernate_machine_entrypoint
) - hibernateBase
;
1579 header
->restore1StackOffset
= ((uintptr_t) &gIOHibernateRestoreStackEnd
[0]) - 64 - hibernateBase
;
1581 // sum __HIB seg, with zeros for the stack
1582 src
= (uint8_t *) trunc_page(hibernateBase
);
1583 for (page
= 0; page
< count
; page
++)
1585 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1586 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
1588 restore1Sum
+= 0x00000000;
1593 // write the __HIB seg, with zeros for the stack
1595 src
= (uint8_t *) trunc_page(hibernateBase
);
1596 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1599 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1600 if (kIOReturnSuccess
!= err
)
1603 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1605 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1607 if (kIOReturnSuccess
!= err
)
1609 src
= &gIOHibernateRestoreStackEnd
[0];
1610 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1613 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1614 if (kIOReturnSuccess
!= err
)
1618 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1620 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(AES_BLOCK_SIZE
- 1));
1621 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1622 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1625 // write the preview buffer
1627 if (vars
->previewBuffer
)
1633 phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
);
1634 pageAndCount
[0] = atop_64(phys64
);
1635 pageAndCount
[1] = atop_32(segLen
);
1636 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1637 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1639 if (kIOReturnSuccess
!= err
)
1642 ppnum
+= sizeof(pageAndCount
);
1645 if (kIOReturnSuccess
!= err
)
1648 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1650 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
1652 count
= vars
->previewBuffer
->getLength();
1654 header
->previewPageListSize
= ppnum
;
1655 header
->previewSize
= count
+ ppnum
;
1657 for (page
= 0; page
< count
; page
+= page_size
)
1659 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
1660 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
1662 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1663 if (kIOReturnSuccess
!= err
)
1667 // mark areas for no save
1668 IOMemoryDescriptor
* ioBuffer
;
1669 ioBuffer
= IOPolledFileGetIOBuffer(vars
->fileVars
);
1671 (phys64
= ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1674 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1675 atop_64(phys64
), atop_32(segLen
),
1676 kIOHibernatePageStateFree
);
1677 pageCount
-= atop_32(segLen
);
1681 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1684 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1685 atop_64(phys64
), atop_32(segLen
),
1686 kIOHibernatePageStateFree
);
1687 pageCount
-= atop_32(segLen
);
1690 // copy out bitmap of pages available for trashing during restore
1692 bitmap_size
= vars
->page_list_wired
->list_size
;
1693 src
= (uint8_t *) vars
->page_list_wired
;
1694 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, bitmap_size
, cryptvars
);
1695 if (kIOReturnSuccess
!= err
)
1698 // mark more areas for no save, but these are not available
1699 // for trashing during restore
1701 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
1704 page
= atop_32(KERNEL_IMAGE_TO_PHYS(hibernateBase
));
1705 count
= atop_32(round_page(KERNEL_IMAGE_TO_PHYS(hibernateEnd
))) - page
;
1706 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1708 kIOHibernatePageStateFree
);
1711 if (vars
->previewBuffer
) for (count
= 0;
1712 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1715 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1716 atop_64(phys64
), atop_32(segLen
),
1717 kIOHibernatePageStateFree
);
1718 pageCount
-= atop_32(segLen
);
1722 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1725 hibernate_set_page_state(vars
->page_list
, vars
->page_list_wired
,
1726 atop_64(phys64
), atop_32(segLen
),
1727 kIOHibernatePageStateFree
);
1728 pageCount
-= atop_32(segLen
);
1731 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1732 compressed
= src
+ page_size
;
1733 scratch
= compressed
+ page_size
;
1738 HIBLOG("bitmap_size 0x%x, previewSize 0x%x, writing %d pages @ 0x%llx\n",
1739 bitmap_size
, header
->previewSize
,
1740 pageCount
, vars
->fileVars
->position
);
1747 kWiredEncrypt
= kWired
| kEncrypt
,
1748 kWiredClear
= kWired
,
1749 kUnwiredEncrypt
= kEncrypt
1752 bool cpuAES
= (0 != (CPUID_FEATURE_AES
& cpuid_features()));
1753 #define _pmap_is_noencrypt(x) (cpuAES ? false : pmap_is_noencrypt((x)))
1755 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
1757 if (kUnwiredEncrypt
== pageType
)
1759 // start unwired image
1760 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
1762 vars
->fileVars
->encryptStart
= (vars
->fileVars
->position
& ~(((uint64_t)AES_BLOCK_SIZE
) - 1));
1763 vars
->fileVars
->encryptEnd
= UINT64_MAX
;
1764 HIBLOG("encryptStart %qx\n", vars
->fileVars
->encryptStart
);
1766 bcopy(&cryptvars
->aes_iv
[0],
1767 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1768 sizeof(cryptvars
->aes_iv
));
1769 cryptvars
= &gIOHibernateCryptWakeContext
;
1771 for (iterDone
= false, ppnum
= 0; !iterDone
; )
1773 count
= hibernate_page_list_iterate((kWired
& pageType
)
1774 ? vars
->page_list_wired
: vars
->page_list
,
1776 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1779 if (count
&& (kWired
& pageType
) && needEncrypt
)
1781 uint32_t checkIndex
;
1782 for (checkIndex
= 0;
1783 (checkIndex
< count
)
1784 && (((kEncrypt
& pageType
) == 0) == _pmap_is_noencrypt(ppnum
+ checkIndex
));
1797 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
1798 case kWiredClear
: wiredPagesClear
+= count
; break;
1799 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
1802 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
1805 pageAndCount
[0] = ppnum
;
1806 pageAndCount
[1] = count
;
1807 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1808 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1810 if (kIOReturnSuccess
!= err
)
1814 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
1816 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
1819 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
1823 sum
= hibernate_sum_page(src
, page
);
1824 if (kWired
& pageType
)
1829 clock_get_uptime(&startTime
);
1830 wkresult
= WKdm_compress_new((const WK_word
*) src
,
1831 (WK_word
*) compressed
,
1835 clock_get_uptime(&endTime
);
1836 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1837 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1839 compBytes
+= page_size
;
1840 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
1842 if (pageCompressedSize
== 0)
1844 pageCompressedSize
= 4;
1847 if (*(uint32_t *)src
)
1854 if (pageCompressedSize
!= page_size
)
1860 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1861 err
= IOHibernatePolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1862 if (kIOReturnSuccess
!= err
)
1865 err
= IOHibernatePolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1866 if (kIOReturnSuccess
!= err
)
1869 compressedSize
+= pageCompressedSize
;
1870 uncompressedSize
+= page_size
;
1873 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
1875 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
1876 if (blob
!= lastBlob
)
1878 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
1882 if (0 == (8191 & pagesDone
))
1884 clock_get_uptime(&endTime
);
1885 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1886 absolutetime_to_nanoseconds(endTime
, &nsec
);
1887 progressStamp
= nsec
/ 750000000ULL;
1888 if (progressStamp
!= lastProgressStamp
)
1890 lastProgressStamp
= progressStamp
;
1891 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1895 if (kIOReturnSuccess
!= err
)
1900 if (kIOReturnSuccess
!= err
)
1903 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
)
1905 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
1906 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
1909 if (kWiredEncrypt
!= pageType
)
1911 // end of image1/2 - fill to next block
1912 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1913 if (kIOReturnSuccess
!= err
)
1916 if (kWiredClear
== pageType
)
1918 // enlarge wired image for test
1919 // err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
1922 header
->encryptStart
= vars
->fileVars
->encryptStart
;
1923 header
->encryptEnd
= vars
->fileVars
->encryptEnd
;
1924 image1Size
= vars
->fileVars
->position
;
1925 HIBLOG("image1Size 0x%qx, encryptStart1 0x%qx, End1 0x%qx\n",
1926 image1Size
, header
->encryptStart
, header
->encryptEnd
);
1929 if (kIOReturnSuccess
!= err
)
1931 if (kIOReturnOverrun
== err
)
1933 // update actual compression ratio on not enough space (for retry)
1934 gIOHibernateCompression
= (compressedSize
<< 8) / uncompressedSize
;
1937 // update partial amount written (for IOPolledFileClose cleanup/unmap)
1938 header
->imageSize
= vars
->fileVars
->position
;
1944 header
->imageSize
= vars
->fileVars
->position
;
1945 header
->image1Size
= image1Size
;
1946 header
->bitmapSize
= bitmap_size
;
1947 header
->pageCount
= pageCount
;
1949 header
->restore1Sum
= restore1Sum
;
1950 header
->image1Sum
= sum1
;
1951 header
->image2Sum
= sum2
;
1952 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
1954 header
->compression
= (compressedSize
<< 8) / uncompressedSize
;
1955 gIOHibernateCompression
= header
->compression
;
1957 count
= vars
->fileVars
->fileExtents
->getLength();
1958 if (count
> sizeof(header
->fileExtentMap
))
1960 header
->fileExtentMapSize
= count
;
1961 count
= sizeof(header
->fileExtentMap
);
1964 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1965 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1967 header
->deviceBase
= vars
->fileVars
->block0
;
1968 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
1970 IOPolledFileSeek(vars
->fileVars
, 0);
1971 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1972 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1974 if (kIOReturnSuccess
!= err
)
1976 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1980 clock_get_uptime(&endTime
);
1982 IOService::getPMRootDomain()->pmStatsRecordEvent(
1983 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
1985 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1986 absolutetime_to_nanoseconds(endTime
, &nsec
);
1987 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
1989 absolutetime_to_nanoseconds(compTime
, &nsec
);
1990 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
1993 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
1995 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
1996 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
1997 vars
->fileVars
->cryptBytes
,
1999 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2001 HIBLOG("\nimage %qd (%lld%%), uncompressed %qd (%d), compressed %qd (%d%%), sum1 %x, sum2 %x\n",
2002 header
->imageSize
, (header
->imageSize
* 100) / vars
->fileVars
->fileSize
,
2003 uncompressedSize
, atop_32(uncompressedSize
), compressedSize
,
2004 uncompressedSize
? ((int) ((compressedSize
* 100ULL) / uncompressedSize
)) : 0,
2007 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2008 svPageCount
, zvPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
2011 IOPolledFilePollersClose(vars
->fileVars
, (kIOReturnSuccess
== err
) ? kIOPolledBeforeSleepState
: kIOPolledBeforeSleepStateAborted
);
2013 if (vars
->consoleMapping
)
2014 ProgressUpdate(gIOHibernateGraphicsInfo
,
2015 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2017 HIBLOG("hibernate_write_image done(%x)\n", err
);
2019 // should we come back via regular wake, set the state in memory.
2020 gIOHibernateState
= kIOHibernateStateInactive
;
2022 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
,
2023 wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
, 0, 0);
2025 if (kIOReturnSuccess
== err
)
2027 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2029 return (kIOHibernatePostWriteSleep
);
2031 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2033 return (kIOHibernatePostWriteRestart
);
2037 /* by default, power down */
2038 return (kIOHibernatePostWriteHalt
);
2041 else if (kIOReturnAborted
== err
)
2043 return (kIOHibernatePostWriteWake
);
2047 /* on error, sleep */
2048 return (kIOHibernatePostWriteSleep
);
2052 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2055 hibernate_machine_init(void)
2060 uint32_t pagesRead
= 0;
2061 AbsoluteTime startTime
, compTime
;
2062 AbsoluteTime allTime
, endTime
;
2063 AbsoluteTime startIOTime
, endIOTime
;
2064 uint64_t nsec
, nsecIO
;
2066 uint32_t lastProgressStamp
= 0;
2067 uint32_t progressStamp
;
2068 IOPolledFileCryptVars
* cryptvars
= 0;
2070 IOHibernateVars
* vars
= &gIOHibernateVars
;
2071 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
2073 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
2076 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2077 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2079 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2081 HIBLOG("regular wake\n");
2085 HIBPRINT("diag %x %x %x %x\n",
2086 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2087 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
2089 #define t40ms(x) (tmrCvt((((uint64_t)(x)) << 8), tscFCvtt2n) / 1000000)
2090 #define tStat(x, y) gIOHibernateStats->x = t40ms(gIOHibernateCurrentHeader->y);
2091 tStat(booterStart
, booterStart
);
2092 gIOHibernateStats
->smcStart
= gIOHibernateCurrentHeader
->smcStart
;
2093 tStat(booterDuration0
, booterTime0
);
2094 tStat(booterDuration1
, booterTime1
);
2095 tStat(booterDuration2
, booterTime2
);
2096 tStat(booterDuration
, booterTime
);
2097 tStat(booterConnectDisplayDuration
, connectDisplayTime
);
2098 tStat(booterSplashDuration
, splashTime
);
2099 tStat(trampolineDuration
, trampolineTime
);
2101 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
2102 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
2103 gIOHibernateStats
->image1Pages
= pagesDone
;
2105 HIBLOG("booter start at %d ms smc %d ms, [%d, %d, %d] total %d ms, dsply %d, %d ms, tramp %d ms\n",
2106 gIOHibernateStats
->booterStart
,
2107 gIOHibernateStats
->smcStart
,
2108 gIOHibernateStats
->booterDuration0
,
2109 gIOHibernateStats
->booterDuration1
,
2110 gIOHibernateStats
->booterDuration2
,
2111 gIOHibernateStats
->booterDuration
,
2112 gIOHibernateStats
->booterConnectDisplayDuration
,
2113 gIOHibernateStats
->booterSplashDuration
,
2114 gIOHibernateStats
->trampolineDuration
);
2116 HIBLOG("hibernate_machine_init: state %d, image pages %d, sum was %x, imageSize 0x%qx, image1Size 0x%qx, conflictCount %d, nextFree %x\n",
2117 gIOHibernateState
, pagesDone
, sum
, gIOHibernateStats
->imageSize
, gIOHibernateStats
->image1Size
,
2118 gIOHibernateCurrentHeader
->conflictCount
, gIOHibernateCurrentHeader
->nextFree
);
2120 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
2121 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)))
2123 hibernate_page_list_discard(vars
->page_list
);
2126 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2128 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
2129 panic("handoff overflow");
2131 IOHibernateHandoff
* handoff
;
2133 bool foundCryptData
= false;
2135 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2137 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2139 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2140 uint8_t * data
= &handoff
->data
[0];
2141 switch (handoff
->type
)
2143 case kIOHibernateHandoffTypeEnd
:
2147 case kIOHibernateHandoffTypeGraphicsInfo
:
2148 if (handoff
->bytecount
== sizeof(*gIOHibernateGraphicsInfo
))
2150 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2154 case kIOHibernateHandoffTypeCryptVars
:
2157 hibernate_cryptwakevars_t
*
2158 wakevars
= (hibernate_cryptwakevars_t
*) &handoff
->data
[0];
2159 bcopy(&wakevars
->aes_iv
[0], &cryptvars
->aes_iv
[0], sizeof(cryptvars
->aes_iv
));
2161 foundCryptData
= true;
2162 bzero(data
, handoff
->bytecount
);
2165 case kIOHibernateHandoffTypeMemoryMap
:
2167 clock_get_uptime(&allTime
);
2169 hibernate_newruntime_map(data
, handoff
->bytecount
,
2170 gIOHibernateCurrentHeader
->systemTableOffset
);
2172 clock_get_uptime(&endTime
);
2174 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2175 absolutetime_to_nanoseconds(endTime
, &nsec
);
2177 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
2181 case kIOHibernateHandoffTypeDeviceTree
:
2183 // DTEntry chosen = NULL;
2184 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2189 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2193 if (cryptvars
&& !foundCryptData
)
2194 panic("hibernate handoff");
2196 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2197 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2198 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2200 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
2202 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2203 * gIOHibernateGraphicsInfo
->rowBytes
);
2204 if (vars
->videoMapSize
> vars
->videoAllocSize
) vars
->videoMapSize
= 0;
2207 IOMapPages(kernel_map
,
2208 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2209 vars
->videoMapSize
, kIOMapInhibitCache
);
2213 if (vars
->videoMapSize
)
2214 ProgressUpdate(gIOHibernateGraphicsInfo
,
2215 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
2217 uint8_t * src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
2218 uint8_t * compressed
= src
+ page_size
;
2219 uint8_t * scratch
= compressed
+ page_size
;
2220 uint32_t decoOffset
;
2222 clock_get_uptime(&allTime
);
2223 AbsoluteTime_to_scalar(&compTime
) = 0;
2226 HIBLOG("IOPolledFilePollersOpen(), ml_get_interrupts_enabled %d\n", ml_get_interrupts_enabled());
2227 err
= IOPolledFilePollersOpen(vars
->fileVars
, kIOPolledAfterSleepState
, false);
2228 clock_get_uptime(&startIOTime
);
2229 endTime
= startIOTime
;
2230 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2231 absolutetime_to_nanoseconds(endTime
, &nsec
);
2232 HIBLOG("IOPolledFilePollersOpen(%x) %qd ms\n", err
, nsec
/ 1000000ULL);
2234 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
2236 // kick off the read ahead
2237 vars
->fileVars
->bufferHalf
= 0;
2238 vars
->fileVars
->bufferLimit
= 0;
2239 vars
->fileVars
->lastRead
= 0;
2240 vars
->fileVars
->readEnd
= gIOHibernateCurrentHeader
->imageSize
;
2241 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2242 vars
->fileVars
->cryptBytes
= 0;
2243 AbsoluteTime_to_scalar(&vars
->fileVars
->cryptTime
) = 0;
2245 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2246 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2249 HIBLOG("hibernate_machine_init reading\n");
2251 uint32_t * header
= (uint32_t *) src
;
2254 while (kIOReturnSuccess
== err
)
2259 vm_offset_t ppnum
, compressedSize
;
2261 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2262 if (kIOReturnSuccess
!= err
)
2268 // HIBPRINT("(%x, %x)\n", ppnum, count);
2273 for (page
= 0; page
< count
; page
++)
2275 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2276 if (kIOReturnSuccess
!= err
)
2279 compressedSize
= kIOHibernateTagLength
& tag
;
2280 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2282 err
= kIOReturnIPCError
;
2286 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2287 if (kIOReturnSuccess
!= err
) break;
2289 if (compressedSize
< page_size
)
2291 decoOffset
= page_size
;
2292 clock_get_uptime(&startTime
);
2294 if (compressedSize
== 4) {
2298 s
= (uint32_t *)src
;
2299 d
= (uint32_t *)(uintptr_t)compressed
;
2301 for (i
= 0; i
< (int)(PAGE_SIZE
/ sizeof(int32_t)); i
++)
2305 WKdm_decompress_new((WK_word
*) src
, (WK_word
*) compressed
, (WK_word
*) scratch
, compressedSize
);
2306 clock_get_uptime(&endTime
);
2307 ADD_ABSOLUTETIME(&compTime
, &endTime
);
2308 SUB_ABSOLUTETIME(&compTime
, &startTime
);
2309 compBytes
+= page_size
;
2311 else decoOffset
= 0;
2313 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
2314 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2317 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2325 if (0 == (8191 & pagesDone
))
2327 clock_get_uptime(&endTime
);
2328 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2329 absolutetime_to_nanoseconds(endTime
, &nsec
);
2330 progressStamp
= nsec
/ 750000000ULL;
2331 if (progressStamp
!= lastProgressStamp
)
2333 lastProgressStamp
= progressStamp
;
2334 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2335 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2340 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
2341 err
= kIOReturnLockedRead
;
2343 if (kIOReturnSuccess
!= err
)
2344 panic("Hibernate restore error %x", err
);
2346 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2347 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
2349 clock_get_uptime(&endIOTime
);
2351 err
= IOPolledFilePollersClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2353 clock_get_uptime(&endTime
);
2355 IOService::getPMRootDomain()->pmStatsRecordEvent(
2356 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2357 IOService::getPMRootDomain()->pmStatsRecordEvent(
2358 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2360 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2361 absolutetime_to_nanoseconds(endTime
, &nsec
);
2363 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
2364 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
2366 gIOHibernateStats
->kernelImageReadDuration
= nsec
/ 1000000ULL;
2367 gIOHibernateStats
->imagePages
= pagesDone
;
2369 HIBLOG("hibernate_machine_init pagesDone %d sum2 %x, time: %d ms, disk(0x%x) %qd Mb/s, ",
2370 pagesDone
, sum
, gIOHibernateStats
->kernelImageReadDuration
, kDefaultIOSize
,
2371 nsecIO
? ((((gIOHibernateCurrentHeader
->imageSize
- gIOHibernateCurrentHeader
->image1Size
) * 1000000000ULL) / 1024 / 1024) / nsecIO
) : 0);
2373 absolutetime_to_nanoseconds(compTime
, &nsec
);
2374 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2377 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2379 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2380 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2381 vars
->fileVars
->cryptBytes
,
2383 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2385 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 2) | DBG_FUNC_NONE
, pagesRead
, pagesDone
, 0, 0, 0);
2388 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2390 void IOHibernateSetWakeCapabilities(uint32_t capability
)
2392 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2394 gIOHibernateStats
->wakeCapability
= capability
;
2396 if (kIOPMSystemCapabilityGraphics
& capability
)
2398 vm_compressor_do_warmup();
2403 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2405 void IOHibernateSystemRestart(void)
2407 static uint8_t noteStore
[32] __attribute__((aligned(32)));
2408 IORegistryEntry
* regEntry
;
2409 const OSSymbol
* sym
;
2412 uintptr_t * smcVars
;
2417 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
2420 smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
2421 smcBytes
= (typeof(smcBytes
)) smcVars
[1];
2423 if (len
> sizeof(noteStore
)) len
= sizeof(noteStore
);
2424 noteProp
= OSData::withCapacity(3 * sizeof(element
));
2425 if (!noteProp
) return;
2427 noteProp
->appendBytes(&element
, sizeof(element
));
2428 element
= crc32(0, smcBytes
, len
);
2429 noteProp
->appendBytes(&element
, sizeof(element
));
2431 bcopy(smcBytes
, noteStore
, len
);
2432 element
= (addr64_t
) ¬eStore
[0];
2433 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
2434 noteProp
->appendBytes(&element
, sizeof(element
));
2436 if (!gIOOptionsEntry
)
2438 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2439 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
2440 if (regEntry
&& !gIOOptionsEntry
)
2441 regEntry
->release();
2444 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
2445 if (gIOOptionsEntry
&& sym
) gIOOptionsEntry
->setProperty(sym
, noteProp
);
2446 if (noteProp
) noteProp
->release();
2447 if (sym
) sym
->release();