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

2023-10-27

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 简化版


前言

最近因为工作内容发生了变化,导致《最简单的DRM驱动程序》系列文章暂停了更新,但我仍然会坚持把它写完。由于在后面讲解 DRM 驱动程序的过程中,会不可避免的介绍到 dma-buf,因此这里将该模块单独提取出来,形成一个系列文章,为后续讲解 DRM PRIME 打下基础。

如果你和我一样,是一位从事Android多媒体底层开发的工程师,那么你对 dma-buf 这个词语一定不会陌生,因为不管是 Video、Camera 还是 Display、GPU,它们的buffer都来自于ION,而 ION 正是基于 dma-buf 实现的。

假如你对 dma-buf 的理解并不深刻,又期望找个时间来彻底公关一下,那么很高兴,这几篇文章一定能让你对 dma-buf 有个更深入、更透彻的理解。

历史

dma-buf 最初的原型为 shrbuf,由 Marek Szyprowski (Samsung)于2011年8月2日首次提出,他实现了 “Buffer Sharing” 的概念验证(Proof-of-Concept),并在三星平台的 V4L2 驱动中实现了 camera 与 display 的 buffer 共享问题。该 patch 发表后,在内核社区引起了巨大反响,因为当时关于 buffer 共享问题很早就开始讨论了,但是由于内核没有现成的框架支持,导致各个厂商实现的驱动五花八门,此时急需要一个统一的框架来解决 buffer 共享问题。

于是 Sumit Semwal (Linaro) 基于 Marek Szyprowski 的 patch 重构了一套新的框架,也就是我们今天看到的 dma-buf 核心代码,它经历了社区开发人员给出的重重考验,并最终于 2012 年 2 月 merge 到了 Linux-3.3 主线版本中,这也是 dma-buf 的第一个正式版本。此后 dma-buf 被广泛应用于内核多媒体驱动开发中,尤其在 V4L2、DRM 子系统中得到了充分应用。

概念

dma-buf 的出现就是为了解决各个驱动之间 buffer 共享的问题,因此它本质上是 buffer 与 file 的结合,即 dma-buf 既是块物理 buffer,又是个 linux file。buffer 是内容,file 是媒介,只有通过 file 这个媒介才能实现同一 buffer 在不同驱动之间的流转。

一个典型的 dma-buf 应用框图如下:
在这里插入图片描述

通常,我们将分配 buffer 的模块称为 exporter,将使用该 buffer 的模块称为 importeruser。但在本系列文章中,importer 特指内核空间的使用者,user 特指用户空间的使用者。

有的人习惯将 exporter 说成是生产者,importer 说成是消费者,我个人认为这样的说法并不严谨。举例来说,Android 系统中,graphic buffer 都是由 ION 来分配的,GPU 负责填充该 buffer,DPU 负责显示该 buffer。那么在这里,ION 则是 exporter,GPU 和 DPU 则都是 importer。但是从生产者/消费者模型来讲,GPU 则是生产者,DPU 是消费者,因此不能片面的认为 exporter 就是生产者。

最简单的 dma-buf 驱动程序

如下代码演示了如何编写一个最简单的 dma-buf 驱动程序,我将其称为 dummy 驱动,因为它什么事情也不做。注意:该代码已经是精简的不能再精简了,少一行代码都不行!

exporter-dummy.c

#include <linux/dma-buf.h>
#include <linux/module.h>

static struct sg_table *exporter_map_dma_buf(struct dma_buf_attachment *attachment,
					 enum dma_data_direction dir)
{
	return NULL;
}

static void exporter_unmap_dma_buf(struct dma_buf_attachment *attachment,
			       struct sg_table *table,
			       enum dma_data_direction dir)
{
}

static void exporter_release(struct dma_buf *dmabuf)
{
}

static void *exporter_kmap_atomic(struct dma_buf *dmabuf, unsigned long page_num)
{
	return NULL;
}

static void *exporter_kmap(struct dma_buf *dmabuf, unsigned long page_num)
{
	return NULL;
}

static int exporter_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
	return -ENODEV;
}

