从内存到用户空间中的设备执行DMA时出现内存不一致问题

时间:2016-04-03 12:14:19

标签: c linux linux-kernel operating-system arm

我花了几个小时试图找出用户空间驱动程序中内存行为不一致的根本原因。我似乎设法至少让它工作,但是,我仍然不了解根本原因本身,我对解决方案并不完全满意,因为它绕过了内核的内存管理系统。

首先,关于此设置的一些背景知识:

该平台基于ARM,我正在运行Linux(4.4) 我正在研究一个用户空间驱动程序(UIO)来控制一个非常简单的硬件。该器件需要从主存储器(DMA)读取数据,对数据进行一些计算,并将结果输出到其中一个寄存器中。 该设备与ARM保持一致,因为它连接到ACP端口(这实际上意味着我不需要刷新缓存或分配DMA连贯内存)。 由于该设备与uio通用驱动程序兼容,因此访问寄存器和中断非常容易。棘手的部分是从用户空间分配物理上连续的内存,并确保设备实际上在适当的时刻从它应该的位置读取。

现在,我尝试了两种不同的方式来分配这个内存,其中一种似乎正在工作,而另一种则没有。

非工作解决方案基本上由一个非常简单的内核模块组成,该模块将内核空间中的物理连续内存与用户空间中的vm区域进行mmaps。

struct page *page = alloc_page(GFP_KERNEL);
vma->vm_pgoff = page_to_phys(page) >> PAGE_SHIFT;
SetPageReserved(page);
remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, 1 << PAGE_SHIFT, vma->vm_page_prot))

我在这种情况下观察到的是,当设备从“内存”读取时(引用因为它实际上也可以从L1 / L2缓存中读取),它会获得过时的数据。我还观察到,如果我在设置内存内容之后等待并启动设备之前(例如通过休眠(10)),这个选项也可以工作(显然这是不可接受的,但至少它表明我'在正确的位置写作。)

至于工作解决方案 - 我通过修改uboot中的bootparams变量来保留2MB内存,这样内核甚至不知道它在那里。然后,在用户空间应用程序端,我在适当的地址mmap / dev / mem。这总是有效,这表明我不仅要写到正确的位置,而且设备与CPU是一致的。

我更喜欢基于内核的解决方案。有谁知道这里可能出了什么问题?我猜测内核正在设置页面表,以防止一致性端口正常工作,但我不知道接下来要看什么。有谁知道这两种方法之间存在潜在的差异以及可能出现的问题?

0 个答案:

没有答案