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 驱动程序 的相关文章

  • 进程虚拟地址空间以及三种内存管理方式 分页式/分段式/段页式

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

    OpenCL快速入门教程 OpenCL快速入门教程 原文地址 http opencl codeplex com wikipage title OpenCL 20Tutorials 20 201 翻译日期 2012年6月4日星期一 这是第一篇
  • RT-Thread记录(八、理解 RT-Thread 内存管理)

    RT Thread内核的我们已经基本都学习过了 除了基本的线程操作和通信 内核部分还有内存管理和中断处理 本文主要就来说说内存管理相关问题 目录 前言 一 为什么要内存管理 二 RT Thread 内存堆管理 2 1 RT Thread 内
  • 操作系统内存管理及虚拟内存技术

    一 内存管理 操作系统的内存管理主要负责内存的分配与回收 malloc 函数 申请内存 free 函数 释放内存 另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情 1 常见的内存管理机制 1 1 连续分配管
  • 内存管理分配,连续分配、分页存储、分段存储、段页式

    目录 1 连续分配管理 1 1 固定分区分配 1 2 动态分区分配 2 非连续分配方式 2 1 基本分页式内存分配管理 2 1 1 基本分页式内存思想与方法 2 1 2 进程逻辑地址与内存物理地址如何转换 2 1 3 页面在内存中的起始地址
  • malloc底层原理实现

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

  • 一文读懂 PyTorch 显存管理机制

    点击上方 视学算法 选择加 星标 或 置顶 重磅干货 第一时间送达 作者丨米阿罗 知乎 已授权 来源丨https zhuanlan zhihu com p 486360176 编辑丨极市平台 首发于踢翻炼丹炉 https www zhihu
  • Linux内存管理(7) - page fault

    了解linux page fault 1 概述 A page fault sometimes called PF PF or hard fault a is a type of exception raised by computer ha
  • 大端小端以及内存对齐的优势

    为什么区分大小端 编程语言中不同类型的变量所占的字节大小不一样 大端 低位数据存放在高位地址为大端编码 小端 低位数据存放在低位地址为小端编码 如图所示 对于选择大端小端对程序性能的思考 首先 数据离散程度不同 字节序会在很大程度上影响速度
  • C++栈区、堆区、全局静态区、代码区的介绍

    示例代码 include
  • 2017校招 360 笔试题 编程题 内存管理

    内存管理 时间限制 C C 语言 1000MS 其他语言 3000MS 内存限制 C C 语言 65536KB 其他语言 589824KB 题目描述 物联网技术的蓬勃发展 各种传感器纷纷出现 小B所在的项目组正在开发一个物联网项目 她们在研
  • CE+OD外挂制作实战 [提高篇]

    人造指针 基址 实验目标 通过向游戏注入一段特殊汇编代码 实现自动获取动态地址 省略找基址的麻烦 为什么会出现人造指针 1 基址偏移层数太多 很难找 2 有些游戏根本找不到基址 人造指针有什么优缺点 1 人造指针就算游戏更新也无需去重复找基
  • 直播系统源码平台内容安全与版权维护技术:DRM

    在数字化的时代 人们的生活中已深入到网络中来 许多人加入了直播系统源码平台中来 直播系统源码平台为用户们提供了一个发布图文短视频 开启直播 获取最新资讯的地方 这也衍生出了许多网红 主播等用户 他们会在直播系统源码平台发布高质量 受众多粉丝
  • 【系统】C/C++内存管理之内存分配

    文章目录 0 内存分配方式 从静态存储区域分配 在栈上创建 在堆上分配 程序内存空间 1 C语言内存分配方式 静态与动态内存分配区别 1 1 静态分配方式 1 2 动态分配方式 1 malloc函数 2 calloc 函数 3 reallo
  • 【数据结构】堆、栈的区别

    heap 是堆 stack 是栈 在编程语言中 内存分配方式主要包括 栈 堆 静态存储分配 栈的内存是由操作系统自动分配 释放的 存放函数的参数值 局部变量等 堆的内存是由程序员手动申请和释放的 对应C语言中的malloc函数和C 中的ne
  • 编写程序模拟完成动态分区存储管理方式的内存分配和回收。

    usr bin python coding utf 8 class Table object 空闲分区表 0 开始地址 1 长度 freeTable 占用分区表 0 程序名 1 开始地址 2 长度 useTable def init sel
  • 55黑马QT笔记之关闭子线程

    55黑马QT笔记之关闭子线程 1 这里为什么要单独写多一篇文章来说线程的关闭呢 主要是想让大家提升印象 养成资源回收的好习惯 任何时候都要想起开辟过的内存回收 这里的关闭子线程上一篇也写到了 就是利用关闭窗口时调用槽函数回收掉 2 具体步骤
  • 如何确定 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

随机推荐

  • 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 由浅入深