static const struct dma_buf_ops exp_dmabuf_ops = {
	.map_dma_buf = exporter_map_dma_buf,
	.unmap_dma_buf = exporter_unmap_dma_buf,
	.release = exporter_release,
	.map_atomic = exporter_kmap_atomic,
	.map = exporter_kmap,
	.mmap = exporter_mmap,
};

static int __init exporter_init(void)
{
	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
	struct dma_buf *dmabuf;

	exp_info.ops = &exp_dmabuf_ops;
	exp_info.size = PAGE_SIZE;
	exp_info.flags = O_CLOEXEC;
	exp_info.priv = "null";

	dmabuf = dma_buf_export(&exp_info);

	return 0;
}

module_init(exporter_init);

从上面的代码来看,要实现一个 dma-buf exporter驱动,需要执行3个步骤:

  1. dma_buf_ops
  2. DEFINE_DMA_BUF_EXPORT_INFO
  3. dma_buf_export()

注意: 其中 dma_buf_ops 的回调接口中,如下接口又是必须要实现的,缺少任何一个都将导致 dma_buf_export() 函数调用失败!

  • map_dma_buf
  • unmap_dma_buf
  • map
  • map_atomic
  • mmap
  • release

从 linux-4.19 开始,map_atomic 接口被废弃,map 和 mmap 接口不再被强制要求。

开发环境

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

编译

dma-buf 的核心代码由 CONFIG_DMA_SHARED_BUFFER 宏来控制是否参与编译,而该 config 并不是一个显式的菜单项,我们无法直接在 menuconfig 菜单中找到它,因此我这里就直接简单粗暴的修改 Kconfig 文件,设置 default y 来实现 dma-buf.c 的强制编译:

linux-4.14.43/drivers/base/Kconfig:

config DMA_SHARED_BUFFER
	bool
	default y

或者你也可以通过 menuconfig 菜单选择那些依赖 dma-buf 的设备驱动,如 DRM VGEM。

然后编译 exporter_dummy.ko 文件,并打包到 my-qemu 环境中。

运行

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

# insmod /lib/modules/4.14.143/kernel/drivers/dma-buf/exporter-dummy.ko
# lsmod
exporter_dummy 16384 1 - Live 0x7f000000

通过如下命令来查看 dma-buf 的相关信息:

# cat /sys/kernel/debug/dma_buf/bufinfo
Dma-buf Objects:
size		flags		mode		count		exp_name
00004096	00000000	00000005	00000001	exporter_dummy
		Attached Devices:
Total 0 devices attached

Total 1 objects, 4096 bytes

运行截图:
my-qemu运行截图
在实际运行的过程中,细心的小伙伴可能会发现,该 exporter_dummy.ko 只能被 insmod,无法被 rmmod。关于该问题的原因,我将在《dma-buf 由浅入深(五)—— File》中为大家解答。

总结

  1. dma-buf 本质上是 buffer + file 的结合。
  2. 编写 dma-buf 驱动的三个步骤:
    (1)dma_buf_ops
    (2)DEFINE_DMA_BUF_EXPORT_INFO
    (3)dma_buf_export()

通过本篇我们学习了如何编写一个最简单的 dma-buf 驱动程序。但是该驱动什么事情也做不了,因为它的 dma_buf_ops 回调函数都是空的。从下一篇起,我们将一步步实现 dma_buf_ops 的回调函数,让大家一步步的掌握 dma-buf 的使用技巧。

参考资料

敬叶:Linux DMA-BUF




下一篇:《dma-buf 由浅入深(二)—— kmap / vmap》
文章汇总:《DRM(Direct Rendering Manager)学习简介》

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

dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序 的相关文章

  • LWN 翻译:Atomic Mode Setting 设计简介(下)

    译者注 紧接上篇文章 本篇翻译起来有难度 同时对读者的技术背景有一定要求 适合深入研究 DRM 驱动的开发人员阅读 通过阅读本文 你将了解如下内容 DRM MODE ATOMIC ALLOW MODESET 标志位的由来及其作用 驱动中随处
  • 进程虚拟地址空间以及三种内存管理方式 分页式/分段式/段页式

    平时我们都知道地址 是内存单元的编号 指针则是存储变量地址的变量 那么程序是否会有地址呢 程序是不占用内存的 存储在磁盘中 只有当运行时才会将数据载入内存中 进程的狭义概念是一个正在运行中的程序 进程详解看上一篇博客 因此进程是有地址空间的
  • 操作系统-内存管理习题

    题干 在页式存储管理中 假设作业的地址为16位 页长为4KB 作业的第0 1 2逻辑页分别放在内存的第5 10 11物理块中 试计算作业中逻辑地址2F6AH 0E3CH 526CH 十六进制数 相对应的内存物理地址 说明转换过程 写出转换结
  • DRM(Direct Rendering Manager)学习简介

    DRM DRM是Linux目前主流的图形显示框架 相比FB架构 DRM更能适应当前日益更新的显示硬件 比如FB原生不支持多层合成 不支持VSYNC 不支持DMA BUF 不支持异步更新 不支持fence机制等等 而这些功能DRM原生都支持
  • c++ 内存管理一:初识内存分配工具

    文章目录 前言 1 new 和 delete 2 new 和delete 3 operator new 4 placement new 5 malloc和free 6 allocator 前言 侯捷 c 内存管理学习总结笔记 在C 中 有几
  • 了解实现一个高并发的内存池——TLS Memmory Pool

    为什么需要内存池 1 效率问题 如果我们直接向系统申请内存 当我们需要频繁的申请释放内存时 就需要频繁的与系统层产生交互 多次切换用户态和内核态 而用户态和内核态之间的切换的消耗是非常大的 因此申请内存的消耗就会很大 程序效率也就随之降低了
  • C++11 谈谈shared_ptr

    C 11 谈谈shared ptr 细节 个人用 十分主观 仅供参考 shared ptr是C 11中加入的一种智能指针 其实并不够智能 其作用就是帮助我们管理在堆中开辟的空间 避免野指针等众多内存管理不当造成的问题 重点 智能指针会自动的
  • malloc底层原理实现

    使用过c语言的都知道malloc是一个动态分配内存的函数 还可以通过free释放内存空间 如果我们想分析一下malloc的源码 这其实不是一会就能看懂的 但是我们可以讨论一下malloc的简单实现 在这之前 我们先来看一下虚拟内存空间 虚拟
  • Rockchip

    1 Graphics介绍 1 1 使用X11 Graphics Xserver 是在常规桌面 Linux 平台上使用的显示系统 Rockchip 有一个定制的 Xserver 可以实现 glamor 2D acceleration Xser
  • [指针八]有关指针的面试题

    有关指针的经典面试题 C语言为何如此长寿并实用 C 为什么有那么多精彩 指针可以说是C C 中的灵魂所在 虽然早期中pascal也有指针 但是和C C 比起来不是一个级别的 今天为大家深入浅出的解析一下指针的有关笔试 面试题 所有题目来源网
  • Qt内存管理(三) Qt的智能指针

    智能指针则可以在退出作用域时 不管是正常流程离开或是因异常离开 总调用delete来析构在堆上动态分配的对象 Qt常用的智能指针有QPointer QScopedPointer QSharedPointer 关于这几个智能指针 网上的博客基
  • 为什么栈的数组长度必须是一个常量?而堆的数组长度可以是变量。为什么栈的大小有限制?

    为什么栈的数组长度必须是一个常量 而堆的数组长度可以是变量 栈区数组长度使用变量会报错 其原因就在于栈是编译器管理的 在程序运行前就已经分配好了空间的大小 而使用变量 编译器无法知道该分配多大的内存空间 于是报错 但堆上的内存是动态创建的
  • MIPI DSI的linux kernel驱动原理

    为了点亮一块MIPI屏幕 我们除了要了解MIPI DSI的工作原理之外 大前提是要了解整个MIPI DSI图显系统的组成 更需要清楚点亮一块MIPI屏幕需要做哪些事情 本文会捋顺各个环节所实现的功能以及基于RK3399来分析各个环节实现的原
  • 55黑马QT笔记之关闭子线程

    55黑马QT笔记之关闭子线程 1 这里为什么要单独写多一篇文章来说线程的关闭呢 主要是想让大家提升印象 养成资源回收的好习惯 任何时候都要想起开辟过的内存回收 这里的关闭子线程上一篇也写到了 就是利用关闭窗口时调用槽函数回收掉 2 具体步骤
  • 与加密流相比,DRM 的附加值是多少?

    这个问题是关于使用 MPEG DASH 和 或 HLS 的视频流 我试图了解商业 DRM 系统 例如 EZDRM BuyDRM 等 与简单的加密流媒体 例如 DRM 相比的附加值 AES 128 加密的 HLS 我对商业口号有点迷失了 因此
  • Silverlight - 保护网络内的内容(DRM?)

    我想使用Windows 2003 的流媒体服务器和Silverlight 设置一些WMV 视频流 现在 不幸的是 Silverlight 仅支持 HTTP 这意味着人们只能下载视频 虽然这本身不是问题 但我想知道有哪些选项可以阻止它们在网络
  • 如何确定 Android 应用程序是否使用可信执行环境 (TEE) 和安全元件 (SE)?

    我已经解决了问题One https stackoverflow com questions 61225795 how to check whether android phone supports tee 64422042 64422042
  • 有没有办法在 HTML5 视频上使用 DRM?

    由于 Flash 正在节节败退 我想知道是否有办法通过 DRM H264 ogg 和 WebM 保护 html5 视频 On the HTML5 上的 W3C 常见问题解答 http www w3 org html wiki FAQs Is
  • 如何在 Cast Receiver Player 中续订过期的 DRM 许可证?

    我基于以下内容开发自定义 Cast Receiver 应用程序Google Cast 应用程序框架 https developers google com cast docs caf receiver 接收器应用程序负责播放 Widevin
  • 检测 Widevine DRM HDCP 保护级别

    我目前正在切换到使用 Dash Widevine DRM 的 ExoPlayer 通过测试 我发现很大比例的设备没有启用 HDCP 保护 由于合同协议 这是一个问题 我必须在允许播放之前检测到并记录它 I took inspiration

