dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序
dma-buf 由浅入深(二) —— kmap / vmap
dma-buf 由浅入深(三) —— map attachment
dma-buf 由浅入深(四) —— mmap
dma-buf 由浅入深(五) —— File
dma-buf 由浅入深(六) —— begin / end cpu_access
dma-buf 由浅入深(七) —— alloc page 版本
dma-buf 由浅入深(八) —— ION 简化版


前言

在上一篇《最简单的 dma-buf 驱动程序》中,我们学习了编写 dma-buf 驱动程序的三个基本步骤,即 dma_buf_opsdma_buf_export_infodma_buf_export()。在本篇中,我们将在 exporter-dummy 驱动的基础上,对其 dma_buf_opskmap / vmap 接口进行扩展,以此来演示这两个接口的使用方法。

dma-buf 只能用于 DMA 硬件访问吗?

在内核代码中,我们见得最多的 dma-buf API 莫过于 dma_buf_attach()dma_buf_map_attachment(),以至于有些小伙伴会问:dma-buf 难道只能给 DMA 硬件来访问吗?当然不是!在上一篇的 概念 小节中就曾讲过,dma-buf 本质上是 buffer 与 file 的结合,因此它仍然是一块 buffer。不要看它带了 dma 字样就被迷惑了,dma-buf 不仅能用于 DMA 硬件访问,也同样适用于 CPU 软件访问,这也是 dma-buf 在内核中大受欢迎的一个重要原因。

正因如此,我才决定将 dma_buf_kmap() / dma_buf_vmap() 作为 dma-buf 系列教程的第二篇文章来讲解,因为这两个接口使用起来实在是比 DMA 操作接口简单太多了!

dma-buf 只能分配离散 buffer 吗?

当然不是!就和内核中 dma-mapping 接口一样,dma-buf 既可以是物理连续的 buffer,也可以是离散的 buffer,这最终取决于 exporter 驱动采用何种方式来分配 buffer。
因此为了尽量让读者易于理解,本篇特意使用了内核中最简单、最常见的 kzalloc() 函数来分配 dma-buf,自然,这块 buffer 就是物理连续的了。

CPU Access

从 linux-3.4 开始,dma-buf 引入了 CPU 操作接口,使得开发人员可以在内核空间里直接使用 CPU 来访问 dma-buf 的物理内存。

  • dma-buf: add support for kernel cpu access

如下 dma-buf API 实现了 CPU 在内核空间对 dma-buf 内存的访问:

  • dma_buf_kmap()
  • dma_buf_kmap_atomic()
  • dma_buf_vmap()

(它们的反向操作分别对应各自的 unmap 接口)

通过 dma_buf_kmap() / dma_buf_vmap() 操作,就可以把实际的物理内存,映射到 kernel 空间,并转化成 CPU 可以连续访问的虚拟地址,方便后续软件直接读写这块物理内存。因此,无论这块 buffer 在物理上是否连续,在经过 kmap / vmap 映射后的虚拟地址一定是连续的。

上述的3个接口分别和 linux 内存管理子系统(MM)中的 kmap()kmap_atomic()vmap() 函数一一对应,三者的区别如下:

函数 说明
kmap() 一次只能映射1个page,可能会睡眠,只能在进程上下文中调用
kmap_atomic() 一次只能映射1个page,不会睡眠,可在中断上下文中调用
vmap() 一次可以映射多个pages,且这些pages物理上可以不连续,只能在进程上下文中调用
  1. 从 linux-4.19 开始,dma_buf_kmap_atomic() 不再被支持。
  2. dma_buf_ops 中的 map / map_atomic 接口名,其实原本就叫 kmap / kmap_atomic,只是后来发现与 highmem.h 中的宏定义重名了,为了避免开发人员在自己的驱动中引用 highmem.h 而带来的命名冲突问题,于是去掉了前面的“k”字。

想了解更多关于 kmap() 、vmap() 的信息,推荐阅读参考资料中的《Linux内核内存管理架构》一文。

示例程序

本示例分为 exporter 和 importer 两个驱动。

首先是 exporter 驱动,我们基于上一篇的 exporter-dummy.c,对其 exporter_kmap()exporter_vmap() 进行扩展,具体如下:

exporter-kmap.c

