dma_mmap_coherent 和 remap_pfn_range 有什么区别?

2024-02-05

目前,我正在使用示例驱动程序 https://github.com/claudioscordino/mmap_alloc/blob/master/mmap_alloc.c从中学习,并从中我建立了自己的自定义驱动程序。 mmap 代码几乎是相同的,除了我允许用户管理他们自己请求的大小并以此为基础进行内存分配以及我在 /dev 中自动创建 char 设备这一事实之外。

为了解释上下文,对于我的用例,我想缩小我遇到的问题的范围。dma_mmap_coherent在使用 kmalloc 内存时可测试地工作,但是当我有一个保留的物理地址区域,我想使用 remap_pfn_range 时,它​​似乎安静地工作,并且 dmesg 不会报告任何错误,但是当我去读取时,无论什么我在那里写过它总是返回 0xff 字节。无论我在 ioremap'ing 内存后在内核空间中使用 iowrite 和 ioread 还是尝试使用小型 mmap'ing 用户空间测试在用户空间中写入,都是如此。

我已经尽我所能对这个主题进行了尽可能多的研究。我能找到的所有 remap_pfn_range 文档是kernel.org 页面 https://www.kernel.org/doc/htmldocs/kernel-api/API-remap-pfn-range.html,以及一些关于 remap_pfn_range 的内核 gmain 邮件列表存档,替换了 remap_page_range。至于 dma_mmap_coherent,我能够找到更多一点,包括来自 linux 档案的演示 https://events.linuxfoundation.org/sites/events/files/slides/20140429-dma.pdf.

最终必定存在差异;似乎有很多不同的方法可以将内核内存映射到用户空间。我的具体问题是:两者之间有什么区别dma_mmap_coherent and remap_pfn_range?

Edit一般而言,最好提供将内核内存映射到用户空间的方法的总体概述,包括如何在内核驱动程序 mmap 回调中使用不同的 api。


dma_mmap_coherent() 定义于dma-映射.h https://github.com/torvalds/linux/blob/master/include/linux/dma-mapping.h作为 dma_mmap_attrs() 的包装。 dma_mmap_attrs() 尝试查看一组 dma_mmap_ops 是否 与您正在操作的设备(struct device *dev)关联,如果没有,它会调用 dma_common_mmap() ,在将页面保护设置为不可缓存之后,最终会导致调用 remap_pfn_range() (请参阅 dma- 中的 dma_common_mmap() )映射.c)。

至于将内核内存映射到用户空间的工作原理的一般概述,以下是我从用户空间映射 DMA 缓冲区的快速而简单的方法:

  1. 通过 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;
            ...
    }
    
  2. 定义一个 mmap 文件 ops :

    static const struct file_operations my_fops = {
            .open = my_open,
            .close = my_close,
            .mmap = my_mmap,
            .unlocked_ioctl = my_ioctl,
    };
    

    不要忘记在驱动程序的探测函数中的某个位置注册 my_fops 结构。

  3. 实现 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 缓冲区。释放缓冲区是一项奖励积分的练习!

在应用程序中,您将 open() 文件并获取有效的文件描述符 fd,调用分配 IOCTL 并在执行复制到内核之前设置缓冲区 ID。在 mmap 中,您可以通过 offset 参数给出缓冲区 ID:

      mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buffer_id << PAGE_SHIFT);

PAGE_SHIFT 是内核中固定的依赖于体系结构的编译时宏。 希望这可以帮助。

这不是符合 checkpatch.pl 的代码,也不是最佳实践,但这是我知道如何做到这一点的一种方法。欢迎评论/改进/建议!

请参阅 Linux 设备驱动程序 - 第 15 章:内存映射和 DMA,了解教科书示例以及为感兴趣的读者提供的良好背景信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

