DMA过程分析
1.1
当我们在应用程序中编写write系统调用,向磁盘中写入数据时,写入请求会先调用底层写函数,将请求先写入内存中的页快速缓存(page cache)中,写入成功则立马返回,真正的写入磁盘操作会延迟运行。Page cache是硬盘在内存中的一个缓存,是linux内核所使用的主要磁盘快速缓存,在绝大多数情况下,内核在读写磁盘时都引用page cache(极少数应用会绕过页快速缓存,如数据库软件)。
当把page cache中的一页数据写到块设备之前,内核首先检查相应的页是否已经在快速缓存中,假设不在,就要先在当中添加一个新项,并用要写到磁盘中的数据填充该项。I/O数据的传送并非立即開始,而是要延迟几秒后才对磁盘进行更新,从而使进程有机会对要写入磁盘的数据做进一步的改动(也就是内核进行延迟写操作)。
当内核以文件系统、虚拟内存子系统或者系统调用的形式决定从块I/O设备输入、输出块数据时,它将再结合一个bio结构,用来描写叙述这个操作。该结构被传递给 I/O代码,代码会把它合并到一个已经存在的request结构中,或者依据须要,再创建一个新的request结构。bio结构包括了驱动程序运行请求的所有信息,而不必与初始化这个请求的用户空间的进程相关联。
内核中块设备的I/O操作基本容器由bio结构体表示,定义在<linux/bio.h>中,该结构体代表了正在现场的(活动的)以片段(segment)链表形式组织的块I/O操作。一个片段是一小块连续的内存缓冲区。这种优点就是不须要保证单个缓冲区一定要连续。所以通过片段来描写叙述缓冲区,即使一个缓冲区分散在内存的多个位置上,bio结构体也 能对内核保证I/O操作的运行,这种就叫做聚散I/O(scatter/gather).
bio为通用层的主要数据结构,既描写叙述了磁盘的位置,又描写叙述了内存的位置,是上层内核vfs与下层驱动的连接纽带。
struct bio {
sector_t bi_sector;字节)扇区:磁盘的位置
struct bio *bi_next; //请求链表
struct block_device *bi_bdev;//相关的块设备
unsigned long bi_flags//状态和命令标志
unsigned long bi_rw; //读写
unsigned short bi_vcnt;//bio_vesc偏移的个数
unsigned short bi_idx; //bi_io_vec的当前索引
unsigned short bi_phys_segments;//结合后的片段数目
unsigned short bi_hw_segments;//重映射后的片段数目
unsigned int bi_size; //I/O计数
unsigned int bi_hw_front_size;//第一个可合并的段大小;
unsigned int bi_hw_back_size;//最后一个可合并的段大小
unsigned int bi_max_vecs; //bio_vecs数目上限
struct bio_vec *bi_io_vec; //bio_vec链表:内存的位置
bio_end_io_t *bi_end_io;//I/O完毕方法
atomic_t bi_cnt; //使用计数
void *bi_private; //拥有者的私有方法
bio_destructor_t *bi_destructor; //销毁方法
};
文件系统须要写到硬盘的数据保存在page cache里面,那么这个过程又是怎么和dma建立关系的呢?
DMA写磁盘过程概述:
若硬盘支持DMA,而且在操作系统中打开了DMA,则每次读写磁盘,都会涉及到DMA操作。尽管文件系统对硬盘的I/O请求不是连续的,数据所在的物理内存页也是不连续的,可是操作系统会将这些不连续的内存页组合到一起,再启用DMA操作(启用DMA的过程开销较大,须要设置一系列寄存器),那么这些数据就行一次传输完毕,这样也就能高效的数据传输。内核中有个物理设备描写叙述符表(physical region descriptor table,PRDT),要进行数据的传输必需将对应的物理页以及物理页内数据长度填充到PRDT里面。,PRDT结构例如以下:
Figure 1说明:
每一个PRDT大小为8字节,0-3字节说明物理页的内存地址,4-5字节说明内存区域的数量,以字节为单位,全零表示64K大小。最后一个字节的最后一位表示PRDT表的结束。
scsi层的scsi_init_io函数把bio封装,然后将其映射给DMA的scatterlist结构体,该结构体即PRDT中的一项,(内核中dma_desc_array相应PRDT),用来指向每一个内存块。剩余工作就是设置DMA寄存器,然后发送,我们后面将具体分析该部分代码。
下面是write系统调用内核态处理函数的路径:
经过一系列处理,write系统调用处理结束后,若须要写磁盘数据终于会经过下面路径:
scsi_scan_target(scsi扫面函数)——》__scsi_scan_target ——》scsi_sequential_lun_scan ——》scsi_probe_and_add_lun ——>scsi_alloc_sdev ——》scsi_alloc_queue(scsi分配队列),从这里分开,一条路径是设置DMA并发送命令到DMA控制器(路径一),还有一条是初始化函数路径(路径二)。
路径一:scsi_request_fn——>scsi_dispatch_cmd——》scsi_log_send——》(.queuecommand =ata_scsi_queuecmd,)ata_scsi_queuecmd——》__ata_scsi_queuecmd——》ata_scsi_translate——》ata_qc_issue——》ata_bmdma_qc_issue——》(bfin_bmdma_setup:设置DMA寄存器/ bfin_bmdma_start:開始DMA)
路径二:scsi_prep_fn——>scsi_setup_blk_pc_cmnd ——》scsi_init_io ——》scsi_init_sgtable ——》blk_rq_map_sg(该函数的參数request这个结构体封装了bio结构体).
下面主要分析bfin_bmdma_setup和bfin_bmdma_start函数,即DMA操作过程:
(1) 软件准备好一个PRD Table放在内存中,每一个8字节,对齐到4字节边界。
(2) 软件把PRD table的起始地址设置好,同一时候通过设置读/写控制位设置数据和传输方向,清除状态寄存器中的中断位和错误位。
(3) 软件发出DMA传送指令到disk设备。
(4) 向总线控制器IDE命令寄存器的相应通道中写入1,使能总线控制器。
(5) DMA从IDE设备中请求控制器传送数据到/从内存中
(6) 传送结束,IDE设备发出中断
(7) 接收到中断后,软件设置命令寄存器的開始/结束位,然后先后读控制器状态、驱动状态,进而确定是否传送成功。
代码例如以下:
DMA过程分析的更多相关文章
- STM32之ADC实例(基于DMA方式)
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zouleideboke/article/details/75112224 ADC简介: ADC(An ...
- u-boot-2016.09 make编译过程分析(二)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/guyongqiangx/article/ ...
- u-boot-2016.09 make编译过程分析(一)
https://blog.csdn.net/guyongqiangx/article/details/52565493 综述 u-boot自v2014.10版本开始引入KBuild系统,Makefil ...
- STM32基于HAL库通过DMA读写SDIO
通过STM32CUBEMX生成DMA读写sdio的工程,再读写过程中总会卡死在DMA中断等待读写完成的while中,最终发现while等待的标志在SDIO的中断里置位的,而SDIO中断优先级如果小于或 ...
- freeswitch注册过程分析
操作系统:debian8.5_x64freeswitch 版本 : 1.6.8 本文仅描述sip注册的简单场景,即话机直接向处于同一个局域网的fs进行注册. SIP协议的消息结构 消息框架 SIP协议 ...
- GDB调试汇编堆栈过程分析
GDB调试汇编堆栈过程分析 分析过程 这是我的C源文件:click here 使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用gdb ...
- 20145212——GDB调试汇编堆栈过程分析
GDB调试汇编堆栈过程分析 测试代码 #include <stdio.h> short val = 1; int vv = 2; int g(int xxx) { return xxx + ...
- z-stack协议uart分析(DMA)
1.从ZMain里面的main函数开始分析 2.进入int main( void ); HalDriverInit(); //硬件相关初始化,有DMA初始化和UART初始化 3.进入HalDriv ...
- 20145223《信息安全系统设计基础》 GDB调试汇编堆栈过程分析
20145223<信息安全系统设计基础> GDB调试汇编堆栈过程分析 分析的c语言源码 生成汇编代码--命令:gcc -g example.c -o example -m32 进入gdb调 ...
随机推荐
- 关于C(m,n)%p的故事
序 遥远的\(\mod p\)(\(p\)是质数)大陆有一个恶魔:\[C(m,n)={m!\over n! (m-n)!}\] 于是大家有了各种求逆元的方法.这里MOD = p. 壹 for (int ...
- 【Cron Expressions】Quartz Scheduler 2.1.x 英文节选
Cron Expressions Cron-Expressions are used to configure instances ofCronTrigger. Cron-Expressions ar ...
- hdu 4771 Stealing Harry Potter's Precious(bfs)
题目链接:hdu 4771 Stealing Harry Potter's Precious 题目大意:在一个N*M的银行里,贼的位置在'@',如今给出n个宝物的位置.如今贼要将全部的宝物拿到手.问最 ...
- 嵌入式环境:CentOS下添加用户并且让用户获得root权限
CentOS下添加用户并且让用户获得root权限 http://www.centoscn.com/CentOS/config/2014/0810/3471.html 1.添加用户,首先用adduser ...
- com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: SELECT command denied to user 'xxxx'@''
这两天项目一直在报这个错误消息: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: SELECT command denied to ...
- Eclipse用法和技巧十一:分栏显示
在编码的时候,有时候需要同时看到两个文件的代码.或者在代码走读的时候,能同时看到两个文件的代码能加快我们对代码的理解.来看看如何在eclipse中同时显示两个文件的代码. 步骤一:拖住一 ...
- element.style覆盖了我的样式!!
原文:element.style覆盖了我的样式!! 有时候在写css时,显示效果会出现非常诡异的效果 不知道有没有遇到这种 css: #logo{ border: solid 1px blue; } ...
- 减少HTTP请求之合并图片详解(大型网站优化技术)
原文:减少HTTP请求之合并图片详解(大型网站优化技术) 一.相关知识讲解 看过雅虎的前端优化35条建议,都知道优化前端是有多么重要.页面的加载速度直接影响到用户的体验.80%的终端用户响应时间都花在 ...
- 用SignalR做类似QQ登录的应用
原文:用SignalR做类似QQ登录的应用 首先通过NuGet下载signalr包 在工程下新建一个类,继承Hub public class DemoHub:Hub { public class Us ...
- 反射API
反射,是指一种能在运行时动态加载.分析类的能力.反射被广泛地用于那些需要在运行时检测或修改程序行为的程序中.这是一个相对高级的特性,使用反射技术应当具备相当的Java语言基础.我们可以通过反射机制让应 ...