#include <linux/dma-buf.h>
#include <linux/module.h>
#include <linux/slab.h>struct dma_buf *dmabuf_exported;
EXPORT_SYMBOL(dmabuf_exported);static void *exporter_kmap(struct dma_buf *dmabuf, unsigned long page_num)
{return dmabuf->priv;
}static void *exporter_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
{return dmabuf->priv;
}static void *exporter_vmap(struct dma_buf *dmabuf)
{return dmabuf->priv;
}static void exporter_release(struct dma_buf *dmabuf)
{kfree(dmabuf->priv);
}...static const struct dma_buf_ops exp_dmabuf_ops = {.map = exporter_kmap,.map_atomic = exporter_kmap_atomic,.vmap = exporter_vmap,.release = exporter_release,...
};static struct dma_buf *exporter_alloc_page(void)
{DEFINE_DMA_BUF_EXPORT_INFO(exp_info);struct dma_buf *dmabuf;void *vaddr;vaddr = kzalloc(PAGE_SIZE, GFP_KERNEL);exp_info.ops = &exp_dmabuf_ops;exp_info.size = PAGE_SIZE;exp_info.flags = O_CLOEXEC;exp_info.priv = vaddr;dmabuf = dma_buf_export(&exp_info);sprintf(vaddr, "hello world!");return dmabuf;
}static int __init exporter_init(void)
{dmabuf_exported = exporter_alloc_page();return 0;
}module_init(exporter_init);

然后我们再编写一个 importer 驱动,用于演示如何在 kernel 空间,通过 dma_buf_kmap() / dma_buf_vmap() 接口操作 exporter 驱动导出的 dma-buf。

importer-kmap.c

#include <linux/dma-buf.h>
#include <linux/module.h>
#include <linux/slab.h>extern struct dma_buf *dmabuf_exported;static int importer_test(struct dma_buf *dmabuf)
{void *vaddr;vaddr = dma_buf_kmap(dmabuf, 0);pr_info("read from dmabuf kmap: %s\n", (char *)vaddr);dma_buf_kunmap(dmabuf, 0, vaddr);vaddr = dma_buf_vmap(dmabuf);pr_info("read from dmabuf vmap: %s\n", (char *)vaddr);dma_buf_vunmap(dmabuf, vaddr);return 0;
}static int __init importer_init(void)
{return importer_test(dmabuf_exported);
}module_init(importer_init);

示例描述:

  1. exporter 通过 kzalloc 分配了一个 PAGE 大小的物理连续 buffer,并向该 buffer 写入了“hello world!” 字符串;
  2. importer 驱动通过 extern 关键字导入了 exporter 的 dma-buf,并通过 dma_buf_kmap()dma_buf_vmap() 函数读取该 buffer 的内容并输出到终端显示。

开发环境

内核源码 4.14.143
示例源码 hexiaolong2008-GitHub/sample-code/dma-buf/02
开发平台 Ubuntu14.04/16.04
运行平台 my-qemu 仿真环境

运行

在 my-qemu 仿真环境中执行如下命令:

# insmod /lib/modules/4.14.143/kernel/drivers/dma-buf/exporter-kmap.ko
# insmod /lib/modules/4.14.143/kernel/drivers/dma-buf/importer-kmap.ko

将看到如下打印结果:

read from dmabuf kmap: hello world!
read from dmabuf vmap: hello world!

注意:执行 insmod 命令时,必须先加载 exporter-kmap.ko,后加载 importer-kmap.ko,否则将出现符号依赖错误。
或者直接使用“modprobe importer_kmap”命令来自动解决模块依赖问题。

结语

通过本篇,我们学习了 dma_buf_kmap()dma_buf_vmap() 函数的底层实现,以及如何使用这两个 API,它们是 CPU 在 kernel 空间访问 dma-buf 的典型代表。在下一篇,我们将一起来学习如何通过 DMA 硬件来访问 dma-buf 的物理内存。

参考资料

wahaha02博客:Linux内核内存管理架构
i915 drm selftests: mock_dmabuf.c

上一篇:《dma-buf 由浅入深(一)—— 对简单的 dma-buf 驱动程序》
下一篇:《dma-buf 由浅入深(三)—— map attachment》
文章汇总:《DRM(Direct Rendering Manager)学习简介》

