如何使用 PCIDriverKit 内存映射 PCI BAR?

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

如何将 PCI 基址寄存器 (BAR) 从 PCIDriverKit 驱动程序 (DEXT) 内存映射到用户空间应用程序?

从驱动程序扩展到应用程序的内存映射可以通过在用户客户端子类(在driver侧)中实现IOUserClient::CopyClientMemoryForType然后调用IOConnectMapMemory64(从用户空间应用程序)来完成 侧)。这在相关答案中得到了非常好的、彻底的解释。

唯一缺少的一点是获取与所需 PCI BAR 相对应的 IOMemoryDescriptor,以便从

CopyClientMemoryForType
实现返回它。

示例代码

换个方式问,给定以下简化代码,

imaginaryFunctionWhichReturnsTheBARBuffer
的实现是什么?

kern_return_t IMPL(MyUserClient, CopyClientMemoryForType) //(uint64_t type, uint64_t *options, IOMemoryDescriptor **memory)
{
    IOMemoryDescriptor* buffer = nullptr;
    
    imaginaryFunctionWhichReturnsTheBARBuffer(ivars->pciDevice /* IOPCIDevice */, kPCIMemoryRangeBAR0, &buffer);

    *memory = buffer;

    return kIOReturnSuccess;
}

在前面的代码中

ivars->pciDevice
指的是一个随时可用的IOPCIDevice(例如:它已经根据最新最佳实践成功匹配、打开和配置)。

这意味着已经可以使用各种配置内存读/写方法来访问所需 PCI BAR 内存的显式偏移量。缺少(或不清楚)的是如何使用这些 API(或等效 API)来将与 PCI BAR 对应的整个缓冲区映射到用户空间应用程序。

可能相关也可能不相关的随机注释

  • 来自相关问题的答案如何在 DriverKit 系统扩展中分配内存并将其映射到另一个进程?包含以下引用:

    [...] 返回的内存描述符不必是我在示例中使用的 IOBufferMemoryDescriptor,它也可以是 PCI BAR 或其他任何东西。

    这正是我想做的,所以至少听起来应该是可能的。唯一剩下的问题是如何实施它。

  • 类似的问题

    已发布在Apple论坛上,尽管尚未收到任何答案(截至撰写本文时),但它确实包含一些有用的提示。 看起来 PCIDriverKit 中有一个

    private

    函数,其签名如下: virtual kern_return_t IOPCIDevice::_CopyDeviceMemoryWithIndex(uint64_t memoryIndex, IOMemoryDescriptor** memory, IOService* forClient)

    很难说出它到底应该做什么(因为它没有记录),但签名似乎确实与我正在寻找的功能匹配。然而,尝试使用它总是会导致错误代码(类似于原始论坛帖子中报告的错误代码)。错误代码似乎有所不同,具体取决于作为 
    IOService *forClient

    ) 传递的参数。

    该文章的另一个优点是,有一个可用于内核扩展(KEXT)的 

    getDeviceMemoryWithIndex

    ,它可以用来完成我们需要的任务(if 驱动程序是作为 PCI 内核扩展实现的,现在似乎已弃用) ). 但是,此功能似乎不适用于驱动程序扩展(DEXT)。因此,构建这个问题的另一个问题可能是:PCIDriverKit 驱动程序扩展的等效

    getDeviceMemoryWithIndex

    是什么?

    
    

c++ macos iokit driverkit macos-system-extension
1个回答
1
投票
IOPCIDevice::_CopyDeviceMemoryWithIndex

确实是实现此功能所需的函数(但事实上它是私有的仍然很不方便)。

示例代码

下面是一些示例代码,展示了如何实现这一点(代码使用

MyDriver

作为驱动程序类名称,使用

MyDriverUserClient
作为用户客户端)。

MyDriver.cpp

实施的相关部分:

struct MyDriver_IVars {
    IOPCIDevice* pciDevice = nullptr;
};

// MyDriver::init/free/Start/Stop/NewUserClient implementation ommited for brevity

IOMemoryDescriptor* MyDriver::copyBarMemory(uint8_t barIndex)
{
    IOMemoryDescriptor* memory;
    uint8_t barMemoryIndex, barMemoryType;
    uint64_t barMemorySize;

    // Warning: error handling is omitted for brevity
    ivars->pciDevice->GetBARInfo(barIndex, &barMemoryIndex, &barMemorySize, &barMemoryType);
    ivars->pciDevice->_CopyDeviceMemoryWithIndex(barMemoryIndex, &memory, this);

    return memory;
}

MyDriverUserClient.cpp

实施的相关部分:

struct MyDriverUserClient_IVars {
    MyDriver* myDriver = nullptr;
};

// MyDriverUserClient::init/free/Start/Stop implementation ommited for brevity

kern_return_t
IMPL(MyDriverUserClient, CopyClientMemoryForType) //(uint64_t type, uint64_t *options, IOMemoryDescriptor **memory)
{
    *memory = ivars->myDriver->copyBARMemory(kPCIMemoryRangeBAR0);

    return kIOReturnSuccess;
}

其他资源

可以在

ivshmem.dext

项目中找到使用此模式的完整实现(该项目实现了 IVSHMEM 的 macOS 驱动程序)。

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