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 "IOKitKernelInternal.h"
43 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
45 OSDefineMetaClassAndAbstractStructors(IOPolledInterface
, OSObject
);
47 OSMetaClassDefineReservedUsed(IOPolledInterface
, 0);
48 OSMetaClassDefineReservedUnused(IOPolledInterface
, 1);
49 OSMetaClassDefineReservedUnused(IOPolledInterface
, 2);
50 OSMetaClassDefineReservedUnused(IOPolledInterface
, 3);
51 OSMetaClassDefineReservedUnused(IOPolledInterface
, 4);
52 OSMetaClassDefineReservedUnused(IOPolledInterface
, 5);
53 OSMetaClassDefineReservedUnused(IOPolledInterface
, 6);
54 OSMetaClassDefineReservedUnused(IOPolledInterface
, 7);
55 OSMetaClassDefineReservedUnused(IOPolledInterface
, 8);
56 OSMetaClassDefineReservedUnused(IOPolledInterface
, 9);
57 OSMetaClassDefineReservedUnused(IOPolledInterface
, 10);
58 OSMetaClassDefineReservedUnused(IOPolledInterface
, 11);
59 OSMetaClassDefineReservedUnused(IOPolledInterface
, 12);
60 OSMetaClassDefineReservedUnused(IOPolledInterface
, 13);
61 OSMetaClassDefineReservedUnused(IOPolledInterface
, 14);
62 OSMetaClassDefineReservedUnused(IOPolledInterface
, 15);
64 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
66 #ifndef kIOMediaPreferredBlockSizeKey
67 #define kIOMediaPreferredBlockSizeKey "Preferred Block Size"
70 enum { kDefaultIOSize
= 128 * 1024 };
72 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
74 class IOPolledFilePollers
: public OSObject
76 OSDeclareDefaultStructors(IOPolledFilePollers
);
81 IOBufferMemoryDescriptor
* ioBuffer
;
87 static IOPolledFilePollers
* copyPollers(IOService
* media
);
90 OSDefineMetaClassAndStructors(IOPolledFilePollers
, OSObject
)
92 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
95 IOPolledFilePollers::copyPollers(IOService
* media
)
97 IOPolledFilePollers
* vars
;
101 IORegistryEntry
* next
;
102 IORegistryEntry
* child
;
104 if ((obj
= media
->copyProperty(kIOPolledInterfaceStackKey
))) {
105 return OSDynamicCast(IOPolledFilePollers
, obj
);
109 vars
= OSTypeAlloc(IOPolledFilePollers
);
112 vars
->pollers
= OSArray::withCapacity(4);
113 if (!vars
->pollers
) {
114 err
= kIOReturnNoMemory
;
118 next
= vars
->media
= media
;
120 IOPolledInterface
* poller
;
123 obj
= next
->getProperty(kIOPolledInterfaceSupportKey
);
124 if (kOSBooleanFalse
== obj
) {
125 vars
->pollers
->flushCollection();
127 } else if ((poller
= OSDynamicCast(IOPolledInterface
, obj
))) {
128 vars
->pollers
->setObject(poller
);
131 if ((service
= OSDynamicCast(IOService
, next
))
132 && service
->getDeviceMemory()
133 && !vars
->pollers
->getCount()) {
138 }while ((next
= child
->getParentEntry(gIOServicePlane
))
139 && child
->isParent(next
, gIOServicePlane
, true));
141 if (!vars
->pollers
->getCount()) {
142 err
= kIOReturnUnsupported
;
147 media
->setProperty(kIOPolledInterfaceStackKey
, vars
);
152 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
155 IOPolledFilePollersIODone(IOPolledFilePollers
* vars
, bool abortable
);
157 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
160 IOPolledFilePollersProbe(IOPolledFilePollers
* vars
)
162 IOReturn err
= kIOReturnError
;
164 IOPolledInterface
* poller
;
166 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--) {
167 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
168 err
= poller
->probe(vars
->media
);
170 HIBLOG("IOPolledInterface::probe[%d] 0x%x\n", idx
, err
);
178 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
181 IOPolledFilePollersOpen(IOPolledFileIOVars
* filevars
, uint32_t state
, bool abortable
)
183 IOPolledFilePollers
* vars
= filevars
->pollers
;
184 IOBufferMemoryDescriptor
* ioBuffer
;
185 IOPolledInterface
* poller
;
187 IOReturn err
= kIOReturnError
;
190 vars
->abortable
= abortable
;
193 if (kIOPolledAfterSleepState
== state
) {
197 (void) IOPolledFilePollersIODone(vars
, false);
199 if ((kIOPolledPreflightState
== state
) || (kIOPolledPreflightCoreDumpState
== state
)) {
200 ioBuffer
= vars
->ioBuffer
;
202 vars
->ioBuffer
= ioBuffer
= IOBufferMemoryDescriptor::withOptions(kIODirectionInOut
,
203 2 * kDefaultIOSize
, page_size
);
205 return kIOReturnNoMemory
;
210 for (idx
= vars
->pollers
->getCount() - 1; idx
>= 0; idx
--) {
211 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
212 err
= poller
->open(state
, ioBuffer
);
213 if (kIOReturnSuccess
!= err
) {
214 HIBLOG("IOPolledInterface::open[%d] 0x%x\n", idx
, err
);
218 if ((kIOReturnSuccess
== err
) && (kIOPolledPreflightState
== state
)) {
221 next
->setProperty(kIOPolledInterfaceActiveKey
, kOSBooleanTrue
);
222 next
= next
->getProvider();
229 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
232 IOPolledFilePollersClose(IOPolledFileIOVars
* filevars
, uint32_t state
)
234 IOPolledFilePollers
* vars
= filevars
->pollers
;
235 IOPolledInterface
* poller
;
236 IORegistryEntry
* next
;
240 (void) IOPolledFilePollersIODone(vars
, false);
242 if ((kIOPolledPostflightState
== state
) || (kIOPolledPostflightCoreDumpState
== state
)) {
246 for (idx
= 0, err
= kIOReturnSuccess
;
247 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
249 err
= poller
->close(state
);
250 if ((kIOReturnSuccess
!= err
) && (kIOPolledBeforeSleepStateAborted
== state
)) {
251 err
= poller
->close(kIOPolledBeforeSleepState
);
254 HIBLOG("IOPolledInterface::close[%d] 0x%x\n", idx
, err
);
258 if (kIOPolledPostflightState
== state
) {
261 next
->removeProperty(kIOPolledInterfaceActiveKey
);
262 next
= next
->getParentEntry(gIOServicePlane
);
266 if ((kIOPolledPostflightState
== state
) || (kIOPolledPostflightCoreDumpState
== state
)) {
268 if (vars
->openCount
) {
271 if (vars
->ioBuffer
) {
272 vars
->ioBuffer
->release();
273 vars
->ioBuffer
= NULL
;
281 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
284 IOPolledInterface::setEncryptionKey(const uint8_t * key
, size_t keySize
)
286 return kIOReturnUnsupported
;
289 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
292 IOPolledFilePollersSetEncryptionKey(IOPolledFileIOVars
* filevars
,
293 const uint8_t * key
, size_t keySize
)
295 IOReturn ret
= kIOReturnUnsupported
;
298 IOPolledFilePollers
* vars
= filevars
->pollers
;
299 IOPolledInterface
* poller
;
302 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
304 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
);
305 err
= poller
->setEncryptionKey(key
, keySize
);
306 if (kIOReturnSuccess
== err
) {
314 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
317 IOPolledFileGetIOBuffer(IOPolledFileIOVars
* vars
)
319 return vars
->pollers
->ioBuffer
;
322 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
325 IOPolledIOComplete(void * target
,
328 UInt64 actualByteCount
)
330 IOPolledFilePollers
* vars
= (IOPolledFilePollers
*) parameter
;
332 vars
->ioStatus
= status
;
335 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
338 IOStartPolledIO(IOPolledFilePollers
* vars
,
339 uint32_t operation
, uint32_t bufferOffset
,
340 uint64_t deviceOffset
, uint64_t length
)
343 IOPolledInterface
* poller
;
344 IOPolledCompletion completion
;
346 err
= vars
->ioStatus
;
347 if (kIOReturnSuccess
!= err
) {
351 completion
.target
= NULL
;
352 completion
.action
= &IOPolledIOComplete
;
353 completion
.parameter
= vars
;
357 poller
= (IOPolledInterface
*) vars
->pollers
->getObject(0);
358 err
= poller
->startIO(operation
, bufferOffset
, deviceOffset
, length
, completion
);
360 if (kernel_debugger_entry_count
) {
361 HIBLOG("IOPolledInterface::startIO[%d] 0x%x\n", 0, err
);
363 HIBLOGFROMPANIC("IOPolledInterface::IOStartPolledIO(0x%p, %d, 0x%x, 0x%llx, %llu) : poller->startIO(%d, 0x%x, 0x%llx, %llu, completion) returned 0x%x",
364 vars
, operation
, bufferOffset
, deviceOffset
, length
, operation
, bufferOffset
, deviceOffset
, length
, err
);
370 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
373 IOPolledFilePollersIODone(IOPolledFilePollers
* vars
, bool abortable
)
375 IOReturn err
= kIOReturnSuccess
;
377 IOPolledInterface
* poller
;
378 AbsoluteTime deadline
;
381 return kIOReturnSuccess
;
384 abortable
&= vars
->abortable
;
386 clock_interval_to_deadline(2000, kMillisecondScale
, &deadline
);
388 while (-1 == vars
->ioStatus
) {
390 (poller
= (IOPolledInterface
*) vars
->pollers
->getObject(idx
));
393 newErr
= poller
->checkForWork();
394 if ((newErr
== kIOReturnAborted
) && !abortable
) {
395 newErr
= kIOReturnSuccess
;
397 if (kIOReturnSuccess
== err
) {
401 if ((false) && (kIOReturnSuccess
== err
) && (mach_absolute_time() > AbsoluteTime_to_scalar(&deadline
))) {
402 HIBLOG("IOPolledInterface::forced timeout\n");
403 vars
->ioStatus
= kIOReturnTimeout
;
409 if ((kIOReturnSuccess
== err
) && abortable
&& hibernate_should_abort()) {
410 err
= kIOReturnAborted
;
411 HIBLOG("IOPolledInterface::checkForWork sw abort\n");
416 HIBLOG("IOPolledInterface::checkForWork[%d] 0x%x\n", idx
, err
);
418 err
= vars
->ioStatus
;
419 if (kIOReturnSuccess
!= err
) {
420 HIBLOG("IOPolledInterface::ioStatus 0x%x\n", err
);
427 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
428 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
430 struct _OpenFileContext
{
436 file_extent_callback(void * ref
, uint64_t start
, uint64_t length
)
438 _OpenFileContext
* ctx
= (_OpenFileContext
*) ref
;
439 IOPolledFileExtent extent
;
441 extent
.start
= start
;
442 extent
.length
= length
;
443 ctx
->extents
->appendBytes(&extent
, sizeof(extent
));
447 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
450 IOCopyMediaForDev(dev_t device
)
452 OSDictionary
* matching
;
455 IOService
* result
= NULL
;
457 matching
= IOService::serviceMatching("IOMedia");
462 num
= OSNumber::withNumber(major(device
), 32);
466 matching
->setObject(kIOBSDMajorKey
, num
);
468 num
= OSNumber::withNumber(minor(device
), 32);
472 matching
->setObject(kIOBSDMinorKey
, num
);
477 iter
= IOService::getMatchingServices(matching
);
479 result
= (IOService
*) iter
->getNextObject();
489 #define APFSMEDIA_GETHIBERKEY "getHiberKey"
492 IOGetVolumeCryptKey(dev_t block_dev
,
493 LIBKERN_RETURNS_RETAINED OSString
** pKeyUUID
,
494 uint8_t * volumeCryptKey
,
499 OSString
* keyUUID
= NULL
;
500 OSString
* keyStoreUUID
= NULL
;
501 uuid_t volumeKeyUUID
;
502 aks_volume_key_t vek
;
503 size_t callerKeySize
;
505 static IOService
* sKeyStore
;
507 part
= IOCopyMediaForDev(block_dev
);
509 return kIOReturnNotFound
;
512 callerKeySize
= *keySize
;
515 uuid_t volUuid
= {0};
516 err
= part
->callPlatformFunction(APFSMEDIA_GETHIBERKEY
, false, &volUuid
, volumeCryptKey
, keySize
, keySize
);
517 if (kIOReturnBadArgument
== err
) {
518 // apfs fails on buffer size >32
520 err
= part
->callPlatformFunction(APFSMEDIA_GETHIBERKEY
, false, &volUuid
, volumeCryptKey
, keySize
, keySize
);
522 if (err
!= kIOReturnSuccess
) {
525 // No need to create uuid string if it's not requested
527 uuid_string_t volUuidStr
;
528 uuid_unparse(volUuid
, volUuidStr
);
529 *pKeyUUID
= OSString::withCString(volUuidStr
);
533 return kIOReturnSuccess
;
538 err
= part
->callPlatformFunction(PLATFORM_FUNCTION_GET_MEDIA_ENCRYPTION_KEY_UUID
, false,
539 (void *) &keyUUID
, (void *) &keyStoreUUID
, NULL
, NULL
);
540 if ((kIOReturnSuccess
== err
) && keyUUID
&& keyStoreUUID
) {
541 // IOLog("got volume key %s\n", keyStoreUUID->getCStringNoCopy());
544 sKeyStore
= (IOService
*) IORegistryEntry::fromPath(AKS_SERVICE_PATH
, gIOServicePlane
);
547 err
= uuid_parse(keyStoreUUID
->getCStringNoCopy(), volumeKeyUUID
);
549 err
= kIOReturnNoResources
;
551 if (kIOReturnSuccess
== err
) {
552 err
= sKeyStore
->callPlatformFunction(gAKSGetKey
, true, volumeKeyUUID
, &vek
, NULL
, NULL
);
554 if (kIOReturnSuccess
!= err
) {
555 IOLog("volume key err 0x%x\n", err
);
557 if (vek
.key
.keybytecount
<= callerKeySize
) {
558 *keySize
= vek
.key
.keybytecount
;
560 bcopy(&vek
.key
.keybytes
[0], volumeCryptKey
, *keySize
);
562 bzero(&vek
, sizeof(vek
));
565 // Create a copy because the caller would release it
566 *pKeyUUID
= OSString::withString(keyUUID
);
574 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
577 IOPolledFileOpen(const char * filename
,
579 uint64_t setFileSize
, uint64_t fsFreeSize
,
580 void * write_file_addr
, size_t write_file_len
,
581 IOPolledFileIOVars
** fileVars
,
583 uint8_t * volumeCryptKey
, size_t * keySize
)
585 IOReturn err
= kIOReturnSuccess
;
586 IOPolledFileIOVars
* vars
;
587 _OpenFileContext ctx
;
588 OSData
* extentsData
= NULL
;
590 IOService
* part
= NULL
;
593 AbsoluteTime startTime
, endTime
;
596 vars
= IONew(IOPolledFileIOVars
, 1);
598 return kIOReturnNoMemory
;
600 bzero(vars
, sizeof(*vars
));
601 vars
->allocated
= true;
604 extentsData
= OSData::withCapacity(32);
605 ctx
.extents
= extentsData
;
607 clock_get_uptime(&startTime
);
609 vars
->fileRef
= kern_open_file_for_direct_io(filename
,
611 &file_extent_callback
, &ctx
,
615 0, write_file_addr
, write_file_len
,
623 uint32_t msDelay
= (131071 & random());
624 HIBLOG("sleep %d\n", msDelay
);
627 clock_get_uptime(&endTime
);
628 SUB_ABSOLUTETIME(&endTime
, &startTime
);
629 absolutetime_to_nanoseconds(endTime
, &nsec
);
631 if (!vars
->fileRef
) {
632 err
= kIOReturnNoSpace
;
635 HIBLOG("kern_open_file_for_direct_io took %qd ms\n", nsec
/ 1000000ULL);
636 if (kIOReturnSuccess
!= err
) {
640 HIBLOG("Opened file %s, size %qd, extents %ld, maxio %qx ssd %d\n", filename
, ctx
.size
,
641 (extentsData
->getLength() / sizeof(IOPolledFileExtent
)) - 1,
642 vars
->maxiobytes
, kIOPolledFileSSD
& vars
->flags
);
643 assert(!vars
->block0
);
644 if (extentsData
->getLength() < sizeof(IOPolledFileExtent
)) {
645 err
= kIOReturnNoSpace
;
649 vars
->fileSize
= ctx
.size
;
650 vars
->extentMap
= (IOPolledFileExtent
*) extentsData
->getBytesNoCopy();
652 part
= IOCopyMediaForDev(image_dev
);
654 err
= kIOReturnNotFound
;
658 if (!(vars
->pollers
= IOPolledFilePollers::copyPollers(part
))) {
662 if ((num
= OSDynamicCast(OSNumber
, part
->getProperty(kIOMediaPreferredBlockSizeKey
)))) {
663 vars
->blockSize
= num
->unsigned32BitValue();
665 if (vars
->blockSize
< 4096) {
666 vars
->blockSize
= 4096;
669 HIBLOG("polled file major %d, minor %d, blocksize %ld, pollers %d\n",
670 major(image_dev
), minor(image_dev
), (long)vars
->blockSize
,
671 vars
->pollers
->pollers
->getCount());
673 OSString
* keyUUID
= NULL
;
674 if (volumeCryptKey
) {
675 err
= IOGetVolumeCryptKey(block_dev
, &keyUUID
, volumeCryptKey
, keySize
);
679 vars
->fileExtents
= extentsData
;
684 #if defined(__i386__) || defined(__x86_64__)
685 char str2
[24 + sizeof(uuid_string_t
) + 2];
688 snprintf(str2
, sizeof(str2
), "%qx:%s",
689 vars
->extentMap
[0].start
, keyUUID
->getCStringNoCopy());
691 snprintf(str2
, sizeof(str2
), "%qx", vars
->extentMap
[0].start
);
694 err
= IOService::getPlatform()->callPlatformFunction(
695 gIOCreateEFIDevicePathSymbol
, false,
696 (void *) part
, (void *) str2
,
697 (void *) (uintptr_t) true, (void *) &data
);
700 err
= kIOReturnSuccess
;
702 if (kIOReturnSuccess
!= err
) {
703 HIBLOG("error 0x%x getting path\n", err
);
709 // Release key UUID if we have one
712 keyUUID
= NULL
; // Just in case
716 if (kIOReturnSuccess
!= err
) {
717 HIBLOG("error 0x%x opening polled file\n", err
);
718 IOPolledFileClose(&vars
, 0, NULL
, 0, 0, 0);
720 extentsData
->release();
731 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
734 IOPolledFileClose(IOPolledFileIOVars
** pVars
,
735 off_t write_offset
, void * addr
, size_t write_length
,
736 off_t discard_offset
, off_t discard_end
)
738 IOPolledFileIOVars
* vars
;
742 return kIOReturnSuccess
;
746 kern_close_file_for_direct_io(vars
->fileRef
, write_offset
, addr
, write_length
,
747 discard_offset
, discard_end
);
748 vars
->fileRef
= NULL
;
750 if (vars
->fileExtents
) {
751 vars
->fileExtents
->release();
752 vars
->fileExtents
= NULL
;
755 vars
->pollers
->release();
756 vars
->pollers
= NULL
;
759 if (vars
->allocated
) {
760 IODelete(vars
, IOPolledFileIOVars
, 1);
762 bzero(vars
, sizeof(IOPolledFileIOVars
));
766 return kIOReturnSuccess
;
769 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
772 IOPolledFilePollersSetup(IOPolledFileIOVars
* vars
,
777 err
= kIOReturnSuccess
;
779 if (!vars
->pollers
->openCount
) {
780 err
= IOPolledFilePollersProbe(vars
->pollers
);
781 if (kIOReturnSuccess
!= err
) {
785 err
= IOPolledFilePollersOpen(vars
, openState
, false);
786 if (kIOReturnSuccess
!= err
) {
789 if ((kIOPolledPreflightState
== openState
) || (kIOPolledPreflightCoreDumpState
== openState
)) {
790 vars
->pollers
->openCount
++;
792 vars
->pollers
->io
= false;
793 vars
->buffer
= (uint8_t *) vars
->pollers
->ioBuffer
->getBytesNoCopy();
794 vars
->bufferHalf
= 0;
795 vars
->bufferOffset
= 0;
796 vars
->bufferSize
= (vars
->pollers
->ioBuffer
->getLength() >> 1);
798 if (vars
->maxiobytes
< vars
->bufferSize
) {
799 vars
->bufferSize
= vars
->maxiobytes
;
803 if (kIOReturnSuccess
!= err
) {
804 HIBLOG("IOPolledFilePollersSetup(%d) error 0x%x\n", openState
, err
);
811 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
814 IOPolledFileSeek(IOPolledFileIOVars
* vars
, uint64_t position
)
816 IOPolledFileExtent
* extentMap
;
818 extentMap
= vars
->extentMap
;
820 vars
->position
= position
;
822 if (position
> vars
->fileSize
) {
823 HIBLOG("IOPolledFileSeek: called to seek to 0x%llx greater than file size of 0x%llx\n", vars
->position
, vars
->fileSize
);
824 return kIOReturnNoSpace
;
827 while (position
>= extentMap
->length
) {
828 position
-= extentMap
->length
;
832 vars
->currentExtent
= extentMap
;
833 vars
->extentRemaining
= extentMap
->length
- position
;
834 vars
->extentPosition
= vars
->position
- position
;
836 if (vars
->bufferSize
<= vars
->extentRemaining
) {
837 vars
->bufferLimit
= vars
->bufferSize
;
839 vars
->bufferLimit
= vars
->extentRemaining
;
842 return kIOReturnSuccess
;
845 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
848 IOPolledFileWrite(IOPolledFileIOVars
* vars
,
849 const uint8_t * bytes
, IOByteCount size
,
850 IOPolledFileCryptVars
* cryptvars
)
852 IOReturn err
= kIOReturnSuccess
;
853 IOByteCount copy
, original_size
= size
;
857 if (!bytes
&& !size
) {
858 // seek to end of block & flush
859 size
= vars
->position
& (vars
->blockSize
- 1);
861 size
= vars
->blockSize
- size
;
864 // use some garbage for the fill
865 bytes
= vars
->buffer
+ vars
->bufferOffset
;
868 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
877 /* Since this may copy mach-o segments in bulk, use the nosan variants of bcopy to
878 * avoid triggering global redzone sanitizer violations when accessing
879 * interstices between 'C' structures
881 __nosan_bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
883 bcopy(bytes
, vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
887 bzero(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, copy
);
891 vars
->bufferOffset
+= copy
;
892 vars
->position
+= copy
;
894 if (flush
&& vars
->bufferOffset
) {
895 uint64_t offset
= (vars
->position
- vars
->bufferOffset
896 - vars
->extentPosition
+ vars
->currentExtent
->start
);
897 uint32_t length
= (vars
->bufferOffset
);
900 if (cryptvars
&& vars
->encryptStart
901 && (vars
->position
> vars
->encryptStart
)
902 && ((vars
->position
- length
) < vars
->encryptEnd
)) {
903 AbsoluteTime startTime
, endTime
;
905 uint64_t encryptLen
, encryptStart
;
906 encryptLen
= vars
->position
- vars
->encryptStart
;
907 if (encryptLen
> length
) {
910 encryptStart
= length
- encryptLen
;
911 if (vars
->position
> vars
->encryptEnd
) {
912 encryptLen
-= (vars
->position
- vars
->encryptEnd
);
915 clock_get_uptime(&startTime
);
917 // encrypt the buffer
918 aes_encrypt_cbc(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
919 &cryptvars
->aes_iv
[0],
920 encryptLen
/ AES_BLOCK_SIZE
,
921 vars
->buffer
+ vars
->bufferHalf
+ encryptStart
,
922 &cryptvars
->ctx
.encrypt
);
924 clock_get_uptime(&endTime
);
925 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
926 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
927 vars
->cryptBytes
+= encryptLen
;
929 // save initial vector for following encrypts
930 bcopy(vars
->buffer
+ vars
->bufferHalf
+ encryptStart
+ encryptLen
- AES_BLOCK_SIZE
,
931 &cryptvars
->aes_iv
[0],
936 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
937 if (kIOReturnSuccess
!= err
) {
941 if (vars
->position
& (vars
->blockSize
- 1)) {
942 HIBLOG("misaligned file pos %qx\n", vars
->position
);
944 //if (length != vars->bufferSize) HIBLOG("short write of %qx ends@ %qx\n", length, offset + length);
946 err
= IOStartPolledIO(vars
->pollers
, kIOPolledWrite
, vars
->bufferHalf
, offset
, length
);
947 if (kIOReturnSuccess
!= err
) {
948 HIBLOGFROMPANIC("IOPolledFileWrite(0x%p, 0x%p, %llu, 0x%p) : IOStartPolledIO(0x%p, kIOPolledWrite, %llu, 0x%llx, %d) returned 0x%x\n",
949 vars
, bytes
, (uint64_t) original_size
, cryptvars
, vars
->pollers
, (uint64_t) vars
->bufferHalf
, offset
, length
, err
);
952 vars
->pollers
->io
= true;
954 vars
->extentRemaining
-= vars
->bufferOffset
;
955 if (!vars
->extentRemaining
) {
956 vars
->currentExtent
++;
957 vars
->extentRemaining
= vars
->currentExtent
->length
;
958 vars
->extentPosition
= vars
->position
;
961 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
962 vars
->bufferOffset
= 0;
963 if (vars
->bufferSize
<= vars
->extentRemaining
) {
964 vars
->bufferLimit
= vars
->bufferSize
;
966 vars
->bufferLimit
= vars
->extentRemaining
;
969 if (!vars
->extentRemaining
) {
970 err
= kIOReturnOverrun
;
981 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
984 IOPolledFileFlush(IOPolledFileIOVars
* vars
)
986 // Only supported by the underlying polled mode driver on embedded currently (expect kIOReturnUnsupported on other platforms)
987 IOReturn err
= kIOReturnSuccess
;
989 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
990 if (kIOReturnSuccess
!= err
) {
994 err
= IOStartPolledIO(vars
->pollers
, kIOPolledFlush
, 0, 0, 0);
995 if (kIOReturnSuccess
!= err
) {
996 HIBLOGFROMPANIC("IOPolledFileFlush(0x%p) : IOStartPolledIO(0x%p, kIOPolledFlush, 0, 0, 0) returned 0x%x\n",
997 vars
, vars
->pollers
, err
);
1000 vars
->pollers
->io
= true;
1005 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1008 IOPolledFileRead(IOPolledFileIOVars
* vars
,
1009 uint8_t * bytes
, IOByteCount size
,
1010 IOPolledFileCryptVars
* cryptvars
)
1012 IOReturn err
= kIOReturnSuccess
;
1015 // bytesWritten += size;
1018 copy
= vars
->bufferLimit
- vars
->bufferOffset
;
1025 __nosan_bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1027 bcopy(vars
->buffer
+ vars
->bufferHalf
+ vars
->bufferOffset
, bytes
, copy
);
1032 vars
->bufferOffset
+= copy
;
1033 // vars->position += copy;
1035 if ((vars
->bufferOffset
== vars
->bufferLimit
) && (vars
->position
< vars
->readEnd
)) {
1036 if (!vars
->pollers
->io
) {
1039 err
= IOPolledFilePollersIODone(vars
->pollers
, true);
1040 if (kIOReturnSuccess
!= err
) {
1044 if (vars
->position
& (vars
->blockSize
- 1)) {
1045 HIBLOG("misaligned file pos %qx\n", vars
->position
);
1048 vars
->position
+= vars
->lastRead
;
1049 vars
->extentRemaining
-= vars
->lastRead
;
1050 vars
->bufferLimit
= vars
->lastRead
;
1052 if (!vars
->extentRemaining
) {
1053 vars
->currentExtent
++;
1054 vars
->extentRemaining
= vars
->currentExtent
->length
;
1055 vars
->extentPosition
= vars
->position
;
1056 if (!vars
->extentRemaining
) {
1057 err
= kIOReturnOverrun
;
1063 uint64_t lastReadLength
= vars
->lastRead
;
1064 uint64_t offset
= (vars
->position
1065 - vars
->extentPosition
+ vars
->currentExtent
->start
);
1066 if (vars
->extentRemaining
<= vars
->bufferSize
) {
1067 length
= vars
->extentRemaining
;
1069 length
= vars
->bufferSize
;
1071 if ((length
+ vars
->position
) > vars
->readEnd
) {
1072 length
= vars
->readEnd
- vars
->position
;
1075 vars
->lastRead
= length
;
1077 //if (length != vars->bufferSize) HIBLOG("short read of %qx ends@ %qx\n", length, offset + length);
1078 err
= IOStartPolledIO(vars
->pollers
, kIOPolledRead
, vars
->bufferHalf
, offset
, length
);
1079 if (kIOReturnSuccess
!= err
) {
1082 vars
->pollers
->io
= true;
1085 vars
->bufferHalf
= vars
->bufferHalf
? 0 : vars
->bufferSize
;
1086 vars
->bufferOffset
= 0;
1090 uint8_t thisVector
[AES_BLOCK_SIZE
];
1091 AbsoluteTime startTime
, endTime
;
1093 // save initial vector for following decrypts
1094 bcopy(&cryptvars
->aes_iv
[0], &thisVector
[0], AES_BLOCK_SIZE
);
1095 bcopy(vars
->buffer
+ vars
->bufferHalf
+ lastReadLength
- AES_BLOCK_SIZE
,
1096 &cryptvars
->aes_iv
[0], AES_BLOCK_SIZE
);
1098 // decrypt the buffer
1099 clock_get_uptime(&startTime
);
1101 aes_decrypt_cbc(vars
->buffer
+ vars
->bufferHalf
,
1103 lastReadLength
/ AES_BLOCK_SIZE
,
1104 vars
->buffer
+ vars
->bufferHalf
,
1105 &cryptvars
->ctx
.decrypt
);
1107 clock_get_uptime(&endTime
);
1108 ADD_ABSOLUTETIME(&vars
->cryptTime
, &endTime
);
1109 SUB_ABSOLUTETIME(&vars
->cryptTime
, &startTime
);
1110 vars
->cryptBytes
+= lastReadLength
;
1119 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */