Hello everyone,
We are in the process of migrating a high-performance storage KEXT to DriverKit. During our initial validation phase, we noticed a performance gap between the DEXT and the KEXT, which prompted us to try and optimize our I/O handling process.
Background and Motivation:
Our test hardware is a RAID 0 array of two HDDs. According to AJA System Test, our legacy KEXT achieves a write speed of about 645 MB/s on this hardware, whereas the new DEXT reaches about 565 MB/s. We suspect the primary reason for this performance gap might be that the DEXT, by default, uses a serial work-loop to submit I/O commands, which fails to fully leverage the parallelism of the hardware array.
Therefore, to eliminate this bottleneck and improve performance, we configured a dedicated parallel dispatch queue (MyParallelIOQueue) for the UserProcessParallelTask method.
However, during our implementation attempt, we encountered a critical issue that caused a system-wide crash.
The Operation Causing the Panic:
We configured MyParallelIOQueue using the following combination of methods:
In the .iig file: We appended the QUEUENAME(MyParallelIOQueue) macro after the override keyword of the UserProcessParallelTask method declaration.
In the .cpp file: We manually created a queue with the same name by calling the IODispatchQueue::Create() function within our UserInitializeController method.
The Result:
This results in a macOS kernel panic during the DEXT loading process, forcing the user to perform a hard reboot.
After the reboot, checking with the systemextensionsctl list command reveals the DEXT's status as [activated waiting for user], which indicates that it encountered an unrecoverable, fatal error during its initialization.
Key Code Snippets to Reproduce the Panic:
In .iig file - this was our exact implementation:
class DRV_MAIN_CLASS_NAME: public IOUserSCSIParallelInterfaceController
{
public:
virtual kern_return_t UserProcessParallelTask(...) override
QUEUENAME(MyParallelIOQueue);
};
In .h file:
struct DRV_MAIN_CLASS_NAME_IVars {
// ...
IODispatchQueue* MyParallelIOQueue;
};
In UserInitializeController implementation:
kern_return_t
IMPL(DRV_MAIN_CLASS_NAME, UserInitializeController)
{
// ...
// We also included code to manually create the queue.
kern_return_t ret = IODispatchQueue::Create("MyParallelIOQueue",
kIODispatchQueueReentrant,
0,
&ivars->MyParallelIOQueue);
if (ret != kIOReturnSuccess) {
// ... error handling ...
}
// ...
return kIOReturnSuccess;
}
Our Question:
What is the officially recommended and most stable method for configuring UserProcessParallelTask_Impl() to use a parallel I/O queue?
Clarifying this is crucial for all developers pursuing high-performance storage solutions with DriverKit. Any explanation or guidance would be greatly appreciated.
Best Regards,
Charles
Drivers
RSS for tagUnderstand the role of drivers in bridging the gap between software and hardware, ensuring smooth hardware functionality.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am developing a DriverKit driver with the goal of sending vendor-specific commands to a USB storage device.
I have successfully created the DriverKit driver, and when I connect the USB storage device, it appears correctly in IORegistryExplorer.
My driver class inherits from IOUserSCSIPeripheralDeviceType00 in the SCSIPeripheralsDriverKit framework.
I also created a UserClient class that inherits from IOUserClient, and from its ExternalMethod I tried sending an INQUIRY command as a basic test to confirm that command transmission works.
However, the device returns an ILLEGAL REQUEST (Sense Key 0x5 / ASC 0x20).
Could someone advise what I might be doing wrong?
Below are the logs output from the driver:
2025-11-14 21:00:43.573730+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] Driver - NewUserClient() - Finished.
2025-11-14 21:00:43.573733+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - Start()
2025-11-14 21:00:43.573807+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - Start() - Finished.
2025-11-14 21:00:43.574249+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - ExternalMethod() called
2025-11-14 21:00:43.574258+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - ----- SCSICmdINQUIRY -----
2025-11-14 21:00:43.574268+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - command.fRequestedByteCountOfTransfer = 512
2025-11-14 21:00:43.575980+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB fCompletionStatus = 0x0
2025-11-14 21:00:43.575988+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB fServiceResponse = 0x2
2025-11-14 21:00:43.575990+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB fSenseDataValid = 0x1
2025-11-14 21:00:43.575992+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB VALID_RESPONSE_CODE = 0x70
2025-11-14 21:00:43.575994+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB SENSE_KEY = 0x5
2025-11-14 21:00:43.575996+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB ADDITIONAL_SENSE_CODE = 0x20
2025-11-14 21:00:43.575998+0900 0x26e9 Default 0x0 0 0 kernel: (SampleDriverKitApp.SampleDriverKitDriver.dext) [DEBUG] UserClient - SCSICmdINQUIRY() UserSendCDB ADDITIONAL_SENSE_CODE_QUALIFIER = 0x0
Here is the UserClient class:
class SampleDriverKitUserClient: public IOUserClient
{
public:
virtual bool init(void) override;
virtual kern_return_t Start(IOService* provider) override;
virtual kern_return_t Stop(IOService* provider) override;
virtual void free(void) override;
virtual kern_return_t ExternalMethod(
uint64_t selector,
IOUserClientMethodArguments* arguments,
const IOUserClientMethodDispatch* dispatch,
OSObject* target,
void* reference) override;
void SCSICmdINQUIRY(SampleDriverKitDriver *driver) LOCALONLY;
};
Here is the part that sends the INQUIRY command:
void SampleDriverKitUserClient::SCSICmdINQUIRY(SampleDriverKitDriver *driver)
{
kern_return_t kr = KERN_SUCCESS;
SCSIType00OutParameters command = {};
UInt8 dataBuffer[512] = {0};
SCSI_Sense_Data senseData = {0};
Log("----- SCSICmdINQUIRY -----");
SetCommandCDB(&command.fCommandDescriptorBlock, 0x12, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
command.fLogicalUnitNumber = 0;
command.fTimeoutDuration = 10000; // milliseconds
command.fRequestedByteCountOfTransfer = sizeof(dataBuffer);
Log("command.fRequestedByteCountOfTransfer = %lld", command.fRequestedByteCountOfTransfer);
command.fBufferDirection = kIOMemoryDirectionIn;
command.fDataTransferDirection = kSCSIDataTransfer_FromTargetToInitiator;
command.fDataBufferAddr = reinterpret_cast<uint64_t>(dataBuffer);
command.fSenseBufferAddr = reinterpret_cast<uint64_t>(&senseData);
command.fSenseLengthRequested = sizeof(senseData);
if( driver ) {
SCSIType00InParameters response = {};
kr = driver->UserSendCDB(command, &response);
if( kr != KERN_SUCCESS ) {
Log("SCSICmdINQUIRY() UserSendCDB failed (0x%x)", kr);
return;
}
Log("SCSICmdINQUIRY() UserSendCDB fCompletionStatus = 0x%x", response.fCompletionStatus);
Log("SCSICmdINQUIRY() UserSendCDB fServiceResponse = 0x%x", response.fServiceResponse);
Log("SCSICmdINQUIRY() UserSendCDB fSenseDataValid = 0x%x", response.fSenseDataValid);
Log("SCSICmdINQUIRY() UserSendCDB VALID_RESPONSE_CODE = 0x%x", senseData.VALID_RESPONSE_CODE);
Log("SCSICmdINQUIRY() UserSendCDB SENSE_KEY = 0x%x", senseData.SENSE_KEY);
Log("SCSICmdINQUIRY() UserSendCDB ADDITIONAL_SENSE_CODE = 0x%x", senseData.ADDITIONAL_SENSE_CODE);
Log("SCSICmdINQUIRY() UserSendCDB ADDITIONAL_SENSE_CODE_QUALIFIER = 0x%x", senseData.ADDITIONAL_SENSE_CODE_QUALIFIER);
if( response.fServiceResponse == kSCSIServiceResponse_TASK_COMPLETE ) {
Log("SCSICmdINQUIRY() UserSendCDB complete success!!");
}
for( int i=0; i < 5; i++ ) {
Log("data [%04d]=0x%x [%04d]=0x%x [%04d]=0x%x [%04d]=0x%x [%04d]=0x%x [%04d]=0x%x [%04d]=0x%x [%04d]=0x%x",
i*8+0, dataBuffer[i*8+0],
i*8+1, dataBuffer[i*8+1],
i*8+2, dataBuffer[i*8+2],
i*8+3, dataBuffer[i*8+3],
i*8+4, dataBuffer[i*8+4],
i*8+5, dataBuffer[i*8+5],
i*8+6, dataBuffer[i*8+6],
i*8+7, dataBuffer[i*8+7] );
}
char vendorID[9] = {0};
memcpy(vendorID, &dataBuffer[8], 8);
Log("vendorID = %s",vendorID);
char productID[17] = {0};
memcpy(productID, &dataBuffer[16], 16);
Log("productID = %s",productID);
}
}
My environment is:
MacBook Pro (M2), macOS 15.6
If anyone has insight into what causes the ILLEGAL REQUEST, or what I am missing when using IOUserSCSIPeripheralDeviceType00 and UserSendCDB, I would greatly appreciate your help.
Thank you.
Topic:
App & System Services
SubTopic:
Drivers
Tags:
SCSIControllerDriverKit
DriverKit
BlockStorageDeviceDriverKit
We are developing a DriverKit driver on Apple M1. We use the following code to prepare DMA buffer:
IODMACommandSpecification dmaSpecification;
bzero(&dmaSpecification, sizeof(dmaSpecification));
dmaSpecification.options = kIODMACommandSpecificationNoOptions;
dmaSpecification.maxAddressBits = p_dma_mgr->maxAddressBits;
kret = IODMACommand::Create(p_dma_mgr->device,
kIODMACommandCreateNoOptions,
&dmaSpecification,
&impl->dma_cmd
);
if (kret != kIOReturnSuccess) {
os_log(OS_LOG_DEFAULT, "Error: IODMACommand::Create failed! ret=0x%x\n", kret);
impl->user_mem.reset();
IOFree(impl, sizeof(*impl));
return ret;
}
uint64_t flags = 0;
uint32_t segmentsCount = 32;
IOAddressSegment segments[32];
kret = impl->dma_cmd->PrepareForDMA(kIODMACommandPrepareForDMANoOptions,
impl->user_mem.get(),
0,
0, // 0 for entire memory
&flags,
&segmentsCount,
segments
);
if (kret != kIOReturnSuccess) {
OSSafeReleaseNULL(impl->dma_cmd);
impl->user_mem.reset();
IOFree(impl, sizeof(*impl));
os_log(OS_LOG_DEFAULT, "Error: PrepareForDMA failed! ret=0x%x\n", kret);
return kret;
}
I allocated several 8K BGRA video frames, each with a size of 141557760 bytes, and prepared the DMA according to the method mentioned above. The process was successful when the number of frames was 15 or fewer. However, issues arose when allocating 16 frames:
Error: PrepareForDMA failed! ret=0xe00002bd
By calculating, I found that the total size of 16 video frames exceeds 2GB. Is there such a limitation in DriverKit that the total DMA size cannot exceed 2GB? Are there any methods that would allow me to bypass this restriction so I can use more video frame buffers?
I'm trying to implement a virtual serial port driver for my ham radio projects which require emulating some serial port devices and I need to have a "backend" to translate the commands received by the virtual serial port into some network-based communications. I think the best way to do that is to subclass IOUserSerial? Based on the available docs on this class (https://developer.apple.com/documentation/serialdriverkit/iouserserial), I've done the basic implementation below. When the driver gets loaded, I can see sth like tty.serial-1000008DD in /dev and I can use picocom to do I/O on the virtual serial port. And I see TxDataAvailable() gets called every time I type a character in picocom.
The problems are however, firstly, when TxDataAvailable() is called, the TX buffer is all-zero so although the driver knows there is some incoming data received from picocom, it cannot actually see the data in neither Tx/Rx buffers.
Secondly, I couldn't figure out how to notify the system that there are data available for sending back to picocom. I call RxDataAvailable(), but nothing appears on picocom, and RxFreeSpaceAvailable() never gets called back. So I think I must be doing something wrong somewhere. Really appreciate it if anyone could point out how should I fix it, many thanks!
VirtualSerialPortDriver.cpp:
constexpr int bufferSize = 2048;
using SerialPortInterface = driverkit::serial::SerialPortInterface;
struct VirtualSerialPortDriver_IVars
{
IOBufferMemoryDescriptor *ifmd, *rxq, *txq;
SerialPortInterface *interface;
uint64_t rx_buf, tx_buf;
bool dtr, rts;
};
bool VirtualSerialPortDriver::init()
{
bool result = false;
result = super::init();
if (result != true)
{
goto Exit;
}
ivars = IONewZero(VirtualSerialPortDriver_IVars, 1);
if (ivars == nullptr)
{
goto Exit;
}
kern_return_t ret;
ret = ivars->rxq->Create(kIOMemoryDirectionInOut, bufferSize, 0, &ivars->rxq);
if (ret != kIOReturnSuccess) {
goto Exit;
}
ret = ivars->txq->Create(kIOMemoryDirectionInOut, bufferSize, 0, &ivars->txq);
if (ret != kIOReturnSuccess) {
goto Exit;
}
IOAddressSegment ioaddrseg;
ivars->rxq->GetAddressRange(&ioaddrseg);
ivars->rx_buf = ioaddrseg.address;
ivars->txq->GetAddressRange(&ioaddrseg);
ivars->tx_buf = ioaddrseg.address;
return true;
Exit:
return false;
}
kern_return_t
IMPL(VirtualSerialPortDriver, HwActivate)
{
kern_return_t ret;
ret = HwActivate(SUPERDISPATCH);
if (ret != kIOReturnSuccess) {
goto Exit;
}
// Loopback, set CTS to RTS, set DSR and DCD to DTR
ret = SetModemStatus(ivars->rts, ivars->dtr, false, ivars->dtr);
if (ret != kIOReturnSuccess) {
goto Exit;
}
Exit:
return ret;
}
kern_return_t
IMPL(VirtualSerialPortDriver, HwDeactivate)
{
kern_return_t ret;
ret = HwDeactivate(SUPERDISPATCH);
if (ret != kIOReturnSuccess) {
goto Exit;
}
Exit:
return ret;
}
kern_return_t
IMPL(VirtualSerialPortDriver, Start)
{
kern_return_t ret;
ret = Start(provider, SUPERDISPATCH);
if (ret != kIOReturnSuccess) {
return ret;
}
IOMemoryDescriptor *rxq_, *txq_;
ret = ConnectQueues(&ivars->ifmd, &rxq_, &txq_, ivars->rxq, ivars->txq, 0, 0, 11, 11);
if (ret != kIOReturnSuccess) {
return ret;
}
IOAddressSegment ioaddrseg;
ivars->ifmd->GetAddressRange(&ioaddrseg);
ivars->interface = reinterpret_cast<SerialPortInterface*>(ioaddrseg.address);
SerialPortInterface &intf = *ivars->interface;
ret = RegisterService();
if (ret != kIOReturnSuccess) {
goto Exit;
}
TxFreeSpaceAvailable();
Exit:
return ret;
}
void
IMPL(VirtualSerialPortDriver, TxDataAvailable)
{
SerialPortInterface &intf = *ivars->interface;
// Loopback
// FIXME consider wrapped case
size_t tx_buf_sz = intf.txPI - intf.txCI;
void *src = reinterpret_cast<void *>(ivars->tx_buf + intf.txCI);
// char src[] = "Hello, World!";
void *dest = reinterpret_cast<void *>(ivars->rx_buf + intf.rxPI);
memcpy(dest, src, tx_buf_sz);
intf.rxPI += tx_buf_sz;
RxDataAvailable();
intf.txCI = intf.txPI;
TxFreeSpaceAvailable();
Log("[TX Buf]: %{public}s", reinterpret_cast<char *>(ivars->tx_buf));
Log("[RX Buf]: %{public}s", reinterpret_cast<char *>(ivars->rx_buf));
// dmesg confirms both buffers are all-zero
Log("[TX] txPI: %d, txCI: %d, rxPI: %d, rxCI: %d, txqoffset: %d, rxqoffset: %d, txlogsz: %d, rxlogsz: %d",
intf.txPI, intf.txCI, intf.rxPI, intf.rxCI, intf.txqoffset, intf.rxqoffset, intf.txqlogsz, intf.rxqlogsz);
}
void
IMPL(VirtualSerialPortDriver, RxFreeSpaceAvailable)
{
Log("RxFreeSpaceAvailable() called!");
}
kern_return_t IMPL(VirtualSerialPortDriver,HwResetFIFO){
Log("HwResetFIFO() called with tx: %d, rx: %d!", tx, rx);
kern_return_t ret = kIOReturnSuccess;
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver,HwSendBreak){
Log("HwSendBreak() called!");
kern_return_t ret = kIOReturnSuccess;
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver,HwProgramUART){
Log("HwProgramUART() called, BaudRate: %u, nD: %d, nS: %d, P: %d!", baudRate, nDataBits, nHalfStopBits, parity);
kern_return_t ret = kIOReturnSuccess;
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver,HwProgramBaudRate){
Log("HwProgramBaudRate() called, BaudRate = %d!", baudRate);
kern_return_t ret = kIOReturnSuccess;
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver,HwProgramMCR){
Log("HwProgramMCR() called, DTR: %d, RTS: %d!", dtr, rts);
ivars->dtr = dtr;
ivars->rts = rts;
kern_return_t ret = kIOReturnSuccess;
Exit:
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver, HwGetModemStatus){
*cts = ivars->rts;
*dsr = ivars->dtr;
*ri = false;
*dcd = ivars->dtr;
Log("HwGetModemStatus() called, returning CTS=%d, DSR=%d, RI=%d, DCD=%d!", *cts, *dsr, *ri, *dcd);
kern_return_t ret = kIOReturnSuccess;
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver,HwProgramLatencyTimer){
Log("HwProgramLatencyTimer() called!");
kern_return_t ret = kIOReturnSuccess;
return ret;
}
kern_return_t IMPL(VirtualSerialPortDriver,HwProgramFlowControl){
Log("HwProgramFlowControl() called! arg: %u, xon: %d, xoff: %d", arg, xon, xoff);
kern_return_t ret = kIOReturnSuccess;
Exit:
return ret;
}
Hello forum, I'm trying to build communications between a non-MFi HID device (say, a keyboard with a USB-C port) and an iOS device over a MFi-licensed cable with Swift, what framework would you suggest?
The USB-C cable is MFi-licensed.
The keyboard is not MFi-licensed.
Topic:
App & System Services
SubTopic:
Drivers
I would like to write a driver that supports our custom USB-C connected device, which provides a serial port interface. USBSerialDriverKit looks like the solution I need. Unfortunately, without a decent sample, I'm not sure how to accomplish this. The DriverKit documentation does a good job of telling me what APIs exist but it is very light on semantic information and details about how to use all of these API elements. A function call with five unexplained parameters just is that useful to me.
Does anyone have or know of a resource that can help me figure out how to get started?
I have a driver project where I'm opening and closing a connection to a custom driver.
If I do what I think I need to be doing to unmap the memory, when I try to open the service again, it fails. If I skip the step where I do that unmapping, the service opens successfully.
If I call unmap() before trying to call openConnection() again, it will fail with a -308 error return code. If I skip that call to unmap(), it works and I'm able to communicate with my device.
Here's the code where I open the service:
public func openConnection() throws {
guard !isOpen else { return }
// Open device
var connection: io_connect_t = IO_OBJECT_NULL
var result = IOServiceOpen(device, mach_task_self_, 0, &connection)
if result != kIOReturnSuccess {
NSLog("Failed opening device with error: 0x%08x.\n", result);
throw NSError.cdc_kernelReturnErrorWithError(result)
}
defer { IOConnectRelease(connection) }
if device == IO_OBJECT_NULL || connection == IO_OBJECT_NULL {
throw NSError.cdc_kernelReturnErrorWithError(result)
}
let receiveDataMappedMemory = ClientDriverMappedMemory(connection: connection, memoryType: MappedMemoryType_ReceiveDataBuffer)
try receiveDataMappedMemory.map()
let transmitDataMappedMemory = ClientDriverMappedMemory(connection: connection, memoryType: MappedMemoryType_TransmitDataBuffer)
try transmitDataMappedMemory.map()
// Setup async notification
IONotificationPortSetDispatchQueue(dataReceivedPort, dataReceivedQueue)
let callbackPort = IONotificationPortGetMachPort(dataReceivedPort)
let input = DataStruct(foo: 0, bar: 0)
var output = DataStruct(foo: 0, bar: 0)
var outputSize = MemoryLayout<DataStruct>.size
// Trampoline to C function because I don't quite know how to make this work in Swift
result = setupCallback(self, connection, callbackPort, input, &output, &outputSize)
if result != kIOReturnSuccess {
NSLog("Error registering async callback with driver: \(result)");
throw NSError.cdc_kernelReturnErrorWithError(result)
}
self.connection = connection
self.receivedDataMappedMemory = receiveDataMappedMemory
self.transmitDataMappedMemory = transmitDataMappedMemory
}
map() and unmap() functions:
- (BOOL)mapWithError:(NSError **)error
{
error = error ?: &(NSError * __autoreleasing){ nil };
kern_return_t result = IOConnectMapMemory64(self.connection,
self.memoryType,
mach_task_self(),
&_address,
&_size,
kIOMapAnywhere);
if (result != kIOReturnSuccess) {
*error = [NSError cdc_kernelReturnErrorWithError:result];
return NO;
}
self.mapped = YES;
return YES;
}
- (BOOL)unmapWithError:(NSError **)error
{
error = error ?: &(NSError * __autoreleasing){ nil };
kern_return_t result = IOConnectUnmapMemory64(self.connection,
self.memoryType,
mach_task_self(),
_address);
if (result != kIOReturnSuccess) {
*error = [NSError cdc_kernelReturnErrorWithError:result];
return NO;
}
self.mapped = NO;
return YES;
}
Any insights? What all should I be doing to close the service? Why would the unmapping create this issue or what else could the -308 error be indicated has gone wrong?
Is anyone having any luck getting there phone fixed?
I have recently done the iOS 18.1 update and then my phone camera has stopped working.
i don’t appear to be on my own either but burnt seeing any positive posts about apple cooperating?
not sure how it can be my fault if their software has caused it? I am out of warranty too
Topic:
App & System Services
SubTopic:
Drivers
#4 Thread
NSInternalInconsistencyException
Call must be made on main thread
CoreFoundation ___exceptionPreprocess + 164
libsystem_pthread.dylib _start_wqthread + 8
#0 Thread
semaphore_wait_trap
libsystem_kernel.dylib semaphore_wait_trap + 8
libdispatch.dylib 0x00000001b96ed000 + 457547470247841612
UnityFramework Staticburst_initialize + 17597401577822386088
UnityFramework DllCanUnloadNow + 52172
UnityFramework. DllCanUnloadNow + 51292
UnityFramework DllCanUnloadNow + 421068
UnityFramework. Unityplcrash_async_mach_exception_get_siginfo + 5073080
UnityFramework. GlobalizationNative_GetTimeZoneDisplayName + 1585284
UnityFramework. GlobalizationNative_GetTimeZoneDisplayName + 926212
UnityFramework. 0x000000010ce18000 + 77478852
UnityFramework. GlobalizationNative_GetTimeZoneDisplayName + 124804
UnityFramework. GlobalizationNative_GetTimeZoneDisplayName + 124592
UnityFramework. _ZdaPvRKSt9nothrow_t + 2445400
UnityFramework. _ZdaPvRKSt9nothrow_t + 2502608
UnityFramework. _ZdaPvRKSt9nothrow_t + 2556896
UnityFramework. _ZdaPvRKSt9nothrow_t + 2555820
UnityFramework. _ZdaPvRKSt9nothrow_t + 211836
UnityFramework. _ZdaPvRKSt9nothrow_t + 1216980
UnityFramework. _ZdaPvRKSt9nothrow_t + 1145620
UnityFramework. _ZdaPvRKSt9nothrow_t + 1145684
UnityFramework. _ZdaPvRKSt9nothrow_t + 1146408
UnityFramework. UnitySendMessage + 6940844
UnityFramework. _Z12DecodeBase64PKhPhi + 138076
QuartzCore. 0x00000001b2d06000 + 193228
UIKitCore. UIApplicationMain + 1589427071078105428
UnityFramework. _Z12DecodeBase64PKhPhi + 11056988545834161928
Topic:
App & System Services
SubTopic:
Drivers
Run on Xcode
Unchecked Scheme -> Run -> 'Debug excitable' is fine.
But, I need the debug log, how to fix?
i tried opening iMovie for the first time on my 2017 Macbook Air but i get an error saying that iMovie is too new to my mac but i was trying to run the built in one it says i need to downgrade it on the appstore but there is no option to downgrade
Topic:
App & System Services
SubTopic:
Drivers
Hi Team ,
I want to create a system where i can mirror the iPhone screen connected through USB and control it from the web browser.
can anyone help me ?
Thanks ,
Mukta
Topic:
App & System Services
SubTopic:
Drivers
Hi there. I inadvertently deleted the Passwords app. The App Store is telling me restrictions are enabled so I can’t reinstall from the cloud. Not sure where to go from here. Help.
Topic:
App & System Services
SubTopic:
Drivers
We are developing an iOS app that communicates with a device using an NXP NTAG 5 chip in ISO15693 pass-through mode. While the app works flawlessly on older iPhone models (iPhone 8, SE, X) and most Android devices, we are experiencing severe reliability issues on iPhone 12, 13, 14, and 15.
Issue Summary
On newer iPhones (12–15), 90% of communication attempts fail.
Retry strategies do not work, as the NFC session is unexpectedly canceled while handling CoreNFC custom commands.
The issue is not consistent—sometimes all requests fail immediately, while other times, a batch of reads might succeed unexpectedly before failing again.
Technical Details
The failure occurs while executing the following request, which should return 256 bytes:
tag.customCommand(requestFlags: .highDataRate, customCommandCode: commandCode, customRequestParameters: Data(byteArray)) { (responseData, error) in
}
The returned error is:
-[NFCTagReaderSession transceive:tagUpdate:error:]:897 Error Domain=NFCError Code=100 "Tag connection lost" UserInfo={NSLocalizedDescription=Tag connection lost}
For reference, we tested a comparable STM ST25 chip in ISO15693 and NDEF mode, and the exact same issue occurs.
Observations and Debugging Attempts
Positioning of the NFC antenna has been tested extensively.
Disabling Bluetooth and Wi-Fi does not improve reliability.
Rebooting the device or waiting between attempts sometimes improves success rates but does not provide a structural fix.
When reading multiple blocks (e.g., 15 blocks of 256 bytes each):
The process often fails within the first three blocks.
After multiple failures, it may suddenly succeed in reading all blocks in one go before returning to a series of failures.
The nfcd logs suggest issues at the low-level NFC and SPMI layers, indicating potential hardware or firmware-related problems:
error 17:36:18.289099+0100 nfcd phOsalNfc_LogStr:65 NCI DATA RSP : Timer expired before data is received!
error 17:36:18.292936+0100 nfcd NFHardwareSerialQuerySPMIError:1339 "Invalid argument" errno=22 setsockopt: SYSPROTO_CONTROL:IO_STOCKHOLM_SPMIERRORS
error 17:36:18.293036+0100 nfcd phTmlNfc_SpmiDrvErrorStatus:1157 "Invalid argument" errno=22 Failed to query SPMI error registers
error 17:36:18.293235+0100 nfcd phOsalNfc_LogStr:65 phLibNfc_SpmiStsRegInfoNtfHandler: Read Spmi Status Failed - pInfo set to NULL
error 17:36:18.293313+0100 nfcd _Callback_NFDriverNotifyGeneral:2353 Unknown notification: 0x5b
error 17:36:18.294163+0100 nfcd phOsalNfc_LogStr:65 Target Lost!!
error 17:36:18.294678+0100 nfcd -[_NFReaderSession handleSecureElementTransactionData:appletIdentifier:]:164 Unimplemented
error 17:36:18.294760+0100 nfcd -[_NFReaderSession handleSecureElementTransactionData:appletIdentifier:]:164 Unimplemented
error 17:36:18.320132+0100 nfcd phOsalNfc_LogStr:65 ISO15693 XchgData,PH_NCINFC_STATUS_RF_FRAME_CORRUPTED Detected by NFCC during Data Exchange
error 17:36:18.320291+0100 nfcd phOsalNfc_LogU32:74 phNciNfc_ChkDataRetransmission: Re-transmitting Data pkt Attempt..=1
error 17:36:18.622050+0100 nfcd phOsalNfc_LogStr:65 NCI DATA RSP : Timer expired before data is received!
error 17:36:18.625857+0100 nfcd NFHardwareSerialQuerySPMIError:1339 "Invalid argument" errno=22 setsockopt: SYSPROTO_CONTROL:IO_STOCKHOLM_SPMIERRORS
error 17:36:18.625919+0100 nfcd phTmlNfc_SpmiDrvErrorStatus:1157 "Invalid argument" errno=22 Failed to query SPMI error registers
error 17:36:18.626132+0100 nfcd phOsalNfc_LogStr:65 phLibNfc_SpmiStsRegInfoNtfHandler: Read Spmi Status Failed - pInfo set to NULL
error 17:36:18.626182+0100 nfcd _Callback_NFDriverNotifyGeneral:2353 Unknown notification: 0x5b
error 17:36:18.626899+0100 nfcd phOsalNfc_LogStr:65 Target Lost!!
error 17:36:18.627482+0100 nfcd -[_NFReaderSession handleSecureElementTransactionData:appletIdentifier:]:164 Unimplemented
error 17:36:18.627568+0100 nfcd -[_NFReaderSession handleSecureElementTransactionData:appletIdentifier:]:164 Unimplemented
error 17:36:18.833174+0100 nfcd -[_NFReaderSession handleSecureElementTransactionData:appletIdentifier:]:164 Unimplemented
error 17:36:19.145289+0100 nfcd phOsalNfc_LogStr:65 NCI DATA RSP : Timer expired before data is received!
error 17:36:19.149233+0100 nfcd NFHardwareSerialQuerySPMIError:1339 "Invalid argument" errno=22 setsockopt: SYSPROTO_CONTROL:IO_STOCKHOLM_SPMIERRORS
error 17:36:19.149353+0100 nfcd phTmlNfc_SpmiDrvErrorStatus:1157 "Invalid argument" errno=22 Failed to query SPMI error registers
error 17:36:19.149730+0100 nfcd phOsalNfc_LogStr:65 phLibNfc_SpmiStsRegInfoNtfHandler: Read Spmi Status Failed - pInfo set to NULL
error 17:36:19.149797+0100 nfcd _Callback_NFDriverNotifyGeneral:2353 Unknown notification: 0x5b
error 17:36:19.150463+0100 nfcd phOsalNfc_LogStr:65 Target Lost!!
Any solutions?
Has anyone else encountered similar behavior with CoreNFC on iPhone 12–15? Could this be related to changes in NFC hardware or power management in newer iPhone models? Any suggestions on possible workarounds or alternative approaches would be greatly appreciated.
Hello Everyone,
I am trying to develop a DriverKit for RAID system, using PCIDriverKit & SCSIControllerDriverKit framework. The driver can detect the Vendor ID and Device ID. But before communicating to the RAID system, I would like to simulate a virtual Volume using a memory block to talk with macOS.
In the UserInitializeController(), I allocated a 512K memory for a IOBufferMemoryDescriptor* volumeBuffer, but fail to use Map() to map memory for volumeBuffer.
result = ivars->volumeBuffer->Map(
0, // Options: Use default
0, // Offset: Start of the buffer
ivars->volumeSize, // Length: Must not exceed buffer size
0, // Flags: Use default
nullptr, // Address space: Default address space
&mappedAddress // Output parameter
);
Log("Memory mapped completed at address: 0x%llx", mappedAddress); // this line never run
The Log for Map completed never run, just restart to run the Start() and makes this Driver re-run again and again, in the end, the driver eat out macOS's memory and system halt.
Are the parameters for Map() error? or I should not put this code in UserInitializeController()?
Any help is appreciated!
Thanks in advance.
Charles
I'm trying to iterate through a USB device but the iterator is always empty or contains only the matched interface:
Single interface in Iterator
This happens when my driver matches against the interface. Because I need to use 2 interfaces (control and cdc), I try to open the IOUSBHostDevice (copied from the interface) and iterate through the rest, but I only get the interface my dext matched with.
Empty Iterator
I decided to match against USB communication devices, thinking things would be different. However, this time the interface iterator is completely empty (provider is IOUSBHostDevice).
Here's a snippet of my code before iterating with IOUSBHostDevice->CopyInterface():
// teardown the configured interfaces.
result = device->SetConfiguration(ivars->Config, true);
__Require_noErr_Action(result, _failure_Out,
ELOG("IOUSBHostDevice::SetConfiguration failed 0x%x", result));
// open usb device
result = device->Open(this, 0, 0);
__Require_noErr_Action(result, _failure_Out,
ELOG("Failed to open IOUSBHostDevice"));
// Get interface iterator
result = device->CreateInterfaceIterator(&iterRef);
__Require_noErr_Action(result, _failure_Out,
ELOG("IOUSBHostDevice::CreateInterfaceIterator failed failed: 0x%x", result));
Hello,
We are experiencing some issues with our USB accessory unexpectedly charging the iOS device it is connected with only when the iOS device supports USB-C and is on iOS 18+
The following is a description of the discrepancy we note between iOS versions:
After performing a USB Role switch, our Accessory becomes a typical USB Device and the Apple device becomes the USB host.
with iOS 17:
The Accessory then sends a PowerSourceUpdate message to the iOS 17 device via iAP2 protocol. Apple device has a USB Type C Connector. *
We are specifying:
AvailableCurrentForDevice = 0 mA
DeviceBatteryShouldChargeIfPowerIsPresent = 1.
Three observations:
iPad Battery Settings page - we observe 'Last charged to…' (indicating no charging)
On the Lumify App running (iOS 17), we observe that UIKit.current.batteryState indicated 'Not charging'
Battery icon on top right of the screen indicates 'No Charging'
with iOS 18:
The same Accessory sends the same PowerSourceUpdate message to the iOS 18 device via iAP2 protocol using USB Type C Connector.
We are specifying the same:
AvailableCurrentForDevice = 0 mA
DeviceBatteryShouldChargeIfPowerIsPresent = 1.
We observe:
iPad Battery Settings page - we observe 'Charging'
On the Lumify App running (iOS 18), we observe that UIKit.current.batteryState indicated 'Charging'
Battery icon on top right of the screen indicates 'No Charging'
Please could you help us understand why the Battery status is showing as 'Charging' in the Settings page and with the 'UIKit.current.batteryState' even though we have specified 'AvailableCurrentForDevice = 0 mA'?
Since our accessory is heavily reliant on the Battery status / Charging state, is there potentially another way we get an accurate battery charging status that we are missing? Or are there other suggestions outside of what we do currently to ensure our accessory does not place the iOS18 device into a charging state?
I'm working on a project to allow HID input from macOS to a connected iOS device. Are we prohibited from matching to a connected iPhone with DriverKit? I see the attribute kCDCDoNotMatchThisDevice for my iPhone is YES when looking at the IO registry and my dext does not initialize
When plugging in my matched USB device I see the logs below. It seems the kernelmanagerd process is sandboxed and can't write out the reason my Dext failed to load. Is there somewhere else I can look for this info?
default 11:03:22.175152-0700 kernelmanagerd Received kext load notification: me.keithg.MyUserUSBInterfaceDriver
default 11:03:22.177637-0700 kernel 1 duplicate report for Sandbox: icdd(2124) allow file-read-data /Library/Image Capture/Devices
error 11:03:22.177681-0700 kernel Sandbox: kernelmanagerd(545) deny(1) file-write-create /private/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/com.apple.kernelmanagerd/TemporaryItems
com.apple.libcoreservices error 11:03:22.177711-0700 kernelmanagerd mkdir: path=/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/com.apple.kernelmanagerd/TemporaryItems/ mode= -rwx------: [1: Operation not permitted]
error 11:03:22.179361-0700 kernel Sandbox: kernelmanagerd(545) deny(1) file-write-create /private/var/db/loadedkextmt.plist.sb-5a00fc77-LNttZF
com.apple.libcoreservices error 11:03:22.177755-0700 kernelmanagerd _dirhelper_relative_internal: error for path <private>: [1: Operation not permitted]
com.apple.accessories default 11:03:22.177674-0700 WindowServer Sending analytics event... (eventName: com.apple.ioport.transport.USB.published)
error 11:03:22.179913-0700 kernelmanagerd Failed to write extension load report plist.
I’m experiencing a persistent issue with the new USB-C lossless audio feature on AirPods Max (firmware 7E101). I’m using original Apple USB-C to USB-C cable and have tested this setup across multiple Apple devices, including:
• iPhone (running iOS 18.5 beta)
• iPad Pro with USB-C
• MacBook Pro (15.5 Beta)
❗️Problem:
Despite Apple’s announcement that AirPods Max now support wired lossless audio over USB-C, I’m unable to get any audio output via USB-C on any device.
• On iPhone: I disabled Bluetooth, connected via USB-C — no sound.
• On MacBook: The device is shown as “AirPods Max USB Audio” in System Information > USB, but it does not appear in Sound settings or Audio MIDI Setup as an available output.
• On iPad Pro: Same behavior — no audio output.
Other details:
• I performed a factory reset of the headphones, but the LED flashes red instead of the expected amber → white sequence.
(Apple’s documentation does not mention red flash behavior during reset — might indicate an error state.)
• The issue is not isolated to the iOS 18.5 beta — since the same behavior occurs on macOS and iPadOS.
What works:
• Bluetooth audio still works fine.
• The cable and USB-C ports function with other audio devices.
⸻
Summary:
It looks like:
• USB audio is being detected on a hardware level (at least on Mac),
• but software support for output (especially on macOS/iPadOS) is either not implemented, disabled, or bugged — possibly connected to iOS 18.5 beta or broader OS-level limitations.
Topic:
App & System Services
SubTopic:
Drivers