dma_mmap_coherent和remap_pfn_range有什么区别?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dma_mmap_coherent和remap_pfn_range有什么区别?相关的知识,希望对你有一定的参考价值。
目前,我正在使用example driver来学习,并从中我自己定制的驱动程序。 mmap代码几乎完全相同,除了我允许用户管理他们自己的请求大小并围绕它进行内存分配以及我在/ dev中自动创建char设备这一事实。
为了解释上下文,对于我的用例,我想缩小我遇到的问题。 dma_mmap_coherent
在使用kmalloc内存时可以正常工作,但是当我有一个保留的物理地址区域,我想使用remap_pfn_range时它会安静地工作,而dmesg不报告任何错误,但是当我去阅读时,无论如何我在那里写的它总是返回0xff字节。无论我在ioremap内存之后使用iowrite和ioread在内核中使用还是尝试使用小型mmap'ing用户态测试在userland中编写,都是如此。
我已经做了尽可能多的关于这个主题的研究。我所能找到的有关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回调中使用不同的apis。
dma_mmap_coherent()在dma-mapping.h中定义为dma_mmap_attrs()的包装器。 dma_mmap_attrs()尝试查看一组dma_mmap_ops是否与您正在操作的设备(struct device * dev)相关联,如果没有,则调用dma_common_mmap(),最终会在设置页面保护后调用remap_pfn_range()作为不可缓存的(请参阅dma-mapping.c中的dma_common_mmap())。
至于mmap的内核内存到用户空间的一般概述,以下是我从用户空间mmap'ed DMA缓冲区的快速而简单的方法:
- 通过IOCTL分配缓冲区,并为每个缓冲区指定一个带有一些标志的缓冲区ID:
/* 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; ... }
- 定义mmap文件ops:
static const struct file_operations my_fops = { .open = my_open, .close = my_close, .mmap = my_mmap, .unlocked_ioctl = my_ioctl, };
不要忘记在驱动程序的探测函数中的某处注册my_fops结构。 - 实现mmap文件操作:
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,在执行复制到内核之前调用allocate 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以获取教科书示例和良好的背景信息。
以上是关于dma_mmap_coherent和remap_pfn_range有什么区别?的主要内容,如果未能解决你的问题,请参考以下文章
第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等
shell中$()和 ` `${}${!}${#}$[] 和$(()),[ ] 和(( ))和 [[ ]]
Java基础8---面向对象代码块和继承和this和super和重写和重载和final
Java基础8---面向对象代码块和继承和this和super和重写和重载和final
JS中some()和every()和join()和concat()和pop(),push(),shift(),unshfit()和map()和filter()