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 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
;
235 static IOReturn
IOHibernateDone(IOHibernateVars
* vars
);
236 static IOReturn
IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
);
237 static void IOSetBootImageNVRAM(OSData
* data
);
239 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
241 enum { kDefaultIOSize
= 128 * 1024 };
242 enum { kVideoMapSize
= 80 * 1024 * 1024 };
244 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
246 // copy from phys addr to MD
249 IOMemoryDescriptorWriteFromPhysical(IOMemoryDescriptor
* md
,
250 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
252 addr64_t srcAddr
= bytes
;
253 IOByteCount remaining
;
255 remaining
= length
= min(length
, md
->getLength() - offset
);
256 while (remaining
) { // (process another target segment?)
260 dstAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
264 // Clip segment length to remaining
265 if (dstLen
> remaining
)
269 bcopy_phys(srcAddr
, dstAddr64
, dstLen
);
271 copypv(srcAddr
, dstAddr64
, dstLen
,
272 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
281 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
284 // copy from MD to phys addr
287 IOMemoryDescriptorReadToPhysical(IOMemoryDescriptor
* md
,
288 IOByteCount offset
, addr64_t bytes
, IOByteCount length
)
290 addr64_t dstAddr
= bytes
;
291 IOByteCount remaining
;
293 remaining
= length
= min(length
, md
->getLength() - offset
);
294 while (remaining
) { // (process another target segment?)
298 srcAddr64
= md
->getPhysicalSegment(offset
, &dstLen
, kIOMemoryMapperNone
);
302 // Clip segment length to remaining
303 if (dstLen
> remaining
)
307 bcopy_phys(srcAddr64
, dstAddr
, dstLen
);
309 copypv(srcAddr
, dstAddr64
, dstLen
,
310 cppvPsnk
| cppvFsnk
| cppvNoRefSrc
| cppvNoModSnk
| cppvKmap
);
319 return remaining
? kIOReturnUnderrun
: kIOReturnSuccess
;
322 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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
)
331 case kIOHibernatePageStateUnwiredSave
:
333 for (; ppnum
< count
; ppnum
++)
335 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
336 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
339 case kIOHibernatePageStateWiredSave
:
341 for (; ppnum
< count
; ppnum
++)
343 hibernate_page_bitset(page_list
, FALSE
, ppnum
);
344 hibernate_page_bitset(page_list_wired
, FALSE
, ppnum
);
347 case kIOHibernatePageStateFree
:
349 for (; ppnum
< count
; ppnum
++)
351 hibernate_page_bitset(page_list
, TRUE
, ppnum
);
352 hibernate_page_bitset(page_list_wired
, TRUE
, ppnum
);
356 panic("hibernate_set_page_state");
361 hibernate_page_list_iterate(hibernate_page_list_t
* list
, vm_offset_t
* pPage
)
363 uint32_t page
= *pPage
;
365 hibernate_bitmap_t
* bitmap
;
367 while ((bitmap
= hibernate_page_bitmap_pin(list
, &page
)))
369 count
= hibernate_page_bitmap_count(bitmap
, TRUE
, page
);
373 if (page
<= bitmap
->last_page
)
379 count
= hibernate_page_bitmap_count(bitmap
, FALSE
, page
);
386 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
389 IOHibernateSystemSleep(void)
396 bool dsSSD
, vmflush
, swapPinned
;
397 IOHibernateVars
* vars
;
398 uint64_t setFileSize
= 0;
400 gIOHibernateState
= kIOHibernateStateInactive
;
402 gIOHibernateDebugFlags
= 0;
403 if (kIOLogHibernate
& gIOKitDebug
)
404 gIOHibernateDebugFlags
|= kIOHibernateDebugRestoreLogs
;
406 if (IOService::getPMRootDomain()->getHibernateSettings(
407 &gIOHibernateMode
, &gIOHibernateFreeRatio
, &gIOHibernateFreeTime
))
409 if (kIOHibernateModeSleep
& gIOHibernateMode
)
410 // default to discard clean for safe sleep
411 gIOHibernateMode
^= (kIOHibernateModeDiscardCleanInactive
412 | kIOHibernateModeDiscardCleanActive
);
415 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileKey
)))
417 if ((str
= OSDynamicCast(OSString
, obj
)))
418 strlcpy(gIOHibernateFilename
, str
->getCStringNoCopy(),
419 sizeof(gIOHibernateFilename
));
423 if (!gIOHibernateMode
|| !gIOHibernateFilename
[0])
424 return (kIOReturnUnsupported
);
426 HIBLOG("hibernate image path: %s\n", gIOHibernateFilename
);
428 vars
= IONew(IOHibernateVars
, 1);
429 if (!vars
) return (kIOReturnNoMemory
);
430 bzero(vars
, sizeof(*vars
));
433 if (!gIOHibernateTrimCalloutEntry
)
435 gIOHibernateTrimCalloutEntry
= thread_call_allocate(&IOHibernateSystemPostWakeTrim
, &gFSLock
);
437 IOHibernateSystemPostWakeTrim(NULL
, NULL
);
438 if (kFSIdle
!= gFSState
)
440 HIBLOG("hibernate file busy\n");
441 IOLockUnlock(gFSLock
);
442 IODelete(vars
, IOHibernateVars
, 1);
443 return (kIOReturnBusy
);
445 gFSState
= kFSOpening
;
446 IOLockUnlock(gFSLock
);
451 vars
->srcBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
452 2 * page_size
+ WKdm_SCRATCH_BUF_SIZE_INTERNAL
, page_size
);
454 vars
->handoffBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn
,
455 ptoa_64(gIOHibernateHandoffPageCount
), page_size
);
457 if (!vars
->srcBuffer
|| !vars
->handoffBuffer
)
459 err
= kIOReturnNoMemory
;
463 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMinSizeKey
)))
465 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMinSize
= num
->unsigned64BitValue();
468 if ((obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernateFileMaxSizeKey
)))
470 if ((num
= OSDynamicCast(OSNumber
, obj
))) vars
->fileMaxSize
= num
->unsigned64BitValue();
474 boolean_t encryptedswap
= true;
476 AbsoluteTime startTime
, endTime
;
479 bzero(gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
));
480 gIOHibernateCurrentHeader
->debugFlags
= gIOHibernateDebugFlags
;
481 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
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;
489 err
= hibernate_pin_swap(TRUE
);
490 if (KERN_SUCCESS
!= err
) break;
493 if (vars
->fileMinSize
|| (kIOHibernateModeFileResize
& gIOHibernateMode
))
495 hibernate_page_list_setall(vars
->page_list
,
496 vars
->page_list_wired
,
498 true /* preflight */,
499 vmflush
/* discard */,
501 PE_Video consoleInfo
;
502 bzero(&consoleInfo
, sizeof(consoleInfo
));
503 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
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));
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
);
517 if (!(kIOHibernateModeFileResize
& gIOHibernateMode
)
518 && (setFileSize
< vars
->fileMinSize
))
520 setFileSize
= vars
->fileMinSize
;
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);
531 IOLockUnlock(gDebugImageLock
);
534 err
= IOPolledFileOpen(gIOHibernateFilename
, setFileSize
, 0,
535 gIOHibernateCurrentHeader
, sizeof(gIOHibernateCurrentHeader
),
536 &vars
->fileVars
, &nvramData
,
537 &vars
->volumeCryptKey
[0], sizeof(vars
->volumeCryptKey
));
539 if (KERN_SUCCESS
!= err
)
542 if (kFSOpening
!= gFSState
) err
= kIOReturnTimeout
;
543 IOLockUnlock(gFSLock
);
546 if (KERN_SUCCESS
!= err
)
548 HIBLOG("IOPolledFileOpen(%x)\n", err
);
552 // write extents for debug data usage in EFI
553 IOWriteExtentsToFile(vars
->fileVars
, kIOHibernateHeaderOpenSignature
);
555 err
= IOPolledFilePollersSetup(vars
->fileVars
, kIOPolledPreflightState
);
556 if (KERN_SUCCESS
!= err
) break;
558 clock_get_uptime(&startTime
);
559 err
= hibernate_setup(gIOHibernateCurrentHeader
,
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
);
566 boolean_t haveSwapPin
, hibFileSSD
;
567 haveSwapPin
= vm_swap_files_pinned();
569 hibFileSSD
= (kIOPolledFileSSD
& vars
->fileVars
->flags
);
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;
576 gIOHibernateStandbyDisabled
= ((!haveSwapPin
|| !hibFileSSD
));
578 dsSSD
= ((0 != (kIOPolledFileSSD
& vars
->fileVars
->flags
))
579 && (kOSBooleanTrue
== IOService::getPMRootDomain()->getProperty(kIOPMDeepSleepEnabledKey
)));
581 if (dsSSD
) gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionSSD
| kIOHibernateOptionColor
;
582 else gIOHibernateCurrentHeader
->options
|= kIOHibernateOptionProgress
;
585 #if defined(__i386__) || defined(__x86_64__)
586 if (!uuid_is_null(vars
->volumeCryptKey
) &&
587 (kOSBooleanTrue
!= IOService::getPMRootDomain()->getProperty(kIOPMDestroyFVKeyOnStandbyKey
)))
589 uintptr_t smcVars
[2];
590 smcVars
[0] = sizeof(vars
->volumeCryptKey
);
591 smcVars
[1] = (uintptr_t)(void *) &gIOHibernateVars
.volumeCryptKey
[0];
593 IOService::getPMRootDomain()->setProperty(kIOHibernateSMCVariablesKey
, smcVars
, sizeof(smcVars
));
594 bzero(smcVars
, sizeof(smcVars
));
599 if (encryptedswap
|| !uuid_is_null(vars
->volumeCryptKey
))
600 gIOHibernateMode
^= kIOHibernateModeEncrypt
;
602 if (kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
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;
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();
617 IOSetBootImageNVRAM(nvramData
);
618 nvramData
->release();
620 #if defined(__i386__) || defined(__x86_64__)
622 struct AppleRTCHibernateVars
624 uint8_t signature
[4];
626 uint8_t booterSignature
[20];
627 uint8_t wiredCryptKey
[16];
629 AppleRTCHibernateVars rtcVars
;
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])
643 (c
= gIOHibernateBootSignature
[i
]) && (i
< (sizeof(rtcVars
.booterSignature
) << 1));
646 if (c
>= 'a') c
-= 'a' - 10;
647 else if (c
>= 'A') c
-= 'A' - 10;
648 else if (c
>= '0') c
-= '0';
650 value
= (value
<< 4) | c
;
651 if (i
& 1) rtcVars
.booterSignature
[i
>> 1] = value
;
654 data
= OSData::withBytes(&rtcVars
, sizeof(rtcVars
));
657 if (gIOHibernateRTCVariablesKey
)
658 IOService::getPMRootDomain()->setProperty(gIOHibernateRTCVariablesKey
, data
);
663 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOHibernateMachineSignatureKey
));
664 if (data
) gIOHibernateCurrentHeader
->machineSignature
= *((UInt32
*)data
->getBytesNoCopy());
666 if (!gIOHibernateBoot0082Data
)
668 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty("boot-device-path"));
671 // AppleNVRAM_EFI_LOAD_OPTION
674 uint16_t FilePathLength
;
677 loadOptionHeader
.Attributes
= 1;
678 loadOptionHeader
.FilePathLength
= data
->getLength();
679 loadOptionHeader
.Desc
= 0;
680 gIOHibernateBoot0082Data
= OSData::withCapacity(sizeof(loadOptionHeader
) + loadOptionHeader
.FilePathLength
);
681 if (gIOHibernateBoot0082Data
)
683 gIOHibernateBoot0082Data
->appendBytes(&loadOptionHeader
, sizeof(loadOptionHeader
));
684 gIOHibernateBoot0082Data
->appendBytes(data
);
688 if (!gIOHibernateBootNextData
)
690 uint16_t bits
= 0x0082;
691 gIOHibernateBootNextData
= OSData::withBytes(&bits
, sizeof(bits
));
693 if (gIOHibernateBoot0082Key
&& gIOHibernateBoot0082Data
&& gIOHibernateBootNextKey
&& gIOHibernateBootNextData
)
695 gIOHibernateBootNextSave
= gIOOptionsEntry
->copyProperty(gIOHibernateBootNextKey
);
696 gIOOptionsEntry
->setProperty(gIOHibernateBoot0082Key
, gIOHibernateBoot0082Data
);
697 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextData
);
702 #endif /* !i386 && !x86_64 */
706 if (swapPinned
) hibernate_pin_swap(FALSE
);
709 if ((kIOReturnSuccess
== err
) && (kFSOpening
!= gFSState
))
711 HIBLOG("hibernate file close due timeout\n");
712 err
= kIOReturnTimeout
;
714 if (kIOReturnSuccess
== err
)
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
;
726 IOPolledFileIOVars
* fileVars
= vars
->fileVars
;
727 IOHibernateDone(vars
);
728 IOPolledFileClose(&fileVars
,
732 0, NULL
, 0, sizeof(IOHibernateImageHeader
), setFileSize
);
736 IOLockUnlock(gFSLock
);
738 if (vars
->fileVars
) IODelete(vars
->fileVars
, IOPolledFileIOVars
, 1);
739 IODelete(vars
, IOHibernateVars
, 1);
744 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
747 IOSetBootImageNVRAM(OSData
* data
)
749 IORegistryEntry
* regEntry
;
751 if (!gIOOptionsEntry
)
753 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
754 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
755 if (regEntry
&& !gIOOptionsEntry
)
758 if (gIOOptionsEntry
&& gIOHibernateBootImageKey
)
760 if (data
) gIOOptionsEntry
->setProperty(gIOHibernateBootImageKey
, data
);
763 gIOOptionsEntry
->removeProperty(gIOHibernateBootImageKey
);
764 gIOOptionsEntry
->sync();
769 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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.
775 IOWriteExtentsToFile(IOPolledFileIOVars
* vars
, uint32_t signature
)
777 IOHibernateImageHeader hdr
;
779 IOReturn err
= kIOReturnSuccess
;
781 IOPolledFileExtent
* fileExtents
;
783 fileExtents
= (typeof(fileExtents
)) vars
->fileExtents
->getBytesNoCopy();
785 memset(&hdr
, 0, sizeof(IOHibernateImageHeader
));
786 count
= vars
->fileExtents
->getLength();
787 if (count
> sizeof(hdr
.fileExtentMap
))
789 hdr
.fileExtentMapSize
= count
;
790 count
= sizeof(hdr
.fileExtentMap
);
793 hdr
.fileExtentMapSize
= sizeof(hdr
.fileExtentMap
);
795 bcopy(fileExtents
, &hdr
.fileExtentMap
[0], count
);
797 // copy file block extent list if larger than header
798 if (hdr
.fileExtentMapSize
> sizeof(hdr
.fileExtentMap
))
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
);
805 HIBLOG("kern_write_file returned %d\n", rc
);
806 err
= kIOReturnIOError
;
810 hdr
.signature
= signature
;
811 hdr
.deviceBlockSize
= vars
->blockSize
;
813 rc
= kern_write_file(vars
->fileRef
, 0, (char *)&hdr
, sizeof(hdr
), IO_SKIP_ENCRYPTION
);
815 HIBLOG("kern_write_file returned %d\n", rc
);
816 err
= kIOReturnIOError
;
824 extern "C" boolean_t root_is_CF_drive
;
827 IOOpenDebugDataFile(const char *fname
, uint64_t size
)
830 OSData
* imagePath
= NULL
;
833 if (!gDebugImageLock
) {
834 gDebugImageLock
= IOLockAlloc();
837 if (root_is_CF_drive
) return;
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");
845 if (gDebugImageFileVars
|| !fname
|| !size
) {
846 HIBLOG("IOOpenDebugDataFile: conditions failed\n");
850 padding
= (PAGE_SIZE
*2); // allocate couple more pages for header and fileextents
851 err
= IOPolledFileOpen(fname
, size
+padding
, 32ULL*1024*1024*1024,
853 &gDebugImageFileVars
, &imagePath
, NULL
, 0);
855 if ((kIOReturnSuccess
== err
) && imagePath
)
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");
865 // write extents for debug data usage in EFI
866 IOWriteExtentsToFile(gDebugImageFileVars
, kIOHibernateHeaderOpenSignature
);
867 IOSetBootImageNVRAM(imagePath
);
871 IOLockUnlock(gDebugImageLock
);
873 if (imagePath
) imagePath
->release();
878 IOCloseDebugDataFile()
880 IOSetBootImageNVRAM(0);
882 if (gDebugImageLock
) {
883 IOLockLock(gDebugImageLock
);
884 if (gDebugImageFileVars
!= 0) {
885 IOPolledFileClose(&gDebugImageFileVars
, 0, 0, 0, 0, 0);
887 IOLockUnlock(gDebugImageLock
);
893 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
895 DECLARE_IOHIBERNATEPROGRESSALPHA
898 ProgressInit(hibernate_graphics_t
* display
, uint8_t * screen
, uint8_t * saveunder
, uint32_t savelen
)
900 uint32_t rowBytes
, pixelShift
;
903 uint32_t alpha
, in
, color
, result
;
905 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
907 rowBytes
= display
->rowBytes
;
908 pixelShift
= display
->depth
>> 4;
909 if (pixelShift
< 1) return;
911 screen
+= ((display
->width
912 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
913 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
915 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
917 out
= screen
+ y
* rowBytes
;
918 for (blob
= 0; blob
< kIOHibernateProgressCount
; blob
++)
920 color
= blob
? kIOHibernateProgressDarkGray
: kIOHibernateProgressMidGray
;
921 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
923 alpha
= gIOHibernateProgressAlpha
[y
][x
];
931 in
= *((uint16_t *)out
) & 0x1f; // 16
932 in
= (in
<< 3) | (in
>> 2);
935 in
= *((uint32_t *)out
) & 0xff; // 32
936 saveunder
[blob
* kIOHibernateProgressSaveUnderSize
+ saveindex
[blob
]++] = in
;
937 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) >> 8;
942 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
945 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
947 out
+= (1 << pixelShift
);
949 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
956 ProgressUpdate(hibernate_graphics_t
* display
, uint8_t * screen
, int32_t firstBlob
, int32_t select
)
958 uint32_t rowBytes
, pixelShift
;
960 int32_t blob
, lastBlob
;
961 uint32_t alpha
, in
, color
, result
;
963 uint32_t saveindex
[kIOHibernateProgressCount
] = { 0 };
965 pixelShift
= display
->depth
>> 4;
969 rowBytes
= display
->rowBytes
;
971 screen
+= ((display
->width
972 - kIOHibernateProgressCount
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << (pixelShift
- 1))
973 + (display
->height
- kIOHibernateProgressOriginY
- kIOHibernateProgressHeight
) * rowBytes
;
975 lastBlob
= (select
< kIOHibernateProgressCount
) ? select
: (kIOHibernateProgressCount
- 1);
977 screen
+= (firstBlob
* (kIOHibernateProgressWidth
+ kIOHibernateProgressSpacing
)) << pixelShift
;
979 for (y
= 0; y
< kIOHibernateProgressHeight
; y
++)
981 out
= screen
+ y
* rowBytes
;
982 for (blob
= firstBlob
; blob
<= lastBlob
; blob
++)
984 color
= (blob
< select
) ? kIOHibernateProgressLightGray
: kIOHibernateProgressMidGray
;
985 for (x
= 0; x
< kIOHibernateProgressWidth
; x
++)
987 alpha
= gIOHibernateProgressAlpha
[y
][x
];
993 in
= display
->progressSaveUnder
[blob
][saveindex
[blob
]++];
994 result
= ((255 - alpha
) * in
+ alpha
* result
+ 0xff) / 255;
999 *((uint16_t *)out
) = (result
<< 10) | (result
<< 5) | result
; // 16
1002 *((uint32_t *)out
) = (result
<< 16) | (result
<< 8) | result
; // 32
1004 out
+= (1 << pixelShift
);
1006 out
+= (kIOHibernateProgressSpacing
<< pixelShift
);
1011 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1014 IOHibernateIOKitSleep(void)
1016 IOReturn ret
= kIOReturnSuccess
;
1017 IOLockLock(gFSLock
);
1018 if (kFSOpening
== gFSState
)
1020 gFSState
= kFSTimedOut
;
1021 HIBLOG("hibernate file open timed out\n");
1022 ret
= kIOReturnTimeout
;
1024 IOLockUnlock(gFSLock
);
1028 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1031 IOHibernateSystemHasSlept(void)
1033 IOReturn ret
= kIOReturnSuccess
;
1034 IOHibernateVars
* vars
= &gIOHibernateVars
;
1038 IOLockLock(gFSLock
);
1039 if ((kFSOpened
!= gFSState
) && gIOHibernateMode
)
1041 ret
= kIOReturnTimeout
;
1043 IOLockUnlock(gFSLock
);
1044 if (kIOReturnSuccess
!= ret
) return (ret
);
1046 if (gIOHibernateMode
) obj
= IOService::getPMRootDomain()->copyProperty(kIOHibernatePreviewBufferKey
);
1047 vars
->previewBuffer
= OSDynamicCast(IOMemoryDescriptor
, obj
);
1048 if (obj
&& !vars
->previewBuffer
)
1051 vars
->consoleMapping
= NULL
;
1052 if (vars
->previewBuffer
&& (kIOReturnSuccess
!= vars
->previewBuffer
->prepare()))
1054 vars
->previewBuffer
->release();
1055 vars
->previewBuffer
= 0;
1058 if ((kIOHibernateOptionProgress
& gIOHibernateCurrentHeader
->options
)
1059 && vars
->previewBuffer
1060 && (data
= OSDynamicCast(OSData
,
1061 IOService::getPMRootDomain()->getProperty(kIOHibernatePreviewActiveKey
))))
1063 UInt32 flags
= *((UInt32
*)data
->getBytesNoCopy());
1064 HIBPRINT("kIOHibernatePreviewActiveKey %08lx\n", (long)flags
);
1066 IOService::getPMRootDomain()->removeProperty(kIOHibernatePreviewActiveKey
);
1068 if (kIOHibernatePreviewUpdates
& flags
)
1070 PE_Video consoleInfo
;
1071 hibernate_graphics_t
* graphicsInfo
= gIOHibernateGraphicsInfo
;
1073 IOService::getPlatform()->getConsoleInfo(&consoleInfo
);
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
;
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
));
1090 if (gIOOptionsEntry
)
1091 gIOOptionsEntry
->sync();
1096 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1098 static DeviceTreeNode
*
1099 MergeDeviceTree(DeviceTreeNode
* entry
, IORegistryEntry
* regEntry
)
1101 DeviceTreeNodeProperty
* prop
;
1102 DeviceTreeNode
* child
;
1103 IORegistryEntry
* childRegEntry
;
1104 const char * nameProp
;
1105 unsigned int propLen
, idx
;
1107 prop
= (DeviceTreeNodeProperty
*) (entry
+ 1);
1108 for (idx
= 0; idx
< entry
->nProperties
; idx
++)
1110 if (regEntry
&& (0 != strcmp("name", prop
->name
)))
1112 regEntry
->setProperty((const char *) prop
->name
, (void *) (prop
+ 1), prop
->length
);
1113 // HIBPRINT("%s: %s, %d\n", regEntry->getName(), prop->name, prop->length);
1115 prop
= (DeviceTreeNodeProperty
*) (((uintptr_t)(prop
+ 1)) + ((prop
->length
+ 3) & ~3));
1118 child
= (DeviceTreeNode
*) prop
;
1119 for (idx
= 0; idx
< entry
->nChildren
; idx
++)
1121 if (kSuccess
!= DTGetProperty(child
, "name", (void **) &nameProp
, &propLen
))
1123 childRegEntry
= regEntry
? regEntry
->childFromPath(nameProp
, gIODTPlane
) : NULL
;
1124 // HIBPRINT("%s == %p\n", nameProp, childRegEntry);
1125 child
= MergeDeviceTree(child
, childRegEntry
);
1131 IOHibernateSystemWake(void)
1133 if (kFSOpened
== gFSState
)
1135 IOPolledFilePollersClose(gIOHibernateVars
.fileVars
, kIOPolledPostflightState
);
1136 IOHibernateDone(&gIOHibernateVars
);
1140 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1141 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1143 return (kIOReturnSuccess
);
1147 IOHibernateDone(IOHibernateVars
* vars
)
1149 hibernate_teardown(vars
->page_list
, vars
->page_list_wired
, vars
->page_list_pal
);
1151 if (vars
->videoMapping
)
1153 if (vars
->videoMapSize
)
1155 IOUnmapPages(kernel_map
, vars
->videoMapping
, vars
->videoMapSize
);
1156 if (vars
->videoAllocSize
)
1158 kmem_free(kernel_map
, trunc_page(vars
->videoMapping
), vars
->videoAllocSize
);
1161 if (vars
->previewBuffer
)
1163 vars
->previewBuffer
->release();
1164 vars
->previewBuffer
= 0;
1167 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1169 IOService::getPMRootDomain()->setProperty(kIOHibernateOptionsKey
,
1170 gIOHibernateCurrentHeader
->options
, 32);
1174 IOService::getPMRootDomain()->removeProperty(kIOHibernateOptionsKey
);
1177 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1178 && (kIOHibernateGfxStatusUnknown
!= gIOHibernateGraphicsInfo
->gfxStatus
))
1180 IOService::getPMRootDomain()->setProperty(kIOHibernateGfxStatusKey
,
1181 &gIOHibernateGraphicsInfo
->gfxStatus
,
1182 sizeof(gIOHibernateGraphicsInfo
->gfxStatus
));
1186 IOService::getPMRootDomain()->removeProperty(kIOHibernateGfxStatusKey
);
1189 // invalidate nvram properties - (gIOOptionsEntry != 0) => nvram was touched
1191 #if defined(__i386__) || defined(__x86_64__)
1192 IOService::getPMRootDomain()->removeProperty(gIOHibernateRTCVariablesKey
);
1193 IOService::getPMRootDomain()->removeProperty(kIOHibernateSMCVariablesKey
);
1196 * Hibernate variable is written to NVRAM on platforms in which RtcRam
1197 * is not backed by coin cell. Remove Hibernate data from NVRAM.
1199 if (gIOOptionsEntry
) {
1201 if (gIOHibernateRTCVariablesKey
) {
1202 if (gIOOptionsEntry
->getProperty(gIOHibernateRTCVariablesKey
)) {
1203 gIOOptionsEntry
->removeProperty(gIOHibernateRTCVariablesKey
);
1207 if (gIOHibernateBootNextKey
)
1209 if (gIOHibernateBootNextSave
)
1211 gIOOptionsEntry
->setProperty(gIOHibernateBootNextKey
, gIOHibernateBootNextSave
);
1212 gIOHibernateBootNextSave
->release();
1213 gIOHibernateBootNextSave
= NULL
;
1216 gIOOptionsEntry
->removeProperty(gIOHibernateBootNextKey
);
1218 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
) gIOOptionsEntry
->sync();
1222 if (vars
->srcBuffer
) vars
->srcBuffer
->release();
1223 bzero(&gIOHibernateHandoffPages
[0], gIOHibernateHandoffPageCount
* sizeof(gIOHibernateHandoffPages
[0]));
1224 if (vars
->handoffBuffer
)
1226 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
1228 IOHibernateHandoff
* handoff
;
1230 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
1232 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
1234 HIBPRINT("handoff %p, %x, %x\n", handoff
, handoff
->type
, handoff
->bytecount
);
1235 uint8_t * data
= &handoff
->data
[0];
1236 switch (handoff
->type
)
1238 case kIOHibernateHandoffTypeEnd
:
1242 case kIOHibernateHandoffTypeDeviceTree
:
1243 MergeDeviceTree((DeviceTreeNode
*) data
, IOService::getServiceRoot());
1246 case kIOHibernateHandoffTypeKeyStore
:
1247 #if defined(__i386__) || defined(__x86_64__)
1249 IOBufferMemoryDescriptor
*
1250 md
= IOBufferMemoryDescriptor::withBytes(data
, handoff
->bytecount
, kIODirectionOutIn
);
1253 IOSetKeyStoreData(md
);
1260 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
1265 vars
->handoffBuffer
->release();
1268 bzero(vars
, sizeof(*vars
));
1270 // gIOHibernateState = kIOHibernateStateInactive; // leave it for post wake code to see
1272 return (kIOReturnSuccess
);
1276 IOHibernateSystemPostWakeTrim(void * p1
, void * p2
)
1278 // invalidate & close the image file
1279 if (p1
) IOLockLock(gFSLock
);
1280 if (kFSTrimDelay
== gFSState
)
1282 IOPolledFileIOVars
* vars
= &gFileVars
;
1283 IOPolledFileClose(&vars
,
1287 0, (caddr_t
)gIOHibernateCurrentHeader
, sizeof(IOHibernateImageHeader
),
1288 sizeof(IOHibernateImageHeader
), gIOHibernateCurrentHeader
->imageSize
);
1292 if (p1
) IOLockUnlock(gFSLock
);
1296 IOHibernateSystemPostWake(void)
1298 gIOHibernateCurrentHeader
->signature
= kIOHibernateHeaderInvalidSignature
;
1299 IOLockLock(gFSLock
);
1300 if (kFSTrimDelay
== gFSState
) IOHibernateSystemPostWakeTrim(NULL
, NULL
);
1301 else if (kFSOpened
!= gFSState
) gFSState
= kFSIdle
;
1304 AbsoluteTime deadline
;
1306 gFSState
= kFSTrimDelay
;
1307 clock_interval_to_deadline(TRIM_DELAY
, kMillisecondScale
, &deadline
);
1308 thread_call_enter1_delayed(gIOHibernateTrimCalloutEntry
, NULL
, deadline
);
1310 IOLockUnlock(gFSLock
);
1312 // IOCloseDebugDataFile() calls IOSetBootImageNVRAM() unconditionally
1313 IOCloseDebugDataFile( );
1314 return (kIOReturnSuccess
);
1317 uint32_t IOHibernateWasScreenLocked(void)
1320 if ((kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) && gIOChosenEntry
)
1323 data
= OSDynamicCast(OSData
, gIOChosenEntry
->getProperty(kIOScreenLockStateKey
));
1326 ret
= ((uint32_t *)data
->getBytesNoCopy())[0];
1327 gIOChosenEntry
->setProperty(kIOBooterScreenLockStateKey
, data
);
1330 else gIOChosenEntry
->removeProperty(kIOBooterScreenLockStateKey
);
1335 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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
, "");
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, "");
1365 IOHibernateSystemInit(IOPMrootDomain
* rootDomain
)
1367 gIOHibernateBootImageKey
= OSSymbol::withCStringNoCopy(kIOHibernateBootImageKey
);
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__) */
1376 OSData
* data
= OSData::withBytesNoCopy(&gIOHibernateState
, sizeof(gIOHibernateState
));
1379 rootDomain
->setProperty(kIOHibernateStateKey
, data
);
1383 if (PE_parse_boot_argn("hfile", gIOHibernateFilename
, sizeof(gIOHibernateFilename
)))
1384 gIOHibernateMode
= kIOHibernateModeOn
;
1386 gIOHibernateFilename
[0] = 0;
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
);
1397 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
1399 gFSLock
= IOLockAlloc();
1402 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1405 IOHibernatePolledFileWrite(IOPolledFileIOVars
* vars
,
1406 const uint8_t * bytes
, IOByteCount size
,
1407 IOPolledFileCryptVars
* cryptvars
)
1411 err
= IOPolledFileWrite(vars
, bytes
, size
, cryptvars
);
1412 if ((kIOReturnSuccess
== err
) && hibernate_should_abort()) err
= kIOReturnAborted
;
1417 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1420 hibernate_write_image(void)
1422 IOHibernateImageHeader
* header
= gIOHibernateCurrentHeader
;
1423 IOHibernateVars
* vars
= &gIOHibernateVars
;
1424 IOPolledFileExtent
* fileExtents
;
1426 _static_assert_1_arg(sizeof(IOHibernateImageHeader
) == 512);
1428 uint32_t pageCount
, pagesDone
;
1430 vm_offset_t ppnum
, page
;
1434 uint8_t * compressed
;
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
;
1445 uint32_t pageAndCount
[2];
1448 uintptr_t hibernateBase
;
1449 uintptr_t hibernateEnd
;
1451 AbsoluteTime startTime
, endTime
;
1452 AbsoluteTime allTime
, compTime
;
1455 uint32_t lastProgressStamp
= 0;
1456 uint32_t progressStamp
;
1457 uint32_t blob
, lastBlob
= (uint32_t) -1L;
1459 uint32_t wiredPagesEncrypted
;
1460 uint32_t dirtyPagesEncrypted
;
1461 uint32_t wiredPagesClear
;
1462 uint32_t svPageCount
;
1463 uint32_t zvPageCount
;
1465 IOPolledFileCryptVars _cryptvars
;
1466 IOPolledFileCryptVars
* cryptvars
= 0;
1468 wiredPagesEncrypted
= 0;
1469 dirtyPagesEncrypted
= 0;
1470 wiredPagesClear
= 0;
1475 || !vars
->fileVars
->pollers
1476 || !(kIOHibernateModeOn
& gIOHibernateMode
)) return (kIOHibernatePostWriteSleep
);
1478 if (kIOHibernateModeSleep
& gIOHibernateMode
)
1479 kdebug_enable
= save_kdebug_enable
;
1481 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_START
, 0, 0, 0, 0, 0);
1482 IOService::getPMRootDomain()->tracePoint(kIOPMTracePointHibernate
);
1484 restore1Sum
= sum1
= sum2
= 0;
1487 // encryption data. "iv" is the "initial vector".
1488 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
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 };
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
);
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
);
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
));
1518 hibernate_page_list_setall(vars
->page_list
,
1519 vars
->page_list_wired
,
1520 vars
->page_list_pal
,
1521 false /* !preflight */,
1523 ((0 == (kIOHibernateModeSleep
& gIOHibernateMode
))
1524 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
))),
1527 HIBLOG("hibernate_page_list_setall found pageCount %d\n", pageCount
);
1529 fileExtents
= (IOPolledFileExtent
*) vars
->fileVars
->fileExtents
->getBytesNoCopy();
1532 count
= vars
->fileExtents
->getLength() / sizeof(IOPolledFileExtent
);
1533 for (page
= 0; page
< count
; page
++)
1535 HIBLOG("fileExtents[%d] %qx, %qx (%qx)\n", page
,
1536 fileExtents
[page
].start
, fileExtents
[page
].length
,
1537 fileExtents
[page
].start
+ fileExtents
[page
].length
);
1541 needEncrypt
= (0 != (kIOHibernateModeEncrypt
& gIOHibernateMode
));
1542 AbsoluteTime_to_scalar(&compTime
) = 0;
1545 clock_get_uptime(&allTime
);
1546 IOService::getPMRootDomain()->pmStatsRecordEvent(
1547 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStartFlag
, allTime
);
1551 uncompressedSize
= 0;
1555 IOPolledFileSeek(vars
->fileVars
, vars
->fileVars
->blockSize
);
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
);
1565 // copy file block extent list if larger than header
1567 count
= vars
->fileVars
->fileExtents
->getLength();
1568 if (count
> sizeof(header
->fileExtentMap
))
1570 count
-= sizeof(header
->fileExtentMap
);
1571 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1572 ((uint8_t *) &fileExtents
[0]) + sizeof(header
->fileExtentMap
), count
, cryptvars
);
1573 if (kIOReturnSuccess
!= err
)
1577 hibernateBase
= HIB_BASE
; /* Defined in PAL headers */
1578 hibernateEnd
= (segHIBB
+ segSizeHIB
);
1580 // copy out restore1 code
1583 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
1586 for (pagesDone
= 0; pagesDone
< atop_32(segLen
); pagesDone
++)
1588 gIOHibernateHandoffPages
[atop_32(count
) + pagesDone
] = atop_64(phys64
) + pagesDone
;
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
;
1600 // sum __HIB seg, with zeros for the stack
1601 src
= (uint8_t *) trunc_page(hibernateBase
);
1602 for (page
= 0; page
< count
; page
++)
1604 if ((src
< &gIOHibernateRestoreStack
[0]) || (src
>= &gIOHibernateRestoreStackEnd
[0]))
1605 restore1Sum
+= hibernate_sum_page(src
, header
->restore1CodeVirt
+ page
);
1607 restore1Sum
+= 0x00000000;
1612 // write the __HIB seg, with zeros for the stack
1614 src
= (uint8_t *) trunc_page(hibernateBase
);
1615 count
= ((uintptr_t) &gIOHibernateRestoreStack
[0]) - trunc_page(hibernateBase
);
1618 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1619 if (kIOReturnSuccess
!= err
)
1622 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1624 &gIOHibernateRestoreStackEnd
[0] - &gIOHibernateRestoreStack
[0],
1626 if (kIOReturnSuccess
!= err
)
1628 src
= &gIOHibernateRestoreStackEnd
[0];
1629 count
= round_page(hibernateEnd
) - ((uintptr_t) src
);
1632 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1633 if (kIOReturnSuccess
!= err
)
1637 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
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
);
1644 // write the preview buffer
1646 if (vars
->previewBuffer
)
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
),
1658 if (kIOReturnSuccess
!= err
)
1661 ppnum
+= sizeof(pageAndCount
);
1664 if (kIOReturnSuccess
!= err
)
1667 src
= (uint8_t *) vars
->previewBuffer
->getPhysicalSegment(0, NULL
, _kIOMemorySourceSegment
);
1669 ((hibernate_preview_t
*)src
)->lockTime
= gIOConsoleLockTime
;
1671 count
= vars
->previewBuffer
->getLength();
1673 header
->previewPageListSize
= ppnum
;
1674 header
->previewSize
= count
+ ppnum
;
1676 for (page
= 0; page
< count
; page
+= page_size
)
1678 phys64
= vars
->previewBuffer
->getPhysicalSegment(page
, NULL
, kIOMemoryMapperNone
);
1679 sum1
+= hibernate_sum_page(src
+ page
, atop_64(phys64
));
1681 err
= IOHibernatePolledFileWrite(vars
->fileVars
, src
, count
, cryptvars
);
1682 if (kIOReturnSuccess
!= err
)
1686 // mark areas for no save
1687 IOMemoryDescriptor
* ioBuffer
;
1688 ioBuffer
= IOPolledFileGetIOBuffer(vars
->fileVars
);
1690 (phys64
= ioBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
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
);
1700 (phys64
= vars
->srcBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
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
);
1709 // copy out bitmap of pages available for trashing during restore
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
)
1717 // mark more areas for no save, but these are not available
1718 // for trashing during restore
1720 hibernate_page_list_set_volatile(vars
->page_list
, vars
->page_list_wired
, &pageCount
);
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
,
1727 kIOHibernatePageStateFree
);
1730 if (vars
->previewBuffer
) for (count
= 0;
1731 (phys64
= vars
->previewBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
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
);
1741 (phys64
= vars
->handoffBuffer
->getPhysicalSegment(count
, &segLen
, kIOMemoryMapperNone
));
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
);
1750 src
= (uint8_t *) vars
->srcBuffer
->getBytesNoCopy();
1751 compressed
= src
+ page_size
;
1752 scratch
= compressed
+ page_size
;
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
);
1766 kWiredEncrypt
= kWired
| kEncrypt
,
1767 kWiredClear
= kWired
,
1768 kUnwiredEncrypt
= kEncrypt
1771 bool cpuAES
= (0 != (CPUID_FEATURE_AES
& cpuid_features()));
1772 #define _pmap_is_noencrypt(x) (cpuAES ? false : pmap_is_noencrypt((x)))
1774 for (pageType
= kWiredEncrypt
; pageType
>= kUnwiredEncrypt
; pageType
--)
1776 if (kUnwiredEncrypt
== pageType
)
1778 // start unwired image
1779 if (kIOHibernateModeEncrypt
& gIOHibernateMode
)
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
);
1785 bcopy(&cryptvars
->aes_iv
[0],
1786 &gIOHibernateCryptWakeContext
.aes_iv
[0],
1787 sizeof(cryptvars
->aes_iv
));
1788 cryptvars
= &gIOHibernateCryptWakeContext
;
1790 for (iterDone
= false, ppnum
= 0; !iterDone
; )
1792 count
= hibernate_page_list_iterate((kWired
& pageType
)
1793 ? vars
->page_list_wired
: vars
->page_list
,
1795 // kprintf("[%d](%x : %x)\n", pageType, ppnum, count);
1798 if (count
&& (kWired
& pageType
) && needEncrypt
)
1800 uint32_t checkIndex
;
1801 for (checkIndex
= 0;
1802 (checkIndex
< count
)
1803 && (((kEncrypt
& pageType
) == 0) == _pmap_is_noencrypt(ppnum
+ checkIndex
));
1816 case kWiredEncrypt
: wiredPagesEncrypted
+= count
; break;
1817 case kWiredClear
: wiredPagesClear
+= count
; break;
1818 case kUnwiredEncrypt
: dirtyPagesEncrypted
+= count
; break;
1821 if (iterDone
&& (kWiredEncrypt
== pageType
)) {/* not yet end of wired list */}
1824 pageAndCount
[0] = ppnum
;
1825 pageAndCount
[1] = count
;
1826 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1827 (const uint8_t *) &pageAndCount
, sizeof(pageAndCount
),
1829 if (kIOReturnSuccess
!= err
)
1833 for (page
= ppnum
; page
< (ppnum
+ count
); page
++)
1835 err
= IOMemoryDescriptorWriteFromPhysical(vars
->srcBuffer
, 0, ptoa_64(page
), page_size
);
1838 HIBLOG("IOMemoryDescriptorWriteFromPhysical %d [%ld] %x\n", __LINE__
, (long)page
, err
);
1842 sum
= hibernate_sum_page(src
, page
);
1843 if (kWired
& pageType
)
1848 clock_get_uptime(&startTime
);
1849 wkresult
= WKdm_compress_new((const WK_word
*) src
,
1850 (WK_word
*) compressed
,
1854 clock_get_uptime(&endTime
);
1855 ADD_ABSOLUTETIME(&compTime
, &endTime
);
1856 SUB_ABSOLUTETIME(&compTime
, &startTime
);
1858 compBytes
+= page_size
;
1859 pageCompressedSize
= (-1 == wkresult
) ? page_size
: wkresult
;
1861 if (pageCompressedSize
== 0)
1863 pageCompressedSize
= 4;
1866 if (*(uint32_t *)src
)
1873 if (pageCompressedSize
!= page_size
)
1879 tag
= pageCompressedSize
| kIOHibernateTagSignature
;
1880 err
= IOHibernatePolledFileWrite(vars
->fileVars
, (const uint8_t *) &tag
, sizeof(tag
), cryptvars
);
1881 if (kIOReturnSuccess
!= err
)
1884 err
= IOHibernatePolledFileWrite(vars
->fileVars
, data
, (pageCompressedSize
+ 3) & ~3, cryptvars
);
1885 if (kIOReturnSuccess
!= err
)
1888 compressedSize
+= pageCompressedSize
;
1889 uncompressedSize
+= page_size
;
1892 if (vars
->consoleMapping
&& (0 == (1023 & pagesDone
)))
1894 blob
= ((pagesDone
* kIOHibernateProgressCount
) / pageCount
);
1895 if (blob
!= lastBlob
)
1897 ProgressUpdate(gIOHibernateGraphicsInfo
, vars
->consoleMapping
, lastBlob
, blob
);
1901 if (0 == (8191 & pagesDone
))
1903 clock_get_uptime(&endTime
);
1904 SUB_ABSOLUTETIME(&endTime
, &allTime
);
1905 absolutetime_to_nanoseconds(endTime
, &nsec
);
1906 progressStamp
= nsec
/ 750000000ULL;
1907 if (progressStamp
!= lastProgressStamp
)
1909 lastProgressStamp
= progressStamp
;
1910 HIBPRINT("pages %d (%d%%)\n", pagesDone
, (100 * pagesDone
) / pageCount
);
1914 if (kIOReturnSuccess
!= err
)
1919 if (kIOReturnSuccess
!= err
)
1922 if ((kEncrypt
& pageType
) && vars
->fileVars
->encryptStart
)
1924 vars
->fileVars
->encryptEnd
= ((vars
->fileVars
->position
+ 511) & ~511ULL);
1925 HIBLOG("encryptEnd %qx\n", vars
->fileVars
->encryptEnd
);
1928 if (kWiredEncrypt
!= pageType
)
1930 // end of image1/2 - fill to next block
1931 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1932 if (kIOReturnSuccess
!= err
)
1935 if (kWiredClear
== pageType
)
1937 // enlarge wired image for test
1938 // err = IOHibernatePolledFileWrite(vars->fileVars, 0, 0x60000000, cryptvars);
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
);
1948 if (kIOReturnSuccess
!= err
)
1950 if (kIOReturnOverrun
== err
)
1952 // update actual compression ratio on not enough space (for retry)
1953 gIOHibernateCompression
= (compressedSize
<< 8) / uncompressedSize
;
1956 // update partial amount written (for IOPolledFileClose cleanup/unmap)
1957 header
->imageSize
= vars
->fileVars
->position
;
1963 header
->imageSize
= vars
->fileVars
->position
;
1964 header
->image1Size
= image1Size
;
1965 header
->bitmapSize
= bitmap_size
;
1966 header
->pageCount
= pageCount
;
1968 header
->restore1Sum
= restore1Sum
;
1969 header
->image1Sum
= sum1
;
1970 header
->image2Sum
= sum2
;
1971 header
->sleepTime
= gIOLastSleepTime
.tv_sec
;
1973 header
->compression
= (compressedSize
<< 8) / uncompressedSize
;
1974 gIOHibernateCompression
= header
->compression
;
1976 count
= vars
->fileVars
->fileExtents
->getLength();
1977 if (count
> sizeof(header
->fileExtentMap
))
1979 header
->fileExtentMapSize
= count
;
1980 count
= sizeof(header
->fileExtentMap
);
1983 header
->fileExtentMapSize
= sizeof(header
->fileExtentMap
);
1984 bcopy(&fileExtents
[0], &header
->fileExtentMap
[0], count
);
1986 header
->deviceBase
= vars
->fileVars
->block0
;
1987 header
->deviceBlockSize
= vars
->fileVars
->blockSize
;
1989 IOPolledFileSeek(vars
->fileVars
, 0);
1990 err
= IOHibernatePolledFileWrite(vars
->fileVars
,
1991 (uint8_t *) header
, sizeof(IOHibernateImageHeader
),
1993 if (kIOReturnSuccess
!= err
)
1995 err
= IOHibernatePolledFileWrite(vars
->fileVars
, 0, 0, cryptvars
);
1999 clock_get_uptime(&endTime
);
2001 IOService::getPMRootDomain()->pmStatsRecordEvent(
2002 kIOPMStatsHibernateImageWrite
| kIOPMStatsEventStopFlag
, endTime
);
2004 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2005 absolutetime_to_nanoseconds(endTime
, &nsec
);
2006 HIBLOG("all time: %qd ms, ", nsec
/ 1000000ULL);
2008 absolutetime_to_nanoseconds(compTime
, &nsec
);
2009 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2012 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2014 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2015 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s, ",
2016 vars
->fileVars
->cryptBytes
,
2018 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
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,
2026 HIBLOG("svPageCount %d, zvPageCount %d, wiredPagesEncrypted %d, wiredPagesClear %d, dirtyPagesEncrypted %d\n",
2027 svPageCount
, zvPageCount
, wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
);
2030 IOPolledFilePollersClose(vars
->fileVars
, (kIOReturnSuccess
== err
) ? kIOPolledBeforeSleepState
: kIOPolledBeforeSleepStateAborted
);
2032 if (vars
->consoleMapping
)
2033 ProgressUpdate(gIOHibernateGraphicsInfo
,
2034 vars
->consoleMapping
, 0, kIOHibernateProgressCount
);
2036 HIBLOG("hibernate_write_image done(%x)\n", err
);
2038 // should we come back via regular wake, set the state in memory.
2039 gIOHibernateState
= kIOHibernateStateInactive
;
2041 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 1) | DBG_FUNC_END
,
2042 wiredPagesEncrypted
, wiredPagesClear
, dirtyPagesEncrypted
, 0, 0);
2044 if (kIOReturnSuccess
== err
)
2046 if (kIOHibernateModeSleep
& gIOHibernateMode
)
2048 return (kIOHibernatePostWriteSleep
);
2050 else if(kIOHibernateModeRestart
& gIOHibernateMode
)
2052 return (kIOHibernatePostWriteRestart
);
2056 /* by default, power down */
2057 return (kIOHibernatePostWriteHalt
);
2060 else if (kIOReturnAborted
== err
)
2062 return (kIOHibernatePostWriteWake
);
2066 /* on error, sleep */
2067 return (kIOHibernatePostWriteSleep
);
2071 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2074 hibernate_machine_init(void)
2079 uint32_t pagesRead
= 0;
2080 AbsoluteTime startTime
, compTime
;
2081 AbsoluteTime allTime
, endTime
;
2082 AbsoluteTime startIOTime
, endIOTime
;
2083 uint64_t nsec
, nsecIO
;
2085 uint32_t lastProgressStamp
= 0;
2086 uint32_t progressStamp
;
2087 IOPolledFileCryptVars
* cryptvars
= 0;
2089 IOHibernateVars
* vars
= &gIOHibernateVars
;
2090 bzero(gIOHibernateStats
, sizeof(hibernate_statistics_t
));
2092 if (!vars
->fileVars
|| !vars
->fileVars
->pollers
)
2095 sum
= gIOHibernateCurrentHeader
->actualImage1Sum
;
2096 pagesDone
= gIOHibernateCurrentHeader
->actualUncompressedPages
;
2098 if (kIOHibernateStateWakingFromHibernate
!= gIOHibernateState
)
2100 HIBLOG("regular wake\n");
2104 HIBPRINT("diag %x %x %x %x\n",
2105 gIOHibernateCurrentHeader
->diag
[0], gIOHibernateCurrentHeader
->diag
[1],
2106 gIOHibernateCurrentHeader
->diag
[2], gIOHibernateCurrentHeader
->diag
[3]);
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
);
2120 gIOHibernateStats
->image1Size
= gIOHibernateCurrentHeader
->image1Size
;
2121 gIOHibernateStats
->imageSize
= gIOHibernateCurrentHeader
->imageSize
;
2122 gIOHibernateStats
->image1Pages
= pagesDone
;
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
);
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
);
2139 if ((0 != (kIOHibernateModeSleep
& gIOHibernateMode
))
2140 && (0 != ((kIOHibernateModeDiscardCleanActive
| kIOHibernateModeDiscardCleanInactive
) & gIOHibernateMode
)))
2142 hibernate_page_list_discard(vars
->page_list
);
2145 cryptvars
= (kIOHibernateModeEncrypt
& gIOHibernateMode
) ? &gIOHibernateCryptWakeContext
: 0;
2147 if (gIOHibernateCurrentHeader
->handoffPageCount
> gIOHibernateHandoffPageCount
)
2148 panic("handoff overflow");
2150 IOHibernateHandoff
* handoff
;
2152 bool foundCryptData
= false;
2154 for (handoff
= (IOHibernateHandoff
*) vars
->handoffBuffer
->getBytesNoCopy();
2156 handoff
= (IOHibernateHandoff
*) &handoff
->data
[handoff
->bytecount
])
2158 // HIBPRINT("handoff %p, %x, %x\n", handoff, handoff->type, handoff->bytecount);
2159 uint8_t * data
= &handoff
->data
[0];
2160 switch (handoff
->type
)
2162 case kIOHibernateHandoffTypeEnd
:
2166 case kIOHibernateHandoffTypeGraphicsInfo
:
2167 if (handoff
->bytecount
== sizeof(*gIOHibernateGraphicsInfo
))
2169 bcopy(data
, gIOHibernateGraphicsInfo
, sizeof(*gIOHibernateGraphicsInfo
));
2173 case kIOHibernateHandoffTypeCryptVars
:
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
));
2180 foundCryptData
= true;
2181 bzero(data
, handoff
->bytecount
);
2184 case kIOHibernateHandoffTypeMemoryMap
:
2186 clock_get_uptime(&allTime
);
2188 hibernate_newruntime_map(data
, handoff
->bytecount
,
2189 gIOHibernateCurrentHeader
->systemTableOffset
);
2191 clock_get_uptime(&endTime
);
2193 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2194 absolutetime_to_nanoseconds(endTime
, &nsec
);
2196 HIBLOG("hibernate_newruntime_map time: %qd ms, ", nsec
/ 1000000ULL);
2200 case kIOHibernateHandoffTypeDeviceTree
:
2202 // DTEntry chosen = NULL;
2203 // HIBPRINT("DTLookupEntry %d\n", DTLookupEntry((const DTEntry) data, "/chosen", &chosen));
2208 done
= (kIOHibernateHandoffType
!= (handoff
->type
& 0xFFFF0000));
2212 if (cryptvars
&& !foundCryptData
)
2213 panic("hibernate handoff");
2215 HIBPRINT("video 0x%llx %d %d %d status %x\n",
2216 gIOHibernateGraphicsInfo
->physicalAddress
, gIOHibernateGraphicsInfo
->depth
,
2217 gIOHibernateGraphicsInfo
->width
, gIOHibernateGraphicsInfo
->height
, gIOHibernateGraphicsInfo
->gfxStatus
);
2219 if (vars
->videoMapping
&& gIOHibernateGraphicsInfo
->physicalAddress
)
2221 vars
->videoMapSize
= round_page(gIOHibernateGraphicsInfo
->height
2222 * gIOHibernateGraphicsInfo
->rowBytes
);
2223 if (vars
->videoMapSize
> vars
->videoAllocSize
) vars
->videoMapSize
= 0;
2226 IOMapPages(kernel_map
,
2227 vars
->videoMapping
, gIOHibernateGraphicsInfo
->physicalAddress
,
2228 vars
->videoMapSize
, kIOMapInhibitCache
);
2232 if (vars
->videoMapSize
)
2233 ProgressUpdate(gIOHibernateGraphicsInfo
,
2234 (uint8_t *) vars
->videoMapping
, 0, kIOHibernateProgressCount
);
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
;
2241 clock_get_uptime(&allTime
);
2242 AbsoluteTime_to_scalar(&compTime
) = 0;
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);
2253 IOPolledFileSeek(vars
->fileVars
, gIOHibernateCurrentHeader
->image1Size
);
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;
2264 err
= IOPolledFileRead(vars
->fileVars
, 0, 0, cryptvars
);
2265 vars
->fileVars
->bufferOffset
= vars
->fileVars
->bufferLimit
;
2268 HIBLOG("hibernate_machine_init reading\n");
2270 uint32_t * header
= (uint32_t *) src
;
2273 while (kIOReturnSuccess
== err
)
2278 vm_offset_t ppnum
, compressedSize
;
2280 err
= IOPolledFileRead(vars
->fileVars
, src
, 8, cryptvars
);
2281 if (kIOReturnSuccess
!= err
)
2287 // HIBPRINT("(%x, %x)\n", ppnum, count);
2292 for (page
= 0; page
< count
; page
++)
2294 err
= IOPolledFileRead(vars
->fileVars
, (uint8_t *) &tag
, 4, cryptvars
);
2295 if (kIOReturnSuccess
!= err
)
2298 compressedSize
= kIOHibernateTagLength
& tag
;
2299 if (kIOHibernateTagSignature
!= (tag
& ~kIOHibernateTagLength
))
2301 err
= kIOReturnIPCError
;
2305 err
= IOPolledFileRead(vars
->fileVars
, src
, (compressedSize
+ 3) & ~3, cryptvars
);
2306 if (kIOReturnSuccess
!= err
) break;
2308 if (compressedSize
< page_size
)
2310 decoOffset
= page_size
;
2311 clock_get_uptime(&startTime
);
2313 if (compressedSize
== 4) {
2317 s
= (uint32_t *)src
;
2318 d
= (uint32_t *)(uintptr_t)compressed
;
2320 for (i
= 0; i
< (int)(PAGE_SIZE
/ sizeof(int32_t)); i
++)
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
;
2330 else decoOffset
= 0;
2332 sum
+= hibernate_sum_page((src
+ decoOffset
), ppnum
);
2333 err
= IOMemoryDescriptorReadToPhysical(vars
->srcBuffer
, decoOffset
, ptoa_64(ppnum
), page_size
);
2336 HIBLOG("IOMemoryDescriptorReadToPhysical [%ld] %x\n", (long)ppnum
, err
);
2344 if (0 == (8191 & pagesDone
))
2346 clock_get_uptime(&endTime
);
2347 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2348 absolutetime_to_nanoseconds(endTime
, &nsec
);
2349 progressStamp
= nsec
/ 750000000ULL;
2350 if (progressStamp
!= lastProgressStamp
)
2352 lastProgressStamp
= progressStamp
;
2353 HIBPRINT("pages %d (%d%%)\n", pagesDone
,
2354 (100 * pagesDone
) / gIOHibernateCurrentHeader
->pageCount
);
2359 if ((kIOReturnSuccess
== err
) && (pagesDone
== gIOHibernateCurrentHeader
->actualUncompressedPages
))
2360 err
= kIOReturnLockedRead
;
2362 if (kIOReturnSuccess
!= err
)
2363 panic("Hibernate restore error %x", err
);
2365 gIOHibernateCurrentHeader
->actualImage2Sum
= sum
;
2366 gIOHibernateCompression
= gIOHibernateCurrentHeader
->compression
;
2368 clock_get_uptime(&endIOTime
);
2370 err
= IOPolledFilePollersClose(vars
->fileVars
, kIOPolledAfterSleepState
);
2372 clock_get_uptime(&endTime
);
2374 IOService::getPMRootDomain()->pmStatsRecordEvent(
2375 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStartFlag
, allTime
);
2376 IOService::getPMRootDomain()->pmStatsRecordEvent(
2377 kIOPMStatsHibernateImageRead
| kIOPMStatsEventStopFlag
, endTime
);
2379 SUB_ABSOLUTETIME(&endTime
, &allTime
);
2380 absolutetime_to_nanoseconds(endTime
, &nsec
);
2382 SUB_ABSOLUTETIME(&endIOTime
, &startIOTime
);
2383 absolutetime_to_nanoseconds(endIOTime
, &nsecIO
);
2385 gIOHibernateStats
->kernelImageReadDuration
= nsec
/ 1000000ULL;
2386 gIOHibernateStats
->imagePages
= pagesDone
;
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);
2392 absolutetime_to_nanoseconds(compTime
, &nsec
);
2393 HIBLOG("comp bytes: %qd time: %qd ms %qd Mb/s, ",
2396 nsec
? (((compBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2398 absolutetime_to_nanoseconds(vars
->fileVars
->cryptTime
, &nsec
);
2399 HIBLOG("crypt bytes: %qd time: %qd ms %qd Mb/s\n",
2400 vars
->fileVars
->cryptBytes
,
2402 nsec
? (((vars
->fileVars
->cryptBytes
* 1000000000ULL) / 1024 / 1024) / nsec
) : 0);
2404 KERNEL_DEBUG_CONSTANT(IOKDBG_CODE(DBG_HIBERNATE
, 2) | DBG_FUNC_NONE
, pagesRead
, pagesDone
, 0, 0, 0);
2407 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2409 void IOHibernateSetWakeCapabilities(uint32_t capability
)
2411 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
)
2413 gIOHibernateStats
->wakeCapability
= capability
;
2415 if (kIOPMSystemCapabilityGraphics
& capability
)
2417 vm_compressor_do_warmup();
2422 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2424 void IOHibernateSystemRestart(void)
2426 static uint8_t noteStore
[32] __attribute__((aligned(32)));
2427 IORegistryEntry
* regEntry
;
2428 const OSSymbol
* sym
;
2431 uintptr_t * smcVars
;
2436 data
= OSDynamicCast(OSData
, IOService::getPMRootDomain()->getProperty(kIOHibernateSMCVariablesKey
));
2439 smcVars
= (typeof(smcVars
)) data
->getBytesNoCopy();
2440 smcBytes
= (typeof(smcBytes
)) smcVars
[1];
2442 if (len
> sizeof(noteStore
)) len
= sizeof(noteStore
);
2443 noteProp
= OSData::withCapacity(3 * sizeof(element
));
2444 if (!noteProp
) return;
2446 noteProp
->appendBytes(&element
, sizeof(element
));
2447 element
= crc32(0, smcBytes
, len
);
2448 noteProp
->appendBytes(&element
, sizeof(element
));
2450 bcopy(smcBytes
, noteStore
, len
);
2451 element
= (addr64_t
) ¬eStore
[0];
2452 element
= (element
& page_mask
) | ptoa_64(pmap_find_phys(kernel_pmap
, element
));
2453 noteProp
->appendBytes(&element
, sizeof(element
));
2455 if (!gIOOptionsEntry
)
2457 regEntry
= IORegistryEntry::fromPath("/options", gIODTPlane
);
2458 gIOOptionsEntry
= OSDynamicCast(IODTNVRAM
, regEntry
);
2459 if (regEntry
&& !gIOOptionsEntry
)
2460 regEntry
->release();
2463 sym
= OSSymbol::withCStringNoCopy(kIOHibernateBootNoteKey
);
2464 if (gIOOptionsEntry
&& sym
) gIOOptionsEntry
->setProperty(sym
, noteProp
);
2465 if (noteProp
) noteProp
->release();
2466 if (sym
) sym
->release();