dma_mmap_coherent 和 remap_pfn_range 有什么区别? 的相关文章

  • 分段错误(核心转储)错误

    我的程序编译罚款 但在输入文件时出现 分段错误 核心转储 错误 我没有正确处理 ostream 吗 include
  • 在 C++ 中将成对向量转换为两个独立向量的最快方法

    假设我有一个vector of pair
  • 如何尝试/捕获所有异常

    我正在完成由其他人启动的 UWP 应用程序 该应用程序经常崩溃 我总是陷入困境应用程序 at if global System Diagnostics Debugger IsAttached global System Diagnostic
  • 无需 cron 在后台发送邮件

    我想知道是否有一种方法可以运行 PHP 循环 以便在后台向订阅者发送几百封电子邮件 我的目标是格式化新闻通讯 单击发送 然后关闭浏览器或更改页面 当然 发送电子邮件的实际过程将在后台运行 不会因浏览器关闭而中断 我知道这可以通过 cron
  • 将字符串转换为正确的 URI 格式?

    有没有简单的方法可以将电子邮件地址字符串转换为正确的 URI 格式 Input http mywebsite com validate email 3DE4ED727750215D957F8A1E4B117C38E7250C33 email
  • 如何在特定 systemd 服务重新启动时触发自定义脚本运行

    我想知道如何安排自定义脚本在重新启动服务时运行 我的用例是 每当重新启动 Tomcat 服务时 我都必须运行多个命令 我想知道是否有一种方法可以编写脚本并安排它在重新启动 Tomcat 服务时运行 我已将 tomcat 脚本设置为 syst
  • 如何在 C++ 中将 CString 转换为 double?

    我如何转换CString to a double在 C 中 Unicode 支持也很好 Thanks A CString可以转换为LPCTSTR 这基本上是一个const char const wchar t 在 Unicode 版本中 知
  • 从成员函数指针类型生成函子

    我正在尝试简化 通过make fn 预处理参数的函子的生成 通过wrap 对于 arity 的成员函数n 生成函子基本上可以工作 但到目前为止只能通过显式指定成员函数的参数类型来实现 现在我想从它处理的成员函数类型生成正确的函子 struc
  • 2D morton 码编码/解码 64 位

    如何将给定 x y 的莫顿代码 z 顺序 编码 解码为 32 位无符号整数 生成 64 位莫顿代码 反之亦然 我确实有 xy2d 和 d2xy 但仅适用于 16 位宽的坐标 产生 32 位莫顿数 在网上查了很多 但没有找到 请帮忙 如果您可
  • libxml2 xmlChar * 到 std::wstring

    libxml2似乎将所有字符串存储在 UTF 8 中 如xmlChar xmlChar This is a basic byte in an UTF 8 encoded string It s unsigned allowing to pi
  • 预处理后解析 C++ 源文件

    我正在尝试分析c 使用我定制的解析器的文件 写在c 在开始解析之前 我想摆脱所有 define 我希望源文件在预处理后可以编译 所以最好的方法是运行C Preprocessor在文件上 cpp myfile cpp temp cpp or
  • C++ 错误 - “成员初始值设定项表达式列表被视为复合表达式”

    我收到一个我不熟悉的 C 编译器错误 可能是一个非常愚蠢的错误 但我不能完全指出它 Error test cpp 27 error member initializer expression list treated as compound
  • C++11 动态线程池

    最近 我一直在尝试寻找一个用于线程并发任务的库 理想情况下 是一个在线程上调用函数的简单接口 任何时候都有 n 个线程 有些线程比其他线程完成得更快 并且到达的时间不同 首先我尝试了 Rx 它在 C 中非常棒 我还研究了 Blocks 和
  • 二叉树中的 BFS

    我正在尝试编写二叉树中广度优先搜索的代码 我已将所有数据存储在队列中 但我不知道如何访问所有节点并消耗它们的所有子节点 这是我的 C 代码 void breadthFirstSearch btree bt queue q if bt NUL
  • ASP.NET JQuery AJAX POST 返回数据,但在 401 响应内

    我的应用程序中有一个网页 需要调用我设置的 Web 服务来返回对象列表 这个调用是这样设置的 document ready function var response ajax type POST contentType applicati
  • 0-1背包算法

    以下 0 1 背包问题是否可解 浮动 正值和 浮动 权重 可以是正数或负数 背包的 浮动 容量 gt 0 我平均有 这是一个相对简单的二进制程序 我建议用蛮力进行修剪 如果任何时候你超过了允许的重量 你不需要尝试其他物品的组合 你可以丢弃整
  • 初始化 LPCTSTR /LPCWSTR [重复]

    这个问题在这里已经有答案了 我很难理解并使其正常工作 基本上归结为我无法成功初始化这种类型的变量 它需要有说的内容7 2E25DC9D 0 USB003 有人可以解释 展示这种类型的正确初始化和类似的值吗 我已查看此站点上的所有帮助 将项目
  • 使用 iTextSharp 5.3.3 和 USB 令牌签署 PDF

    我是 iTextSharp 和 StackOverFlow 的新手 我正在尝试使用外部 USB 令牌在 C 中签署 PDF 我尝试使用从互联网上挖掘的以下代码 Org BouncyCastle X509 X509CertificatePar
  • 如何引用解决方案之外的项目?

    我有一个 Visual Studio C 解决方案 其中包含一些项目 其中一个项目需要引用另一个不属于解决方案的项目 一开始我引用了dll
  • Visual Studio 2017 完全支持 C99 吗?

    Visual Studio 的最新版本改进了对 C99 的支持 最新版本VS2017现在支持所有C99吗 如果没有 C99 还缺少哪些功能 No https learn microsoft com en us cpp visual cpp

随机推荐