PCIDriverKit

RSS for tag

Develop device drivers for Peripheral Component Interconnect accessories.

Posts under PCIDriverKit tag

72 Posts

Post

Replies

Boosts

Views

Activity

PCI Transport Entitlements
Hello, I'm trying to develop a driver that uses PCIe through the mac's thunderbold ports. I requested a PCI entitlement, and it's just an empty array in the entitlements file by default. I was wondering if the vendor ID submitted with my entitlement request is supposed to populate this dictionary? I'm currently getting an entitlement check failed from kernel: DK: IOUserServer and was unsure if the PCI entitlement configuration was incorrect. Default entitlement: <key>com.apple.developer.driverkit.transport.pci</key> <array> </array> I'd be happy to provide more information as needed, but any guidance would be much appreciated. Thanks in advance.
1
0
720
Mar ’26
How to sign a DEXT
Kevin's Guide to DEXT Signing The question of "How do I sign a DEXT" comes up a lot, so this post is my attempt to describe both what the issues are and the best current solutions are. So... The Problems: When DEXTs were originally introduced, the recommended development signing process required disabling SIP and local signing. There is a newer, much simpler process that's built on Xcode's integrated code-signing support; however, that newer process has not yet been integrated into the documentation library. In addition, while the older flow still works, many of the details it describes are no longer correct due to changes to Xcode and the developer portal. DriverKit's use of individually customized entitlements is different than the other entitlements on our platform, and Xcode's support for it is somewhat incomplete and buggy. The situation has improved considerably over time, particularly from Xcode 15 and Xcode 16, but there are still issues that are not fully resolved. To address #1, we introduced "development" entitlement variants of all DriverKit entitlements. These entitlement variants are ONLY available in development-signed builds, but they're available on all paid developer accounts without any special approval. They also allow a DEXT to match against any hardware, greatly simplifying working with development or prototype hardware which may not match the configuration of a final product. Unfortunately, this also means that DEXT developers will always have at least two entitlement variants (the public development variant and the "private" approved entitlement), which is what then causes the problem I mentioned in #2. The Automatic Solution: If you're using Xcode 16 or above, then Xcode's Automatic code sign support will work all DEXT Families, with the exception of distribution signing the PCI and USB Families. For completeness, here is how that Automatic flow should work: Change the code signing configuration to "Automatic". Add the capability using Xcode. (USB & PCI) Edit your Entitlement.plist to include the correct "Development Only" configuration: USB Development Only Configuration: <key>com.apple.developer.driverkit.transport.usb</key> <array> <dict> <key>idVendor</key> <string>*</string> </dict> </array> PCI Development Only Configuration: <key>com.apple.developer.driverkit.transport.pci</key> <array> <dict> <key>IOPCIPrimaryMatch</key> <string>0xFFFFFFFF&amp;0x00000000</string> </dict> </array> If you've been approved for one of these entitlements, the one oddity you'll see is that adding your approved capability will add both the approved AND the development variant, while deleting either will delete both. This is a visual side effect of #2 above; however, aside from the exception described below, it can be ignored. Similarly, you can sign distribution builds by creating a build archive and then exporting the build using the standard Xcode flow. Debugging Automatic Code-signing In a new project, the flow I describe above should just work; however, if you're converting an existing project, you may get code signing errors, generally complaining about how the provisioning profile configuration doesn't match. In most cases, this happens because Xcode is choosing to reuse a previously downloaded profile with an older configuration instead of generating a new configuration which would then include the configuration changes you made. Currently, you can find these profile files in: ~/Library/Developer/Xcode/UserData/Provisioning Profiles ...which can make it easier to find and delete the specific profile (if you choose). However, one recommendation I'd have here is to not treat the contents of that folder as "precious" or special. What automatic code signing actually does is generate provisioning profiles "on demand", so if you delete an automatic profile... Xcode will just generate it again at the next build. Manually generating profiles is more cumbersome, but the solution there is to preserve them as a separate resource, probably as part of your project data, NOT to just "lose" them in the folder here. If they get deleted from Xcode's store, then you can just copy them back in from your own store (or using Xcode, which can manually download profiles as well). The advantage of this approach is that when profiles "pile up" over time (which they tend to do), you can just delete[1] all of them then let Xcode regenerate the ones you're actually trying to investigate. In terms of looking at their contents, TN3125: Inside Code Signing: Provisioning Profiles has the details of how to see exactly what's there. [1] Moving them somewhere else works too, but could indicate a fear of commitment. __ Kevin Elliott DTS Engineer, CoreOS/Hardware
1
1
2.5k
Mar ’26
[DriverKit SCSI] SCSI probe stalls for Target ID > 0 with IOUserSCSIParallelInterfaceController
Hello everyone, We are migrating a KEXT storage driver to DriverKit. In our KEXT, we use a "one LUN = one Target" model and successfully create multiple targets in a loop during initialization. We are now trying to replicate this architecture in our DEXT. The issue is that only Target 0 is fully probed and mounted. For Target 1, the lifecycle silently stops after the first TEST UNIT READY command is successfully acknowledged. The macOS SCSI layer never sends any subsequent probe commands (like INQUIRY) to this target. The failure sequence for Target 1, observed from our logs (regardless of whether Target 0 is created), is as follows: AsyncCreateTargetForID(1) -> UserInitializeTargetForID(1) (Succeeds) UserProcessParallelTask(Target: 1, Opcode: TUR) (Succeeds) The DEXT correctly acknowledges the TUR command for Target 1 by returning kSCSITaskStatus_CHECK_CONDITION with UNIT ATTENTION in the Sense Data (Succeeds) <-- Breakpoint --> UserProcessParallelTask(Target: 1, Opcode: INQUIRY) (Never happens) Through log comparison, we have confirmed that the DEXT's response to the TUR command for Target 1 is identical to the successful KEXT's response. We have tried creating only Target 1 (skipping Target 0 entirely), but the behavior is exactly the same -> the probe still stalls after the TUR. We initially suspected a race condition caused by consecutive calls to AsyncCreateTargetForID(). We attempted several methods to ensure that targets are created sequentially, such as trying to build a "creation chain" using OSAction completion handlers. However, these attempts were unsuccessful due to various compilation errors and API misunderstandings. In any case, this "race condition" theory was ultimately disproven by our experiment where creating only Target 1 still resulted in failure. We would like to ask two questions: Is our inability to have a Target ID greater than 0 fully probed by macOS a bug in our own code, or could there be another reason we are unaware of? If we do indeed need a "one-after-another" creation mechanism for AsyncCreateTargetForID, what is the correct way to implement a "chained creation" using OSAction completion handlers in DriverKit? Thank you for any help or guidance. Best Regards, Charles
3
0
1.1k
Jan ’26
VM App - PCIDriverKit Entitlement for Thunderbolt
I want to help contribute a feature in a virtual-machine app in macOS that supports PCIe device passthrough over thunderbolt. I have a question about the entitlements. Since I do not represent the GPU vendors, would I be allowed to get a driver signed that matches GPU vendor IDs? Is there such a thing as wildcard entitlement for PCIDriverKit? I don't want end-users to have to disable SIP to be able to use this. Any suggestions/leads? Thank you.
1
0
1.3k
Jan ’26
DEXT (IOUserSCSIParallelInterfaceController): Direct I/O Succeeds, but Buffered I/O Fails with Data Corruption on Large File Copies
Hi all, We are migrating a SCSI HBA driver from KEXT to DriverKit (DEXT), with our DEXT inheriting from IOUserSCSIParallelInterfaceController. We've encountered a data corruption issue that is reliably reproducible under specific conditions and are hoping for some assistance from the community. Hardware and Driver Configuration: Controller: LSI 3108 DEXT Configuration: We are reporting our hardware limitations to the framework via the UserReportHBAConstraints function, with the following key settings: // UserReportHBAConstraints... addConstraint(kIOMaximumSegmentAddressableBitCountKey, 0x20); // 32-bit addConstraint(kIOMaximumSegmentCountWriteKey, 129); addConstraint(kIOMaximumByteCountWriteKey, 0x80000); // 512KB Observed Behavior: Direct I/O vs. Buffered I/O We've observed that the I/O behavior differs drastically depending on whether it goes through the system file cache: 1. Direct I/O (Bypassing System Cache) -> 100% Successful When we use fio with the direct=1 flag, our read/write and data verification tests pass perfectly for all file sizes, including 20GB+. 2. Buffered I/O (Using System Cache) -> 100% Failure at >128MB Whether we use the standard cp command or fio with the direct=1 option removed to simulate buffered I/O, we observe the exact same, clear failure threshold: Test Results: File sizes ≤ 128MB: Success. Data checksums match perfectly. File sizes ≥ 256MB: Failure. Checksums do not match, and the destination file is corrupted. Evidence of failure reproduced with fio (buffered_integrity_test.fio, with direct=1 removed): fio --size=128M buffered_integrity_test.fio -> Test Succeeded (err=0). fio --size=256M buffered_integrity_test.fio -> Test Failed (err=92), reporting the following error, which proves a data mismatch during the verification phase: verify: bad header ... at file ... offset 1048576, length 1048576 fio: ... error=Illegal byte sequence Our Analysis and Hypothesis The phenomenon of "Direct I/O succeeding while Buffered I/O fails" suggests the problem may be related to the cache synchronization mechanism at the end of the I/O process: Our UserProcessParallelTask_Impl function correctly handles READ and WRITE commands. When cp or fio (buffered) runs, the WRITE commands are successfully written to the LSI 3108 controller's onboard DRAM cache, and success is reported up the stack. At the end of the operation, to ensure data is flushed to disk, the macOS file system issues an fsync, which is ultimately translated into a SYNCHRONIZE CACHE SCSI command (Opcode 0x35 or 0x91) and sent to our UserProcessParallelTask_Impl. We hypothesize that our code may not be correctly identifying or handling this SYNCHRONIZE CACHE opcode. It might be reporting "success" up the stack without actually commanding the hardware to flush its cache to the physical disk. The OS receives this "success" status and assumes the operation is safely complete. In reality, however, the last batch of data remains only in the controller's volatile DRAM cache and is eventually lost. This results in an incomplete or incorrect file tail, and while the file size may be correct, the data checksum will inevitably fail. Summary Our DEXT driver performs correctly when handling Direct I/O but consistently fails with data corruption when handling Buffered I/O for files larger than 128MB. We can reliably reproduce this issue using fio with the direct=1 option removed. The root cause is very likely the improper handling of the SYNCHRONIZE CACHE command within our UserProcessParallelTask. P.S. This issue did not exist in the original KEXT version of the driver. We would appreciate any advice or guidance on this issue. Thank you.
13
0
1.4k
Dec ’25
The total DMA size in DriverKit cannot exceed 2G?
We are developing a DriverKit driver on Apple M1. We use the following code to prepare DMA buffer: IODMACommandSpecification dmaSpecification; bzero(&dmaSpecification, sizeof(dmaSpecification)); dmaSpecification.options = kIODMACommandSpecificationNoOptions; dmaSpecification.maxAddressBits = p_dma_mgr->maxAddressBits; kret = IODMACommand::Create(p_dma_mgr->device, kIODMACommandCreateNoOptions, &dmaSpecification, &impl->dma_cmd ); if (kret != kIOReturnSuccess) { os_log(OS_LOG_DEFAULT, "Error: IODMACommand::Create failed! ret=0x%x\n", kret); impl->user_mem.reset(); IOFree(impl, sizeof(*impl)); return ret; } uint64_t flags = 0; uint32_t segmentsCount = 32; IOAddressSegment segments[32]; kret = impl->dma_cmd->PrepareForDMA(kIODMACommandPrepareForDMANoOptions, impl->user_mem.get(), 0, 0, // 0 for entire memory &flags, &segmentsCount, segments ); if (kret != kIOReturnSuccess) { OSSafeReleaseNULL(impl->dma_cmd); impl->user_mem.reset(); IOFree(impl, sizeof(*impl)); os_log(OS_LOG_DEFAULT, "Error: PrepareForDMA failed! ret=0x%x\n", kret); return kret; } I allocated several 8K BGRA video frames, each with a size of 141557760 bytes, and prepared the DMA according to the method mentioned above. The process was successful when the number of frames was 15 or fewer. However, issues arose when allocating 16 frames: Error: PrepareForDMA failed! ret=0xe00002bd By calculating, I found that the total size of 16 video frames exceeds 2GB. Is there such a limitation in DriverKit that the total DMA size cannot exceed 2GB? Are there any methods that would allow me to bypass this restriction so I can use more video frame buffers?
1
0
594
Dec ’25
Archive Fails: Conflict with Existing KEXT Developer ID Certificate
Hi everyone, We're trying to prepare a DriverKit App for a client test, and we've run into an unavoidable signing conflict that seems to be caused by the Xcode Archive process itself. Background & Environment: Environment: macOS 15.6.1, Xcode 16.4 Our project consists of a main App Target and a DEXT Target. Both the Debug and Release configurations for both targets are set to Xcode's default: Automatically manage signing. Our developer account holds a valid, active Developer ID Application (With Kext) certificate, which we use for signing our legacy KEXT. The Action That Triggers Failure: From this clean state, we execute Product -> Archive. The Archive process fails during the signing validation phase and presents the following three errors, completely halting the process: There is a problem with the request entity - You already have a current Developer ID Application Managed (With Kext) certificate... No profiles for 'com.company.Acxxx.driver' were found... No profiles for 'com.company.Acxxx.app' were found... This error seems to indicate that the Xcode Archive process: Ignores the project's Release configuration (even the default 'Auto' setting). Attempts to automatically create a new, standard Developer ID certificate for us. This action conflicts with the existing (With Kext) certificate in our account, causing the entire Archive process to fail. The "Failed Experiment" to Resolve This: To work around this automation conflict, we tried the solution: configuring a fully manual signing process for the Release configuration to explicitly tell Xcode to use our existing KEXT certificate. Our Steps: We disabled automatic signing for both the App and DEXT targets for the Release configuration and manually assigned the Developer ID Provisioning Profiles created for our Developer ID (With Kext) certificate. The New Problem: After doing this, the Signing Certificate field for the DEXT Target's Signing & Capabilities interface now shows None, accompanied by the misleading warning about needing a DriverKit development profile. The Outcome: This None issue now prevents us from even starting the Archive process, as the project fails to build due to the incorrect signing configuration. We've tried every debugging step — including rebuilding profiles, validating the keychain, and clearing caches — but nothing resolves this None issue. Our Dilemma: State A (Fully Automatic Signing): The Archive process fails due to the KEXT certificate conflict. State B (Manual Release Signing): The project fails to build due to the Signing Certificate: None issue, preventing us from initiating an Archive. For a development team holding a KEXT Developer ID certificate, how should an Xcode project be configured when migrating to DriverKit, so that the Archive process: Does not trigger the flawed automation logic that attempts to create a new certificate? And, does not fall into the Signing Certificate: None configuration trap? Related Forum Threads We've Studied: https://developer.apple.com/forums/thread/781932 https://developer.apple.com/forums/thread/751490 https://developer.apple.com/forums/thread/767152 https://developer.apple.com/forums/thread/721563 Best Reagrds, Charles
2
0
1.1k
Dec ’25
Provider entitlements check failed
Hello, I'm trying to make a DEXT for a thunderbolt device. I started from the DriverKit template that does a very simple Hello World. I added the DriverKit PCI (development) entitlement in the developer portal. The dext is installed and activated but when I connect my thunderbolt device this is what I see in the console log: kernel DK: mydrv-0x100010a85 waiting for server com.mycompany.mydrvApp.mydrv-100010a85 kernel Driver com.mycompany.mydrvApp.mydrv has crashed 0 time(s) kernelmanagerd Launching dext com.mycompany.mydrvApp.mydrv com.mycompany.mydrvApp.mydrv 0x100010a81 e675cb5ca6b6650163cc231c6af2f7e730b56b0bf394b857ce76f8e3105eb0f1 kernel DK: mydrv-0x100010a89 waiting for server com.mycompany.mydrvApp.mydrv-100010a89 kernelmanagerd Launching driver extension: Dext com.mycompany.mydrvApp.mydrv v1 in executable dext bundle com.mycompany.mydrvApp.mydrv at /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext default 16:52:31.551867-0500 kernel /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext/com.mycompany.mydrvApp.mydrv[15788] ==> com.apple.dext kernelmanagerd Found 1 dexts with bundle identifier com.mycompany.mydrvApp.mydrv kernelmanagerd Using unique id e675cb5ca6b6650163cc231c6af2f7e730b56b0bf394b857ce76f8e3105eb0f1 to pick dext matching bundle identifier com.mycompany.mydrvApp.mydrv kernelmanagerd Picked matching dext for bundle identifier com.mycompany.mydrvApp.mydrv: Dext com.mycompany.mydrvApp.mydrv v1 in executable dext bundle com.mycompany.mydrvApp.mydrv at /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext kernelmanagerd Launching dext com.mycompany.mydrvApp.mydrv com.mycompany.mydrvApp.mydrv 0x100010a85 e675cb5ca6b6650163cc231c6af2f7e730b56b0bf394b857ce76f8e3105eb0f1 kernel DK: com.mycompany.mydrvApp.mydrv[15788] has team identifier L86BQ63GK2 kernelmanagerd Launching driver extension: Dext com.mycompany.mydrvApp.mydrv v1 in executable dext bundle com.mycompany.mydrvApp.mydrv at /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext kernel kernel DK: mydrv-0x100010a81: provider entitlements check failed kernel DK: IOUserServer(com.mycompany.mydrvApp.mydrv-0x100010a81)-0x100010a8a::exit(Entitlements check failed) What am I missing for the check to pass? Here is my mydrv.entitlements file: I tried adding IOPCIPrimaryMatch with my vendor id in info.plist, but with same result. Developer mode is on and SIP is disabled. Thanks
7
0
674
Nov ’25
Architectural Performance Difference in External Storage I/O Between Intel and Apple Silicon Macs
Hi everyone, We are in the process of migrating a legacy KEXT for our external multi-disk RAID enclosure to the modern DriverKit framework. During the performance validation of our KEXT, we observed a large and consistent maximum throughput difference between Intel-based Macs and Apple Silicon-based Macs. We would like to share our findings and hope to discuss with others in the community to see if you have had similar experiences that could confirm or correct our understanding. The Observation: A Consistent Performance Gap When using the exact same external RAID hardware (an 8-HDD RAID 5 array), driven by our mature KEXT, we see the following results in high-throughput benchmarks (AJA System Test, large sequential writes): On a 2020 Intel-based Mac: We consistently achieve a throughput of ~2500 MB/s. On modern M-series Macs (from M1 to M4): The throughput is consistently capped at ~1500 MB/s. This performance difference of nearly 40% is significant and is present across the entire Apple Silicon product line. Our Hypothesis: A Shift in Architectural Design Philosophy Since the KEXT and external hardware are identical in both tests, we believe this performance difference is not a bug but a fundamental platform architecture distinction. Our hypothesis is as follows: 1. The Intel Mac Era ("Dedicated Throughput") The Intel-based Macs we tested use a dedicated, discrete Intel Thunderbolt controller chip. This chip has its own dedicated PCIe lanes and resources, and its design appears to be singularly focused on maximizing raw, sustained data throughput for external peripherals. 2. The Apple Silicon Era ("Integrated Efficiency") In contrast, M-series Macs use a deeply integrated I/O controller inside the SoC. This controller must share resources, such as the total unified memory bandwidth and the chip's overall power budget, with all other functional units (CPU, GPU, etc.). We speculate that the design priority for this integrated I/O controller has shifted from "maximizing single-task raw throughput" to "maximizing overall system efficiency, multi-task responsiveness, and low latency." As a result, in a pure, single-task storage benchmark, its performance ceiling may be lower than that of the older, dedicated-chip architecture. Our Question to the Community: Is our understanding correct? Have other developers of high-performance storage drivers or peripherals also observed a similar performance ceiling for external storage on Apple Silicon Macs, when compared to high-end Intel Macs? We believe that understanding this as a deliberate architectural trade-off is crucial for setting realistic performance targets for our DEXT. Our current goal has been adjusted to have our DEXT match the KEXT's ~1500 MB/s on the M-series platform. Any insights, confirmations, or corrections from the community or Apple engineers would be greatly appreciated. Thank you very much! Charles
1
0
899
Nov ’25
CreateMemoryDescriptorFromClient can't write data to user?
We've developed a PCIDriverKit driver for the capture card on macOS and have identified an issue: CreateMemoryDescriptorFromClient can only read data from the user space to the driver, but cannot write data back to the user. typedef struct _MWCAP_EDID_DATA { uint64_t size; uint64_t uaddr; } MWCAP_EDID_DATA; // App size_t xxx::GetEdid(void *buff, size_t size) { MWCAP_EDID_DATA edid; edid.size = size; edid.uaddr = (uint64_t)buff; kr = IOConnectCallStructMethod( connect, kUserGetEdid, &edid, sizeof(MWCAP_EDID_DATA), NULL, NULL ); // kr is 0. But However, the data in the buffer remains unchanged; // it does not reflect the EDID copied from the DEXT. return size; } // Driver MWCAP_EDID_DATA *edid = (MWCAP_EDID_DATA *)input; IOMemoryDescriptor *user_buf_mem = NULL; IOAddressSegment segment; segment.address = edid->uaddr; segment.length = edid->size; // We have verified that the values in edid->uaddr and edid->size are consistent with what was set by the application. ret = CreateMemoryDescriptorFromClient(kIOMemoryDirectionOutIn, 1, &segment, &user_buf_mem); if (ret != kIOReturnSuccess) { os_log(OS_LOG_DEFAULT, "Failed to create memdesc with error: 0x%08x", ret); break; } IOMemoryMap* user_buf_map = nullptr; ret = user_buf_mem->CreateMapping(0, 0, 0, 0, 0, &user_buf_map); if (ret != kIOReturnSuccess) { os_log(OS_LOG_DEFAULT, "Failed to create mapping with error: 0x%08x", ret); OSSafeReleaseNULL(user_buf_mem); break; } // ... fill the user_buf_map with edid data ... // For example: // memcpy(user_buf_map->GetAddress(), source_edid_data, edid->size); // At this point we have also verified the data in user_buf_map->GetAddress(), which matches our expectations. OSSafeReleaseNULL(user_buf_map); OSSafeReleaseNULL(user_buf_mem); Please help take a look, thank you!
1
0
645
Oct ’25
DEXT crashes when app starting
We have developed the driver for the ProCapture video capture card based on PCIDriverKit. The App can communicate with the driver through the UserClient API. Currently, there is an issue where, when the App starts, there is a small probability that it causes a driver crash. However, the crash stack trace does not point to our code but appears to be within the PCIDriverKit framework. We have spent several weeks debugging but still cannot identify the root cause of the crash. Could you please review the crash log and suggest any methods to help pinpoint the issue? com.magewell.ProCaptureDriver-2025-09-15-153522.ips com.magewell.ProCaptureDriver-2025-09-15-082500.ips
2
0
653
Oct ’25
PCIDriverKit entitlements during development
I'm trying to help out one of our vendors by building a skeleton PCI dext which they can flesh out. However, I can't seem to get the signing right. I can't sign it at all using no team or my personal team. "Signing for requires a development team", and "Personal development teams ... do not support the System Extension capability". I can't sign the driver because "DriverKit Team Provisioning Profile: doesn't match the entitlements file's value for the com.apple.developer.driverkit.transport.pci entitlement. I think this problem occurs because our company has already been assigned a transport.pci entitlement, but for our own PCI vendor ID. But I want to build and test software that works with our vendor's PCI device. I tried generating a profile for the driver manually, it contained only our own company's PCI driver match: IOPCIPrimaryMatch = "0x0000MMMM&0x0000FFFF"; where MMMM is our own PCI vendor ID. Is there a better way to inspect the profile Xcode is using than the postage-stamped sized info popup which truncates the information? I would download the generated profile but it doesn't appear on the profile, but Xcode is accessing it from somewhere. When I look at the available capabilities I can add to an app identifier on the Developer portal, I see com.apple.developer.driverkit.transport.usb, which is "development only". There's no "development only" capability for PCI. Does this mean it isn't possible to develop even a proof-of-concept PCI driver without being first granted the DriverKit PCI (Primary Match) entitlement? When adding capabilities to a driver, the list of available capabilities shown in Xcode has one "DriverKit PCI (Primary Match) entry", but if I double click it, two such entries appear in the Signing and Capabilities tab for my driver target. On the Developer portal, when I look at my driver's Identifier, there are two Capabilities labelled DriverKit PCI (Primary Match). Why?
7
0
1.9k
Oct ’25
External PCIe based storage device is not getting relinked with SCSI passthrough command
We have a management application which manages security enable and disable for an external PCIe based storage device using Kernel Extension(SCSI Architecture Model Family for External USB Mass Storage devices which deals with IOSCSIBlockCommandsDevice, IOSCSIPeripheralDeviceType00 and IOBlockStorageService) Now the issue we are facing is when we try to unlock the device using security code (already being set) , we will relink the device using VU command (RelinkBridge). Even-though both the commands are successful , the device is not getting relinked due to which we are not able to use the device for storage. If someone have faced similar issue or any pointer on how to resolve this issue , it would be helpful. Thanks in advance.
1
0
490
Oct ’25
Implementing Hardware Interrupt Handling with InterruptOccurred in DriverKit
Hello everyone, I’m working on implementing hardware interrupt handling in DriverKit and came across the InterruptOccurred method in IOInterruptDispatchSource. I noticed that its declaration ends with a TYPE macro: virtual void InterruptOccurred(OSAction* action, uint64_t count, uint64_t time) TYPE(IOInterruptDispatchSource::InterruptOccurred); This structure seems similar to how Timer Events are set up, where an event is linked to a callback and triggered by a timer. I’m attempting to use a similar approach, but for hardware-triggered interrupts rather than timer events. I’m currently in the trial-and-error phase of the implementation, but if anyone has a working example or reference on how to properly implement and register InterruptOccurred, it would be greatly appreciated! Best regards, Charles
3
0
857
May ’25
macOS Hang After Implementing UserMapHBAData()
Hi everyone, I was following the Video Modernize PCI and SCSI drivers with DriverKit and the Document to implement UserMapHBAData(), and here’s my current implementation: // kern_return_t DRV_MAIN_CLASS_NAME::UserMapHBAData_Impl(uint32_t *uniqueTaskID) kern_return_t IMPL(DRV_MAIN_CLASS_NAME, UserMapHBAData) { Log("UserMapHBAData() - Start"); // Define the vm_page_size explicitly const uint32_t vm_page_size = 4096; kern_return_t ret; IOBufferMemoryDescriptor *buffer = nullptr; IOMemoryMap *memMap = nullptr; void *taskData = nullptr; // Create a buffer for HBA-specific task data ret = IOBufferMemoryDescriptor::Create(kIOMemoryDirectionOutIn, ivars->fTaskDataSize, vm_page_size, &buffer); __Require((kIOReturnSuccess == ret), Exit); // Map memory to the driver extension's memory space ret = buffer->CreateMapping(0, 0, 0, 0, 0, &memMap); __Require((kIOReturnSuccess == ret), Exit); // Retrieve mapped memory address taskData = reinterpret_cast<void *>(memMap->GetAddress()); __Require(taskData, Exit); // WARNING: Potential leak of an object stored into 'buffer' // WARNING: Potential leak of an object stored into 'memMap' // Assign a unique task ID ivars->fTaskID++; // ERROR: No member named 'fTaskID' in 'DriverKitAcxxx_IVars' ivars->fTaskArray[ivars->fTaskID] = taskData; *uniqueTaskID = ivars->fTaskID; Log("UserMapHBAData() - End"); return kIOReturnSuccess; Exit: // Cleanup in case of failure if (memMap) { memMap->free(); // Correct method for releasing memory maps } if (buffer) { buffer->free(); // Correct method for releasing buffer memory } LogErr("ret = 0x%0x", ret); Log("UserMapHBAData() - End"); return ret; } For reference, in KEXT, memory allocation is typically done using: IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions( kernel_task, // Task in which memory is allocated kIODirectionOutIn, // Direction (read/write) 1024, // Size of the buffer in bytes 4); // Alignment requirements However, after installing the dext, macOS hangs, and I have to do a hardware reset. After rebooting, the sysctl list output shows: % sectl list 1 extension(s) --- com.apple.system_extension.driver_extension enabled active teamID bundleID (version) name [state] * - com.accusys.DriverKitAcxxx (5.0/11) com.accusys.DriverKitAcxxx [activated waiting for user] Questions: What could be causing macOS to halt? How should I approach debugging and resolving this issue? Looking forward to your insights, any suggestions would be greatly appreciated! Best regards, Charles
7
0
1.2k
May ’25
Thunderbolt: Implementing shared IO between hosts
Hello all, I am interested in developing a small driver that would facilitate host-to-host communication via Thunderbolt 4/5. While I am aware of features such as Thunderbolt Bridge/Thunderbolt Networking, I find that for my application the overhead is too great. I am interested in sharing a simple, static memory buffer between the two hosts for IO and with some synchronisation primitives. The idea being that the communication is facilitated between different platforms. Would it be possible to develop a driver/service like this? Currently, going through the documentation, to use PCIDriverKit specifying a Vendor and Product Ids is required, so I doubt that this is a viable path. I know that Linux exposes the "XDomain" protocol to announce thunderbolt services (This is the same protocol that is used in macOS to discover Thunderbolt Networking peers). Is this functionality exposed to macOS driver developers?
1
0
370
May ’25
Thunderbolt PCIe 4-devices by daisy chain connection problem
Hello everyone I have been developing PCIe device driver through Thunderbolt. However, it was confirmed that up to three devices connected to the daisy chain worked normally, but the fourth device failed to operate the _CopyDeviceMemoryWithIndex() function for connection with the BAR0 App and did not work properly. The standard specification of Thunderbolt 3/4 is said to be supported by daisy chain connection up to 6 units, but in reality, it is only 3 units, so I ask the forum for technical confirmation. Of course total 4 device by 2-port x 2-device daisy chain connecting has working well. And the PCI entry in System information app indicates that all devices have normal load of the PCIe device driver.
1
0
449
Apr ’25
Multiple thunderbolt device connected by daisy chain.
Hello everyone. I have been developing PCIe device driver through Thunderbolt. However, it was confirmed that up to three devices connected to the daisy chain worked normally, but the fourth device failed to operate the _CopyDeviceMemoryWithIndex() function for connection with the BAR0 App and did not work properly. The standard specification of Thunderbolt 3/4 is said to be supported by daisy chain connection up to 6-device, but in reality, it is only 3 units, so I ask the forum for technical confirmation. Of course total 4 device by 2-port x 2-device daisy chain connecting has working well. The PCI entry in System information indicates that all devices have normal load of the PCIe device driver. Thank you.
2
0
548
Apr ’25
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
887
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
469
Mar ’25
PCI Transport Entitlements
Hello, I'm trying to develop a driver that uses PCIe through the mac's thunderbold ports. I requested a PCI entitlement, and it's just an empty array in the entitlements file by default. I was wondering if the vendor ID submitted with my entitlement request is supposed to populate this dictionary? I'm currently getting an entitlement check failed from kernel: DK: IOUserServer and was unsure if the PCI entitlement configuration was incorrect. Default entitlement: <key>com.apple.developer.driverkit.transport.pci</key> <array> </array> I'd be happy to provide more information as needed, but any guidance would be much appreciated. Thanks in advance.
Replies
1
Boosts
0
Views
720
Activity
Mar ’26
How to sign a DEXT
Kevin's Guide to DEXT Signing The question of "How do I sign a DEXT" comes up a lot, so this post is my attempt to describe both what the issues are and the best current solutions are. So... The Problems: When DEXTs were originally introduced, the recommended development signing process required disabling SIP and local signing. There is a newer, much simpler process that's built on Xcode's integrated code-signing support; however, that newer process has not yet been integrated into the documentation library. In addition, while the older flow still works, many of the details it describes are no longer correct due to changes to Xcode and the developer portal. DriverKit's use of individually customized entitlements is different than the other entitlements on our platform, and Xcode's support for it is somewhat incomplete and buggy. The situation has improved considerably over time, particularly from Xcode 15 and Xcode 16, but there are still issues that are not fully resolved. To address #1, we introduced "development" entitlement variants of all DriverKit entitlements. These entitlement variants are ONLY available in development-signed builds, but they're available on all paid developer accounts without any special approval. They also allow a DEXT to match against any hardware, greatly simplifying working with development or prototype hardware which may not match the configuration of a final product. Unfortunately, this also means that DEXT developers will always have at least two entitlement variants (the public development variant and the "private" approved entitlement), which is what then causes the problem I mentioned in #2. The Automatic Solution: If you're using Xcode 16 or above, then Xcode's Automatic code sign support will work all DEXT Families, with the exception of distribution signing the PCI and USB Families. For completeness, here is how that Automatic flow should work: Change the code signing configuration to "Automatic". Add the capability using Xcode. (USB & PCI) Edit your Entitlement.plist to include the correct "Development Only" configuration: USB Development Only Configuration: <key>com.apple.developer.driverkit.transport.usb</key> <array> <dict> <key>idVendor</key> <string>*</string> </dict> </array> PCI Development Only Configuration: <key>com.apple.developer.driverkit.transport.pci</key> <array> <dict> <key>IOPCIPrimaryMatch</key> <string>0xFFFFFFFF&amp;0x00000000</string> </dict> </array> If you've been approved for one of these entitlements, the one oddity you'll see is that adding your approved capability will add both the approved AND the development variant, while deleting either will delete both. This is a visual side effect of #2 above; however, aside from the exception described below, it can be ignored. Similarly, you can sign distribution builds by creating a build archive and then exporting the build using the standard Xcode flow. Debugging Automatic Code-signing In a new project, the flow I describe above should just work; however, if you're converting an existing project, you may get code signing errors, generally complaining about how the provisioning profile configuration doesn't match. In most cases, this happens because Xcode is choosing to reuse a previously downloaded profile with an older configuration instead of generating a new configuration which would then include the configuration changes you made. Currently, you can find these profile files in: ~/Library/Developer/Xcode/UserData/Provisioning Profiles ...which can make it easier to find and delete the specific profile (if you choose). However, one recommendation I'd have here is to not treat the contents of that folder as "precious" or special. What automatic code signing actually does is generate provisioning profiles "on demand", so if you delete an automatic profile... Xcode will just generate it again at the next build. Manually generating profiles is more cumbersome, but the solution there is to preserve them as a separate resource, probably as part of your project data, NOT to just "lose" them in the folder here. If they get deleted from Xcode's store, then you can just copy them back in from your own store (or using Xcode, which can manually download profiles as well). The advantage of this approach is that when profiles "pile up" over time (which they tend to do), you can just delete[1] all of them then let Xcode regenerate the ones you're actually trying to investigate. In terms of looking at their contents, TN3125: Inside Code Signing: Provisioning Profiles has the details of how to see exactly what's there. [1] Moving them somewhere else works too, but could indicate a fear of commitment. __ Kevin Elliott DTS Engineer, CoreOS/Hardware
Replies
1
Boosts
1
Views
2.5k
Activity
Mar ’26
[DriverKit SCSI] SCSI probe stalls for Target ID > 0 with IOUserSCSIParallelInterfaceController
Hello everyone, We are migrating a KEXT storage driver to DriverKit. In our KEXT, we use a "one LUN = one Target" model and successfully create multiple targets in a loop during initialization. We are now trying to replicate this architecture in our DEXT. The issue is that only Target 0 is fully probed and mounted. For Target 1, the lifecycle silently stops after the first TEST UNIT READY command is successfully acknowledged. The macOS SCSI layer never sends any subsequent probe commands (like INQUIRY) to this target. The failure sequence for Target 1, observed from our logs (regardless of whether Target 0 is created), is as follows: AsyncCreateTargetForID(1) -> UserInitializeTargetForID(1) (Succeeds) UserProcessParallelTask(Target: 1, Opcode: TUR) (Succeeds) The DEXT correctly acknowledges the TUR command for Target 1 by returning kSCSITaskStatus_CHECK_CONDITION with UNIT ATTENTION in the Sense Data (Succeeds) <-- Breakpoint --> UserProcessParallelTask(Target: 1, Opcode: INQUIRY) (Never happens) Through log comparison, we have confirmed that the DEXT's response to the TUR command for Target 1 is identical to the successful KEXT's response. We have tried creating only Target 1 (skipping Target 0 entirely), but the behavior is exactly the same -> the probe still stalls after the TUR. We initially suspected a race condition caused by consecutive calls to AsyncCreateTargetForID(). We attempted several methods to ensure that targets are created sequentially, such as trying to build a "creation chain" using OSAction completion handlers. However, these attempts were unsuccessful due to various compilation errors and API misunderstandings. In any case, this "race condition" theory was ultimately disproven by our experiment where creating only Target 1 still resulted in failure. We would like to ask two questions: Is our inability to have a Target ID greater than 0 fully probed by macOS a bug in our own code, or could there be another reason we are unaware of? If we do indeed need a "one-after-another" creation mechanism for AsyncCreateTargetForID, what is the correct way to implement a "chained creation" using OSAction completion handlers in DriverKit? Thank you for any help or guidance. Best Regards, Charles
Replies
3
Boosts
0
Views
1.1k
Activity
Jan ’26
VM App - PCIDriverKit Entitlement for Thunderbolt
I want to help contribute a feature in a virtual-machine app in macOS that supports PCIe device passthrough over thunderbolt. I have a question about the entitlements. Since I do not represent the GPU vendors, would I be allowed to get a driver signed that matches GPU vendor IDs? Is there such a thing as wildcard entitlement for PCIDriverKit? I don't want end-users to have to disable SIP to be able to use this. Any suggestions/leads? Thank you.
Replies
1
Boosts
0
Views
1.3k
Activity
Jan ’26
DEXT (IOUserSCSIParallelInterfaceController): Direct I/O Succeeds, but Buffered I/O Fails with Data Corruption on Large File Copies
Hi all, We are migrating a SCSI HBA driver from KEXT to DriverKit (DEXT), with our DEXT inheriting from IOUserSCSIParallelInterfaceController. We've encountered a data corruption issue that is reliably reproducible under specific conditions and are hoping for some assistance from the community. Hardware and Driver Configuration: Controller: LSI 3108 DEXT Configuration: We are reporting our hardware limitations to the framework via the UserReportHBAConstraints function, with the following key settings: // UserReportHBAConstraints... addConstraint(kIOMaximumSegmentAddressableBitCountKey, 0x20); // 32-bit addConstraint(kIOMaximumSegmentCountWriteKey, 129); addConstraint(kIOMaximumByteCountWriteKey, 0x80000); // 512KB Observed Behavior: Direct I/O vs. Buffered I/O We've observed that the I/O behavior differs drastically depending on whether it goes through the system file cache: 1. Direct I/O (Bypassing System Cache) -> 100% Successful When we use fio with the direct=1 flag, our read/write and data verification tests pass perfectly for all file sizes, including 20GB+. 2. Buffered I/O (Using System Cache) -> 100% Failure at >128MB Whether we use the standard cp command or fio with the direct=1 option removed to simulate buffered I/O, we observe the exact same, clear failure threshold: Test Results: File sizes ≤ 128MB: Success. Data checksums match perfectly. File sizes ≥ 256MB: Failure. Checksums do not match, and the destination file is corrupted. Evidence of failure reproduced with fio (buffered_integrity_test.fio, with direct=1 removed): fio --size=128M buffered_integrity_test.fio -> Test Succeeded (err=0). fio --size=256M buffered_integrity_test.fio -> Test Failed (err=92), reporting the following error, which proves a data mismatch during the verification phase: verify: bad header ... at file ... offset 1048576, length 1048576 fio: ... error=Illegal byte sequence Our Analysis and Hypothesis The phenomenon of "Direct I/O succeeding while Buffered I/O fails" suggests the problem may be related to the cache synchronization mechanism at the end of the I/O process: Our UserProcessParallelTask_Impl function correctly handles READ and WRITE commands. When cp or fio (buffered) runs, the WRITE commands are successfully written to the LSI 3108 controller's onboard DRAM cache, and success is reported up the stack. At the end of the operation, to ensure data is flushed to disk, the macOS file system issues an fsync, which is ultimately translated into a SYNCHRONIZE CACHE SCSI command (Opcode 0x35 or 0x91) and sent to our UserProcessParallelTask_Impl. We hypothesize that our code may not be correctly identifying or handling this SYNCHRONIZE CACHE opcode. It might be reporting "success" up the stack without actually commanding the hardware to flush its cache to the physical disk. The OS receives this "success" status and assumes the operation is safely complete. In reality, however, the last batch of data remains only in the controller's volatile DRAM cache and is eventually lost. This results in an incomplete or incorrect file tail, and while the file size may be correct, the data checksum will inevitably fail. Summary Our DEXT driver performs correctly when handling Direct I/O but consistently fails with data corruption when handling Buffered I/O for files larger than 128MB. We can reliably reproduce this issue using fio with the direct=1 option removed. The root cause is very likely the improper handling of the SYNCHRONIZE CACHE command within our UserProcessParallelTask. P.S. This issue did not exist in the original KEXT version of the driver. We would appreciate any advice or guidance on this issue. Thank you.
Replies
13
Boosts
0
Views
1.4k
Activity
Dec ’25
The total DMA size in DriverKit cannot exceed 2G?
We are developing a DriverKit driver on Apple M1. We use the following code to prepare DMA buffer: IODMACommandSpecification dmaSpecification; bzero(&dmaSpecification, sizeof(dmaSpecification)); dmaSpecification.options = kIODMACommandSpecificationNoOptions; dmaSpecification.maxAddressBits = p_dma_mgr->maxAddressBits; kret = IODMACommand::Create(p_dma_mgr->device, kIODMACommandCreateNoOptions, &dmaSpecification, &impl->dma_cmd ); if (kret != kIOReturnSuccess) { os_log(OS_LOG_DEFAULT, "Error: IODMACommand::Create failed! ret=0x%x\n", kret); impl->user_mem.reset(); IOFree(impl, sizeof(*impl)); return ret; } uint64_t flags = 0; uint32_t segmentsCount = 32; IOAddressSegment segments[32]; kret = impl->dma_cmd->PrepareForDMA(kIODMACommandPrepareForDMANoOptions, impl->user_mem.get(), 0, 0, // 0 for entire memory &flags, &segmentsCount, segments ); if (kret != kIOReturnSuccess) { OSSafeReleaseNULL(impl->dma_cmd); impl->user_mem.reset(); IOFree(impl, sizeof(*impl)); os_log(OS_LOG_DEFAULT, "Error: PrepareForDMA failed! ret=0x%x\n", kret); return kret; } I allocated several 8K BGRA video frames, each with a size of 141557760 bytes, and prepared the DMA according to the method mentioned above. The process was successful when the number of frames was 15 or fewer. However, issues arose when allocating 16 frames: Error: PrepareForDMA failed! ret=0xe00002bd By calculating, I found that the total size of 16 video frames exceeds 2GB. Is there such a limitation in DriverKit that the total DMA size cannot exceed 2GB? Are there any methods that would allow me to bypass this restriction so I can use more video frame buffers?
Replies
1
Boosts
0
Views
594
Activity
Dec ’25
Archive Fails: Conflict with Existing KEXT Developer ID Certificate
Hi everyone, We're trying to prepare a DriverKit App for a client test, and we've run into an unavoidable signing conflict that seems to be caused by the Xcode Archive process itself. Background & Environment: Environment: macOS 15.6.1, Xcode 16.4 Our project consists of a main App Target and a DEXT Target. Both the Debug and Release configurations for both targets are set to Xcode's default: Automatically manage signing. Our developer account holds a valid, active Developer ID Application (With Kext) certificate, which we use for signing our legacy KEXT. The Action That Triggers Failure: From this clean state, we execute Product -> Archive. The Archive process fails during the signing validation phase and presents the following three errors, completely halting the process: There is a problem with the request entity - You already have a current Developer ID Application Managed (With Kext) certificate... No profiles for 'com.company.Acxxx.driver' were found... No profiles for 'com.company.Acxxx.app' were found... This error seems to indicate that the Xcode Archive process: Ignores the project's Release configuration (even the default 'Auto' setting). Attempts to automatically create a new, standard Developer ID certificate for us. This action conflicts with the existing (With Kext) certificate in our account, causing the entire Archive process to fail. The "Failed Experiment" to Resolve This: To work around this automation conflict, we tried the solution: configuring a fully manual signing process for the Release configuration to explicitly tell Xcode to use our existing KEXT certificate. Our Steps: We disabled automatic signing for both the App and DEXT targets for the Release configuration and manually assigned the Developer ID Provisioning Profiles created for our Developer ID (With Kext) certificate. The New Problem: After doing this, the Signing Certificate field for the DEXT Target's Signing & Capabilities interface now shows None, accompanied by the misleading warning about needing a DriverKit development profile. The Outcome: This None issue now prevents us from even starting the Archive process, as the project fails to build due to the incorrect signing configuration. We've tried every debugging step — including rebuilding profiles, validating the keychain, and clearing caches — but nothing resolves this None issue. Our Dilemma: State A (Fully Automatic Signing): The Archive process fails due to the KEXT certificate conflict. State B (Manual Release Signing): The project fails to build due to the Signing Certificate: None issue, preventing us from initiating an Archive. For a development team holding a KEXT Developer ID certificate, how should an Xcode project be configured when migrating to DriverKit, so that the Archive process: Does not trigger the flawed automation logic that attempts to create a new certificate? And, does not fall into the Signing Certificate: None configuration trap? Related Forum Threads We've Studied: https://developer.apple.com/forums/thread/781932 https://developer.apple.com/forums/thread/751490 https://developer.apple.com/forums/thread/767152 https://developer.apple.com/forums/thread/721563 Best Reagrds, Charles
Replies
2
Boosts
0
Views
1.1k
Activity
Dec ’25
Provider entitlements check failed
Hello, I'm trying to make a DEXT for a thunderbolt device. I started from the DriverKit template that does a very simple Hello World. I added the DriverKit PCI (development) entitlement in the developer portal. The dext is installed and activated but when I connect my thunderbolt device this is what I see in the console log: kernel DK: mydrv-0x100010a85 waiting for server com.mycompany.mydrvApp.mydrv-100010a85 kernel Driver com.mycompany.mydrvApp.mydrv has crashed 0 time(s) kernelmanagerd Launching dext com.mycompany.mydrvApp.mydrv com.mycompany.mydrvApp.mydrv 0x100010a81 e675cb5ca6b6650163cc231c6af2f7e730b56b0bf394b857ce76f8e3105eb0f1 kernel DK: mydrv-0x100010a89 waiting for server com.mycompany.mydrvApp.mydrv-100010a89 kernelmanagerd Launching driver extension: Dext com.mycompany.mydrvApp.mydrv v1 in executable dext bundle com.mycompany.mydrvApp.mydrv at /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext default 16:52:31.551867-0500 kernel /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext/com.mycompany.mydrvApp.mydrv[15788] ==> com.apple.dext kernelmanagerd Found 1 dexts with bundle identifier com.mycompany.mydrvApp.mydrv kernelmanagerd Using unique id e675cb5ca6b6650163cc231c6af2f7e730b56b0bf394b857ce76f8e3105eb0f1 to pick dext matching bundle identifier com.mycompany.mydrvApp.mydrv kernelmanagerd Picked matching dext for bundle identifier com.mycompany.mydrvApp.mydrv: Dext com.mycompany.mydrvApp.mydrv v1 in executable dext bundle com.mycompany.mydrvApp.mydrv at /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext kernelmanagerd Launching dext com.mycompany.mydrvApp.mydrv com.mycompany.mydrvApp.mydrv 0x100010a85 e675cb5ca6b6650163cc231c6af2f7e730b56b0bf394b857ce76f8e3105eb0f1 kernel DK: com.mycompany.mydrvApp.mydrv[15788] has team identifier L86BQ63GK2 kernelmanagerd Launching driver extension: Dext com.mycompany.mydrvApp.mydrv v1 in executable dext bundle com.mycompany.mydrvApp.mydrv at /Library/SystemExtensions/DC2F3964-043D-445E-A6CF-A9D7C529B39A/com.mycompany.mydrvApp.mydrv.dext kernel kernel DK: mydrv-0x100010a81: provider entitlements check failed kernel DK: IOUserServer(com.mycompany.mydrvApp.mydrv-0x100010a81)-0x100010a8a::exit(Entitlements check failed) What am I missing for the check to pass? Here is my mydrv.entitlements file: I tried adding IOPCIPrimaryMatch with my vendor id in info.plist, but with same result. Developer mode is on and SIP is disabled. Thanks
Replies
7
Boosts
0
Views
674
Activity
Nov ’25
Architectural Performance Difference in External Storage I/O Between Intel and Apple Silicon Macs
Hi everyone, We are in the process of migrating a legacy KEXT for our external multi-disk RAID enclosure to the modern DriverKit framework. During the performance validation of our KEXT, we observed a large and consistent maximum throughput difference between Intel-based Macs and Apple Silicon-based Macs. We would like to share our findings and hope to discuss with others in the community to see if you have had similar experiences that could confirm or correct our understanding. The Observation: A Consistent Performance Gap When using the exact same external RAID hardware (an 8-HDD RAID 5 array), driven by our mature KEXT, we see the following results in high-throughput benchmarks (AJA System Test, large sequential writes): On a 2020 Intel-based Mac: We consistently achieve a throughput of ~2500 MB/s. On modern M-series Macs (from M1 to M4): The throughput is consistently capped at ~1500 MB/s. This performance difference of nearly 40% is significant and is present across the entire Apple Silicon product line. Our Hypothesis: A Shift in Architectural Design Philosophy Since the KEXT and external hardware are identical in both tests, we believe this performance difference is not a bug but a fundamental platform architecture distinction. Our hypothesis is as follows: 1. The Intel Mac Era ("Dedicated Throughput") The Intel-based Macs we tested use a dedicated, discrete Intel Thunderbolt controller chip. This chip has its own dedicated PCIe lanes and resources, and its design appears to be singularly focused on maximizing raw, sustained data throughput for external peripherals. 2. The Apple Silicon Era ("Integrated Efficiency") In contrast, M-series Macs use a deeply integrated I/O controller inside the SoC. This controller must share resources, such as the total unified memory bandwidth and the chip's overall power budget, with all other functional units (CPU, GPU, etc.). We speculate that the design priority for this integrated I/O controller has shifted from "maximizing single-task raw throughput" to "maximizing overall system efficiency, multi-task responsiveness, and low latency." As a result, in a pure, single-task storage benchmark, its performance ceiling may be lower than that of the older, dedicated-chip architecture. Our Question to the Community: Is our understanding correct? Have other developers of high-performance storage drivers or peripherals also observed a similar performance ceiling for external storage on Apple Silicon Macs, when compared to high-end Intel Macs? We believe that understanding this as a deliberate architectural trade-off is crucial for setting realistic performance targets for our DEXT. Our current goal has been adjusted to have our DEXT match the KEXT's ~1500 MB/s on the M-series platform. Any insights, confirmations, or corrections from the community or Apple engineers would be greatly appreciated. Thank you very much! Charles
Replies
1
Boosts
0
Views
899
Activity
Nov ’25
CreateMemoryDescriptorFromClient can't write data to user?
We've developed a PCIDriverKit driver for the capture card on macOS and have identified an issue: CreateMemoryDescriptorFromClient can only read data from the user space to the driver, but cannot write data back to the user. typedef struct _MWCAP_EDID_DATA { uint64_t size; uint64_t uaddr; } MWCAP_EDID_DATA; // App size_t xxx::GetEdid(void *buff, size_t size) { MWCAP_EDID_DATA edid; edid.size = size; edid.uaddr = (uint64_t)buff; kr = IOConnectCallStructMethod( connect, kUserGetEdid, &edid, sizeof(MWCAP_EDID_DATA), NULL, NULL ); // kr is 0. But However, the data in the buffer remains unchanged; // it does not reflect the EDID copied from the DEXT. return size; } // Driver MWCAP_EDID_DATA *edid = (MWCAP_EDID_DATA *)input; IOMemoryDescriptor *user_buf_mem = NULL; IOAddressSegment segment; segment.address = edid->uaddr; segment.length = edid->size; // We have verified that the values in edid->uaddr and edid->size are consistent with what was set by the application. ret = CreateMemoryDescriptorFromClient(kIOMemoryDirectionOutIn, 1, &segment, &user_buf_mem); if (ret != kIOReturnSuccess) { os_log(OS_LOG_DEFAULT, "Failed to create memdesc with error: 0x%08x", ret); break; } IOMemoryMap* user_buf_map = nullptr; ret = user_buf_mem->CreateMapping(0, 0, 0, 0, 0, &user_buf_map); if (ret != kIOReturnSuccess) { os_log(OS_LOG_DEFAULT, "Failed to create mapping with error: 0x%08x", ret); OSSafeReleaseNULL(user_buf_mem); break; } // ... fill the user_buf_map with edid data ... // For example: // memcpy(user_buf_map->GetAddress(), source_edid_data, edid->size); // At this point we have also verified the data in user_buf_map->GetAddress(), which matches our expectations. OSSafeReleaseNULL(user_buf_map); OSSafeReleaseNULL(user_buf_mem); Please help take a look, thank you!
Replies
1
Boosts
0
Views
645
Activity
Oct ’25
DEXT crashes when app starting
We have developed the driver for the ProCapture video capture card based on PCIDriverKit. The App can communicate with the driver through the UserClient API. Currently, there is an issue where, when the App starts, there is a small probability that it causes a driver crash. However, the crash stack trace does not point to our code but appears to be within the PCIDriverKit framework. We have spent several weeks debugging but still cannot identify the root cause of the crash. Could you please review the crash log and suggest any methods to help pinpoint the issue? com.magewell.ProCaptureDriver-2025-09-15-153522.ips com.magewell.ProCaptureDriver-2025-09-15-082500.ips
Replies
2
Boosts
0
Views
653
Activity
Oct ’25
PCIDriverKit entitlements during development
I'm trying to help out one of our vendors by building a skeleton PCI dext which they can flesh out. However, I can't seem to get the signing right. I can't sign it at all using no team or my personal team. "Signing for requires a development team", and "Personal development teams ... do not support the System Extension capability". I can't sign the driver because "DriverKit Team Provisioning Profile: doesn't match the entitlements file's value for the com.apple.developer.driverkit.transport.pci entitlement. I think this problem occurs because our company has already been assigned a transport.pci entitlement, but for our own PCI vendor ID. But I want to build and test software that works with our vendor's PCI device. I tried generating a profile for the driver manually, it contained only our own company's PCI driver match: IOPCIPrimaryMatch = "0x0000MMMM&0x0000FFFF"; where MMMM is our own PCI vendor ID. Is there a better way to inspect the profile Xcode is using than the postage-stamped sized info popup which truncates the information? I would download the generated profile but it doesn't appear on the profile, but Xcode is accessing it from somewhere. When I look at the available capabilities I can add to an app identifier on the Developer portal, I see com.apple.developer.driverkit.transport.usb, which is "development only". There's no "development only" capability for PCI. Does this mean it isn't possible to develop even a proof-of-concept PCI driver without being first granted the DriverKit PCI (Primary Match) entitlement? When adding capabilities to a driver, the list of available capabilities shown in Xcode has one "DriverKit PCI (Primary Match) entry", but if I double click it, two such entries appear in the Signing and Capabilities tab for my driver target. On the Developer portal, when I look at my driver's Identifier, there are two Capabilities labelled DriverKit PCI (Primary Match). Why?
Replies
7
Boosts
0
Views
1.9k
Activity
Oct ’25
External PCIe based storage device is not getting relinked with SCSI passthrough command
We have a management application which manages security enable and disable for an external PCIe based storage device using Kernel Extension(SCSI Architecture Model Family for External USB Mass Storage devices which deals with IOSCSIBlockCommandsDevice, IOSCSIPeripheralDeviceType00 and IOBlockStorageService) Now the issue we are facing is when we try to unlock the device using security code (already being set) , we will relink the device using VU command (RelinkBridge). Even-though both the commands are successful , the device is not getting relinked due to which we are not able to use the device for storage. If someone have faced similar issue or any pointer on how to resolve this issue , it would be helpful. Thanks in advance.
Replies
1
Boosts
0
Views
490
Activity
Oct ’25
Implementing Hardware Interrupt Handling with InterruptOccurred in DriverKit
Hello everyone, I’m working on implementing hardware interrupt handling in DriverKit and came across the InterruptOccurred method in IOInterruptDispatchSource. I noticed that its declaration ends with a TYPE macro: virtual void InterruptOccurred(OSAction* action, uint64_t count, uint64_t time) TYPE(IOInterruptDispatchSource::InterruptOccurred); This structure seems similar to how Timer Events are set up, where an event is linked to a callback and triggered by a timer. I’m attempting to use a similar approach, but for hardware-triggered interrupts rather than timer events. I’m currently in the trial-and-error phase of the implementation, but if anyone has a working example or reference on how to properly implement and register InterruptOccurred, it would be greatly appreciated! Best regards, Charles
Replies
3
Boosts
0
Views
857
Activity
May ’25
macOS Hang After Implementing UserMapHBAData()
Hi everyone, I was following the Video Modernize PCI and SCSI drivers with DriverKit and the Document to implement UserMapHBAData(), and here’s my current implementation: // kern_return_t DRV_MAIN_CLASS_NAME::UserMapHBAData_Impl(uint32_t *uniqueTaskID) kern_return_t IMPL(DRV_MAIN_CLASS_NAME, UserMapHBAData) { Log("UserMapHBAData() - Start"); // Define the vm_page_size explicitly const uint32_t vm_page_size = 4096; kern_return_t ret; IOBufferMemoryDescriptor *buffer = nullptr; IOMemoryMap *memMap = nullptr; void *taskData = nullptr; // Create a buffer for HBA-specific task data ret = IOBufferMemoryDescriptor::Create(kIOMemoryDirectionOutIn, ivars->fTaskDataSize, vm_page_size, &buffer); __Require((kIOReturnSuccess == ret), Exit); // Map memory to the driver extension's memory space ret = buffer->CreateMapping(0, 0, 0, 0, 0, &memMap); __Require((kIOReturnSuccess == ret), Exit); // Retrieve mapped memory address taskData = reinterpret_cast<void *>(memMap->GetAddress()); __Require(taskData, Exit); // WARNING: Potential leak of an object stored into 'buffer' // WARNING: Potential leak of an object stored into 'memMap' // Assign a unique task ID ivars->fTaskID++; // ERROR: No member named 'fTaskID' in 'DriverKitAcxxx_IVars' ivars->fTaskArray[ivars->fTaskID] = taskData; *uniqueTaskID = ivars->fTaskID; Log("UserMapHBAData() - End"); return kIOReturnSuccess; Exit: // Cleanup in case of failure if (memMap) { memMap->free(); // Correct method for releasing memory maps } if (buffer) { buffer->free(); // Correct method for releasing buffer memory } LogErr("ret = 0x%0x", ret); Log("UserMapHBAData() - End"); return ret; } For reference, in KEXT, memory allocation is typically done using: IOBufferMemoryDescriptor *buffer = IOBufferMemoryDescriptor::inTaskWithOptions( kernel_task, // Task in which memory is allocated kIODirectionOutIn, // Direction (read/write) 1024, // Size of the buffer in bytes 4); // Alignment requirements However, after installing the dext, macOS hangs, and I have to do a hardware reset. After rebooting, the sysctl list output shows: % sectl list 1 extension(s) --- com.apple.system_extension.driver_extension enabled active teamID bundleID (version) name [state] * - com.accusys.DriverKitAcxxx (5.0/11) com.accusys.DriverKitAcxxx [activated waiting for user] Questions: What could be causing macOS to halt? How should I approach debugging and resolving this issue? Looking forward to your insights, any suggestions would be greatly appreciated! Best regards, Charles
Replies
7
Boosts
0
Views
1.2k
Activity
May ’25
Thunderbolt: Implementing shared IO between hosts
Hello all, I am interested in developing a small driver that would facilitate host-to-host communication via Thunderbolt 4/5. While I am aware of features such as Thunderbolt Bridge/Thunderbolt Networking, I find that for my application the overhead is too great. I am interested in sharing a simple, static memory buffer between the two hosts for IO and with some synchronisation primitives. The idea being that the communication is facilitated between different platforms. Would it be possible to develop a driver/service like this? Currently, going through the documentation, to use PCIDriverKit specifying a Vendor and Product Ids is required, so I doubt that this is a viable path. I know that Linux exposes the "XDomain" protocol to announce thunderbolt services (This is the same protocol that is used in macOS to discover Thunderbolt Networking peers). Is this functionality exposed to macOS driver developers?
Replies
1
Boosts
0
Views
370
Activity
May ’25
Thunderbolt PCIe 4-devices by daisy chain connection problem
Hello everyone I have been developing PCIe device driver through Thunderbolt. However, it was confirmed that up to three devices connected to the daisy chain worked normally, but the fourth device failed to operate the _CopyDeviceMemoryWithIndex() function for connection with the BAR0 App and did not work properly. The standard specification of Thunderbolt 3/4 is said to be supported by daisy chain connection up to 6 units, but in reality, it is only 3 units, so I ask the forum for technical confirmation. Of course total 4 device by 2-port x 2-device daisy chain connecting has working well. And the PCI entry in System information app indicates that all devices have normal load of the PCIe device driver.
Replies
1
Boosts
0
Views
449
Activity
Apr ’25
Multiple thunderbolt device connected by daisy chain.
Hello everyone. I have been developing PCIe device driver through Thunderbolt. However, it was confirmed that up to three devices connected to the daisy chain worked normally, but the fourth device failed to operate the _CopyDeviceMemoryWithIndex() function for connection with the BAR0 App and did not work properly. The standard specification of Thunderbolt 3/4 is said to be supported by daisy chain connection up to 6-device, but in reality, it is only 3 units, so I ask the forum for technical confirmation. Of course total 4 device by 2-port x 2-device daisy chain connecting has working well. The PCI entry in System information indicates that all devices have normal load of the PCIe device driver. Thank you.
Replies
2
Boosts
0
Views
548
Activity
Apr ’25
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
887
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
469
Activity
Mar ’25