gpt4 book ai didi

c - dma_mmap_coherent 和 remap_pfn_range 有什么区别?

转载 作者:IT王子 更新时间:2023-10-29 00:35:31 45 4
gpt4 key购买 nike

目前,我正在使用 example driver从中学习,并从中建立了自己的自定义驱动程序。 mmap 代码几乎完全相同,除了我允许用户管理他们自己请求的大小并以此为基础进行内存分配,以及我在/dev 中自动创建字符设备这一事实。

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

我已经尽我所能对这个主题进行了尽可能多的研究。我能找到的关于 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_coherentremap_pfn_range 之间有什么区别?

编辑 提供将内核内存映射到用户空间的方法的一般概述可能会很好,涵盖如何在内核驱动程序 mmap 回调中使用不同的 api。

最佳答案

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- 中的 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 文件操作:

    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 缓冲区。释放缓冲区是获得奖励积分的练习!

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

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

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

这不是 checkpatch.pl 兼容代码,也不是最佳实践,但这是我知道如何执行此操作的一种方法。欢迎提出意见/改进/建议!

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

关于c - dma_mmap_coherent 和 remap_pfn_range 有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34516847/

45 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com