注:关于IOMMU和VFIO得虚拟化部分,在虚拟化章节研究
DMA的作用
DMA即Direct Memory Access,是一种允许 外设和主内存之间直接传输 数据 而没有CPU参与的技术,当外设对于该块内存的读写完成之后,DMAC通过中断通知CPU,然后由CPU完成后处理。
这种技术多用于对数据量和数据传输速度都有很高要求的外设控制,比如显示设备等。
注:DMA 依赖于系统。每一种体系结构DMA传输不同,编程接口也不同。
DMA的两种方式(软件请求和硬件异步传输)
数据传输可以以两种方式触发:一种软件请求数据,另一种由硬件异步传输。
在第一种情况下,调用的步骤可以概括如下(以read为例):
(1)在进程调用 read 时,驱动程序的方法分配一个 DMA 缓冲区,随后指示硬件传送它的数据。进程进入睡眠。
(2)硬件将数据写入 DMA 缓冲区并在完成时产生一个中断。
(3)中断处理程序获得输入数据,应答中断,最后唤醒进程,该进程现在可以读取数据了。
第二种情形是在 DMA 被异步使用时发生的。以数据采集设备为例:
(1)硬件发出中断来通知新的数据已经到达。
(2)中断处理程序分配一个DMA缓冲区。
(3)外围设备将数据写入缓冲区,然后在完成时发出另一个中断。
(4)处理程序利用DMA分发新的数据,唤醒任何相关进程。
网卡传输也是如此,网卡有一个循环缓冲区(通常叫做 DMA 环形缓冲区)建立在与处理器共享的内存中。每一个输入数据包被放置在环形缓冲区中下一个可用缓冲区,并且发出中断。然后驱动程序将网络数据包传给内核的其它部分处理,并在环形缓冲区中放置一个新的 DMA 缓冲区。
DMA的传送过程
DMA的数据传送分为预处理、数据传送和后处理3个阶段。
(1)预处理
由CPU完成一些必要的准备工作。首先,CPU执行几条I/O指令,用以测试I/O设备状态,向DMA控制器的有关寄存器置初值,设置传送方向、启动该设备等。然后,CPU继续执行原来的程序,直到I/O设备准备好发送的数据(输入情况)或接受的数据(输出情况)时,I/O设备向DMA控制器发送DMA请求,再由DMA控制器向CPU发送总线请求(统称为DMA请求),用以传输数据。
(2)数据传送
DMA的数据传输可以以单字节(或字)为基本单位,对于以数据块为单位的传送(如银盘),DMA占用总线后的数据输入和输出操作都是通过循环来实现。需要特别之处的是,这一循环也是由DMA控制器(而不是通过CPU执行程序)实现的,即数据传送阶段是完全由DMA(硬件)来控制的。
(3)后处理
DMA控制器向CPU发送中断请求,CPU执行中断服务程序做DMA结束处理,包括检验送入主存的数据是否正确,测试传送过程中是否出错(错误则转入诊断程序)和决定是否继续使用DMA传送其他数据块等。
DMA与缓存一致性
Cache与DMA本身并不相关。但Cache被CPU当作内存的缓存使用。
假如DMA操作的内存范围与Cache并没有重叠,那DMA与Cache没关系。但DMA的内存与Cache缓存有重叠区域,那么CPU读取Cache的数据可能与内存数据不一致(内存对应数据被DMA修改,但CPU不知道,认为Cache的数据就是内存中的数据)。
总线地址和存储域地址
简单说,就是 在不同得角度存在三种地址空间:
CPU角度: MMIO体系得CPU将所有得外设(MMIO),内存 等设备 看成统一编址得地址空间, 比如32位CPU支持 2^32=4G得存储域地址空间,具体有多大范围看CPU访问得总线位宽。
DDR控制器角度: 内存地址空间 , 只能看到自己内存条得实际物理空间。
总线地址空间: 从总线得角度,看待主机. 简单说,带DMA得设备, 看待主机端内存和外设, 也有一套自己得地址空间寻址。
Dynamic DMA mapping Guide(翻译: DMA-API-HOWTO.txt)中 描述了虚拟地址和总线地址
驱动在调用dma_map_single/dma_alloc_coherent 这样的接口函数的时候会传递一个虚拟地址X,在这个函数中会设定IOMMU的页表,将地址X映射到Z,并且将返回z这个总线地址
CPU CPU Bus
Virtual Physical Address
Address Address Space
Space Space
+-------+ +------+ +------+
| | |MMIO | Offset | |
| | Virtual |Space | applied | |
C +-------+ --------> B +------+ ----------> +------+ A
| | mapping | | by host | |
+-----+ | | | | bridge | | +--------+
| | | | +------+ | | | |
| CPU | | | | RAM | | | | Device |
| | | | | | | | | |
+-----+ +-------+ +------+ +------+ +--------+
| | Virtual |Buffer| Mapping | |
X +-------+ --------> Y +------+ <---------- +------+ Z
| | mapping | RAM | by IOMMU
| | | |
| | | |
+-------+ +------+
举例说明总线空间和存储域空间:
比如:
CPU寻址: 一个项目组, 组长使用员工真实姓名来定位到每一位员工。
总线寻址:某个员工,比如我。 用峰哥,亮哥,老大 等方式来定位到每一位员工和组长。
所以 从CPU角度 和 从总线角度,看待一个模块, 会有不同得地址描述 。