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
SCSIControllerDriverKit
RSS for tagDevelop drivers for SCSI protocol-based devices.
Posts under SCSIControllerDriverKit tag
5 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
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
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
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
I am using SCSIPeripheralsDriverKit/IOUserSCSIPeripheralDeviceType00 to develop a Dext driver, which has only two classes: MyUserSCSIPeripheralDeviceType00 and MyUserClient,
MyUserClient is responsible for receiving APP commands and passing them to MyUserSCSIPeripheralDeviceType00->UserSendCDB(),
After the device is connected to the computer, the driver can match the device and start, calling MyUserSCSIPeripheralDeviceType00-->init(), MyUserSCSIPeripheralDeviceType00-->Start(),
Any command sent by the APP to MyUserSCSIPeripheralDeviceType00 will return a failure: kIOReturnUnsupported (0xe00002c7), including UserSendCDB(), UserReportMediumBlockSize(),
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IOKitPersonalities</key>
<dict>
<key>MySCSIDriver</key>
<dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleIdentifierKernel</key>
<string>com.apple.kpi.iokit</string>
<key>IOClass</key>
<string>IOUserService</string>
<key>IOMatchCategory</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>IOProviderClass</key>
<string>IOSCSIPeripheralDeviceNub</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOUserClass</key>
<string>MyUserSCSIPeripheralDeviceType00</string>
<key>IOUserServerName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>UserClientProperties</key>
<dict>
<key>IOClass</key>
<string>IOUserUserClient</string>
<key>IOUserClass</key>
<string>MyUserClient</string>
</dict>
<key>bConfigurationValue</key>
<integer>1</integer>
<key>bInterfaceNumber</key>
<integer>0</integer>
<key>bcdDevice</key>
<integer>1</integer>
<key>idProduct</key>
<string>*</string>
<key>idVendor</key>
<integer>12345</integer>
<key>Peripheral Device Type</key>
<integer>0</integer>
<key>IOKitDebug</key>
<integer>65535</integer>
</dict>
</dict>
</dict>
</plist>
This is the method that receives client calls
kern_return_t MyUserSCSIPeripheralDeviceType00::HandleExternalStruct(IOUserClientMethodArguments* arguments)
{
kern_return_t ret = kIOReturnSuccess;
SCSIType00OutParameters command;
SCSIType00InParameters response;
SCSI_Sense_Data sense;
UInt64 fSenseAddr = (intptr_t)&sense;
bzero((void *)&command, sizeof(SCSIType00OutParameters));
bzero((void *)&response, sizeof(SCSIType00InParameters));
bool test = TEST_UNIT_READY(&command, &response, fSenseAddr);
// test is true
ret = this->UserSendCDB(command, &response);
// ret is kIOReturnUnsupported (0xe00002c7)
UInt64 blockSize;
kern_return_t sizeRet = this->UserReportMediumBlockSize(&blockSize);
// sizeRet is kIOReturnUnsupported (0xe00002c7)
};
// Not called. As per the documentation, this should be called during enumeration.
kern_return_t IMPL(I4UserSCSIPeripheralDeviceType00, UserDetermineDeviceCharacteristics)
{
//
*result = true;
return kIOReturnSuccess;
}