dma-buf 由浅入深(二) —— kmap / vmap相关推荐

  1. v4l2 use V4L2_MEMORY_MMAP方式导出为 DMA BUF fd 方式使用

    V4L2_MEMORY_MMAP 导出 fd 需要使用 vb2_ioctl_expbuf (只能使用于VB2_MEMORY_MMAP 方式). int buffer_export(int v4lfd, ...

  2. STM32 串口DMA收发(二)

    STM32 串口DMA收发数据 一.STM32 DMA简介与功能说明 1.STM32F4 DMA简介 DMA(Direct memory access),即直接存储器访问.用于在外设与存储器之间以及存 ...

  3. linux内存管理:kmap、vmap、ioremap

    目录 散列表也是哈希表 kmap实现 page_address_map pkmap_count page_address_slot 哈希函数 kmap函数实现 kmap_init kmap kmap_ ...

  4. dma-buf 由浅入深(三) —— map attachment

    dma-buf 由浅入深(一) -- 最简单的 dma-buf 驱动程序 dma-buf 由浅入深(二) -- kmap / vmap dma-buf 由浅入深(三) -- map attachmen ...

  5. dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序

    dma-buf 由浅入深(一) -- 最简单的 dma-buf 驱动程序 dma-buf 由浅入深(二) -- kmap / vmap dma-buf 由浅入深(三) -- map attachmen ...

  6. dma-buf 由浅入深(六) —— begin / end cpu_access

    dma-buf 由浅入深(一) -- 最简单的 dma-buf 驱动程序 dma-buf 由浅入深(二) -- kmap / vmap dma-buf 由浅入深(三) -- map attachmen ...

  7. dma-buf 由浅入深(五) —— File

    dma-buf 由浅入深(一) -- 最简单的 dma-buf 驱动程序 dma-buf 由浅入深(二) -- kmap / vmap dma-buf 由浅入深(三) -- map attachmen ...

  8. dma-buf 由浅入深(四) —— mmap

    dma-buf 由浅入深(一) -- 最简单的 dma-buf 驱动程序 dma-buf 由浅入深(二) -- kmap / vmap dma-buf 由浅入深(三) -- map attachmen ...

  9. dma-buf 由浅入深(八) —— ION 简化版

    dma-buf 由浅入深(一) -- 最简单的 dma-buf 驱动程序 dma-buf 由浅入深(二) -- kmap / vmap dma-buf 由浅入深(三) -- map attachmen ...

最新文章

  1. cutterman 导出html,电脑中如何使用cutterman插件
  2. Mahout推荐算法API详解
  3. linux 挂载u盘区别不到,linux系统下为什么不能挂载U盘
  4. 常用的7大排序算法汇总
  5. caffe硬件条件配置选择+LeNet识别MNIST(第四章读书笔记)
  6. 深度学习(十二)——Winograd(2)
  7. APP技巧:手机连接WiFi后,移动数据流量要不要关闭,看完你就懂了!
  8. 养肝粥,用电脑过度人群必备! - 健康程序员,至尚生活!
  9. socks5协议详细说明
  10. 一淘搜索之网页抓取系统分析与实现(4)- 实现总结
  11. 小红书话题笔记是什么意思?小红书话题的形式有哪些?
  12. Linux命令全家桶以及vim/gcc/gdb/makefile/yum
  13. Virut.ce-感染型病毒分析报告
  14. 系统分析师易错题整理
  15. webstorm最新激活方法。绝对有效
  16. 优声云打印机打印模板介绍
  17. UE5引擎 PC端的Landscape渲染浅分析
  18. 记一次医院挂号抢号流程
  19. 南昌航空大学计算机操作系统,南昌航空大学计算机操作系统期末考试题及答案...
  20. cocos creator 划动屏幕以移动摄像机

热门文章

  1. msp430g2553输出PWM波
  2. C语言实现YUV420sp图像剪裁
  3. 神经网络通俗理解和理解,卷积神经网络通俗理解
  4. 补充知识——结构光之解相位求解的相关问题
  5. NCE开放可编程培训交流
  6. 李开复:AI 创业的十个真相 | 深度
  7. 内存缓存(from memory cache)和硬盘缓存(from disk cache) 的区别
  8. 交接箱、配线箱、分纤箱……宽带接入工程中的各种箱体有何区别
  9. 蓝桥杯 — 奖券数目(有些人很迷信数字,比如带“4”的数字)
  10. python技术培训机构排名