When my macOS app try to deactivate CameraExtension, my app's didFailWithError is called with this error.
Error Domain=OSSystemExtensionErrorDomain Code=4 "(null)"
I cannot search for error code=4 with that domain.
MyApp calls OSSystemExtensionManager.shared.submitRequest with OSSystemExtensionRequest.deactivationRequest
I did implement these tasks.
BundleID, MyApp: com.myapp,
BundleID, CameraExtension: com.myapp.camera
Added entitlement and App Groups for app and extension
MyApp has SystemExtension capability on Xcode and provision
MyApp is installed on /Applications/MyAppGroup/MyApp.app
MyApp is executed by Finder
macOS is Sonoma 14.2.1 (23C71) on M1 MacBook
Drivers
RSS for tagUnderstand the role of drivers in bridging the gap between software and hardware, ensuring smooth hardware functionality.
Post
Replies
Boosts
Views
Activity
this is a repost with more appropriate tags. The original is here:
https://developer.apple.com/forums/thread/744268
Can anyone advise, or give example of, communicating large (>128 byte) incoming buffers from a dext to a user-space app?
My specific situation is interrupt reads from a USB device. These return reports which are too large to fit into the asyncData field of an AsyncCompletion call. Apple's CommunicatingBetweenADriverKitExtensionAndAClientApp sample shows examples of returning a "large" struct, but the example is synchronous. The asynchronous example returns data by copying into a IOUserClientAsyncArgumentsArray, which isn't very big.
I can allocate a single buffer larger than 4K in user space, and communicate that buffer to my driver as an IOMemoryDescriptor when I set up my async callback. The driver retains the descriptor, maps it into its memory space and can thus write into it when the hardware returns interrupt data. The driver then calls AsyncCompletion, which will cause my user-side callback to be called, so the user side software knows that there's new data available in the previously allocated buffer.
That's fine, it works, but there are data race problems - since USB interrupt reads complete whenever the hardware has provided data, incoming completions happen at unpredictable times, so the shared buffer contents could change while the user side code is examining them.
Is there an example somewhere of how to deal with this? Can I allocate memory on the driver side on demand, create an IOMemoryDescriptor for it and return that descriptor packed inside the asyncData? If so, how does the driver know when it can relinquish that memory? I have a feeling there's something here I just don't understand...
Few user space applications are available in market for example xnvme, but does not have any interaction with Admin Submission/Completion queues.
Also IOCTLs are not very prominent . Is there any ways to get access to the native NVMe Mac driver source code?
Thanks, hopefully we will get some positive response here.
Hi. I wish I'd found a way to determine the USB hub port to which an iPad is connected, even if it means creating a one-time mapping of identifiers and ports beforehand. I thought I'd find some hardware identifiers that might help, but they appear to fluctuate depending on how the iPad carts are connected to the Mac. Is there anything reliable to achieve the desired result? Thanks for your insights. Franck
I'm writing a C/C++ command line program which, at some point, calls IOHIDManagerOpen. I've added both my program executable and lldb as permitted for input monitoring (as far as I remember, my program was added after showing up a permission prompt, I've added lldb manually later, trying to resolve the problem).
My problem is that when I run my program from within lldb in Terminal, the call to IOHIDManagerOpen returns kIOReturnNotPermitted. When I run my program directly in the terminal session (without lldb), this call returns kIOReturnSuccess. Such behaviour means it will be impractical to use lldb for any debugging of this program.
What can be done to make lldb session behave the same way, the normal execution works?
I'm on:
23.2.0 Darwin Kernel Version 23.2.0: Wed Nov 15 21:55:06 PST 2023; root:xnu-10002.61.3~2/RELEASE_ARM64_T6020 arm64
and:
lldb-1500.0.200.58
Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5)
I have two USB cameras, they both recognize the camera properly under windows, but on macos there is one that recognizes only the USB, but not the camera. Would like to ask if there is any solution idea or the underlying code reference. thank you.
Does the Vision Pro Battery Pack allow data passthrough to the Vision Pro?
Specifically, I am wanting to confirm whether the platform supports FIDO2 / YubiKey style devices.
If someone has a DevKit, could you try testing a keyboard or thumb drive to see if either of those work. If so, I should have all I need to proceed with my project.
Thanks.
I have a virtual device, which is redirected to Mac from Windows OS. However, In MacOS, it does not recognized as a HID device even it has only one HID interface.
The device name is Virtual Fido, it more likes to be identified as an audio device. Could any one help check? Thanks.
2024-01-31 16:37:03.102014+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::usbServiceCallback: controller <private> (S1F0) usbServiceArray <private>(count 1) options 0x00000000
2024-01-31 16:37:03.102020+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::usbServiceCallback: [0] <private>
2024-01-31 16:37:03.102023+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::usbServiceCall: controller <private> (S1F0) usbService <private> (Virtual FIDO) options 0x00000000
2024-01-31 16:37:03.102035+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::getOrCreateLegacyControllerGated: located existing AppleUSBController@00000000
2024-01-31 16:37:03.102037+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::usbServiceCallGated: IOUSBHostDevice <private> (Virtual FIDO)
2024-01-31 16:37:03.102046+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::addDeviceToUsbPlane:
2024-01-31 16:37:03.102288+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::usbServiceCall: usbServiceCallbackGated completed with 0x00000000 and service <private>
2024-01-31 16:37:03.102302+0800 0x1df Error 0x0 0 0 kernel: (IOUSBFamily) AppleUSBLegacyRoot@(null): AppleUSBLegacyRoot::usbServiceCall: registering Virtual FIDO@00810000 (<private>) for matching
2024-01-31 16:37:03.104499+0800 0x247c Info 0x0 120 0 kernelmanagerd: Received MIG message
2024-01-31 16:37:03.105412+0800 0x247c Info 0x0 120 0 kernelmanagerd: Received MIG message
2024-01-31 16:37:03.105453+0800 0x284b Default 0x0 120 0 kernelmanagerd: Received kext load notification: com.apple.iokit.IOAudioFamily
2024-01-31 16:37:03.105460+0800 0x284b Default 0x0 120 0 kernelmanagerd: Received kext load notification: com.apple.driver.AppleUSBAudio
2024-01-31 16:37:03.106066+0800 0x11d6 Default 0x0 643 0 icdd: [com.apple.imagecapture:icdd] Device DB | Creating local devices
2024-01-31 16:37:03.106170+0800 0x512 Info 0x0 244 0 com.apple.ifdreader: [com.apple.CryptoTokenKit:smartcard] new device skipped: 0x0e0f/0x0123 810000 (entryId=4294969016)
2024-01-31 16:37:03.106551+0800 0x11d6 Default 0x0 0 0 kernel: (Sandbox) Sandbox: icdd(643) allow file-read-data /Library/Image Capture/Devices
2024-01-31 16:37:03.106602+0800 0x11d6 Default 0x0 643 0 icdd: [com.apple.imagecapture:icdd] Device DB | Creating bonjour devices
2024-01-31 16:37:03.106968+0800 0x11d6 Default 0x0 643 0 icdd: [com.apple.imagecapture:icdd] => [Matching] | [ 0x00,0x00,0x00 ]
2024-01-31 16:37:03.106989+0800 0x11d6 Default 0x0 643 0 icdd: [com.apple.imagecapture:icdd] Added | 0x10000011 - [USB][ Virtual FIDO ] ( 0, 0, 0) @ 0x810000 |
2024-01-31 16:37:03.107041+0800 0x11d6 Default 0x0 643 0 icdd: [com.apple.imagecapture:icdd] Autolaunch | 00000000-0000-0000-0031-323334353637 => (null)
2024-01-31 16:37:03.335288+0800 0x276f Default 0x0 424 0 trustd: [com.apple.securityd:pinningQA] could not enable test hierarchy: no UAT pinning preferences set
| | | +-o VMware Virtual USB Hub@00800000 <class IOUSBHostDevice, id 0x1000003de, registered, matched, active, busy 0 (35 ms), retain 38>
| | | +-o AppleUSBHostLegacyClient <class AppleUSBHostLegacyClient, id 0x1000003e1, !registered, !matched, active, busy 0, retain 8>
| | | +-o AppleUSB20Hub@00800000 <class AppleUSB20Hub, id 0x1000003e4, registered, matched, active, busy 0 (33 ms), retain 35>
| | | | +-o AppleUSB20HubPort@00810000 <class AppleUSB20HubPort, id 0x1000003e7, registered, matched, active, busy 0 (33 ms), retain 16>
| | | | | +-o Virtual FIDO@00810000 <class IOUSBHostDevice, id 0x1000006b8, registered, matched, active, busy 0 (3 ms), retain 20>
| | | | | +-o AppleUSBHostLegacyClient <class AppleUSBHostLegacyClient, id 0x1000006bb, !registered, !matched, active, busy 0, retain 8>
| | | | | +-o AppleUSBHostCompositeDevice <class AppleUSBHostCompositeDevice, id 0x1000006bf, !registered, !matched, active, busy 0, retain 4>
| | | | +-o AppleUSB20HubPort@00820000 <class AppleUSB20HubPort, id 0x1000003e8, registered, matched, active, busy 0 (0 ms), retain 12>
| | | | +-o AppleUSB20HubPort@00830000 <class AppleUSB20HubPort, id 0x1000003e9, registered, matched, active, busy 0 (0 ms), retain 12>
I am using a Silicon labs CP2102 chip. I have configured a custom USB VID and PID on the chip, and want to create a MacOs driver (or rather map this custom VID/PID to an existing driver) to make it accessible as a USB serial device from my Mac.
Preferably I'd like to map my device to the com.apple.DriverKit-AppleUSBSLCOM.dext driver, but I think the generic USB serial driver (com.apple.DriverKit-AppleUSBSerial.dext) should work too. Silabs also has their own driver (com.silabs.cp210x.dext, downloadable from their web page), if for some reason it is easier to map to that than to one of the native drivers that could also work.
Based on
https://developer.apple.com/documentation/kernel/implementing_drivers_system_extensions_and_kexts#3616855
and
https://developer.apple.com/documentation/driverkit/creating_a_driver_using_the_driverkit_sdk
it should be possible to create a codeless dext, which just inherits from e.g. IOUserUSBSerial.
I've tried both creating just a DriverKit driver and putting it under /Library/DriverExtensions/ and creating a (default) app and adding a DriverKit driver to it, and putting the app in my /Applications/ folder, but neither works for me.
My driver implementation is just this:
#include <USBSerialDriverKit/IOUserUSBSerial.iig>
class MyDriver: public IOUserUSBSerial
{
};
and my IOKitPersonalities looks like this:
<key>IOKitPersonalities</key>
<dict>
<key>MyDriver</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.mydriver.MyDriverApp.MyDriver</string>
<key>IOClass</key>
<string>IOUserUSBSerial</string>
<key>IOMatchCategory</key>
<string>com.mydriver.MyDriverApp.MyDriver</string>
<key>IOProviderClass</key>
<string>IOUSBHostInterface</string>
<key>IOUserClass</key>
<string>MyDriver</string>
<key>IOUserServerName</key>
<string>com.mydriver.MyDriverApp.MyDriver</string>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>0</integer>
<key>idProduct</key>
<integer>(my custom PID, decimal value)</integer>
<key>idVendor</key>
<integer>(my custom VID, decimal value)</integer>
</dict>
</dict>
I've disabled SIP and enabled developer mode (systemextensionsctl developer on), though I'm not sure if it's needed. I've scanned through the system logs and looked at the ioreg output. When I connect a CP2102 chip with default VID and PID, I can see that it maps to the native com.apple.DriverKit-AppleUSBSLCOM.dext driver. When I connect the same chip with my custom VID and PID, I don't see any trace of my driver being used. I can see it in the System Information app, but it doesn't map to my driver.
I'm currently suspecting it is an Entitlements issue. In my app I have an Entitlements file, where I've added DriverKit USB Transport and DriverKit Serial Family. Do I need something like this for the driver target? There is no default Entitlements file there, but maybe I should create one? Or is there something else I'm missing?
I've also noted one odd thing: When I install my app I can see a system log entry, complaining that "package type not SYSX" (for my driver). But I don't think it should be a SYSX package? It's currently specified as a DEXT package.
Hello! I'm trying to get data (like audio) stream from custom vendor usb device with bulk endpoint. When I use AsyncIO in cycle some data was lost. And I saw that AsyncIOBundled can help me with this issue.
I've trying to use it:
Create memory buffers
for (int i = 0; i < DEFAULT_BUF_NUMBER; i++) {
kern_return_t ret = IOBufferMemoryDescriptor::Create(
kIOMemoryDirectionInOut,
DEFAULT_BUF_LENGTH,
0,
&ivars->buffers[i]
);
}
Create MemoryDescriptorRing and set MemoryDescriptor for each index
kern_return_t MyDriver::SetupRingBuffer(IOMemoryDescriptor** memoryDescriptors, uint16_t length)
{
kern_return_t ret = kIOReturnSuccess;
ret = ivars->inPipe->CreateMemoryDescriptorRing(length);
if (ret != kIOReturnSuccess) {
IOLog("CreateMemoryDescriptorRing failed %s", StringFromReturn(ret));
return ret;
}
for (int i = 0; i < length; i++) {
ret = ivars->inPipe->SetMemoryDescriptor(memoryDescriptors[i], i);
if (ret != kIOReturnSuccess) {
IOLog("SetMemoryDescriptor failed %s", StringFromReturn(ret));
break;
}
}
return ret;
}
Create completion
Run AsyncIOBundled for only 1 index
ret = ivars->inPipe->AsyncIOBundled(
i,
1,
&transferAccepted,
(const unsigned int *)&ivars->dataBufferLengthArray,
DEFAULT_BUF_NUMBER,
ivars->readBundledCompletion,
0
);
In completion i'm always get the error 0xe0005000 (UNDEFINED)
But if I use AsyncIO with same buffer - it's success.
What am I doing wrong? There are no differences btw AsyncIOBundled and AsyncIO requests in wireshark
We added a packet filter to our app, then found a way to not need it, so we want to be able to remove it on upgrades. But we don't want to install it if it's not already installed. Simple, right?
The basic flow of the code is, on start-up, it does a propertiesRequestForExtensiion request. The method for the delegate goes through the various versions, ignoring any that are property.isEnabled == NO. When it comes to one that is enabled, it checks the version -- if it's the same version as the running app, it goes to deactivate it. If it's a different version, it goes to enable the current version (creating a activationRequestForExtensiion request).
This should all be very simple. Except.
At some point during this, the properties request gets a failure -- Domain=OSSystemExtensionErrorDomain Code=1. Ok, it seems there are lots of them laying around (I haven't rebooted in a while), and that method doesn't return once it finds one that is enabled. So maybe it doesn't like that.
And then the activation request that was submitted also fails, also with the same error that doesn't explain anything.
I thought, ok, maybe they don't like to stop on each other's toes, so let's create a serial dispatch queue, and have all of the system extension requests use that queue. That way, the activation request won't begin until the properties request has finished!
Only I did that. And it did get a bit further -- the request method was invoked! Only then I still got messages about the properties and activation requests failing with the same unknown error.
So then I looked at console. And sysextd is crashing, every time this happens. And then I dump all of the logs around that time, and look through them, and see... nothing.
I had hoped to end this with a description of how I achieved victory, but instead... I'm going to have to reboot and see if that solves the mysterious crashing of sysextd.
How does VMWare access USB devices without have any specifics of the USB device? Does it use the same profile/entitlement process or does it take a different approach?
Hi,I am trying to write Dext code for my existing Kext,How to convert this code to be compatible with Dext?
BufferMemoryDescriptorAME_Module = NULL;
IOMemoryMap *MemMap;
BufferMemoryDescriptorAME_Module= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task,kIOMemoryPhysicallyContiguous,otal_memory_size);
BufferMemoryDescriptorAME_Module->prepare(kIODirectionInOut);
MemMap = BufferMemoryDescriptorAME_Module->map(kIOMapInhibitCache);
logicalAddressAME_Module = (UInt8 *) MemMap->getVirtualAddress();
physicalAddressAME_Module = MemMap->getPhysicalAddress();
Thanks,
Frederic
I am attempting to communicate over serial with a USB-C device and an M-Series iPad. I have proven the device to communicate as expected (baud rate, parity, etc) via a Swift app on Mac using a third party library (IOKit) that utilizes the "AppleUSBACM (v5.0.0)" driver on macOS. I am looking to recreate this communication via iPadOS and a custom DriverKit driver that provides this same interface.
There is not an example from Apple for serial communication and DriverKit but there is a couple for communicating from an app to the dext, and for other networking examples. There are also other mentions in WWDC videos but they are incomplete and do not provide the needed structure.
Communicating between a driver extension and a client app
Connecting a network driver
Bring your driver to iPad with DriverKit
System Extensions and DriverKit
My question revolves around architecture and how to set up a driver for these needs. I have gotten the examples to run and understand what is needed for entitlements and other local signing needs. But what I don't understand is if you need a basic setup similar to the "Communicating between a driver extension and a client app" where your base driver subclasses IOService and has two arms. One that subclasses IOUserclient and allows communication between the dext and your Swift app. And another arm that subclasses IOUserSerial or IOUserUSBSerial. I assume then that these two share buffers of memory set up by the base class that allows communication between the two.
I have had little luck getting IOUserUSBSerial to compile and have made more progress on IOUserSerial. But when running that and with the supposed idVendor plist entry I am not getting that part of the dext to start or recognize when the USB device is plugged in.
Long story short, I'm looking for a basic architecture or example reference to explain serial communication in DriverKit.
Devices:
Custom USB-C hardware that is CDC ACM compliant
iPad Air 5th gen with M1 chip (iPadOS 17.2)
M1 MBP (macOS 14.2.1)
We have been doing a R&D work related to the NVMe controller on Mac platform, where we need to get control of the admin queues(submission as well as completion). From the spec of NVMe it’s very clear that what are all registers do we need to deal with to get access of the queues. We are accordingly following those registers to create our own queues. Also we have prepared and enqueued a sample admin command to the newly created submission queue. But surprisingly we can’t get any assurance whether the command got processed by the controller or not, because from the completion queue entry we can see all the entries are zero, which is not expected anyway. So here the question is, how to communicate with the controller properly ? We are also aware of the fact of existing NVMe driver(IONVMeFamily) on Mac platform, is this somehow crossing our way ? We have done all the proper setup for registers, DMAs and interrupt. Path is very ok if we use builtin driver with the XNVME user space application (we can trigger limited admin commands over there). But here we need to have our own created queues up and running with seamless admin command transaction. Here we must tell about our setup, we have one SSD which is connected via a thunderbolt cable to Mac laptop using type C usb port. We have tried to access pre-configured admin queues from IONVMeFamily driver but that is also a blocker for us, as we can’t see any valid data from submission/completion queues.
Request you to all please help us coming out of this trapped zone.
I'm working on hardware that communicates wireless and wired with mobile systems. Anything non-i[Pad]OS we can connect via USB and achieve great bandwidth, in situations where this is necessary.
Since i[pad]OS does not support FTDI class compliant devices through USB (and also omits the IOUSB framework), I wonder whether we have a way to "work around" this, e.g. how about (ab)using another protocol that i[pad]OS allows?
Concretely, would you think it's possible to tunnel our serial data stream via USBHID?
Hardware and software configuration
MacBook Air M2 2022 16GB,
MacOS Ventura 13.2.1
Full description
This is a DriverKit that controls PCIE FPGA devices for low-latency data exchange.
This driver has been implemented on Iokit, and now it needs to be launched on Driverkit to adapt to newer Macs.
Driverkit lacks the IOMemoryDescriptor::withAddressRange(Iokit) function to convert the app's memory of any size to a Descriptor.
Currently, we use args->structureOutputDescriptor->CreateMapping to map the Descriptor passed by the application to the kernel layer.
// App
size_t ***::xxRead(long long addr, size_t size, void * buff){
std::lock_guard<std::mutex> guard(usrLock);
kern_return_t kr;
uint64_t info[2] = {(uint64_t)addr, (uint64_t)size};
kr = IOConnectCallMethod(
connect,
kUserReadIO,
info,
2,
NULL, NULL, NULL, NULL,
buff,
&size);
return size;
}
// Driverkit
const IOUserClientMethodDispatch sMethods[kNumMethods] = {
[kUserReadIO] =
{
(IOUserClientMethodFunction) &SmiPcieUc::sUserReadIo,
.checkCompletionExists = false,
.checkScalarInputCount = 2, // Read Addr, size
.checkStructureInputSize = 0,
.checkScalarOutputCount = 0,
.checkStructureOutputSize = kIOUserClientVariableStructureSize} // Read Data
};
kern_return_t SmiPcieUc::sUserReadIo (OSObject * target, void* reference, IOUserClientMethodArguments* args){
IOMemoryMap * memMap = nullptr;
uint32_t * buffKptr = nullptr;
kern_return_t rt = 0;
if(target == nullptr){
Log("***Err***: sUserReadIo Target is Null!");
return kIOReturnError;
}
if(args->structureOutputDescriptor){
rt = args->structureOutputDescriptor->CreateMapping(0,0,0,0,0, &memMap);
if(rt == kIOReturnSuccess){
buffKptr = reinterpret_cast<uint32_t *>(memMap->GetAddress());
}
else {
Log("***Err***: sUserReadIo Mapping Failed!");
return kIOReturnNoMemory;
}
} else {
buffKptr = (uint32_t *) args->structureOutput;
}
rt = ((SmiPcieUc *)target)->UserReadIo((uint64_t *)&args->scalarInput[0], (size_t *)&args->scalarInput[1], buffKptr);
OSSafeReleaseNULL(memMap);
return rt;
}
phenomenon
When StructureOutputSize is greater than 4096, args>structureOutputDescriptor exists, and when it is less than or equal to 4096, args->structureOutputDescriptor and args->structureOutput are both equal to nullptr, (in IOkit, args->structureOutput is not empty)。
How to properly convert any size of application memory into the kernel space of Driverkit?
Greetings.
I'm trying to build an Apple Silicon driver for a Roland keyboard which is no longer supported by the manufacturer. The most recent official driver is from 2010.
From my limited understanding of the Apple documentation, it seems to be telling me that I need to build a codeless dext which overrides some sort of base class.
The keyboard uses bog standard USB 1.0 to communicate with the host. Total newb in the driver area so if anyone could point me in the right direction on where to start I would be totally grateful.
When the product of USB drive we made connected to iPhone 15, what should we set for TransportComponentName? Should we set ‘USB Connector’ for TransportComponentName? The default value is 'Lightning Connector' before. But how about the Type-C port of iPhone 15 now?
I have an app that loads a DEXT (driver). This app includes a settings bundle that allows me to activate/deactivate the driver. When I issue the API call to activate the driver, iOS switches to the Settings app and displays the page for my DEXT loading application but the switch to enable the driver, which is part of my settings bundle, does not appear.
I'm using this API call:
OSSystemExtensionRequest.activationRequest(forExtensionWithIdentifier: "driver-id", queue: .main)
Here are the contents of my settings bundle Root.plist:
`
Here are the contents of my Root.strings file:
"Group" = "Group"; "Name" = "Name"; "none given" = "none given"; "Enabled" = "Enabled";