Download presentation
Presentation is loading. Please wait.
1
DMA
2
DMA DMA即Direct Memory access 无需计算机的CPU的干预就可以在内存和外设之间传输数据
通常都有DMA控制器来进行DMA操作,DMA控制器可能是主板上的,也有可能是外设特有的。 为什么需要 DMA?
3
传输模型 Windows 中的DMA传输基于这个模型
4
适配器对象(adapter) Windows 2000内核使用一个称为适配器对象的数据结构来描述设备上的DMA特征,并用它来控制访问潜在的共享资源,如系统DMA通道和映射寄存器 通常在StartDevice函数中调用IoGetDmaAdapter获得适配器对象 适配器对象中有一个指针,指向一个DmaOperations的结构,该结构包含了所有需要的DMA相关的其它函数,这些函数如下表
5
DmaOperations Function Pointer
Description PutDmaAdapter Destroys adapter object AllocateCommonBuffer Allocates a common buffer FreeCommonBuffer Releases a common buffer AllocateAdapterChannel Reserves adapter and map registers FlushAdapterBuffers Flushes intermediate data buffers after transfer FreeAdapterChannel Releases adapter object and map registers FreeMapRegisters Releases map registers only MapTransfer Programs one stage of a transfer GetDmaAlignment Gets address alignment required for adapter ReadDmaCounter Determines residual count GetScatterGatherList Reserves adapter and constructs scatter/gather list PutScatterGatherList Releases scatter/gather list
6
传输策略选择 1。如果设备有总线主控能力,那么它就有访问主存的必要硬件部件,因此只需要告诉它几个基本事实,如从哪开始,需要传输多少单位的数据,是输入操作还是输出操作,等等。可以向硬件设计者咨询或者固件程序员咨询以得到细节部分,否则只能参考许多硬件级的说明文档。
7
传输策略选择 2。一个有分散/聚集(scatter/gather)能力的设备可以在自身与不连续的物理内存区之间传输大块数据。设备的分散/聚集能力对软件十分有利,它可以避免对具有连续页帧的大块的内存的需求。页可以被简单地锁定在所在的物理内存,只要把内存地址告诉设备就可以进行。
8
传输策略选择 3。如果设备不是总线主控设备,那么需要使用计算机主板上的系统DMA控制器。这种形式的DMA传输被称为从属DMA(slave DMA)。与ISA总线连接的系统DMA控制器对所能访问的物理内存和一次传输的数据量会有些限制。EISA总线的DMA控制器去掉了这些限制。在Windows 2000中,不必知道硬件具体插入到哪种类型的总线,因为系统自动参考这些不同的限定。
9
传输策略选择 4。通常,DMA操作将包括编程硬件映射寄存器或操作前后的数据复制。如果设备需要连续地读写数据,我们不希望在每次I/O请求中都做这两步,这将大大地降低处理速度,在某些情况下也是不能接受的。因此,应该分配一个公用缓冲区(common buffer),设备和驱动程序可以在任何时间同时访问这个缓冲区。
10
说明 在涉及DMA传输的过程中策略的选择是第一步也是最重要的一步。 不仅需要参考硬件,还要参考可能的软件需求(主控,从属,包,通用缓冲区)
尽管这四种因素的相互影响会产生许多种不同的结果,但执行的步骤中有许多共同的特征。如下图显示了一次传输过程:
12
执行DMA传输 基于包(packet-based)的DMA传输。在这种方式中,将使用IRP携带的数据缓冲区来传输一定量的数据。
为了简单,让我们假设面对当前最普通的情况:一个基于PCI的总线主控设备并且没有分散/聚集能力。 为什么简单? 下面按照程序编写的通常步骤来详细说明DMA的过程
13
缓冲方式 当创建设备对象时,通常指定使用Direct缓冲方式,即设置DO_DIRECT_IO标志。或者在定义CTL_CODE时指定direct input或者direct output方式。 因为调用的MapTransfer函数需要一个MDL作为参数 ,这种方式会在每一个IRP的MdlAddress保存描述用户缓冲区的MDL
14
创建和销毁适配器对象 在处理start device的pnp请求时,我们除了要取得IO,内存,中断资源外,还要创建一个适配器对象(adapter obiect)。 在处理stop device请求时,除了释放映射的IO,内存资源,断开中断的连接外,还要销毁适配器对象。 例如:DMA.doc
15
和其它资源区别 前面讲过的IO,内存,和中断资源,我们都回在一个CmResourceTypeXxx类型的case子句中获得,这里不需要CmResourceTypeDma类型的case子句,因为设备是总线主控方式,硬件本身包含有执行DMA传输所必须的所有电路逻辑,所以系统没必要赋予设备DMA资源。
16
获取DMA通道 为了初始化一个I/O操作,StartIo例程必须首先调用适配器对象的AllocateAdapterChannel例程以获取适配器对象。该函数的一个参数是AdapterControl例程的地址,I/O管理器将在获取操作完成后调用这个例程。 AllocateAdapterChannel函数的准备和调用过程:DMA.doc
17
AllocateAdapterChannel何时完成
等待DMA控制器,和映射寄存器可用 主控,从属,支持映射寄否? 当DMA控制器,和映射寄存器都可用时, AllocateAdapterChannel调用AdapterControl例程
18
调用AdapterControl AllocateAdapterChannel最终将调用驱动程序提供的AdapterControl例程(在DISPATCH_LEVEL,就象StartIo例程一样)。 AdapterControl例程的两个任务:
19
AdapterControl例程的两个任务
第一,应该调用适配器对象的MapTransfer例程以便为I/O操作的第一阶段准备映射寄存器和其它系统资源。如果是总线主控设备,MapTransfer将返回一个代表传输第一阶段开始点的逻辑地址。这个逻辑地址可能会与CPU的物理内存地址相同,但也可能会不同。所需要知道的就是该地址就是编程设备硬件的正确地址。 第二个任务是执行与“通知设备这个物理地址”操作中涉及的任何设备相关的操作步骤,然后开始操作设备硬件:DMA.doc
20
DPC 中断通常都发生在传输启动后的很短一段时间后,并且Isr只做很少的事情,比如判断中断类型清除中断状态位
之后,Isr通常都请求一个DPC来处理传输第一阶段的完成,并开始下一个操作。DMA.doc
21
使用分散集中列表进行传输 如果硬件支持分散/聚集能力,那么系统可以更容易地处理设备的DMA传输。分散/聚集能力允许设备传输所涉及的页在物理内存中不连续。 这种设备的StartDevice例程在创建适配器对象上使用与前面讨论的同样的方式,除了ScatterGather标志应该设为TRUE。 传统方法在安排一个涉及分散/聚集功能的DMA传输时,几乎等同于前面段“执行DMA传输”中的基于包的例子。唯一不同之处是它需要为传输的每个阶段多次调用MapTransfer。每次调用后都会得到分散/聚集列表中的一个包含物理地址和长度的数组元素。 当循环完成时,可以使用设备专用的方法把分散/聚集列表发送到设备,然后开始传输。DMA.doc
22
使用GetScatterGatherList
DMA.doc 在决定使用GetScatterGatherList 前,以下的前提需要满足: 程序运行在2000及以后系统,98/ME不支持这个函数 如果不确定或者为了程序的兼容性,应该使用传统的循环获取Scatter/gather 列表
23
使用系统DMA控制器 即slave DMA 所有slave设备必须共享有限的DMA通道数量。AllocateAdapterChannel在这种共享情形中具有真正意义,因为一次只能有一个设备可以使用特定的通道 可以在PnP管理器发送的I/O资源列表中找到一个CmResourceTypeDma资源。 大部分方面和总线Master设备类似,一些差别
24
使用公用缓冲区 通常应该在StartDevice中,在创建适配器对象后分配公用缓冲区:DMA.doc
25
使用公用缓冲区的Slave模式DMA传输
必须为接收数据的虚拟地址创建一个MDL。MDL的实际目的是在最后调用MapTransfer中占用一个参数,这个MDL指名不需要任何数据复制。 通常应该在StartDevice函数中,紧接着分配公用缓冲区之后创建该MDL 为了执行一个输出操作,首先应通过某些手段(如一个明确的内存复制)使公用缓冲区中包含有要发往到设备的数据 在输入操作的结尾,应该把数据从公用缓冲区复制到其它某个地方
26
使用公用缓冲区的Slave模式DMA传输
其它部分和进行基于包的DMA传输类似:调用AllocateAdapterChannel,该函数调用驱动程序提供的适配器控制例程,这个例程又调用KeFlushIoBuffers(如果分配了一个可被高速缓冲的缓冲区),最后调用MapTransfer。DPC例程将调用FlushAdapterBuffers和FreeAdapterChannel函数。 唯一要注意的是应该指定公用缓冲区的MDL来代替读写IRP携带的MDL
27
使用公用缓冲区的master模式DMA传输
如果设备是总线主控模式,那么在分配公用缓冲区后就没有必要调用AllocateAdapterChannel、MapTransfer、FreeMapRegisters函数。 因为AllocateCommonBuffer也能保留必要的映射寄存器。每个总线主控设备都有一个适配器对象,该对象不与其它设备共享,因此不必等待。由于拥有可以在任何时间都能访问缓冲区的虚拟地址,又由于设备的总线主控能力允许使用物理地址(由AllocateCommonBuffer返回)访问该缓冲区,所以没有额外的工作需要做。 这是所有形式的DMA传输中最简单的。
28
使用公用缓冲区的注意事项 在运行系统中,物理上连续的内存是十分稀有的,有时根本得不到这样的内存,除非在系统启动的早期请求这样的内存。内存管理器为了满足请求会对内存页进行重排列,但它的尝试十分有限,并且这个过程会推迟AllocateCommonBuffer的返回。有时尝试会失败,所以必须能够处理这种失败情况。公用缓冲区不仅与稀有的物理内存页相关,而且还与其它设备争用映射寄存器。
29
释放公用缓冲区 在处理停止设备时需要释放公用缓冲区
(*pdx->AdapterObject->DmaOperations->FreeCommonBuffer) ( pdx->AdapterObject, <length>, pdx->paCommonBuffer, pdx->vaCommonBuffer, FALSE );
Similar presentations