Linux动态DMA映射
1. 几种地址类型
虚拟地址
Linux内核使用的地址是虚拟地址,数据类型为void *。例如,kmalloc()和vmalloc()函数返回值就是虚拟地址。
物理地址
处理器真实地址总线上的地址,数据类型为phys_addr_t。
对I/O设备寄存器和内存统一编址的处理器,如ARM/PowerPC,参考手册一般会给出memory map,也就是各种I/O设备的寄存器在物理地址空间的分布。对I/O设备寄存器独立编址的处理器。如X86,访问I/O设备寄存器或内存时,向地址总线发送地址,并通过控制信号来实现对I/O设备寄存器和内存的不同寻址。这些I/O设备寄存器的地址可以在/proc/iomem中查看,必须使用ioremap()映射到虚拟地址空间才可以使用。
总线地址
从I/O设备的角度看,I/O设备使用的地址是总线地址。DMA使用地址也是总线地址,数据类型为dma_addr_t。对一些简单的系统,设备通过DMA可以直接访问物理地址,但大多数系统都有IOMMU将总线地址转换为物理地址。
2. DMA寻址能力
默认情况下Linux认为设备DMA可以进行32位寻址。必须对DMA mask进行设置,将设备的DMA寻址能力通知内核。
int dma_set_mask_and_coherent(struct device *dev, u64 mask)
该函数也可以分为如下两个函数,如果有需要,可以分别对流式映射设置DMA mask,对一致性分配设置DMA mask。
int dma_set_mask(struct device *dev, u64 mask);
int dma_set_coherent_mask(struct device *dev, u64 mask);
3. DMA映射的类型
3.1 一致性DMA映射
一致性DMA映射通常在驱动初始化阶段分配buffer,并且保持cache的一致性。分配和释放一致性DMA buffer通常使用下面方法。
dma_addr_t dma_handle;
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp); dma_free_coherent(dev, size, cpu_addr, dma_handle)
当分配的buffer较小,小于一个页的时候,通常使用dma_pool的APIs。
struct dma_pool *pool;
pool = dma_pool_create(name, dev, size, align, boundary);
cpu_addr = dma_pool_alloc(pool, flags, &dma_handle); dma_pool_free(pool, cpu_addr, dma_handle);
dma_pool_destroy(pool)
3.2 流式DMA映射
流式DMA映射必须声明DMA数据流的方向。
- DMA_BIDIRECTIONAL
- DMA_TO_DEVICE
- DMA_FROM_DEVICE
- DMA_NONE
对单个内存区域的映射和取消映射使用如下方法。
struct device *dev = &my_dev->dev;
dma_addr_t dma_handle;
void *addr = buffer->ptr;
size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); dma_unmap_single(dev, dma_handle, size, direction);
该方法直接使用虚拟地址addr的缺点就是不能对HIGHMEM内存进行映射。下面的函数提供对page映射和取消映射的方法。
struct device *dev = &my_dev->dev;
dma_addr_t dma_handle;
struct page *page = buffer->page;
unsigned long offset = buffer->offset;
size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); dma_unmap_page(dev, dma_handle, size, direction);
对散列表的映射和取消映射如下,nents是sglist中entry的数目。通过散列表,将多个不连续的内存区域进行映射。返回的count的数值可能比nents小,因为有些scatterlist在内存区域连续可能进行了合并。
int i, count = dma_map_sg(dev, sglist, nents, direction);
struct scatterlist *sg; for_each_sg(sglist, sg, count, i) {
hw_address[i] = sg_dma_address(sg);
hw_len[i] = sg_dma_len(sg);
} dma_unmap_sg(dev, sglist, nents, direction)
在流式DMA映射取消映射之前,CPU不应该访问DMA buffer,如果需要访问,则必须在DMA传输后相应地调用如下函数。
dma_sync_single_for_cpu(dev, dma_handle, size, direction); dma_sync_sg_for_cpu(dev, sglist, nents, direction);
CPU访问结束后,将buffer还给设备DMA使用时,需要相应调用如下函数。
dma_sync_single_for_device(dev, dma_handle, size, direction); dma_sync_sg_for_device(dev, sglist, nents, direction);
参考
https://elixir.bootlin.com/linux/v5.4/source/Documentation/DMA-API-HOWTO.txt
Linux动态DMA映射的更多相关文章
- linux kernel内存映射实例分析
作者:JHJ(jianghuijun211@gmail.com)日期:2012/08/24 欢迎转载,请注明出处 引子 现在android智能手机市场异常火热,硬件升级非常迅猛,arm cortex ...
- 使用 firewalld 构建 Linux 动态防火墙
firewalld 是新一 Linux 代防火墙工具,它提供了支持网络 / 防火墙区域 (zone) 定义网络链接以及接口安全等级的动态防火墙管理工具.它也支持允许服务或者应用程序直接添加防火墙规则的 ...
- linux动态库默认搜索路径设置的三种方法
众所周知, Linux 动态库的默认搜索路径是 /lib 和 /usr/lib .动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库, 并且该动态库还未加载到内存中,则系统会自动到这两 ...
- 再探Linux动态链接 -- 关于动态库的基础知识
在近一段时间里,由于多次参与相关专业软件Linux运行环境建设,深感有必要将这些知识理一理,供往后参考. 编译时和运行时 纵观程序编译整个过程,细分可分为编译(Compiling,指的是语言到平台 ...
- 技巧:Linux 动态库与静态库制作及使用详解
技巧:Linux 动态库与静态库制作及使用详解 标准库的三种连接方式及静态库制作与使用方法 Linux 应用开发通常要考虑三个问题,即:1)在 Linux 应用程序开发过程中遇到过标准库链接在不同 L ...
- linux动态库加载RPATH, RUNPATH
摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...
- Linux 动态库剖析
进程与 API 动态链接的共享库是 GNU/Linux® 的一个重要方面.该种库允许可执行文件在运行时动态访问外部函数,从而(通过在需要时才会引入函数的方式)减少它们对内存的总体占用.本文研究了创建和 ...
- linux动态库编译和使用
linux动态库编译和使用详细剖析 引言 重点讲述linux上使用gcc编译动态库的一些操作.并且对其深入的案例分析.最后介绍一下动态库插件技术, 让代码向后兼容.关于linux上使用gcc基础编译, ...
- Android NDK开发及调用标准linux动态库.so文件
源:Android NDK开发及调用标准linux动态库.so文件 预备知识及环境搭建 1.NDK(native development Kit)原生开发工具包,用来快速开发C.C++动态库,并能自动 ...
随机推荐
- JDBC详细说明+使用
JDBC详解 一.相关概念 1.什么是JDBC JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提 ...
- Integer梳理
Integer常量池 问题1 public class Main_1 { public static void main(String[] args) { Integer a = 1; Integer ...
- 一个基于RabbitMQ的可复用的事务消息方案
前提 分布式事务是微服务实践中一个比较棘手的问题,在笔者所实施的微服务实践方案中,都采用了折中或者规避强一致性的方案.参考Ebay多年前提出的本地消息表方案,基于RabbitMQ和MySQL(JDBC ...
- JDK源码之StringBuffer与StringBuilder类分析
一 概述 StringBuffer类被 final 所修饰,不能被继承,StringBuffer继承了AbstractStringBuilder类, 是一个可变的字符序列,并且类中方法都有synchr ...
- swagger基本使用指南
Maven依赖 <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-s ...
- python学习记录(八)
0910--https://www.cnblogs.com/fnng/archive/2013/04/28/3048356.html Python异常 Python用异常对象(exception ob ...
- <七>对于之前的一些遗漏的地方的补充
1.线程的状态: 我们可以通过wait,start,notify等关键字来切换线程的状态,但是我们如何知道线程目前是处于哪一种状态呢?使用Thread.getState()来获取,有下面几种常见的状态 ...
- sqlserver check running process 1
check process script 1, check which is current running: use master SELECTspid,ER.percent_complete,CA ...
- Spring事务中的隔离级别
TransactionDefinition接口中定义了五个表示隔离级别的常量: TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离界别,MySQL ...
- CVE-2019-0232:Apache Tomcat RCE复现
CVE-2019-0232:Apache Tomcat RCE复现 0X00漏洞简介 该漏洞是由于Tomcat CGI将命令行参数传递给Windows程序的方式存在错误,使得CGIServlet被命令 ...