如何在DriverKit系统扩展中分配内存并将其映射到另一个进程?

问题描述 投票:1回答:1

我已经在应用程序中分配了内存,并将其指针和大小传递给了IOConnectCallStructMethod。然后,使用IOMemoryDescriptor::CreateMapping将内存映射到DriverKit系统扩展过程,并且可以写入此映射的内存位置并从应用程序中读取数据。

我现在想对系统扩展中分配的内存执行类似的操作,然后将其映射到使用系统扩展的应用程序。我想在系统扩展中创建一组内存缓冲区,然后从应用程序对其进行写入,然后使用IOMemoryDescriptor::CreateMapping向系统扩展发出信号,即应使用IOConnectCallScalarMethod将给定的缓冲区发送到USB设备。 。发送完成后,当IOUSBHostPipe::AsyncIO回调出现时,我会通知应用程序,现在可以将数据复制到发送的第一个缓冲区中。可以使用IOUSBHostPipe::AsyncIO和在系统扩展中创建的CompleteAsyncIO对象来完成此机制。我不了解的是如何将系统扩展中分配的内存映射到应用程序。

c++17 macos-catalina iokit driverkit macos-system-extension
1个回答
0
投票

这就是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参数相应地设置为kIOReturnSuccessIOBufferMemoryDescriptor
  • 要破坏映射,用户空间进程必须调用kIOMapAnywhere

© www.soinside.com 2019 - 2024. All rights reserved.