2 * Copyright (c) 2006-2019 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@
32 #include <IOKit/IOLib.h>
33 #include <IOKit/IOBSD.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IOPlatformExpert.h>
36 #include <IOKit/IOPolledInterface.h>
37 #include <IOKit/IOHibernatePrivate.h>
38 #include <IOKit/IOBufferMemoryDescriptor.h>
39 #include <IOKit/AppleKeyStoreInterface.h>
40 #include <libkern/c++/OSSharedPtr.h>
41 #include "IOKitKernelInternal.h"
43 #if defined(__arm64__)
44 #include <pexpert/arm64/board_config.h>
45 #if XNU_MONITOR_PPL_HIB
46 #include <IOKit/SEPHibernator.h>
47 #endif /* XNU_MONITOR_PPL_HIB */
48 #endif /* defined(__arm64__) */
50 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
54 OSMetaClassDefineReservedUsedX86(IOPolledInterface
, 0);
55 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
56 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
57 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
58 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
59 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
60 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
61 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
62 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
63 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
64 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
65 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
66 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
67 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
68 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
69 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
71 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
73 #ifndef kIOMediaPreferredBlockSizeKey
74 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
77 enum { kDefaultIOSize
= 128 * 1024 };
79 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
81 class IOPolledFilePollers
: public OSObject
83 OSDeclareDefaultStructors(IOPolledFilePollers
);
88 IOBufferMemoryDescriptor
* ioBuffer
;
94 static IOPolledFilePollers
* copyPollers(IOService
* media
);
97 OSDefineMetaClassAndStructors(IOPolledFilePollers
, OSObject
)
99 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
101 IOPolledFilePollers
*
102 IOPolledFilePollers::copyPollers(IOService
* media
)
104 IOPolledFilePollers
* vars
;
108 IORegistryEntry
* next
;
109 IORegistryEntry
* child
;
111 if ((obj
= media
->copyProperty(kIOPolledInterfaceStackKey
))) {
112 return OSDynamicCast(IOPolledFilePollers
, obj
);
116 vars
= OSTypeAlloc(IOPolledFilePollers
);
119 vars
->pollers
= OSArray::withCapacity(4);
120 if (!vars
->pollers
) {
121 err
= kIOReturnNoMemory
;
125 next
= vars
->media
= media
;
127 IOPolledInterface
* poller
;
130 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
131 if (kOSBooleanFalse
== obj
) {
132 vars
->pollers
->flushCollection();
134 } else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
))) {
135 vars
->pollers
->setObject(poller
);
138 if ((service
= OSDynamicCast(IOService
, next
))
139 && service
->getDeviceMemory()
140 && !vars
->pollers
->getCount()) {
145 }while ((next
= child
->getParentEntry(gIOServicePlane
))
146 && child
->isParent(next
, gIOServicePlane
, true));
148 if (!vars
->pollers
->getCount()) {
149 err
= kIOReturnUnsupported
;
154 media
->setProperty(kIOPolledInterfaceStackKey
, vars
);
159 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
162 IOPolledFilePollersIODone(IOPolledFilePollers
* vars
, bool abortable
);
164 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
167 IOPolledFilePollersProbe(IOPolledFilePollers
* vars
)
169 IOReturn err
= kIOReturnError
;
171 IOPolledInterface
* poller
;
173 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--) {
174 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
175 err
= poller
->probe(vars
->media
);
177 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
185 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
188 IOPolledFilePollersOpen(IOPolledFileIOVars
* filevars
, uint32_t state
, bool abortable
)
190 IOPolledFilePollers
* vars
= filevars
->pollers
;
191 IOBufferMemoryDescriptor
* ioBuffer
;
192 IOPolledInterface
* poller
;
194 IOReturn err
= kIOReturnError
;
197 vars
->abortable
= abortable
;
200 if (kIOPolledAfterSleepState
== state
) {
204 (void) IOPolledFilePollersIODone(vars
, false);
206 if ((kIOPolledPreflightState
== state
) || (kIOPolledPreflightCoreDumpState
== state
)) {
207 ioBuffer
= vars
->ioBuffer
;
209 vars
->ioBuffer
= ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionInOut
,
210 2 * kDefaultIOSize
, page_size
);
212 return kIOReturnNoMemory
;
217 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--) {
218 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
219 err
= poller
->open(state
, ioBuffer
);
220 if (kIOReturnSuccess
!= err
) {
221 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
225 if ((kIOReturnSuccess
== err
) && (kIOPolledPreflightState
== state
)) {
228 next
->setProperty(kIOPolledInterfaceActiveKey
, kOSBooleanTrue
);
229 next
= next
->getProvider();
236 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
239 IOPolledFilePollersClose(IOPolledFileIOVars
* filevars
, uint32_t state
)
241 IOPolledFilePollers
* vars
= filevars
->pollers
;
242 IOPolledInterface
* poller
;
243 IORegistryEntry
* next
;
247 (void) IOPolledFilePollersIODone(vars
, false);
249 if ((kIOPolledPostflightState
== state
) || (kIOPolledPostflightCoreDumpState
== state
)) {
253 for (idx
= 0, err
= kIOReturnSuccess
;
254 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
256 err
= poller
->close(state
);
257 if ((kIOReturnSuccess
!= err
) && (kIOPolledBeforeSleepStateAborted
== state
)) {
258 err
= poller
->close(kIOPolledBeforeSleepState
);
261 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
265 if (kIOPolledPostflightState
== state
) {
268 next
->removeProperty(kIOPolledInterfaceActiveKey
);
269 next
= next
->getParentEntry(gIOServicePlane
);
273 if ((kIOPolledPostflightState
== state
) || (kIOPolledPostflightCoreDumpState
== state
)) {
275 if (vars
->openCount
) {
278 if (vars
->ioBuffer
) {
279 vars
->ioBuffer
->release();
280 vars
->ioBuffer
= NULL
;
288 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
291 IOPolledInterface::setEncryptionKey(const uint8_t * key
, size_t keySize
)
293 return kIOReturnUnsupported
;
296 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
299 IOPolledFilePollersSetEncryptionKey(IOPolledFileIOVars
* filevars
,
300 const uint8_t * key
, size_t keySize
)
302 IOReturn ret
= kIOReturnUnsupported
;
305 IOPolledFilePollers
* vars
= filevars
->pollers
;
306 IOPolledInterface
* poller
;
309 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
311 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
312 err
= poller
->setEncryptionKey(key
, keySize
);
313 if (kIOReturnSuccess
== err
) {
321 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
324 IOPolledFileGetIOBuffer(IOPolledFileIOVars
* vars
)
326 return vars
->pollers
->ioBuffer
;
329 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
332 IOPolledIOComplete(void * target
,
335 UInt64 actualByteCount
)
337 IOPolledFilePollers
* vars
= (IOPolledFilePollers
*) parameter
;
339 vars
->ioStatus
= status
;
342 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
345 IOStartPolledIO(IOPolledFilePollers
* vars
,
346 uint32_t operation
, uint32_t bufferOffset
,
347 uint64_t deviceOffset
, uint64_t length
)
350 IOPolledInterface
* poller
;
351 IOPolledCompletion completion
;
353 err
= vars
->ioStatus
;
354 if (kIOReturnSuccess
!= err
) {
358 completion
.target
= NULL
;
359 completion
.action
= &IOPolledIOComplete
;
360 completion
.parameter
= vars
;
364 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
365 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
, length
, completion
);
367 if (kernel_debugger_entry_count
) {
368 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
370 HIBLOGFROMPANIC("IOPolledInterface::IOStartPolledIO(0x%p, %d, 0x%x, 0x%llx, %llu) : poller->startIO(%d, 0x%x, 0x%llx, %llu, completion) returned 0x%x",
371 vars
, operation
, bufferOffset
, deviceOffset
, length
, operation
, bufferOffset
, deviceOffset
, length
, err
);
377 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
380 IOPolledFilePollersIODone(IOPolledFilePollers
* vars
, bool abortable
)
382 IOReturn err
= kIOReturnSuccess
;
384 IOPolledInterface
* poller
;
385 AbsoluteTime deadline
;
388 return kIOReturnSuccess
;
391 abortable
&= vars
->abortable
;
393 clock_interval_to_deadline(2000, kMillisecondScale
, &deadline
);
395 while (-1 == vars
->ioStatus
) {
397 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
400 newErr
= poller
->checkForWork();
401 if ((newErr
== kIOReturnAborted
) && !abortable
) {
402 newErr
= kIOReturnSuccess
;
404 if (kIOReturnSuccess
== err
) {
408 if ((false) && (kIOReturnSuccess
== err
) && (mach_absolute_time() > AbsoluteTime_to_scalar(&deadline
))) {
409 HIBLOG("IOPolledInterface::forced timeout\n");
410 vars
->ioStatus
= kIOReturnTimeout
;
416 if ((kIOReturnSuccess
== err
) && abortable
&& hibernate_should_abort()) {
417 err
= kIOReturnAborted
;
418 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
423 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
425 err
= vars
->ioStatus
;
426 if (kIOReturnSuccess
!= err
) {
427 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
434 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
435 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
437 struct _OpenFileContext
{
443 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
445 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
446 IOPolledFileExtent extent
;
448 extent
.start
= start
;
449 extent
.length
= length
;
450 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
454 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
457 IOCopyMediaForDev(dev_t device
)
459 OSDictionary
* matching
;
462 IOService
* result
= NULL
;
464 matching
= IOService::serviceMatching("IOMedia");
469 num
= OSNumber::withNumber(major(device
), 32);
473 matching
->setObject(kIOBSDMajorKey
, num
);
475 num
= OSNumber::withNumber(minor(device
), 32);
479 matching
->setObject(kIOBSDMinorKey
, num
);
484 iter
= IOService::getMatchingServices(matching
);
486 result
= (IOService
*) iter
->getNextObject();
496 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
498 #if defined(__i386__) || defined(__x86_64__)
499 #define APFSMEDIA_GETHIBERKEY "getHiberKey"
502 IOGetVolumeCryptKey(dev_t block_dev
,
503 LIBKERN_RETURNS_RETAINED OSString
** pKeyUUID
,
504 uint8_t * volumeCryptKey
,
509 OSString
* keyUUID
= NULL
;
510 OSString
* keyStoreUUID
= NULL
;
511 uuid_t volumeKeyUUID
;
512 aks_volume_key_t vek
;
513 size_t callerKeySize
;
515 static IOService
* sKeyStore
;
517 part
= IOCopyMediaForDev(block_dev
);
519 return kIOReturnNotFound
;
522 callerKeySize
= *keySize
;
525 uuid_t volUuid
= {0};
526 err
= part
->callPlatformFunction(APFSMEDIA_GETHIBERKEY
, false, &volUuid
, volumeCryptKey
, keySize
, keySize
);
527 if (kIOReturnBadArgument
== err
) {
528 // apfs fails on buffer size >32
530 err
= part
->callPlatformFunction(APFSMEDIA_GETHIBERKEY
, false, &volUuid
, volumeCryptKey
, keySize
, keySize
);
532 if (err
!= kIOReturnSuccess
) {
535 // No need to create uuid string if it's not requested
537 uuid_string_t volUuidStr
;
538 uuid_unparse(volUuid
, volUuidStr
);
539 *pKeyUUID
= OSString::withCString(volUuidStr
);
543 return kIOReturnSuccess
;
548 err
= part
->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID
, false,
549 (void *) &keyUUID
, (void *) &keyStoreUUID
, NULL
, NULL
);
550 if ((kIOReturnSuccess
== err
) && keyUUID
&& keyStoreUUID
) {
551 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
554 sKeyStore
= (IOService
*) IORegistryEntry::fromPath(AKS_SERVICE_PATH
, gIOServicePlane
);
557 err
= uuid_parse(keyStoreUUID
->getCStringNoCopy(), volumeKeyUUID
);
559 err
= kIOReturnNoResources
;
561 if (kIOReturnSuccess
== err
) {
562 err
= sKeyStore
->callPlatformFunction(gAKSGetKey
, true, volumeKeyUUID
, &vek
, NULL
, NULL
);
564 if (kIOReturnSuccess
!= err
) {
565 IOLog("volume key err 0x%x\n", err
);
567 if (vek
.key
.keybytecount
<= callerKeySize
) {
568 *keySize
= vek
.key
.keybytecount
;
570 bcopy(&vek
.key
.keybytes
[0], volumeCryptKey
, *keySize
);
572 bzero(&vek
, sizeof(vek
));
575 // Create a copy because the caller would release it
576 *pKeyUUID
= OSString::withString(keyUUID
);
583 #endif /* defined(__i386__) || defined(__x86_64__) */
585 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
587 #if defined(__arm64__)
589 IOGetHibernationCryptKey(uint8_t * hibernationKey
,
594 return kIOReturnNotFound
;
596 #endif /* defined(__arm64__) */
598 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
601 IOPolledFileOpen(const char * filename
,
603 uint64_t setFileSize
, uint64_t fsFreeSize
,
604 void * write_file_addr
, size_t write_file_len
,
605 IOPolledFileIOVars
** fileVars
,
607 uint8_t * volumeCryptKey
, size_t * keySize
)
609 IOReturn err
= kIOReturnSuccess
;
610 IOPolledFileIOVars
* vars
;
611 _OpenFileContext ctx
;
612 OSData
* extentsData
= NULL
;
614 IOService
* part
= NULL
;
617 AbsoluteTime startTime
, endTime
;
620 vars
= IONew(IOPolledFileIOVars
, 1);
622 return kIOReturnNoMemory
;
624 bzero(vars
, sizeof(*vars
));
625 vars
->allocated
= true;
628 extentsData
= OSData::withCapacity(32);
629 ctx
.extents
= extentsData
;
631 clock_get_uptime(&startTime
);
633 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
635 &file_extent_callback
, &ctx
,
639 0, write_file_addr
, write_file_len
,
647 uint32_t msDelay
= (131071 & random());
648 HIBLOG("sleep %d\n", msDelay
);
651 clock_get_uptime(&endTime
);
652 SUB_ABSOLUTETIME(&endTime
, &startTime
);
653 absolutetime_to_nanoseconds(endTime
, &nsec
);
655 if (!vars
->fileRef
) {
656 err
= kIOReturnNoSpace
;
659 HIBLOG("kern_open_file_for_direct_io took %qd ms\n", nsec
/ 1000000ULL);
660 if (kIOReturnSuccess
!= err
) {
664 HIBLOG("Opened file %s, size %qd, extents %ld, maxio %qx ssd %d\n", filename
, ctx
.size
,
665 (extentsData
->getLength() / sizeof(IOPolledFileExtent
)) - 1,
666 vars
->maxiobytes
, kIOPolledFileSSD
& vars
->flags
);
667 assert(!vars
->block0
);
668 if (extentsData
->getLength() < sizeof(IOPolledFileExtent
)) {
669 err
= kIOReturnNoSpace
;
673 vars
->fileSize
= ctx
.size
;
674 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
676 part
= IOCopyMediaForDev(image_dev
);
678 err
= kIOReturnNotFound
;
682 if (!(vars
->pollers
= IOPolledFilePollers::copyPollers(part
))) {
686 if ((num
= OSDynamicCast(OSNumber
, part
->getProperty(kIOMediaPreferredBlockSizeKey
)))) {
687 vars
->blockSize
= num
->unsigned32BitValue();
689 if (vars
->blockSize
< 4096) {
690 vars
->blockSize
= 4096;
693 HIBLOG("polled file major %d, minor %d, blocksize %ld, pollers %d\n",
694 major(image_dev
), minor(image_dev
), (long)vars
->blockSize
,
695 vars
->pollers
->pollers
->getCount());
697 OSString
* keyUUID
= NULL
;
698 #if defined(__i386__) || defined(__x86_64__)
699 if (volumeCryptKey
) {
700 err
= IOGetVolumeCryptKey(block_dev
, &keyUUID
, volumeCryptKey
, keySize
);
702 #elif defined(__arm64__)
704 if (volumeCryptKey
) {
705 if (flags
& kIOPolledFileHibernate
) {
706 err
= IOGetHibernationCryptKey(volumeCryptKey
, keySize
, &swSeed
);
707 if (kIOReturnSuccess
!= err
) {
708 HIBLOG("error 0x%x from IOGetHibernationCryptKey\n", err
);
716 if (volumeCryptKey
) {
717 HIBLOG("IOPolledFileOpen: unable to get volumeCryptKey\n");
718 err
= kIOReturnNotFound
;
724 vars
->fileExtents
= extentsData
;
727 OSData
* data
= NULL
;
729 #if defined(__i386__) || defined(__x86_64__)
730 char str2
[24 + sizeof(uuid_string_t
) + 2];
733 snprintf(str2
, sizeof(str2
), "%qx:%s",
734 vars
->extentMap
[0].start
, keyUUID
->getCStringNoCopy());
736 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
739 err
= IOService::getPlatform()->callPlatformFunction(
740 gIOCreateEFIDevicePathSymbol
, false,
741 (void *) part
, (void *) str2
,
742 (void *) (uintptr_t) true, (void *) &data
);
743 #elif defined(__arm64__)
745 snprintf(str2
, sizeof(str2
), "%qx:%x", vars
->extentMap
[0].start
, swSeed
);
746 data
= OSData::withBytes(str2
, (unsigned int) strlen(str2
));
747 err
= kIOReturnSuccess
;
749 err
= kIOReturnNotFound
;
751 if (kIOReturnSuccess
!= err
) {
752 HIBLOG("error 0x%x getting path\n", err
);
758 // Release key UUID if we have one
761 keyUUID
= NULL
; // Just in case
765 if (kIOReturnSuccess
!= err
) {
766 HIBLOG("error 0x%x opening polled file\n", err
);
767 IOPolledFileClose(&vars
, 0, NULL
, 0, 0, 0);
769 extentsData
->release();
781 IOPolledFileOpen(const char * filename
,
783 uint64_t setFileSize
, uint64_t fsFreeSize
,
784 void * write_file_addr
, size_t write_file_len
,
785 IOPolledFileIOVars
** fileVars
,
786 OSSharedPtr
<OSData
>& imagePath
,
787 uint8_t * volumeCryptKey
, size_t * keySize
)
789 OSData
* imagePathRaw
= NULL
;
790 IOReturn result
= IOPolledFileOpen(filename
, flags
, setFileSize
, fsFreeSize
, write_file_addr
, write_file_len
,
791 fileVars
, &imagePathRaw
, volumeCryptKey
, keySize
);
792 imagePath
.reset(imagePathRaw
, OSNoRetain
);
796 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
799 IOPolledFileClose(IOPolledFileIOVars
** pVars
,
800 off_t write_offset
, void * addr
, size_t write_length
,
801 off_t discard_offset
, off_t discard_end
)
803 IOPolledFileIOVars
* vars
;
807 return kIOReturnSuccess
;
811 kern_close_file_for_direct_io(vars
->fileRef
, write_offset
, addr
, write_length
,
812 discard_offset
, discard_end
);
813 vars
->fileRef
= NULL
;
815 if (vars
->fileExtents
) {
816 vars
->fileExtents
->release();
817 vars
->fileExtents
= NULL
;
820 vars
->pollers
->release();
821 vars
->pollers
= NULL
;
824 if (vars
->allocated
) {
825 IODelete(vars
, IOPolledFileIOVars
, 1);
827 bzero(vars
, sizeof(IOPolledFileIOVars
));
831 return kIOReturnSuccess
;
834 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
837 IOPolledFilePollersSetup(IOPolledFileIOVars
* vars
,
842 err
= kIOReturnSuccess
;
844 if (!vars
->pollers
->openCount
) {
845 err
= IOPolledFilePollersProbe(vars
->pollers
);
846 if (kIOReturnSuccess
!= err
) {
850 err
= IOPolledFilePollersOpen(vars
, openState
, false);
851 if (kIOReturnSuccess
!= err
) {
854 if ((kIOPolledPreflightState
== openState
) || (kIOPolledPreflightCoreDumpState
== openState
)) {
855 vars
->pollers
->openCount
++;
857 vars
->pollers
->io
= false;
858 vars
->buffer
= (uint8_t *) vars
->pollers
->ioBuffer
->getBytesNoCopy();
859 vars
->bufferHalf
= 0;
860 vars
->bufferOffset
= 0;
861 assert(vars
->pollers
->ioBuffer
->getLength() <= UINT_MAX
);
862 vars
->bufferSize
= (typeof(vars
->bufferSize
))(vars
->pollers
->ioBuffer
->getLength() >> 1);
864 if (vars
->maxiobytes
< vars
->bufferSize
) {
865 vars
->bufferSize
= (typeof(vars
->bufferSize
))vars
->maxiobytes
;
869 if (kIOReturnSuccess
!= err
) {
870 HIBLOG("IOPolledFilePollersSetup(%d) error 0x%x\n", openState
, err
);
877 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
880 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
882 IOPolledFileExtent
* extentMap
;
884 extentMap
= vars
->extentMap
;
886 vars
->position
= position
;
888 if (position
> vars
->fileSize
) {
889 HIBLOG("IOPolledFileSeek: called to seek to 0x%llx greater than file size of 0x%llx\n", vars
->position
, vars
->fileSize
);
890 return kIOReturnNoSpace
;
893 while (position
>= extentMap
->length
) {
894 position
-= extentMap
->length
;
898 vars
->currentExtent
= extentMap
;
899 vars
->extentRemaining
= extentMap
->length
- position
;
900 vars
->extentPosition
= vars
->position
- position
;
902 if (vars
->bufferSize
<= vars
->extentRemaining
) {
903 vars
->bufferLimit
= vars
->bufferSize
;
905 vars
->bufferLimit
= ((uint32_t) vars
->extentRemaining
);
908 return kIOReturnSuccess
;
911 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
914 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
915 const uint8_t * bytes
, IOByteCount size
,
916 IOPolledFileCryptVars
* cryptvars
)
918 IOReturn err
= kIOReturnSuccess
;
919 IOByteCount copy
, original_size
= size
;
923 if (!bytes
&& !size
) {
924 // seek to end of block & flush
925 size
= vars
->position
& (vars
->blockSize
- 1);
927 size
= vars
->blockSize
- size
;
932 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
941 /* Since this may copy mach-o segments in bulk, use the nosan variants of bcopy to
942 * avoid triggering global redzone sanitizer violations when accessing
943 * interstices between 'C' structures
945 __nosan_bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
947 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
951 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
955 vars
->bufferOffset
+= copy
;
956 vars
->position
+= copy
;
958 if (flush
&& vars
->bufferOffset
) {
959 uint64_t offset
= (vars
->position
- vars
->bufferOffset
960 - vars
->extentPosition
+ vars
->currentExtent
->start
);
961 uint32_t length
= (vars
->bufferOffset
);
964 if (cryptvars
&& vars
->encryptStart
965 && (vars
->position
> vars
->encryptStart
)
966 && ((vars
->position
- length
) < vars
->encryptEnd
)) {
967 AbsoluteTime startTime
, endTime
;
969 uint64_t encryptLen
, encryptStart
;
970 encryptLen
= vars
->position
- vars
->encryptStart
;
971 if (encryptLen
> length
) {
974 encryptStart
= length
- encryptLen
;
975 if (vars
->position
> vars
->encryptEnd
) {
976 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
979 clock_get_uptime(&startTime
);
981 assert(encryptLen
<= UINT_MAX
);
982 // encrypt the buffer
983 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
984 &cryptvars
->aes_iv
[0],
985 (unsigned int) (encryptLen
/ AES_BLOCK_SIZE
),
986 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
987 &cryptvars
->ctx
.encrypt
);
989 clock_get_uptime(&endTime
);
990 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
991 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
992 vars
->cryptBytes
+= encryptLen
;
994 // save initial vector for following encrypts
995 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
996 &cryptvars
->aes_iv
[0],
1001 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1002 if (kIOReturnSuccess
!= err
) {
1006 if (vars
->position
& (vars
->blockSize
- 1)) {
1007 HIBLOG("misaligned file pos %qx\n", vars
->position
);
1009 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
1011 err
= IOStartPolledIO(vars
->pollers
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
1012 if (kIOReturnSuccess
!= err
) {
1013 HIBLOGFROMPANIC("IOPolledFileWrite(0x%p, 0x%p, %llu, 0x%p) : IOStartPolledIO(0x%p, kIOPolledWrite, %llu, 0x%llx, %d) returned 0x%x\n",
1014 vars
, bytes
, (uint64_t) original_size
, cryptvars
, vars
->pollers
, (uint64_t) vars
->bufferHalf
, offset
, length
, err
);
1017 vars
->pollers
->io
= true;
1019 vars
->extentRemaining
-= vars
->bufferOffset
;
1020 if (!vars
->extentRemaining
) {
1021 vars
->currentExtent
++;
1022 vars
->extentRemaining
= vars
->currentExtent
->length
;
1023 vars
->extentPosition
= vars
->position
;
1026 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1027 vars
->bufferOffset
= 0;
1028 if (vars
->bufferSize
<= vars
->extentRemaining
) {
1029 vars
->bufferLimit
= vars
->bufferSize
;
1031 vars
->bufferLimit
= ((uint32_t) vars
->extentRemaining
);
1034 if (!vars
->extentRemaining
) {
1035 err
= kIOReturnOverrun
;
1046 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1049 IOPolledFileFlush(IOPolledFileIOVars
* vars
)
1051 // Only supported by the underlying polled mode driver on embedded currently (expect kIOReturnUnsupported on other platforms)
1052 IOReturn err
= kIOReturnSuccess
;
1054 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1055 if (kIOReturnSuccess
!= err
) {
1059 err
= IOStartPolledIO(vars
->pollers
, kIOPolledFlush
, 0, 0, 0);
1060 if (kIOReturnSuccess
!= err
) {
1061 HIBLOGFROMPANIC("IOPolledFileFlush(0x%p) : IOStartPolledIO(0x%p, kIOPolledFlush, 0, 0, 0) returned 0x%x\n",
1062 vars
, vars
->pollers
, err
);
1065 vars
->pollers
->io
= true;
1070 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1073 IOPolledFileRead(IOPolledFileIOVars
* vars
,
1074 uint8_t * bytes
, IOByteCount size
,
1075 IOPolledFileCryptVars
* cryptvars
)
1077 IOReturn err
= kIOReturnSuccess
;
1080 // bytesWritten += size;
1083 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
1090 __nosan_bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1092 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1097 vars
->bufferOffset
+= copy
;
1098 // vars->position += copy;
1100 if ((vars
->bufferOffset
== vars
->bufferLimit
) && (vars
->position
< vars
->readEnd
)) {
1101 if (!vars
->pollers
->io
) {
1104 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1105 if (kIOReturnSuccess
!= err
) {
1109 if (vars
->position
& (vars
->blockSize
- 1)) {
1110 HIBLOG("misaligned file pos %qx\n", vars
->position
);
1113 vars
->position
+= vars
->lastRead
;
1114 vars
->extentRemaining
-= vars
->lastRead
;
1115 vars
->bufferLimit
= vars
->lastRead
;
1117 if (!vars
->extentRemaining
) {
1118 vars
->currentExtent
++;
1119 vars
->extentRemaining
= vars
->currentExtent
->length
;
1120 vars
->extentPosition
= vars
->position
;
1121 if (!vars
->extentRemaining
) {
1122 err
= kIOReturnOverrun
;
1128 uint32_t lastReadLength
= vars
->lastRead
;
1129 uint64_t offset
= (vars
->position
1130 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1131 if (vars
->extentRemaining
<= vars
->bufferSize
) {
1132 length
= ((uint32_t) vars
->extentRemaining
);
1134 length
= vars
->bufferSize
;
1136 if ((length
+ vars
->position
) > vars
->readEnd
) {
1137 length
= ((uint32_t) (vars
->readEnd
- vars
->position
));
1140 vars
->lastRead
= length
;
1142 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1143 err
= IOStartPolledIO(vars
->pollers
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
1144 if (kIOReturnSuccess
!= err
) {
1147 vars
->pollers
->io
= true;
1150 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1151 vars
->bufferOffset
= 0;
1155 uint8_t thisVector
[AES_BLOCK_SIZE
];
1156 AbsoluteTime startTime
, endTime
;
1158 // save initial vector for following decrypts
1159 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
1160 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
1161 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1163 // decrypt the buffer
1164 clock_get_uptime(&startTime
);
1166 assert(lastReadLength
<= UINT_MAX
);
1167 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
1169 (unsigned int) (lastReadLength
/ AES_BLOCK_SIZE
),
1170 vars
->buffer
+ vars
->bufferHalf
,
1171 &cryptvars
->ctx
.decrypt
);
1173 clock_get_uptime(&endTime
);
1174 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1175 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1176 vars
->cryptBytes
+= lastReadLength
;
1185 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */