像往常一样,将物理内存映射到用户空间,进行结构页支持的映射

时间:2018-07-24 16:56:28

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

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

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

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

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

1 个答案:

答案 0 :(得分:2)

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

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

据我所知,可以使用mmap在自定义设备驱动程序上以这种方式映射的内存,就像普通的malloc内存一样。也许可以通过DMA库获得类似的结果,但是我在阻止该路由或将设备树节点与驱动程序相关联方面有一些限制。