MIPS平台
设备驱动中mmap实现如下:
static int shm_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
struct tee_shm *shm = dmabuf->priv;
size_t size = vma->vm_end - vma->vm_start;
vma->vm_flags |= VM_IO | VM_SHARED;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
size, vma->vm_page_prot);
}
如果不加下划线两行代码,当应用进程,向共享的虚拟空间写入数据时,数据不会及时更新到物理内存中。
因为应用进程中的虚拟空间和物理内存间还有cache。
但是相同的代码在ARM平台没有问题,X86据说也没问题(未验证)、PPC据说平台也有问题(未验证)。
下面分析来自网上:
Mapping of physical memory in UIO needs pgprot_noncached() to ensure
that IO memory is not cached. Without pgprot_noncached(), it (accidentally)
works on x86 and arm, but fails on PPC.
你把用户态的设成了no cache,直接读物理内存。
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
内核直接用的dcache,肯定又一段延迟才会写到物理内存。
这样用户态自然读的延迟了。
如果 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);把这个去掉的话。用户态和内核态都用cache,虽然可能有cache aliasing的问题(用户态cache line和内核cache line都指向的同一块物理内存),但是一般体系都会自动解决这个alasing的,比如armv7就是自动处理vipt dcache aliasing的。
PPC的这个问题我也遇到过,硬件DMA跟上层共享数据的话不会自动刷新cache,当时我是在访问之前,使用flush_cache_range刷新了cache
ppc是pipt的cache,所以不会出现cache alias的问题
LZ之前代码中有pgprot_noncached,于是kernel就是写的data cache,而app却是直接读的内存,所以数据不一致
而LZ后面又去掉了pgprot_noncached,于是kernel和app都是读写的data cache,而ppc又是pipt的cache,所以app和kernel都是读写的同一个cache line,因此没有问题了