【问题标题】:Map physical memory to userspace as normal, struct page backed mapping将物理内存正常映射到用户空间,结构页面支持的映射
【发布时间】:2018-07-24 16:56:28
【问题描述】:

我有一个自定义设备驱动程序,它实现mmap 操作以将共享 RAM 缓冲区(操作系统外部)映射到用户空间。缓冲区通过传递mem=32M 作为操作系统的引导参数来保留,剩余的 512MB 可用作缓冲区。我想从映射内存执行零复制操作,如果vm_flags 包括VM_PFNMAPVM_IO,这是不可能的。

我的驱动程序当前通过调用vm_iomap_memory(vma, start, size) 来执行映射,而后者又调用io_remap_pfn_rangeremap_pfn_range,它使用VM_PFNMAPVM_IO 设置了vma。这可以将内存映射到用户空间,但是由于设置了VM_PFNMAP 标志或缺少结构页面,零拷贝套接字操作在get_user_pages 失败。 remap_pfn_range 的 cmets 显示这是预期行为,因为 pfn 映射的内存不应被视为“正常”。但是,就我而言,它只是一块保留的 RAM,所以我不明白为什么不应将其视为正常。我已经设置了缓存失效/刷新来手动管理内存。

我尝试在映射期间和映射后取消设置vm_area_struct 上的VM_PFNMAPVM_IO 标志,但get_user_pages 仍然失败。我还查看了 dma 库,但看起来它们依赖于在幕后调用 remap_pfn_range

我的问题是如何将物理内存映射为普通的、非 pfn、结构页支持的用户空间地址?还是我应该以其他方式看待它?谢谢!

【问题讨论】:

    标签: linux linux-device-driver embedded-linux mmap


    【解决方案1】:

    我找到了将内存缓冲区映射到内核外部的解决方案,该解决方案需要对我上面提到的几个错误起点进行更正。无法在此处发布完整的源代码,但使其工作的步骤是:

    1. 设备树:为没有关联驱动程序的缓冲区定义保留的内存区域。不要使用 mem 或 memmap 引导参数。内核将限制自己使用该保留空间之外的内存,但现在可以为保留内存创建结构页面。
    2. 在设备驱动程序(在我的例子中是 LKM)中,将物理地址映射到内核虚拟地址需要使用 memremap 而不是 ioremap,因为我们正在映射的是真实内存。
    3. 在设备驱动程序 mmap 例程中,不要使用 remap_pfn_range 的任何变体来为使用空间设置 vma,而是将自定义 fault nopage 例程分配给 vma->vm_ops.fault 以在用户空间虚拟地址为时查找页面用过的。 lddv3 ch15 中描述了这种方法。
    4. 驱动程序中的 nopage 函数应使用传递给它的 vm_fault 结构参数来计算需要页面的地址在 vma 中的偏移量。然后使用该偏移量计算内核虚拟地址(针对 memremap 的地址),并通过调用page = virt_to_page(pageptr); 获取页面,然后调用get_page(page);,并将其分配给具有@987654329 的vm_fault 结构@ lddv3 第 15 章也说明了这一点的后半部分。

    据我所知,使用 mmap 对自定义设备驱动程序以这种方式映射的内存可以像正常的 malloc 内存一样使用。可能有一些方法可以使用 DMA 库实现类似的结果,但我有一些限制阻止了该路由,或者将设备树节点与驱动程序相关联。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-03
      • 2017-01-12
      • 2014-06-10
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      相关资源
      最近更新 更多