我有一个自定义设备驱动程序,该驱动程序实现mmap
操作以将共享的RAM缓冲区(在操作系统外部)映射到用户空间。通过传递mem=32M
作为操作系统的启动参数来保留缓冲区,而将其余512MB的剩余空间用作缓冲区。我想从映射的内存中执行零复制操作,如果vm_flags
包含VM_PFNMAP
和VM_IO
则不可能。
我的驱动程序当前通过调用vm_iomap_memory(vma, start, size)
执行映射,依次调用io_remap_pfn_range
和remap_pfn_range
,后者使用VM_PFNMAP
和{{1}设置vma }集。这可以将内存映射到用户空间,但是由于设置了VM_IO
标志或缺少结构页,零拷贝套接字操作在get_user_pages
处失败。 VM_PFNMAP
的注释显示这是预期的行为,因为pfn映射的内存不应被视为“正常”。但是,就我而言,它只是一块保留的RAM,所以我不明白为什么不应该将其视为正常。我已经设置了缓存失效/刷新来手动管理内存。
在映射期间和之后,我都尝试在remap_pfn_range
上取消设置VM_PFNMAP
和VM_IO
标志,但是vm_area_struct
仍然失败。我还研究了dma库,但看起来它们依赖于对幕后get_user_pages
的调用。
我的问题是如何将物理内存映射为普通的,非pfn,结构页面支持的用户空间地址?还是我应该看看其他方式?谢谢!
答案 0 :(得分:2)
我已经找到了在内核外部映射内存缓冲区的解决方案,该解决方案需要更正我上面提到的几个错误的起点。无法在此处发布完整的源代码,但是使它工作的步骤是:
memremap
而不是ioremap
,因为它是我们正在映射的实内存。remap_pfn_range
的任何变体来为usespace设置vma,而应为fault
分配自定义vma->vm_ops.fault
nopage例程以查找页面使用用户空间虚拟地址时。 lddv3 ch15中介绍了这种方法。page = virt_to_page(pageptr);
获取页面,然后调用get_page(page);
,并将其分配给vm_fault vmf->page = page;
的结构在lddv3第15章中也进行了说明。据我所知,可以使用mmap在自定义设备驱动程序上以这种方式映射的内存,就像普通的malloc内存一样。也许可以通过DMA库获得类似的结果,但是我在阻止该路由或将设备树节点与驱动程序相关联方面有一些限制。