DriverKit

RSS for tag

Develop device drivers that run in user space using DriverKit.

Posts under DriverKit tag

200 Posts

Post

Replies

Boosts

Views

Activity

How to setup DriverKit Timer Event with OSAction Callback Binding
Hello Everyone, I'm encountering an issue while setting up a timer event in DriverKit and would appreciate any guidance. Here's my current implementation: void DRV_MAIN_CLASS_NAME::SetupEventTimer() { // 1. Create dispatch queue kern_return_t ret = IODispatchQueue::Create("TimerQueue", 0, 0, &ivars->dispatchQueue); if (ret != kIOReturnSuccess) { LogErr("Failed to create dispatch queue: 0x%x", ret); return; } // 2. Create timer source ret = IOTimerDispatchSource::Create(ivars->dispatchQueue, &ivars->dispatchSource); if (ret != kIOReturnSuccess) { LogErr("Failed to create timer: 0x%x", ret); OSSafeReleaseNULL(ivars->dispatchQueue); return; } /*! * @brief Create an instance of OSAction. * @discussion Methods to allocate an OSAction instance are generated for each method defined in a class with * a TYPE attribute, so there should not be any need to directly call OSAction::Create(). * @param target OSObject to receive the callback. This object will be retained until the OSAction is * canceled or freed. * @param targetmsgid Generated message ID for the target method. * @param msgid Generated message ID for the method invoked by the receiver of the OSAction * to generate the callback. * @param referenceSize Size of additional state structure available to the creator of the OSAction * with GetReference. * @param action Created OSAction with +1 retain count to be released by the caller. * @return kIOReturnSuccess on success. See IOReturn.h for error codes. */ // 3: Create an OSAction for the TimerOccurred method // THIS IS WHERE I NEED HELP OSAction* timerAction = nullptr; ret = OSAction::Create(this, 0, 0, 0, &timerAction); if (ret != kIOReturnSuccess) { LogErr("Failed to create OSAction: 0x%x", ret); goto cleanup; } // 4. Set handler ret = ivars->dispatchSource->SetHandler(timerAction); if (ret != kIOReturnSuccess) { LogErr("Failed to set handler: 0x%x", ret); goto cleanup; } // 5. Schedule timer (1 second) uint64_t deadline = mach_absolute_time() + NSEC_PER_SEC; ivars->dispatchSource->WakeAtTime(0, deadline, 0); cleanup: if (ret != kIOReturnSuccess) { OSSafeReleaseNULL(timerAction); OSSafeReleaseNULL(ivars->dispatchSource); OSSafeReleaseNULL(ivars->dispatchQueue); } } Problem: The code runs but the OSAction callback binding seems incorrect (Step 3). According to the OSAction documentation, I need to use the TYPE macro to properly bind the callback method. But I try to use TYPE(DRV_MAIN_CLASS_NAME::TimerOccurred) kern_return_t TimerOccurred() LOCALONLY; TYPE(TimerOccurred) kern_return_t TimerOccurred() LOCALONLY; kern_return_t TimerOccurred() TYPE(DRV_MAIN_CLASS_NAME::TimerOccurred) LOCALONLY; All results in Out-of-line definition of 'TimerOccurred' does not match any declaration in 'DRV_MAIN_CLASS_NAME' Questions: What is the correct way to declare a timer callback method using TYPE? How to get the values targetmsgid & msgid generated by Xcode? Any help would be greatly appreciated! Best Regards, Charles
6
0
549
Apr ’25
Issue Writing to BAR1 After BAR0 is Unavailable
Hello Everyone, I encountered an issue with PCI memory access in DriverKit. In my case, BAR0 is not available, but BAR1 is ready for use. Here’s the log output: !!! ERROR : Failed to get BAR0 info (error: 0xe00002f0). !!! BAR1 - MemoryIndex: 0x00000000, Size: 0x00040000, Type: 0 Issue Description When I initially wrote to BAR0 using memoryIndex = 0, it worked successfully: AME_Address_Write_32(pAMEData, pAMEData->memoryIndex, AME_HOST_INT_MASK_REGISTER, 0x0F); However, I mistakenly forgot to update memoryIndex to 1 for BAR1. Surprisingly, the write operation still succeeded. When I fixed memoryIndex = 1 for BAR1, the write operation no longer had any effect. There was no error, but the expected behavior did not occur. Relevant API (From IOPCIDevice.iig) /*! /*! * @brief Writes a 32-bit value to the PCI device's aperture at a given memory index. * @discussion This method writes a 32-bit register on the device and returns its value. * @param memoryIndex An index into the array of ranges assigned to the device. * @param offset An offset into the device's memory specified by the index. * @param data A 32-bit value to be written in host byte order. */ void MemoryWrite32(uint8_t memoryIndex, uint64_t offset, uint32_t data) LOCALONLY; Log Output: Writes to BAR0 (memoryIndex = 0) AME_Address_Write_32() called memoryIndex: 0, offset: 0x34, data: 0xf Wrote data 0xF to offset 52 AME_Address_Write_32() called memoryIndex: 0, offset: 0xa0, data: 0x1 Wrote data 0x1 to offset 160 AME_Address_Write_32() called memoryIndex: 0, offset: 0x20, data: 0xffffffff Wrote data 0xFFFFFFFF to offset 32 Writes to BAR1 (memoryIndex = 1) – No Response AME_Address_Write_32() called memoryIndex: 1, offset: 0x34, data: 0xf No confirmation log, no visible effect. Questions What should memoryIndex be set to for BAR1? The log shows "BAR1 - MemoryIndex: 0x00000000", but should I be using 1 instead? How can I verify if a write operation to BAR1 is successful? Is there a way to check if the memory region is actually writable? Should I use MemoryRead32() to confirm the written value? Any guidance would be greatly appreciated! Best Regards, Charles
3
1
262
Mar ’25
Dext not initializing with a log "Failed to write extension load report plist"
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.
1
0
381
Mar ’25
Which IOUserClient entitlements are really required?
Hello @all I'm develop a DriverKit driver extension and without entitlement checks by OS everything runs fine. But if the entitlements check is enabled in the NVRAM then I get an error due connecting my IOUserClient instance. Which entitlements are really and exactly required for my driver? My driver contains: one IOUserClient instance and multiple IOUserSerial instances The bundle identifier of the driver ist: org.eof.tools.VSPDriver The bundle identifier of the client app org.eof.tools.VSPInstall My entire source code is available on GitHub if any one want to dive deep in :) kernel[0:5107] () [VSPDriver]: NewUserClient called. kernel[0:5107] () [VSPDriver]: CreateUserClient: create VSP user client from Info.plist. kernel[0:5107] () [VSPUserClient]: init called. kernel[0:5107] () [VSPUserClient]: init finished. kernel[0:5107] () [VSPDriver]: CreateUserClient: check VSPUserClient type. kernel[0:5107] () [VSPDriver]: CreateUserClient: success. kernel[0:5107] () [VSPDriver]: NewUserClient finished. kernel[0:5107] () [VSPUserClient]: Start: called. kernel[0:5107] () [VSPUserClient]: User client successfully started. kernel[0:389f] DK: VSPUserClient-0x100001127:UC failed userclient-access check, needed bundle ID org.eof.tools.VSPDriver kernel[0:389f] DK: VSPUserClient-0x100001127:UC entitlements check failed kernel[0:5107] () [VSPUserClient]: Stop called. kernel[0:5107] () [VSPUserClient]: User client successfully removed. kernel[0:5107] () [VSPUserClient]: free called. Here my drivers entitlement file: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.allow-third-party-userclients</key> <true/> <key>com.apple.developer.driverkit.family.serial</key> <true/> </dict> </plist> Here my drivers Info.plist file <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>CFBundlePackageType</key> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleVersion</key> <string>1</string> <key>NSHumanReadableCopyright</key> <string>Copyright © 2025 by EoF Software Labs</string> <key>OSBundleUsageDescription</key> <string>Provide virtual serial port</string> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.allow-any-userclient-access</key> <true/> <key>com.apple.developer.driverkit.communicates-with-drivers</key> <true/> <key>com.apple.developer.system-extension.redistributable</key> <true/> <key>OSBundleLibraries</key> <dict> <key>com.apple.iokit.IOSerialFamily</key> <string>1.0</string> </dict> <key>IOKitPersonalities</key> <dict> <key>VSPDriver</key> <dict> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleIdentifierKernel</key> <string>com.apple.kpi.iokit</string> <key>IOMatchCategory</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>IOProviderClass</key> <string>IOUserResources</string> <key>IOResourceMatch</key> <string>IOKit</string> <key>IOProbeScore</key> <integer>0</integer> <key>IOClass</key> <string>IOUserService</string> <key>IOUserClass</key> <string>VSPDriver</string> <key>IOUserServerName</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>UserClientProperties</key> <dict> <key>IOClass</key> <string>IOUserUserClient</string> <key>IOUserClass</key> <string>VSPUserClient</string> </dict> <key>SerialPortProperties</key> <dict> <key>CFBundleIdentifierKernel</key> <string>com.apple.driver.driverkit.serial</string> <key>IOProviderClass</key> <string>IOSerialStreamSync</string> <key>IOClass</key> <string>IOUserSerial</string> <key>IOUserClass</key> <string>VSPSerialPort</string> <key>HiddenPort</key> <false/> <key>IOTTYBaseName</key> <string>vsp</string> <key>IOTTYSuffix</key> <string>0</string> </dict> </dict> </dict> </dict> </plist> Here the entitlements of the client app <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.allow-third-party-userclients</key> <true/> <key>com.apple.developer.driverkit.communicates-with-drivers</key> <true/> <key>com.apple.developer.shared-with-you</key> <true/> <key>com.apple.developer.system-extension.install</key> <true/> <key>com.apple.security.application-groups</key> <array> <string>$(TeamIdentifierPrefix).org.eof.apps</string> </array> </dict> </plist> Here the Info.plist of the client app: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>CFBundlePackageType</key> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleVersion</key> <string>1</string> <key>LSMinimumSystemVersion</key> <string>$(MACOSX_DEPLOYMENT_TARGET)</string> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.install</key> <true/> <key>com.apple.developer.system-extension.install</key> <true/> <key>com.apple.developer.system-extension.uninstall</key> <true/> <key>com.apple.developer.driverkit.userclient-access</key> <array> <string>VSPDriver</string> </array> <key>com.apple.private.driverkit.driver-access</key> <array> <string>VSPDriver</string> </array> <key>com.apple.security.temporary-exception.iokit-user-client-class</key> <array> <string>IOUserUserClient</string> </array> </dict> </plist>
2
0
910
Mar ’25
DriverKit IOUSBHostInterface iterator always empty
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));
1
0
393
Mar ’25
Why UserInitializeTargetForID() not be invoked after UserCreateTargetForID() successfully?
Hello Everyone, I am trying to create a Fake SCSI target based on SCSIControllerDriverKit.framework and inherent from IOUserSCSIParallelInterfaceController, here is the code kern_return_t IMPL(DRV_MAIN_CLASS_NAME, Start) { ... // Programmatically create a null SCSI Target SCSIDeviceIdentifier nullTargetID = 0; // Example target ID, adjust as needed ret = UserCreateTargetForID(nullTargetID, nullptr); if (ret != kIOReturnSuccess) { Log("Failed to create Null SCSI Target for ID %llu", nullTargetID); return ret; } ... } According the document UserCreateTargetForID, after creating a TargetID successfully, the framework will call the UserInitializeTargetForID() The document said: As part of the UserCreateTargetForID call, the kernel calls several APIs like UserInitializeTargetForID which run on the default dispatch queue of the dext. But after UserCreateTargetForID created, why the UserInitializeTargetForID() not be invoked automatically? Here is the part of log show init() - Start init() - End Start() - Start Start() - try 1 times UserCreateTargetForID() - Start Allocating resources for Target ID 0 UserCreateTargetForID() - End Start() - Finished. UserInitializeController() - Start - PCI vendorID: 0x14d6, deviceID: 0x626f. - BAR0: 0x1, BAR1: 0x200004. - GetBARInfo() - BAR1 - MemoryIndex: 0, Size: 262144, Type: 0. UserInitializeController() - End UserStartController() - Start - msiInterruptIndex : 0x00000000 - interruptType info is 0x00010000 - PCI Dext interrupt final value, return status info is 0x00000000 UserStartController() - End Any assistance would be greatly appreciated! Thank you in advance for your support. Best regards, Charles
1
0
578
Mar ’25
Assistance Needed for Migrating KEXT Delay Code to DriverKit
Hello Everyone, I am working on migrating a KEXT to DriverKit but am struggling to resolve a specific issue. The code in question is simple, but I haven't been able to find a solution. void AME_IO_milliseconds_Delay(AME_U32 Delay) { Log("AME_IO_milliseconds_Delay()"); IOSleep(Delay); return; } //delay for a number of microseconds void AME_IO_microseconds_Delay(AME_U32 Delay) { Log("AME_IO_microseconds_Delay()"); IODelay(Delay); return; } I've sought help from Copilot and ChatGPT, but their suggestions haven't worked. Any guidance on how to implement this functionality in DriverKit would be greatly appreciated. Thank you for your time and assistance. Best regards, Charles
1
0
330
Mar ’25
Local DriverKit development blocked by provisioning profile requirement
Hi, I am working on a personal HIDDriverKit project. The documentation suggests that you do not need the entitlements from Apple to do local development - that all you need to do is turn of SIP, enable developer mode, and turn signing to "Sign to Run Locally". However, I have followed all of these steps, and am still running into the error that to build, I need to have a provisioning profile with the DriverKit (development) feature (MacOS 15.2 Xcode 16.2). Am I missing something here regarding the steps for local development? Does one need to request a development version of the entitlements even for local development? Do I need a paid developer account to do this? Thank-you in advance.
3
0
721
Mar ’25
Is DEXT Driver supporting these Networking Features?
I would like to know if macOS DEXT supports the following networking features: Tx/Rx Multiqueue, RSS, RSC, NS/ARP offload, PTP or packet timestamping and TSN. I couldn't find relevant documentation for these features in the Apple Developer Documentation. If they are supported, could you let me know which features are supported and how to find the corresponding official Apple documentation? Thanks
9
0
976
Mar ’25
The Map() of IOBufferMemoryDescriptor failure and cause the DriverKit Start() repeat
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
0
0
482
Mar ’25
Implementing a virtual serial port using DriverKit/SerialDriverKit
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; }
1
0
2.2k
Feb ’25
Looking for USBSerialDriver sample code
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?
1
0
930
Feb ’25
Incorrect DriverKit distribution provisioning profile generation?
I am trying to make a driver release, but failing (I think) because the manually generated distribution profiles are for the MacOS platform only, rather than MacOS and iOS together. As far as I can tell, everything is correct in the manual profiles apart from the platform. The necessary entitlements appear to be correct. In contrast, Xcode generated profiles list both MacOS and iOS as the platform and work fine for development and to generate a release archive. But Archives 'Distribute Content' gives only 'Custom' as a distribution mechanism, and no option for notarization. So, the question is: is this a problem with my developer account (and if so, what is the appropriate channel to fix it!), or is this something subtle in the project configuration?
2
0
534
Jan ’25
Crash in IOService::Create
I am getting an unexpected crash from IOService::Create() when attempting to create a new user-client. The crash is a nullptr exception in OSCopyInObjects(). The last call from my code was IOService::Create(). As far as I can tell, all the input parameters to Create() are correct, and the Info.plist is has the correct key and class information - indeed, if I corrupt these I get an error status return rather than a crash. Any suggestions as to what could be causing this? I suspect that the problem may be related from a change in the underlying application that is creating the user client. This was modified from a standard app to a daemon, following the advice here: https://developer.apple.com/documentation/xcode/signing-a-daemon-with-a-restricted-entitlement. However, it is the driver that crashes - not the host opening the user client.
1
0
629
Jan ’25
DriverKit CppUserClient Searching for dext service but Failed opening service with error: 0xe00002c7
Hi Everybody, Follow Communicating between a DriverKit extension and a client app to migrate our kext to dext. The dext might have been loaded successfully by using the command systemextensionsctl list, the dext is loaded and enabled. % sectl list 1 extension(s) --- com.apple.system_extension.driver_extension enabled active teamID bundleID (version) name [state] * * K3TDMD9Y6B com.accusys.scsidriver (1.0/1) com.accusys.scsidriver [activated enabled] We try to use the CppUserClient.cpp to communicate with the dext, but can not get the dext service. The debug message as below: Failed opening service with error: 0xe00002c7. Here is the part of CppUserClient.cpp static const char* dextIdentifier = "com.accusys.scsidriver"; kern_return_t ret = kIOReturnSuccess; io_iterator_t iterator = IO_OBJECT_NULL; io_service_t service = IO_OBJECT_NULL; ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOUserServer"), &iterator); printf("dextIdentifier = %s\n", dextIdentifier); printf("IOServiceNameMatching return = %d\n", ret); if (ret != kIOReturnSuccess) { printf("Unable to find service for identifier with error: 0x%08x.\n", ret); PrintErrorDetails(ret); } printf("Searching for dext service...\n"); while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { // Open a connection to this user client as a server to that client, and store the instance in "service" ret = IOServiceOpen(service, mach_task_self_, kIOHIDServerConnectType, &connection); if (ret == kIOReturnSuccess) { printf("\tOpened service.\n"); break; } else { printf("\tFailed opening service with error: 0x%08x.\n", ret); } IOObjectRelease(service); } IOObjectRelease(iterator); if (service == IO_OBJECT_NULL) { printf("Failed to match to device.\n"); return EXIT_FAILURE; } The console output message is dextIdentifier = com.accusys.scsidriver IOServiceNameMatching return = 0 Searching for dext service... Failed opening service with error: 0xe00002c7. Failed opening service with error: 0xe00002c7. Failed opening service with error: 0xe00002c7. Failed opening service with error: 0xe00002c7. Failed to match to device. Here is the log show message fredapp start UserInitializeController pcitest: fredapp pci vendorID: 14d6 deviceID: 626f fredapp nnnnnew configuaration read32 0x10 info: 1 fredapp nnnnnew configuaration read32 0x14 info: 80100004 fredapp new 128 before enable busmaster ReqMSGport_info 0x00000040 : fffff pcitest: fredapp 131 pci ConfigurationRead16 busmaster value 0 pcitest: fredapp 134 Enable BusMaster and IO space done...... locate 139 fredapp MemoryWrite32 function done...... fredapp new 143 after enable busmaster ReqMSGport_info 0x00000040 : 0 fredapp newwww before GetBARInfo memoryIndex1 info is: 5 fredapp GetBARInfo 1 kernel return status is: 0 fredapp GetBARInfo memoryIndex1 info is: 0 fredapp GetBARInfo barSize1 info is: 262144 fredapp GetBARInfo barType1 info is: 0 fredapp GetBARInfo result0 info is: 3758097136 fredapp GetBARInfo memoryIndex0 info is: 0 fredapp GetBARInfo barSize0 info is: 0 fredapp GetBARInfo barType0 info is: 0 pcitest: newwww fredapp againnnn test ReqMSGport info: 8 fredapp Start MPIO_Init_Prepare fredapp end MPIO_Init_Prepare. fredapp call 741 Total_memory_size: 1bb900 fredapp Start MemoryAllocationForAME_Module. fredapp IOBufferMemoryDescriptor create return status info is kIOReturnSuc fredapp IOBufferMemoryDescriptor virtualAddressSegment address info: 0x1 fredapp virtualAddressSegment length info: 0x00080000 fredapp end IOBufferMemoryDescriptor Create. fredapp dmaSpecification maxAddressBits: 0x00000000 fredapp dmaSpecification maxAddressBits: 0x00000027 fredapp IODMACommand create return status info is kIOReturnSuccess fredapp end IODMACommand Create. fredapp PrepareForDMA return status info is kIOReturnSuccess fredapp PrepareForDMA return status info is 0x00000000 fredapp Allocate memory PrepareforDMA return flags info: 0x00000003 fredapp Allocate memory PrepareforDMA return segmentsCount info: 0x00000 fredapp Allocate memory PrepareforDMA return physicalAddressSegment info: fredapp IOBufferMemoryDescriptor virtualAddressSegment address info-2: 0 fredapp verify data success init() - Finished. fredapp start UserGetDMASpecification fredapp end UserGetDMASpecification fredapp start UserMapHBAData fredapp end UserMapHBAData fredapp start UserStartController fredapp interruptType info is 0x00010000 fredapp PCI Dext interrupt final value return status info is 0x00000000 Any suggestions? Best Regards, Charles
6
0
976
Jan ’25
DriverKit: Check that driver is enabled on iPadOS
Apple Docs mentions that driver should be approved(enabled) in Settings app. I wonder is there any API available to check that driver is not enabled? To my mind, App with driver should have a following flow: Run App Check that driver is(not) enabled Display message(alert) and ask to enable driver in Settings. Optionally: provide shortcut to exact Settings page Unfortunately, it's not obvious how to check that driver is enabled.
3
0
1.5k
Jan ’25
IOServiceOpen fails with -308 Error (smUnExBusError)
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?
3
0
815
Dec ’24
Driver build does not get updated during Development
Hey, I'currently working on a Driver (and its App) for iPadOS (USB Device). I think have the right entitlements, as my driver gets installed with the app properly (after accepting it in the settings). It also gets loaded once the device is plugged in and so on. However the Kernel is not using the updated Version after I install a new Version of App and Driver to the iPad (at least most of the times). I'm verifying this by reading out the Logs via Console and the Driver prints its Build number on Start(). Sometimes it works like it should but I found no pattern. As far as I understand the iPad should automatically install the new Version of the Driver with the new App if its Build is different from the current one. I'm incrementing the Build of App and Driver automatically post-build so each build the iPad gets has its own Build number (This also works). Steps to reproduce: Cleaning Xcode Build Folder Unplugging the USB Device from the iPad. Building and Installing a new Version of the Driver and the App via Xcode (making sure the build number has changed) Plugging the USB back into the iPad Reading Console output of the iPad However it works (each time if I: Uninstall the app from the iPad manually or via Devices in Xcode Build and install the App via Xcode Open the Settings App and activate the Driver But uninstalling the App each time is taking a lot of time and manual Steps so I would like to fix this issue. Do you have any Ideas? Thanks, Bjarne
1
0
807
Dec ’24
DriverKit USB Transport to support multiple devices with different Vendor IDs
I have two different USB devices with different vendor IDs I would like to connect to. I submitted two separate requests for the com.apple.developer.driverkit.transport.usb entitlement for each vendor ID. However I am noticing the provisioning profile only has one of the vendor IDs. How do I submit a request for the USB Transport entitlement to support more than one vendor ID? I'm new to writing a DriverKit driver, so is this even possible?
5
0
1.2k
Dec ’24
How to get my extension’s process ID of the dext for debugging with lldb
I've asked this question in Stackoverflow, but no response, so I ask for help in here. I follow this guide Debugging and testing system extensions, and try to debug my dext code. In the Attach the debugger to your system extension, it said After your system extension launches, run the ps command-line tool and note your extension’s process ID. This is the current output for my dext status % systemextensionsctl list 1 extension(s) --- com.apple.system_extension.driver_extension enabled active teamID bundleID (version) name [state] * * K3TDMD9Y6B com.accusys.scsidriver (1.0/1) com.accusys.scsidriver [activated enabled] and I used the ps command but nothing happen, I can not get my extension’s process ID. ps aux | grep com.accusys.scsidriver or ps -ef | grep com.accusys.scsidriver How to do that? Any suggestion is appreciated.
1
0
796
Dec ’24
How to setup DriverKit Timer Event with OSAction Callback Binding
Hello Everyone, I'm encountering an issue while setting up a timer event in DriverKit and would appreciate any guidance. Here's my current implementation: void DRV_MAIN_CLASS_NAME::SetupEventTimer() { // 1. Create dispatch queue kern_return_t ret = IODispatchQueue::Create("TimerQueue", 0, 0, &ivars->dispatchQueue); if (ret != kIOReturnSuccess) { LogErr("Failed to create dispatch queue: 0x%x", ret); return; } // 2. Create timer source ret = IOTimerDispatchSource::Create(ivars->dispatchQueue, &ivars->dispatchSource); if (ret != kIOReturnSuccess) { LogErr("Failed to create timer: 0x%x", ret); OSSafeReleaseNULL(ivars->dispatchQueue); return; } /*! * @brief Create an instance of OSAction. * @discussion Methods to allocate an OSAction instance are generated for each method defined in a class with * a TYPE attribute, so there should not be any need to directly call OSAction::Create(). * @param target OSObject to receive the callback. This object will be retained until the OSAction is * canceled or freed. * @param targetmsgid Generated message ID for the target method. * @param msgid Generated message ID for the method invoked by the receiver of the OSAction * to generate the callback. * @param referenceSize Size of additional state structure available to the creator of the OSAction * with GetReference. * @param action Created OSAction with +1 retain count to be released by the caller. * @return kIOReturnSuccess on success. See IOReturn.h for error codes. */ // 3: Create an OSAction for the TimerOccurred method // THIS IS WHERE I NEED HELP OSAction* timerAction = nullptr; ret = OSAction::Create(this, 0, 0, 0, &timerAction); if (ret != kIOReturnSuccess) { LogErr("Failed to create OSAction: 0x%x", ret); goto cleanup; } // 4. Set handler ret = ivars->dispatchSource->SetHandler(timerAction); if (ret != kIOReturnSuccess) { LogErr("Failed to set handler: 0x%x", ret); goto cleanup; } // 5. Schedule timer (1 second) uint64_t deadline = mach_absolute_time() + NSEC_PER_SEC; ivars->dispatchSource->WakeAtTime(0, deadline, 0); cleanup: if (ret != kIOReturnSuccess) { OSSafeReleaseNULL(timerAction); OSSafeReleaseNULL(ivars->dispatchSource); OSSafeReleaseNULL(ivars->dispatchQueue); } } Problem: The code runs but the OSAction callback binding seems incorrect (Step 3). According to the OSAction documentation, I need to use the TYPE macro to properly bind the callback method. But I try to use TYPE(DRV_MAIN_CLASS_NAME::TimerOccurred) kern_return_t TimerOccurred() LOCALONLY; TYPE(TimerOccurred) kern_return_t TimerOccurred() LOCALONLY; kern_return_t TimerOccurred() TYPE(DRV_MAIN_CLASS_NAME::TimerOccurred) LOCALONLY; All results in Out-of-line definition of 'TimerOccurred' does not match any declaration in 'DRV_MAIN_CLASS_NAME' Questions: What is the correct way to declare a timer callback method using TYPE? How to get the values targetmsgid & msgid generated by Xcode? Any help would be greatly appreciated! Best Regards, Charles
Replies
6
Boosts
0
Views
549
Activity
Apr ’25
Issue Writing to BAR1 After BAR0 is Unavailable
Hello Everyone, I encountered an issue with PCI memory access in DriverKit. In my case, BAR0 is not available, but BAR1 is ready for use. Here’s the log output: !!! ERROR : Failed to get BAR0 info (error: 0xe00002f0). !!! BAR1 - MemoryIndex: 0x00000000, Size: 0x00040000, Type: 0 Issue Description When I initially wrote to BAR0 using memoryIndex = 0, it worked successfully: AME_Address_Write_32(pAMEData, pAMEData->memoryIndex, AME_HOST_INT_MASK_REGISTER, 0x0F); However, I mistakenly forgot to update memoryIndex to 1 for BAR1. Surprisingly, the write operation still succeeded. When I fixed memoryIndex = 1 for BAR1, the write operation no longer had any effect. There was no error, but the expected behavior did not occur. Relevant API (From IOPCIDevice.iig) /*! /*! * @brief Writes a 32-bit value to the PCI device's aperture at a given memory index. * @discussion This method writes a 32-bit register on the device and returns its value. * @param memoryIndex An index into the array of ranges assigned to the device. * @param offset An offset into the device's memory specified by the index. * @param data A 32-bit value to be written in host byte order. */ void MemoryWrite32(uint8_t memoryIndex, uint64_t offset, uint32_t data) LOCALONLY; Log Output: Writes to BAR0 (memoryIndex = 0) AME_Address_Write_32() called memoryIndex: 0, offset: 0x34, data: 0xf Wrote data 0xF to offset 52 AME_Address_Write_32() called memoryIndex: 0, offset: 0xa0, data: 0x1 Wrote data 0x1 to offset 160 AME_Address_Write_32() called memoryIndex: 0, offset: 0x20, data: 0xffffffff Wrote data 0xFFFFFFFF to offset 32 Writes to BAR1 (memoryIndex = 1) – No Response AME_Address_Write_32() called memoryIndex: 1, offset: 0x34, data: 0xf No confirmation log, no visible effect. Questions What should memoryIndex be set to for BAR1? The log shows "BAR1 - MemoryIndex: 0x00000000", but should I be using 1 instead? How can I verify if a write operation to BAR1 is successful? Is there a way to check if the memory region is actually writable? Should I use MemoryRead32() to confirm the written value? Any guidance would be greatly appreciated! Best Regards, Charles
Replies
3
Boosts
1
Views
262
Activity
Mar ’25
Dext not initializing with a log "Failed to write extension load report plist"
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.
Replies
1
Boosts
0
Views
381
Activity
Mar ’25
Which IOUserClient entitlements are really required?
Hello @all I'm develop a DriverKit driver extension and without entitlement checks by OS everything runs fine. But if the entitlements check is enabled in the NVRAM then I get an error due connecting my IOUserClient instance. Which entitlements are really and exactly required for my driver? My driver contains: one IOUserClient instance and multiple IOUserSerial instances The bundle identifier of the driver ist: org.eof.tools.VSPDriver The bundle identifier of the client app org.eof.tools.VSPInstall My entire source code is available on GitHub if any one want to dive deep in :) kernel[0:5107] () [VSPDriver]: NewUserClient called. kernel[0:5107] () [VSPDriver]: CreateUserClient: create VSP user client from Info.plist. kernel[0:5107] () [VSPUserClient]: init called. kernel[0:5107] () [VSPUserClient]: init finished. kernel[0:5107] () [VSPDriver]: CreateUserClient: check VSPUserClient type. kernel[0:5107] () [VSPDriver]: CreateUserClient: success. kernel[0:5107] () [VSPDriver]: NewUserClient finished. kernel[0:5107] () [VSPUserClient]: Start: called. kernel[0:5107] () [VSPUserClient]: User client successfully started. kernel[0:389f] DK: VSPUserClient-0x100001127:UC failed userclient-access check, needed bundle ID org.eof.tools.VSPDriver kernel[0:389f] DK: VSPUserClient-0x100001127:UC entitlements check failed kernel[0:5107] () [VSPUserClient]: Stop called. kernel[0:5107] () [VSPUserClient]: User client successfully removed. kernel[0:5107] () [VSPUserClient]: free called. Here my drivers entitlement file: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.allow-third-party-userclients</key> <true/> <key>com.apple.developer.driverkit.family.serial</key> <true/> </dict> </plist> Here my drivers Info.plist file <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>CFBundlePackageType</key> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleVersion</key> <string>1</string> <key>NSHumanReadableCopyright</key> <string>Copyright © 2025 by EoF Software Labs</string> <key>OSBundleUsageDescription</key> <string>Provide virtual serial port</string> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.allow-any-userclient-access</key> <true/> <key>com.apple.developer.driverkit.communicates-with-drivers</key> <true/> <key>com.apple.developer.system-extension.redistributable</key> <true/> <key>OSBundleLibraries</key> <dict> <key>com.apple.iokit.IOSerialFamily</key> <string>1.0</string> </dict> <key>IOKitPersonalities</key> <dict> <key>VSPDriver</key> <dict> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleIdentifierKernel</key> <string>com.apple.kpi.iokit</string> <key>IOMatchCategory</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>IOProviderClass</key> <string>IOUserResources</string> <key>IOResourceMatch</key> <string>IOKit</string> <key>IOProbeScore</key> <integer>0</integer> <key>IOClass</key> <string>IOUserService</string> <key>IOUserClass</key> <string>VSPDriver</string> <key>IOUserServerName</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>UserClientProperties</key> <dict> <key>IOClass</key> <string>IOUserUserClient</string> <key>IOUserClass</key> <string>VSPUserClient</string> </dict> <key>SerialPortProperties</key> <dict> <key>CFBundleIdentifierKernel</key> <string>com.apple.driver.driverkit.serial</string> <key>IOProviderClass</key> <string>IOSerialStreamSync</string> <key>IOClass</key> <string>IOUserSerial</string> <key>IOUserClass</key> <string>VSPSerialPort</string> <key>HiddenPort</key> <false/> <key>IOTTYBaseName</key> <string>vsp</string> <key>IOTTYSuffix</key> <string>0</string> </dict> </dict> </dict> </dict> </plist> Here the entitlements of the client app <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.allow-third-party-userclients</key> <true/> <key>com.apple.developer.driverkit.communicates-with-drivers</key> <true/> <key>com.apple.developer.shared-with-you</key> <true/> <key>com.apple.developer.system-extension.install</key> <true/> <key>com.apple.security.application-groups</key> <array> <string>$(TeamIdentifierPrefix).org.eof.apps</string> </array> </dict> </plist> Here the Info.plist of the client app: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>$(DEVELOPMENT_LANGUAGE)</string> <key>CFBundleExecutable</key> <string>$(EXECUTABLE_NAME)</string> <key>CFBundleIdentifier</key> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>$(PRODUCT_NAME)</string> <key>CFBundlePackageType</key> <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string> <key>CFBundleShortVersionString</key> <string>1.0</string> <key>CFBundleVersion</key> <string>1</string> <key>LSMinimumSystemVersion</key> <string>$(MACOSX_DEPLOYMENT_TARGET)</string> <key>com.apple.developer.driverkit</key> <true/> <key>com.apple.developer.driverkit.install</key> <true/> <key>com.apple.developer.system-extension.install</key> <true/> <key>com.apple.developer.system-extension.uninstall</key> <true/> <key>com.apple.developer.driverkit.userclient-access</key> <array> <string>VSPDriver</string> </array> <key>com.apple.private.driverkit.driver-access</key> <array> <string>VSPDriver</string> </array> <key>com.apple.security.temporary-exception.iokit-user-client-class</key> <array> <string>IOUserUserClient</string> </array> </dict> </plist>
Replies
2
Boosts
0
Views
910
Activity
Mar ’25
DriverKit IOUSBHostInterface iterator always empty
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));
Replies
1
Boosts
0
Views
393
Activity
Mar ’25
Why UserInitializeTargetForID() not be invoked after UserCreateTargetForID() successfully?
Hello Everyone, I am trying to create a Fake SCSI target based on SCSIControllerDriverKit.framework and inherent from IOUserSCSIParallelInterfaceController, here is the code kern_return_t IMPL(DRV_MAIN_CLASS_NAME, Start) { ... // Programmatically create a null SCSI Target SCSIDeviceIdentifier nullTargetID = 0; // Example target ID, adjust as needed ret = UserCreateTargetForID(nullTargetID, nullptr); if (ret != kIOReturnSuccess) { Log("Failed to create Null SCSI Target for ID %llu", nullTargetID); return ret; } ... } According the document UserCreateTargetForID, after creating a TargetID successfully, the framework will call the UserInitializeTargetForID() The document said: As part of the UserCreateTargetForID call, the kernel calls several APIs like UserInitializeTargetForID which run on the default dispatch queue of the dext. But after UserCreateTargetForID created, why the UserInitializeTargetForID() not be invoked automatically? Here is the part of log show init() - Start init() - End Start() - Start Start() - try 1 times UserCreateTargetForID() - Start Allocating resources for Target ID 0 UserCreateTargetForID() - End Start() - Finished. UserInitializeController() - Start - PCI vendorID: 0x14d6, deviceID: 0x626f. - BAR0: 0x1, BAR1: 0x200004. - GetBARInfo() - BAR1 - MemoryIndex: 0, Size: 262144, Type: 0. UserInitializeController() - End UserStartController() - Start - msiInterruptIndex : 0x00000000 - interruptType info is 0x00010000 - PCI Dext interrupt final value, return status info is 0x00000000 UserStartController() - End Any assistance would be greatly appreciated! Thank you in advance for your support. Best regards, Charles
Replies
1
Boosts
0
Views
578
Activity
Mar ’25
Assistance Needed for Migrating KEXT Delay Code to DriverKit
Hello Everyone, I am working on migrating a KEXT to DriverKit but am struggling to resolve a specific issue. The code in question is simple, but I haven't been able to find a solution. void AME_IO_milliseconds_Delay(AME_U32 Delay) { Log("AME_IO_milliseconds_Delay()"); IOSleep(Delay); return; } //delay for a number of microseconds void AME_IO_microseconds_Delay(AME_U32 Delay) { Log("AME_IO_microseconds_Delay()"); IODelay(Delay); return; } I've sought help from Copilot and ChatGPT, but their suggestions haven't worked. Any guidance on how to implement this functionality in DriverKit would be greatly appreciated. Thank you for your time and assistance. Best regards, Charles
Replies
1
Boosts
0
Views
330
Activity
Mar ’25
Local DriverKit development blocked by provisioning profile requirement
Hi, I am working on a personal HIDDriverKit project. The documentation suggests that you do not need the entitlements from Apple to do local development - that all you need to do is turn of SIP, enable developer mode, and turn signing to "Sign to Run Locally". However, I have followed all of these steps, and am still running into the error that to build, I need to have a provisioning profile with the DriverKit (development) feature (MacOS 15.2 Xcode 16.2). Am I missing something here regarding the steps for local development? Does one need to request a development version of the entitlements even for local development? Do I need a paid developer account to do this? Thank-you in advance.
Replies
3
Boosts
0
Views
721
Activity
Mar ’25
Is DEXT Driver supporting these Networking Features?
I would like to know if macOS DEXT supports the following networking features: Tx/Rx Multiqueue, RSS, RSC, NS/ARP offload, PTP or packet timestamping and TSN. I couldn't find relevant documentation for these features in the Apple Developer Documentation. If they are supported, could you let me know which features are supported and how to find the corresponding official Apple documentation? Thanks
Replies
9
Boosts
0
Views
976
Activity
Mar ’25
The Map() of IOBufferMemoryDescriptor failure and cause the DriverKit Start() repeat
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
Replies
0
Boosts
0
Views
482
Activity
Mar ’25
Implementing a virtual serial port using DriverKit/SerialDriverKit
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; }
Replies
1
Boosts
0
Views
2.2k
Activity
Feb ’25
Looking for USBSerialDriver sample code
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?
Replies
1
Boosts
0
Views
930
Activity
Feb ’25
Incorrect DriverKit distribution provisioning profile generation?
I am trying to make a driver release, but failing (I think) because the manually generated distribution profiles are for the MacOS platform only, rather than MacOS and iOS together. As far as I can tell, everything is correct in the manual profiles apart from the platform. The necessary entitlements appear to be correct. In contrast, Xcode generated profiles list both MacOS and iOS as the platform and work fine for development and to generate a release archive. But Archives 'Distribute Content' gives only 'Custom' as a distribution mechanism, and no option for notarization. So, the question is: is this a problem with my developer account (and if so, what is the appropriate channel to fix it!), or is this something subtle in the project configuration?
Replies
2
Boosts
0
Views
534
Activity
Jan ’25
Crash in IOService::Create
I am getting an unexpected crash from IOService::Create() when attempting to create a new user-client. The crash is a nullptr exception in OSCopyInObjects(). The last call from my code was IOService::Create(). As far as I can tell, all the input parameters to Create() are correct, and the Info.plist is has the correct key and class information - indeed, if I corrupt these I get an error status return rather than a crash. Any suggestions as to what could be causing this? I suspect that the problem may be related from a change in the underlying application that is creating the user client. This was modified from a standard app to a daemon, following the advice here: https://developer.apple.com/documentation/xcode/signing-a-daemon-with-a-restricted-entitlement. However, it is the driver that crashes - not the host opening the user client.
Replies
1
Boosts
0
Views
629
Activity
Jan ’25
DriverKit CppUserClient Searching for dext service but Failed opening service with error: 0xe00002c7
Hi Everybody, Follow Communicating between a DriverKit extension and a client app to migrate our kext to dext. The dext might have been loaded successfully by using the command systemextensionsctl list, the dext is loaded and enabled. % sectl list 1 extension(s) --- com.apple.system_extension.driver_extension enabled active teamID bundleID (version) name [state] * * K3TDMD9Y6B com.accusys.scsidriver (1.0/1) com.accusys.scsidriver [activated enabled] We try to use the CppUserClient.cpp to communicate with the dext, but can not get the dext service. The debug message as below: Failed opening service with error: 0xe00002c7. Here is the part of CppUserClient.cpp static const char* dextIdentifier = "com.accusys.scsidriver"; kern_return_t ret = kIOReturnSuccess; io_iterator_t iterator = IO_OBJECT_NULL; io_service_t service = IO_OBJECT_NULL; ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOUserServer"), &iterator); printf("dextIdentifier = %s\n", dextIdentifier); printf("IOServiceNameMatching return = %d\n", ret); if (ret != kIOReturnSuccess) { printf("Unable to find service for identifier with error: 0x%08x.\n", ret); PrintErrorDetails(ret); } printf("Searching for dext service...\n"); while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) { // Open a connection to this user client as a server to that client, and store the instance in "service" ret = IOServiceOpen(service, mach_task_self_, kIOHIDServerConnectType, &connection); if (ret == kIOReturnSuccess) { printf("\tOpened service.\n"); break; } else { printf("\tFailed opening service with error: 0x%08x.\n", ret); } IOObjectRelease(service); } IOObjectRelease(iterator); if (service == IO_OBJECT_NULL) { printf("Failed to match to device.\n"); return EXIT_FAILURE; } The console output message is dextIdentifier = com.accusys.scsidriver IOServiceNameMatching return = 0 Searching for dext service... Failed opening service with error: 0xe00002c7. Failed opening service with error: 0xe00002c7. Failed opening service with error: 0xe00002c7. Failed opening service with error: 0xe00002c7. Failed to match to device. Here is the log show message fredapp start UserInitializeController pcitest: fredapp pci vendorID: 14d6 deviceID: 626f fredapp nnnnnew configuaration read32 0x10 info: 1 fredapp nnnnnew configuaration read32 0x14 info: 80100004 fredapp new 128 before enable busmaster ReqMSGport_info 0x00000040 : fffff pcitest: fredapp 131 pci ConfigurationRead16 busmaster value 0 pcitest: fredapp 134 Enable BusMaster and IO space done...... locate 139 fredapp MemoryWrite32 function done...... fredapp new 143 after enable busmaster ReqMSGport_info 0x00000040 : 0 fredapp newwww before GetBARInfo memoryIndex1 info is: 5 fredapp GetBARInfo 1 kernel return status is: 0 fredapp GetBARInfo memoryIndex1 info is: 0 fredapp GetBARInfo barSize1 info is: 262144 fredapp GetBARInfo barType1 info is: 0 fredapp GetBARInfo result0 info is: 3758097136 fredapp GetBARInfo memoryIndex0 info is: 0 fredapp GetBARInfo barSize0 info is: 0 fredapp GetBARInfo barType0 info is: 0 pcitest: newwww fredapp againnnn test ReqMSGport info: 8 fredapp Start MPIO_Init_Prepare fredapp end MPIO_Init_Prepare. fredapp call 741 Total_memory_size: 1bb900 fredapp Start MemoryAllocationForAME_Module. fredapp IOBufferMemoryDescriptor create return status info is kIOReturnSuc fredapp IOBufferMemoryDescriptor virtualAddressSegment address info: 0x1 fredapp virtualAddressSegment length info: 0x00080000 fredapp end IOBufferMemoryDescriptor Create. fredapp dmaSpecification maxAddressBits: 0x00000000 fredapp dmaSpecification maxAddressBits: 0x00000027 fredapp IODMACommand create return status info is kIOReturnSuccess fredapp end IODMACommand Create. fredapp PrepareForDMA return status info is kIOReturnSuccess fredapp PrepareForDMA return status info is 0x00000000 fredapp Allocate memory PrepareforDMA return flags info: 0x00000003 fredapp Allocate memory PrepareforDMA return segmentsCount info: 0x00000 fredapp Allocate memory PrepareforDMA return physicalAddressSegment info: fredapp IOBufferMemoryDescriptor virtualAddressSegment address info-2: 0 fredapp verify data success init() - Finished. fredapp start UserGetDMASpecification fredapp end UserGetDMASpecification fredapp start UserMapHBAData fredapp end UserMapHBAData fredapp start UserStartController fredapp interruptType info is 0x00010000 fredapp PCI Dext interrupt final value return status info is 0x00000000 Any suggestions? Best Regards, Charles
Replies
6
Boosts
0
Views
976
Activity
Jan ’25
DriverKit: Check that driver is enabled on iPadOS
Apple Docs mentions that driver should be approved(enabled) in Settings app. I wonder is there any API available to check that driver is not enabled? To my mind, App with driver should have a following flow: Run App Check that driver is(not) enabled Display message(alert) and ask to enable driver in Settings. Optionally: provide shortcut to exact Settings page Unfortunately, it's not obvious how to check that driver is enabled.
Replies
3
Boosts
0
Views
1.5k
Activity
Jan ’25
IOServiceOpen fails with -308 Error (smUnExBusError)
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?
Replies
3
Boosts
0
Views
815
Activity
Dec ’24
Driver build does not get updated during Development
Hey, I'currently working on a Driver (and its App) for iPadOS (USB Device). I think have the right entitlements, as my driver gets installed with the app properly (after accepting it in the settings). It also gets loaded once the device is plugged in and so on. However the Kernel is not using the updated Version after I install a new Version of App and Driver to the iPad (at least most of the times). I'm verifying this by reading out the Logs via Console and the Driver prints its Build number on Start(). Sometimes it works like it should but I found no pattern. As far as I understand the iPad should automatically install the new Version of the Driver with the new App if its Build is different from the current one. I'm incrementing the Build of App and Driver automatically post-build so each build the iPad gets has its own Build number (This also works). Steps to reproduce: Cleaning Xcode Build Folder Unplugging the USB Device from the iPad. Building and Installing a new Version of the Driver and the App via Xcode (making sure the build number has changed) Plugging the USB back into the iPad Reading Console output of the iPad However it works (each time if I: Uninstall the app from the iPad manually or via Devices in Xcode Build and install the App via Xcode Open the Settings App and activate the Driver But uninstalling the App each time is taking a lot of time and manual Steps so I would like to fix this issue. Do you have any Ideas? Thanks, Bjarne
Replies
1
Boosts
0
Views
807
Activity
Dec ’24
DriverKit USB Transport to support multiple devices with different Vendor IDs
I have two different USB devices with different vendor IDs I would like to connect to. I submitted two separate requests for the com.apple.developer.driverkit.transport.usb entitlement for each vendor ID. However I am noticing the provisioning profile only has one of the vendor IDs. How do I submit a request for the USB Transport entitlement to support more than one vendor ID? I'm new to writing a DriverKit driver, so is this even possible?
Replies
5
Boosts
0
Views
1.2k
Activity
Dec ’24
How to get my extension’s process ID of the dext for debugging with lldb
I've asked this question in Stackoverflow, but no response, so I ask for help in here. I follow this guide Debugging and testing system extensions, and try to debug my dext code. In the Attach the debugger to your system extension, it said After your system extension launches, run the ps command-line tool and note your extension’s process ID. This is the current output for my dext status % systemextensionsctl list 1 extension(s) --- com.apple.system_extension.driver_extension enabled active teamID bundleID (version) name [state] * * K3TDMD9Y6B com.accusys.scsidriver (1.0/1) com.accusys.scsidriver [activated enabled] and I used the ps command but nothing happen, I can not get my extension’s process ID. ps aux | grep com.accusys.scsidriver or ps -ef | grep com.accusys.scsidriver How to do that? Any suggestion is appreciated.
Replies
1
Boosts
0
Views
796
Activity
Dec ’24