当前,我正在使用example driver进行学习,并以此为基础建立了自己的自定义驱动程序。 mmap代码几乎相同,除了以下事实之外:我允许用户管理他们自己要求的大小,并以此为基础确定我的内存分配,以及我在/dev中自动创建char设备的事实。
为了解释上下文,对于我的用例,我想缩小我遇到的问题。 dma_mmap_coherent
在使用kmalloc的内存时可以正常工作,但是当我有一个保留的物理地址区域要使用remap_pfn_range时,它似乎可以正常工作,并且dmesg不会报告任何错误,但是当我去阅读时,无论如何我在那里写的东西总是返回0xff字节。无论是在对内存进行Ioremap之后还是在内核中使用iowrite&ioread,还是尝试使用小型mmap'ing用户态测试在用户态中写入,都是如此。
我认为我已经做了很多关于该主题的研究。我能找到的有关remap_pfn_range的文档都是kernel.org page,以及remap_pfn_range上的一些内核gmain邮件列表归档文件,代替了remap_page_range。至于dma_mmap_coherent,我可以找到更多点including a presentation from the linux archives。
最终必须有所不同。似乎有很多不同的方法可以将内核内存映射到用户领域。我有一个特别的问题:dma_mmap_coherent
和remap_pfn_range
有什么区别?
编辑可能会很总体上概述将内核内存映射到用户区的方法,其中涵盖了如何在内核驱动程序mmap回调中使用不同的api。
最佳答案
dma_mmap_coherent()在dma-mapping.h中定义为dma_mmap_attrs()的包装。 dma_mmap_attrs()尝试查看一组dma_mmap_ops是否为
与您正在使用的设备(结构设备* dev)关联的设备(如果没有,则调用dma_common_mmap(),最终将页面保护设置为不可缓存后,导致对remap_pfn_range()的调用(请参见dma-中的dma_common_mmap() c。
关于将内核内存映射到用户空间的工作的总体概述,以下是我从用户空间映射DMA缓冲区的快速简便方法:
/* A copy-from-user call needs to be done before in the IOCTL */
static int my_ioctl_alloc(struct my_struct *info, struct alloc_info *alloc)
{
...
info->buf->kvaddr = dma_alloc_coherent(dev, alloc->size, info->buf->phyaddr, GFP_KERNEL);
info->buf->buf_id = alloc->buf_id;
...
}
static const struct file_operations my_fops = {
.open = my_open,
.close = my_close,
.mmap = my_mmap,
.unlocked_ioctl = my_ioctl,
};
不要忘记在驱动程序的探测函数中的某个位置注册my_fops结构。
static int my_mmap(struct file *fptr, struct vm_area_struct *vma)
{
...
desc_id = vma->vm_pgoff;
buf = find_buf_by_id(alloc, desc_id);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
ret = remap_pfn_range(vma, vma->vm_start, buf->phyaddr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot);
if (ret) {
/* Error Handle */
}
return 0;
}
有了这个,您的内核驱动程序应该具有最小的分配和mmap缓冲区。释放缓冲区是加分的一种练习!
在应用程序中,您将打开()文件并获得有效的文件描述符fd,在执行“复制到内核”之前调用分配的IOCTL并设置缓冲区ID。在mmap中,您可以通过offset参数提供缓冲区ID:
mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buffer_id << PAGE_SHIFT);
PAGE_SHIFT是内核中固定的与体系结构相关的编译时间MACRO。
希望这可以帮助。
这不是checkpatch.pl兼容的代码,也不是最佳实践,但这是我知道如何执行此操作的一种方式。欢迎评论/改进/建议!
有关教科书示例和感兴趣的读者的良好背景信息,请参见Linux设备驱动程序-第15章:内存映射和DMA。
关于c - dma_mmap_coherent和remap_pfn_range有什么区别?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34516847/