我已经在应用程序中分配了内存,并将其指针和大小传递给了IOConnectCallStructMethod
。然后,使用IOMemoryDescriptor::CreateMapping
将内存映射到DriverKit系统扩展过程,并且可以写入此映射的内存位置并从应用程序中读取数据。
我现在想对系统扩展中分配的内存执行类似的操作,然后将其映射到使用系统扩展的应用程序。我想在系统扩展中创建一组内存缓冲区,然后从应用程序对其进行写入,然后使用IOMemoryDescriptor::CreateMapping
向系统扩展发出信号,即应使用IOConnectCallScalarMethod
将给定的缓冲区发送到USB设备。 。发送完成后,当IOUSBHostPipe::AsyncIO
回调出现时,我会通知应用程序,现在可以将数据复制到发送的第一个缓冲区中。可以使用IOUSBHostPipe::AsyncIO
和在系统扩展中创建的CompleteAsyncIO
对象来完成此机制。我不了解的是如何将系统扩展中分配的内存映射到应用程序。
这就是DriverKit中的CompleteAsyncIO
的用途,当您的用户进程从IOConnectCallAsyncStructMethod
调用OSAction
时,将调用该函数。顺便说一下,kext等效项是IOUserClient::CopyClientMemoryForType
,并且基本上是完全相同的。]
要使其正常工作,您需要在用户客户端子类中重写IOUserClient::CopyClientMemoryForType
虚拟函数。
在IOConnectMapMemory64
中的类定义中:
IOConnectMapMemory64
在实现
IOKit.framework
中,类似以下内容:
IOUserClient::clientMemoryForType
在用户空间中,您将致电:
IOUserClient::clientMemoryForType
一些注意事项:
CopyClientMemoryForType
参数中的值从.iig
参数到virtual kern_return_t CopyClientMemoryForType(
uint64_t type, uint64_t *options, IOMemoryDescriptor **memory) override;
调用,导致该函数被调用。因此,您的驱动程序可以具有某种编号约定。在最简单的情况下,您可以将其与外部方法中的选择器类似。.cpp
实际上是一个输出参数,当函数返回kern_return_t IMPL(MyUserClient, CopyClientMemoryForType) //(uint64_t type, uint64_t *options, IOMemoryDescriptor **memory)
{
kern_return_t res;
if (type == 0)
{
IOBufferMemoryDescriptor* buffer = nullptr;
res = IOBufferMemoryDescriptor::Create(kIOMemoryDirectionInOut, 128 /* capacity */, 8 /* alignment */, &buffer);
if (res != kIOReturnSuccess)
{
os_log(OS_LOG_DEFAULT, "MyUserClient::CopyClientMemoryForType(): IOBufferMemoryDescriptor::Create failed: 0x%x", res);
}
else
{
*memory = buffer; // returned with refcount 1
}
}
else
{
res = this->CopyClientMemoryForType(type, options, memory, SUPERDISPATCH);
}
return res;
}
时,这是您希望返回要映射到用户空间的内存描述符的地方。该函数具有复制语义,即调用方希望获得该内存描述符的所有权,即,当不再需要该引用时,它将最终将引用计数减少1。返回的内存描述符不必是示例中使用的 mach_vm_address_t address = 0;
mach_vm_size_t size = 0;
IOReturn res = IOConnectMapMemory64(connection, 0 /*memoryType*/, mach_task_self(), &address, &size, kIOMapAnywhere);
,也可以是PCI BAR或其他任何东西。type
调用中的memoryType
选项很重要,通常也是您想要的:如果您未指定此选项,则IOConnectMapMemory64
参数将成为一个输入-输出参数,并且调用方应选择一个位置在应映射驱动程序存储器的地址空间中。通常,您并不关心它在哪里,并且如果已经有映射的地方,则实际上指定明确的位置可能很危险。memory
参数相应地设置为kIOReturnSuccess
:IOBufferMemoryDescriptor
要破坏映射,用户空间进程必须调用kIOMapAnywhere
。