随机推荐

  • Linux MMC驱动架构浅析

    Linux MMC驱动架构浅析 MMC驱动模型 Linux内核设计了MMC子系统 用于管理MMC SD等设备 MMC SD存储设备是一种典型的块设备 MMC子系统的框架结构如下图所示 块设备 MMC BLOCK 块设备的相关驱动 即实现块设
  • Prometheus + Grafana 监控SpringBoot项目

    文章目录 Dubbo Prometheus Grafana 监控SpringBoot项目 方式1 侵入式 通过修改spring boot代码实现 准备镜像 Prometheus 搭建 Grafana 搭建 Spring Boot程序 配置g
  • java_时间戳与Date_相互转化

    1 时间戳的定义 时间戳是指文件属性里的创建 修改 访问时间 数字时间戳技术是数字签名技术一种变种的应用 在电子商务交易文件中 时间是十分重要的信息 在书面合同中 文件签署的日期和签名一样均是十分重要的防止文件被伪造和篡改的关键性内容 数字
  • python:tkinterweb 简单又好用的 htmlview 组件

    tkinterweb 是简单又好用的 webview 组件 也可用来显示本地 html文件 pip install tkinterweb pip install readmdict 参见 使用Python调用mdx字典文件进行查词 安装 M
  • 苹果电脑能装鸿蒙,纯小白必看!鸿蒙编译及烧录环境分开部署For Mac

    前提说明 一 办公环境使用的 mac 电脑 家里用的黑苹果 没有windows环境 二 CentOS7 及 windows 10 均使用 vmware 部署安装 三 编译环境 推荐使用 CentOS7 具体可参照 在CentOS中安装鸿蒙L
  • github下载项目下到一半出现需要登陆此站点objects.githubusercontent.com

    猜你感兴趣 搭建自己的私有git服务器 gitlab 部署 汉化 项目备份 迁移 问题描述 当使用迅雷下载FontForge时 该exe被托管在GitHub上 一直不成功 提示如图所示 解决方案 1 使用检查查看元素链接 2 复制下载链接
  • ESP8266-NodeMCU物联网原理介绍以及说明(新手入门)

    做一期ESP8266 NodeMCU物联网模块的介绍 详解该模块的电路和原理以及引脚的使用说明 后面会逐步上案例的 如有问题 请联系 及时更正 ESP8266 NodeMCU 开发板 物联网模块 有ESP8266网络模块 配置有一般开发板的
  • 常用性能指标、性能指标评估及性能测试通过标准

    一 常用性能指标 1 并发用户数 指同一时间点对系统进行操作的用户数 准确说为 同时向服务器发送服务请求 给服务器产生压力的用户数量 并发用户数和注册用户数 在线用户数的概念不同 注册用户数一般指的是数据库中存在的用户数 在线用户数只是 挂
  • 【C++入门】使用using重新定义继承的成员访问权限

    1 C 的权限管控和继承机制 参考博客 C 入门 访问权限管控和继承机制详解 2 using重新定义成员继承时权限的场景 1 父类的public成员在private protected继承后 在派生类中就成了private protecte
  • mmdet代码复现:安装指定版本的mmcv和mmdet以及版本匹配问题。

    解决环境安装过程中出现的问题 避免踩坑 前言 如果是复现别人论文里的代码 那么要注意mmdet和mmcv版本匹配的问题 从论文中把代码下载下来之后首先要看一下项目文件中的mmdet init py和mmdet version py这两个文件
  • TCP协议疑难杂症全景解析

    原文地址 http blog csdn net dog250 article details 6612496 说明 1 本文以TCP的发展历程解析容易引起混淆 误会的方方面面 2 本文不会贴大量的源码 大多数是以文字形式描述 我相信文字看起
  • 利用Vulnhub复现漏洞 - Gitlab 任意文件读取漏洞(CVE-2016-9086)

    Gitlab 任意文件读取漏洞 CVE 2016 9086 Vulnhub官方复现教程 漏洞原理 复现漏洞 启动环境 漏洞复现 Vulnhub官方复现教程 https vulhub org environments gitlab CVE 2
  • STM32循迹避障小车制作代码详解(简单实现版)

    感谢几年来大家的支持 看到大家对工程的呼声很高 所以来把工程上传了 大家自行下载即可哈 谢谢大家支持 这个代码是进阶版的 就是可以跑的很快的 和上面博客的主要区别就是这个代码的避障机制并不是做在主main函数里的 是通过外部流程来传参给CP
  • 【计算机网络】应用层体系

    我们知道现代常用的计算机网络模型为5层模型 其中应用层是直接与我们平时常见的软件对接的最高层 所以先来学习应用层就显得很有必要了 其中在应用层我们需要学习网络应用程序的实现 原理并且了解网络应用程序所需要的网络服务 客户和服务器 进程和运输
  • 非法指令(核心已转储)

    情况 conda环境输入pip 或调用python输入import都报这个错误 Jetson tx2安装archiconda并创建环境 一开始用着很正常 但是在将CPU版本的torch改成GPU版的过程中出现了这个错误 一开始不知道什么原因
  • 大文件如何做断点续传

    一 断点续传 断点续传指的是在下载或上传时 将下载或上传任务人为的划分为几个部分 每一个部分采用一个线程进行上传或下载 如果碰到网络故障 可以从已经上传或下载的部分开始继续上传下载未完成的部分 而没有必要从头开始上传下载 用户可以节省时间
  • C语言字符串的替换

    C语言字符串的替换 我的思路 遍历字符串 判断是否与修改的字符一至 include
  • vue3 报错解决:无法找到模块“xxx.vue”的声明文件 xxx隐式拥有 “any“ 类型

    报错原因 typescript 只能理解 ts 文件 无法理解 vue文件 解决方法 在项目根目录或 src 文件夹下创建一个后缀为 XXX d ts 的文件 并写入以下内容 declare module vue import Compon
  • pdsh 2.29 安装

    下载 wget https storage googleapis com google code archive downloads v2 code google com pdsh pdsh 2 29 tar bz2 解包 tar jxvf
  • dma-buf 由浅入深(一) —— 最简单的 dma-buf 驱动程序

    dma buf 由浅入深 一 最简单的 dma buf 驱动程序 dma buf 由浅入深 二 kmap vmap dma buf 由浅入深 三 map attachment dma buf 由浅入深 四 mmap dma buf 由浅入深