Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何在DriverKit系统扩展中分配内存并将其映射到另一个进程?_C++_Macos Catalina_Iokit_Driverkit_Macos System Extension - Fatal编程技术网

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

C++ 如何在DriverKit系统扩展中分配内存并将其映射到另一个进程?,c++,macos-catalina,iokit,driverkit,macos-system-extension,C++,Macos Catalina,Iokit,Driverkit,Macos System Extension,我已在应用程序中分配内存,并将其指针和大小传递给IOConnectCallStructMethod。然后,我使用将该内存映射到DriverKit系统扩展进程,可以写入该映射内存位置并从应用程序读取数据 现在,我想对系统扩展中分配的内存执行类似的操作,然后将其映射到使用系统扩展的应用程序。我想在系统扩展中创建一组内存缓冲区,然后从应用程序向其写入,然后使用IOConnectCallScalarMethod向系统扩展发送信号,指示应使用将给定缓冲区发送到USB设备。当发送完成后出现回调时,我会通知应

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

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

这就是DriverKit的作用,当用户进程从
IOKit.framework
调用时,就会调用它。顺便说一句,kext等价物实际上是完全相同的

要使其工作,您需要覆盖用户客户端子类中的
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;
}
在用户空间中,您可以调用:

    mach_vm_address_t address = 0;
    mach_vm_size_t size = 0;
    IOReturn res = IOConnectMapMemory64(connection, 0 /*memoryType*/, mach_task_self(), &address, &size, kIOMapAnywhere);
关于这方面的一些注意事项:

  • type
    参数中的值来自导致调用此函数的
    IOConnectMapMemory64
    调用的
    memoryType
    参数。因此,您的驱动程序可以具有某种编号约定;在最简单的情况下,可以将其类似于外部方法中的选择器来处理
  • memory
    实际上是一个输出参数,当函数返回
    kioreturnsucture
    时,您需要在这里返回要映射到用户空间的内存描述符。该函数具有复制语义,即调用方希望获得内存描述符的所有权,即当不再需要引用计数时,它最终会将引用计数减少1。返回的内存描述符不必像我在示例中使用的那样是
    IOBufferMemoryDescriptor
    ,它也可以是PCI条或任何东西
  • IOConnectMapMemory64
    调用中的
    kiompanywhere
    选项很重要,通常是您想要的:如果不指定此选项,则
    atAddress
    参数将变为一个in-out参数,调用者需要在地址空间中选择一个应该映射驱动程序内存的位置。通常情况下,您不关心它在哪里,如果已经映射了某个位置,那么指定一个显式位置可能会很危险
  • 如果用户空间不能写入映射内存,请相应地将
    选项设置为
    CopyClientMemoryForType
    *选项=kiouseClientMemoryReadOnly

要销毁映射,用户空间进程必须调用
IOConnectUnmapMemory64()

我已经回答了您的问题,但请注意,如果您保留外部方法的
IOUserClient方法的
structureOutputDescriptor
和/或
structureInputDescriptor
,则,您可以根据需要继续在驱动程序中使用该描述符。这实际上取决于哪种方法更适合您的用例。结构描述符方法有一个缺点:结构输入和输出只有在长度超过4096字节时才会在dext/kext中作为内存描述符出现。否则,它们将按值复制到
OSData*
类型化字段中/从中复制。iUserClientMethodArguments中可访问的所有IOMemoryDescriptor都由应用程序分配,对吗?我是否可以传递一个指向应用程序分配的内存的
IOMemoryDescriptor
,例如
IOubHostPipe::AsyncIO
?或者我必须分配任何与
ioubhostpipe::AsyncIO
一起使用的描述符与
ioubhostinterface::CreateIOBuffer
?您可以安全地将内存描述符从
IOUserClientMethodArguments
传递到
ioubhostpipe::AsyncIO
。在大多数情况下,这将是一个零拷贝操作。缺点是大小阈值不合适,而且不能以任何方式细分或连接
IOMemoryDescriptor
。(我认为可以通过将较小的长度传递给
AsyncIO
来删除尾随字节。)
ioubhostinterface::CreateIOBuffer
应优先用于分配给USB I/O的缓冲区,而不是
IOBufferMemoryDescriptor::Create
——也就是说,如果您已经打算在dext中分配缓冲区内存。顺便说一句,在kexts中,您有
IOSubMemoryDescriptor
IOMultiMemoryDescriptor
,在将内存描述符用于I/O之前,您可以使用它们从足够近的任何源拼接内存描述符。(事实上,您可以定义自己的子类,可以应用您喜欢的任何拼接逻辑。)我已经将它们在DriverKit中的缺失作为一个bug报告给Apple,如果这些对你有帮助,我建议你也这样做。