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 #if XNU_MONITOR_PPL_HIB
595 SEPHibernator
*hibernator
= SEPHibernator::sepHibernator();
596 sephib_wrapped_key_t wrappedKey
= {};
597 sephib_seprom_hib_payload_t sepromPayload
= {};
598 hibernator
->prepareToHibernate(&wrappedKey
, &sepromPayload
);
599 *swSeed
= sepromPayload
.sw_seed
;
600 assert(*keySize
>= sizeof(wrappedKey
.data
));
601 *keySize
= sizeof(wrappedKey
.data
);
602 memcpy(hibernationKey
, wrappedKey
.data
, *keySize
);
603 return kIOReturnSuccess
;
605 return kIOReturnNotFound
;
608 #endif /* defined(__arm64__) */
610 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
613 IOPolledFileOpen(const char * filename
,
615 uint64_t setFileSize
, uint64_t fsFreeSize
,
616 void * write_file_addr
, size_t write_file_len
,
617 IOPolledFileIOVars
** fileVars
,
619 uint8_t * volumeCryptKey
, size_t * keySize
)
621 IOReturn err
= kIOReturnSuccess
;
622 IOPolledFileIOVars
* vars
;
623 _OpenFileContext ctx
;
624 OSData
* extentsData
= NULL
;
626 IOService
* part
= NULL
;
629 AbsoluteTime startTime
, endTime
;
632 vars
= IONew(IOPolledFileIOVars
, 1);
634 return kIOReturnNoMemory
;
636 bzero(vars
, sizeof(*vars
));
637 vars
->allocated
= true;
640 extentsData
= OSData::withCapacity(32);
641 ctx
.extents
= extentsData
;
643 clock_get_uptime(&startTime
);
645 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
647 &file_extent_callback
, &ctx
,
651 0, write_file_addr
, write_file_len
,
659 uint32_t msDelay
= (131071 & random());
660 HIBLOG("sleep %d\n", msDelay
);
663 clock_get_uptime(&endTime
);
664 SUB_ABSOLUTETIME(&endTime
, &startTime
);
665 absolutetime_to_nanoseconds(endTime
, &nsec
);
667 if (!vars
->fileRef
) {
668 err
= kIOReturnNoSpace
;
671 HIBLOG("kern_open_file_for_direct_io took %qd ms\n", nsec
/ 1000000ULL);
672 if (kIOReturnSuccess
!= err
) {
676 HIBLOG("Opened file %s, size %qd, extents %ld, maxio %qx ssd %d\n", filename
, ctx
.size
,
677 (extentsData
->getLength() / sizeof(IOPolledFileExtent
)) - 1,
678 vars
->maxiobytes
, kIOPolledFileSSD
& vars
->flags
);
679 assert(!vars
->block0
);
680 if (extentsData
->getLength() < sizeof(IOPolledFileExtent
)) {
681 err
= kIOReturnNoSpace
;
685 vars
->fileSize
= ctx
.size
;
686 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
688 part
= IOCopyMediaForDev(image_dev
);
690 err
= kIOReturnNotFound
;
694 if (!(vars
->pollers
= IOPolledFilePollers::copyPollers(part
))) {
698 if ((num
= OSDynamicCast(OSNumber
, part
->getProperty(kIOMediaPreferredBlockSizeKey
)))) {
699 vars
->blockSize
= num
->unsigned32BitValue();
701 if (vars
->blockSize
< 4096) {
702 vars
->blockSize
= 4096;
705 HIBLOG("polled file major %d, minor %d, blocksize %ld, pollers %d\n",
706 major(image_dev
), minor(image_dev
), (long)vars
->blockSize
,
707 vars
->pollers
->pollers
->getCount());
709 OSString
* keyUUID
= NULL
;
710 #if defined(__i386__) || defined(__x86_64__)
711 if (volumeCryptKey
) {
712 err
= IOGetVolumeCryptKey(block_dev
, &keyUUID
, volumeCryptKey
, keySize
);
714 #elif defined(__arm64__)
716 if (volumeCryptKey
) {
717 if (flags
& kIOPolledFileHibernate
) {
718 err
= IOGetHibernationCryptKey(volumeCryptKey
, keySize
, &swSeed
);
719 if (kIOReturnSuccess
!= err
) {
720 HIBLOG("error 0x%x from IOGetHibernationCryptKey\n", err
);
728 if (volumeCryptKey
) {
729 HIBLOG("IOPolledFileOpen: unable to get volumeCryptKey\n");
730 err
= kIOReturnNotFound
;
736 vars
->fileExtents
= extentsData
;
739 OSData
* data
= NULL
;
741 #if defined(__i386__) || defined(__x86_64__)
742 char str2
[24 + sizeof(uuid_string_t
) + 2];
745 snprintf(str2
, sizeof(str2
), "%qx:%s",
746 vars
->extentMap
[0].start
, keyUUID
->getCStringNoCopy());
748 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
751 err
= IOService::getPlatform()->callPlatformFunction(
752 gIOCreateEFIDevicePathSymbol
, false,
753 (void *) part
, (void *) str2
,
754 (void *) (uintptr_t) true, (void *) &data
);
755 #elif defined(__arm64__)
757 snprintf(str2
, sizeof(str2
), "%qx:%x", vars
->extentMap
[0].start
, swSeed
);
758 data
= OSData::withBytes(str2
, (unsigned int) strlen(str2
));
759 err
= kIOReturnSuccess
;
761 err
= kIOReturnNotFound
;
763 if (kIOReturnSuccess
!= err
) {
764 HIBLOG("error 0x%x getting path\n", err
);
770 // Release key UUID if we have one
773 keyUUID
= NULL
; // Just in case
777 if (kIOReturnSuccess
!= err
) {
778 HIBLOG("error 0x%x opening polled file\n", err
);
779 IOPolledFileClose(&vars
, 0, NULL
, 0, 0, 0);
781 extentsData
->release();
793 IOPolledFileOpen(const char * filename
,
795 uint64_t setFileSize
, uint64_t fsFreeSize
,
796 void * write_file_addr
, size_t write_file_len
,
797 IOPolledFileIOVars
** fileVars
,
798 OSSharedPtr
<OSData
>& imagePath
,
799 uint8_t * volumeCryptKey
, size_t * keySize
)
801 OSData
* imagePathRaw
= NULL
;
802 IOReturn result
= IOPolledFileOpen(filename
, flags
, setFileSize
, fsFreeSize
, write_file_addr
, write_file_len
,
803 fileVars
, &imagePathRaw
, volumeCryptKey
, keySize
);
804 imagePath
.reset(imagePathRaw
, OSNoRetain
);
808 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
811 IOPolledFileClose(IOPolledFileIOVars
** pVars
,
812 off_t write_offset
, void * addr
, size_t write_length
,
813 off_t discard_offset
, off_t discard_end
)
815 IOPolledFileIOVars
* vars
;
819 return kIOReturnSuccess
;
823 kern_close_file_for_direct_io(vars
->fileRef
, write_offset
, addr
, write_length
,
824 discard_offset
, discard_end
);
825 vars
->fileRef
= NULL
;
827 if (vars
->fileExtents
) {
828 vars
->fileExtents
->release();
829 vars
->fileExtents
= NULL
;
832 vars
->pollers
->release();
833 vars
->pollers
= NULL
;
836 if (vars
->allocated
) {
837 IODelete(vars
, IOPolledFileIOVars
, 1);
839 bzero(vars
, sizeof(IOPolledFileIOVars
));
843 return kIOReturnSuccess
;
846 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
849 IOPolledFilePollersSetup(IOPolledFileIOVars
* vars
,
854 err
= kIOReturnSuccess
;
856 if (!vars
->pollers
->openCount
) {
857 err
= IOPolledFilePollersProbe(vars
->pollers
);
858 if (kIOReturnSuccess
!= err
) {
862 err
= IOPolledFilePollersOpen(vars
, openState
, false);
863 if (kIOReturnSuccess
!= err
) {
866 if ((kIOPolledPreflightState
== openState
) || (kIOPolledPreflightCoreDumpState
== openState
)) {
867 vars
->pollers
->openCount
++;
869 vars
->pollers
->io
= false;
870 vars
->buffer
= (uint8_t *) vars
->pollers
->ioBuffer
->getBytesNoCopy();
871 vars
->bufferHalf
= 0;
872 vars
->bufferOffset
= 0;
873 assert(vars
->pollers
->ioBuffer
->getLength() <= UINT_MAX
);
874 vars
->bufferSize
= (typeof(vars
->bufferSize
))(vars
->pollers
->ioBuffer
->getLength() >> 1);
876 if (vars
->maxiobytes
< vars
->bufferSize
) {
877 vars
->bufferSize
= (typeof(vars
->bufferSize
))vars
->maxiobytes
;
881 if (kIOReturnSuccess
!= err
) {
882 HIBLOG("IOPolledFilePollersSetup(%d) error 0x%x\n", openState
, err
);
889 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
892 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
894 IOPolledFileExtent
* extentMap
;
896 extentMap
= vars
->extentMap
;
898 vars
->position
= position
;
900 if (position
> vars
->fileSize
) {
901 HIBLOG("IOPolledFileSeek: called to seek to 0x%llx greater than file size of 0x%llx\n", vars
->position
, vars
->fileSize
);
902 return kIOReturnNoSpace
;
905 while (position
>= extentMap
->length
) {
906 position
-= extentMap
->length
;
910 vars
->currentExtent
= extentMap
;
911 vars
->extentRemaining
= extentMap
->length
- position
;
912 vars
->extentPosition
= vars
->position
- position
;
914 if (vars
->bufferSize
<= vars
->extentRemaining
) {
915 vars
->bufferLimit
= vars
->bufferSize
;
917 vars
->bufferLimit
= ((uint32_t) vars
->extentRemaining
);
920 return kIOReturnSuccess
;
923 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
926 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
927 const uint8_t * bytes
, IOByteCount size
,
928 IOPolledFileCryptVars
* cryptvars
)
930 IOReturn err
= kIOReturnSuccess
;
931 IOByteCount copy
, original_size
= size
;
935 if (!bytes
&& !size
) {
936 // seek to end of block & flush
937 size
= vars
->position
& (vars
->blockSize
- 1);
939 size
= vars
->blockSize
- size
;
944 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
953 /* Since this may copy mach-o segments in bulk, use the nosan variants of bcopy to
954 * avoid triggering global redzone sanitizer violations when accessing
955 * interstices between 'C' structures
957 __nosan_bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
959 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
963 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
967 vars
->bufferOffset
+= copy
;
968 vars
->position
+= copy
;
970 if (flush
&& vars
->bufferOffset
) {
971 uint64_t offset
= (vars
->position
- vars
->bufferOffset
972 - vars
->extentPosition
+ vars
->currentExtent
->start
);
973 uint32_t length
= (vars
->bufferOffset
);
976 if (cryptvars
&& vars
->encryptStart
977 && (vars
->position
> vars
->encryptStart
)
978 && ((vars
->position
- length
) < vars
->encryptEnd
)) {
979 AbsoluteTime startTime
, endTime
;
981 uint64_t encryptLen
, encryptStart
;
982 encryptLen
= vars
->position
- vars
->encryptStart
;
983 if (encryptLen
> length
) {
986 encryptStart
= length
- encryptLen
;
987 if (vars
->position
> vars
->encryptEnd
) {
988 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
991 clock_get_uptime(&startTime
);
993 assert(encryptLen
<= UINT_MAX
);
994 // encrypt the buffer
995 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
996 &cryptvars
->aes_iv
[0],
997 (unsigned int) (encryptLen
/ AES_BLOCK_SIZE
),
998 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
999 &cryptvars
->ctx
.encrypt
);
1001 clock_get_uptime(&endTime
);
1002 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1003 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1004 vars
->cryptBytes
+= encryptLen
;
1006 // save initial vector for following encrypts
1007 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
1008 &cryptvars
->aes_iv
[0],
1013 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1014 if (kIOReturnSuccess
!= err
) {
1018 if (vars
->position
& (vars
->blockSize
- 1)) {
1019 HIBLOG("misaligned file pos %qx\n", vars
->position
);
1021 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
1023 err
= IOStartPolledIO(vars
->pollers
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
1024 if (kIOReturnSuccess
!= err
) {
1025 HIBLOGFROMPANIC("IOPolledFileWrite(0x%p, 0x%p, %llu, 0x%p) : IOStartPolledIO(0x%p, kIOPolledWrite, %llu, 0x%llx, %d) returned 0x%x\n",
1026 vars
, bytes
, (uint64_t) original_size
, cryptvars
, vars
->pollers
, (uint64_t) vars
->bufferHalf
, offset
, length
, err
);
1029 vars
->pollers
->io
= true;
1031 vars
->extentRemaining
-= vars
->bufferOffset
;
1032 if (!vars
->extentRemaining
) {
1033 vars
->currentExtent
++;
1034 vars
->extentRemaining
= vars
->currentExtent
->length
;
1035 vars
->extentPosition
= vars
->position
;
1038 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1039 vars
->bufferOffset
= 0;
1040 if (vars
->bufferSize
<= vars
->extentRemaining
) {
1041 vars
->bufferLimit
= vars
->bufferSize
;
1043 vars
->bufferLimit
= ((uint32_t) vars
->extentRemaining
);
1046 if (!vars
->extentRemaining
) {
1047 err
= kIOReturnOverrun
;
1058 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1061 IOPolledFileFlush(IOPolledFileIOVars
* vars
)
1063 // Only supported by the underlying polled mode driver on embedded currently (expect kIOReturnUnsupported on other platforms)
1064 IOReturn err
= kIOReturnSuccess
;
1066 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1067 if (kIOReturnSuccess
!= err
) {
1071 err
= IOStartPolledIO(vars
->pollers
, kIOPolledFlush
, 0, 0, 0);
1072 if (kIOReturnSuccess
!= err
) {
1073 HIBLOGFROMPANIC("IOPolledFileFlush(0x%p) : IOStartPolledIO(0x%p, kIOPolledFlush, 0, 0, 0) returned 0x%x\n",
1074 vars
, vars
->pollers
, err
);
1077 vars
->pollers
->io
= true;
1082 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1085 IOPolledFileRead(IOPolledFileIOVars
* vars
,
1086 uint8_t * bytes
, IOByteCount size
,
1087 IOPolledFileCryptVars
* cryptvars
)
1089 IOReturn err
= kIOReturnSuccess
;
1092 // bytesWritten += size;
1095 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
1102 __nosan_bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1104 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1109 vars
->bufferOffset
+= copy
;
1110 // vars->position += copy;
1112 if ((vars
->bufferOffset
== vars
->bufferLimit
) && (vars
->position
< vars
->readEnd
)) {
1113 if (!vars
->pollers
->io
) {
1116 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1117 if (kIOReturnSuccess
!= err
) {
1121 if (vars
->position
& (vars
->blockSize
- 1)) {
1122 HIBLOG("misaligned file pos %qx\n", vars
->position
);
1125 vars
->position
+= vars
->lastRead
;
1126 vars
->extentRemaining
-= vars
->lastRead
;
1127 vars
->bufferLimit
= vars
->lastRead
;
1129 if (!vars
->extentRemaining
) {
1130 vars
->currentExtent
++;
1131 vars
->extentRemaining
= vars
->currentExtent
->length
;
1132 vars
->extentPosition
= vars
->position
;
1133 if (!vars
->extentRemaining
) {
1134 err
= kIOReturnOverrun
;
1140 uint32_t lastReadLength
= vars
->lastRead
;
1141 uint64_t offset
= (vars
->position
1142 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1143 if (vars
->extentRemaining
<= vars
->bufferSize
) {
1144 length
= ((uint32_t) vars
->extentRemaining
);
1146 length
= vars
->bufferSize
;
1148 if ((length
+ vars
->position
) > vars
->readEnd
) {
1149 length
= ((uint32_t) (vars
->readEnd
- vars
->position
));
1152 vars
->lastRead
= length
;
1154 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1155 err
= IOStartPolledIO(vars
->pollers
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
1156 if (kIOReturnSuccess
!= err
) {
1159 vars
->pollers
->io
= true;
1162 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1163 vars
->bufferOffset
= 0;
1167 uint8_t thisVector
[AES_BLOCK_SIZE
];
1168 AbsoluteTime startTime
, endTime
;
1170 // save initial vector for following decrypts
1171 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
1172 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
1173 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1175 // decrypt the buffer
1176 clock_get_uptime(&startTime
);
1178 assert(lastReadLength
<= UINT_MAX
);
1179 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
1181 (unsigned int) (lastReadLength
/ AES_BLOCK_SIZE
),
1182 vars
->buffer
+ vars
->bufferHalf
,
1183 &cryptvars
->ctx
.decrypt
);
1185 clock_get_uptime(&endTime
);
1186 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1187 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1188 vars
->cryptBytes
+= lastReadLength
;
1197 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */