我已经编写了一个驱动程序,其目的是允许用户空间程序固定其页面并获取页面的物理地址。
具体来说,我是通过在内核模块中调用get_user_pages_fast
来实现的。
作为参考,可以在以下位置找到此模块的源代码:https://github.com/UofT-HPRC/mpsoc_drivers/tree/master/pinner
使用/dev/mem
(是的,我的内核确实允许不安全的/dev/mem
访问),我已经确认物理地址是正确的。
但是,我有一些外部硬件(准确地说是FPGA中的AXI DMA)无法正常工作,看来这可能是缓存一致性问题。在上面链接的代码的329-337行中,我这样做:(在此代码中,cm.usr_buf是用户虚拟地址)
//Find the VMA containing the user's buffer
struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)cmd.usr_buf);
if (!vma) {
printk(KERN_ALERT "pinner: unrecognized user virtual address\n");
return -EINVAL;
}
flush_cache_range(vma, (unsigned long) cmd.usr_buf, (unsigned long) cmd.usr_buf + cmd.usr_buf_sz);
这似乎没有帮助。我还尝试了更通用的flush_cache_mm
函数。
是否存在刷新用户页面缓存的正确方法?
答案 0 :(得分:1)
我尝试了其他API来刷新缓存。洛朗·平查德(Laurent Pinchard)发表了一个名为“ Mastering the DMA and IOMMU APIs”的演讲,他在讲话中解释说,不应使用<asm/cacheflush.h>
中的函数。而是在固定用户内存时可以使用dma_map_sg
和dma_unmap_sg
之类的东西。我快速浏览了内核源代码,这些功能最终调用了特定于每种体系结构的汇编例程,这些例程可能负责禁用某些内存区域中的缓存。
此外,如果您尝试在DMA传输之间访问内存,则可以使用dma_sync_sg_for_cpu
和dma_sync_sg_for_device
强制进行高速缓存刷新。
我重写了内核驱动程序以使用这些功能,并且它起作用了。