网站做淘宝客还行吗,做shopify网站,制作网站计划书,免费建站小程序DMA(Direct Memory Access)是所有现代电脑的重要特色#xff0c;它允许不同速度的硬件装置来沟通#xff0c;而不需要依于 CPU 的大量中断负载#xff0c;否则CPU 需要从设备缓存中把每一页的数据复制到缓存中#xff0c;然后把它们再次写入到新的地方#xff0c;在这个过…DMA(Direct Memory Access)是所有现代电脑的重要特色它允许不同速度的硬件装置来沟通而不需要依于 CPU 的大量中断负载否则CPU 需要从设备缓存中把每一页的数据复制到缓存中然后把它们再次写入到新的地方在这个过程中中CPU 需要一直控制这个过程。 DMA 则是由DMA控制器直接将数据从一个地址空间复制到另外一个地址空间。
由于现在电脑基本上统一了内部总线所以所有的DMA都是PCI总线来进行的故了解了PCI总线是如何处理DMA的那也就了解了DMA是如何进行的。
如果调试过PCI总线那么会发现DMA是以一个内存页面为单位进行的每次DMA传输的总是内存页面的整数倍PCI会先将windows的内存地址写入到DMA控制器然后向寄存器写入数据来启动DMA传输但是这一切操作已经被windows封装起来了在windows中我们会直接分配适配器对象使用适配器来操作DMA。
适配器对象
任何使用直接 I/O 和 DMA 的驱动程序都必须创建适配器对象。 适配器对象表示 DMA 控制器通道或端口或总线-主设备。
两种最低级别驱动程序必须使用适配器对象
使用系统 DMA 控制器的设备驱动程序。 此类设备称为 从属设备 称为“使用系统 (或 从属) DMA”。用作总线-主适配器的设备驱动程序。 此类设备与系统仲裁以使用 I/O 总线因此使用总线主 DMA。
驱动程序通常位于设备扩展中为指向适配器对象的指针提供存储。
为了执行 DMA 传输使用这些 DMA 方法的设备驱动程序通常具有AdapterControl 例程并调用系统提供的用于操作适配器对象的支持例程。 不需要 AdapterControl 例程的 (驱动程序包括 那些使用Scatter/Gather DMA 的驱动程序以及那些使用 common-buffer、bus-master DMA.)就是使用总线主DMA的驱动。
作为设备启动操作的一部分处理 DMA 操作的驱动程序调用 I/O 管理器后者又调用特定于平台的 HAL 来创建一组适配器对象。 在任何 Windows 平台上适配器对象集通常包括以下对象的适配器对象
从属设备连接到的每个系统 DMA 控制器通道或端口。计算机中的每个总线主 DMA 设备。
获取/释放适配器
在设备启动时使用系统或总线主 DMA 的驱动程序会调用 IoGetDmaAdapter 来获取指向适配器对象的指针并确定每个传输操作可用的映射寄存器的最大数目。 当驱动程序调用 IoGetDmaAdapter 时I/O 管理器反过来会调用 HAL 以获取特定于平台的必要信息。
驱动程序必须在调用 IoGetDmaAdapter 时在系统定义的DEVICE_DESCRIPTION结构中提供某些信息。 驱动程序必须使用 RtlZeroMemory 初始化 DEVICE_DESCRIPTION 结构并在其中设置值。
所需数据包括有关驱动程序设备功能的信息例如设备是否为总线主机、设备是否具有散点/收集功能以及设备一次可以传输多少字节的数据 (MaximumLength) 。
所需的设备说明数据还包括特定于平台的信息例如总线主设备驱动程序控制的特定于平台和系统分配的总线编号。 驱动程序可以通过调用 IoGetDeviceProperty 来获取此信息。
DEVICE_DESCRIPTION结构包括一些可能与某些 DMA 设备或驱动程序无关的字段。 例如WDM 驱动程序中不使用 BusNumber 字段。 每个驱动程序应为相关结构成员提供值并应将所有其他成员的值设置为零。
当请求必须分解为两个或更多个 DMA 操作时除非设备能够等待系统 DMA 控制器重新编程否则从属设备的驱动程序不应在 ScatterGather 字段中传递 TRUE。
IoGetDmaAdapter 返回指向适配器对象的指针和特定于平台或特定于设备的值该值指示适配器对象可用于每个 DMA 传输操作的映射寄存器数。
返回的适配器对象包含三个可供驱动程序访问的字段
版本号 (版本)大小 (大小)指向 DmaOperations(DMA_OPERATIONS) 结构的指针
DMA_OPERATIONS 结构包含指向驱动程序在其设备上执行 DMA 操作时必须使用的函数的指针表, 函数只能通过此数据结构中的指针访问,驱动程序无法直接按名称调用它们。 (请注意这些例程替换以前版本的 Windows NT 中支持的 HalXxx 例程。为了确保旧驱动程序的兼容性Wdm.h 和 Ntddk.h 头文件提供具有过时名称的宏但新驱动程序应始终通过 data structure.)
映射寄存器的数量可能因设备以及平台而异。 通常HAL 根据以下条件分配多个映射寄存器
如果可能HAL 将返回一个值该值比传输 MaximumLength 字节所需的映射寄存器数多一个如驱动程序对 IoGetDmaAdapter 的调用中所述。
否则HAL 将返回一个较小的值该值对于特定平台来说尽可能大。
换句话说HAL 通常为每个驱动程序提供足够的映射寄存器以最大化其设备的 DMA 吞吐量但 HAL 在某些 Windows 平台上可以返回较小的值。 无法保证驱动程序将获取它请求的映射寄存器数因此驱动程序应始终检查返回的值。
任何 DMA 设备驱动程序都必须为 IoGetDmaAdapter 返回的适配器对象指针和 NumberOfMapRegisters 值提供存储。 此指针是指向系统提供的用于 DMA 的支持例程的必需参数。 由于其中许多支持例程必须在 IRQL DISPATCH_LEVEL调用因此驱动程序分配的存储必须是驻留的。 大多数 DMA 驱动程序在 设备扩展中提供必要的存储。 但是如果驱动程序也使用控制器对象或驱动程序分配的非分页池则存储可以位于 控制器 扩展中。
驱动程序完成所有 DMA 操作后会调用 PutDmaAdapter 以释放适配器对象。
AdaptControl例程要求
AdapterControl 例程必须至少执行以下操作
1. 保存输入 MapRegisterBase 值以及驱动程序为当前 IRP 执行一个或多个 DMA 传输操作所需的任何其他上下文信息。 每个 DMA 传输操作完成后驱动程序必须将 MapRegisterBase 值传递给 FlushAdapterBuffers 。
2. 返回相应的 IO_ALLOCATION_ACTION 值
如果设备是从属设备则为 KeepObject因此驱动程序使用系统 DMA。如果设备是总线主机则 DeallocateObjectKeepRegisters因此驱动程序使用基于数据包的总线主 DMA。
根据驱动程序的设计其 AdapterControl 例程也可以在返回控制权之前执行以下操作
1. 确定传输在其设备上的起始位置2. 根据由于传输的开始位置而对其设备的任何限制计算可能的传输大小一般情况下调用 AllocateAdapterChannel 的例程负责确定是否必须将转移请求拆分为部分传输因为针对每个 DMA 传输操作可用的 NumberOfMapRegisters 存在任何特定于平台的限制3. 设置有关设备 (或控制器) 扩展中的每个传输请求的任何驱动程序维护的状态例如AdapterControl 例程可能会使用 CustomTimerDpc 例程的入口点调用 KeSetTimer该例程超时驱动程序的 DMA 传输操作4. 使用在 Irp- MdlAddress传递的 MDL 指针调用 MmGetMdlVirtualAddress以获取传输开始的索引适合传递给 MapTransfer5. 调用 MapTransfer 以设置系统 DMA 控制器或获取总线-主设备的物理到逻辑地址映射。6. 使用通过调用 KeSynchronizeExecution 调用的 SynchCritSection 例程对驱动程序的设备进行编程以便执行传输操作。
如果传输请求要求驱动程序执行一系列部分传输操作以满足当前 IRP则驱动程序的 DpcForIsr 或 CustomDpc 例程通常负责对设备进行重新编程以便执行后续传输操作。 每个传入传输 IRP 仅调用 一次 AdapterControl 例程。
完成当前传输 IRP 的驱动程序例程通常是 DpcForIsr 或 CustomDpc 例程也负责通过分别调用 FreeAdapterChannel 或 FreeMapRegisters 来释放系统 DMA 控制器或总线-主适配器。 此驱动程序例程应在完成其最后一次部分传输操作时尽快发出相应的调用以便从属 DMA 设备的驱动程序可以分配系统 DMA 控制器或者总线-主驱动程序可以立即开始处理下一个传输 IRP。
IRP_MN_START_DEVICE 请求的驱动程序调度例程必须为 AdapterControl 例程执行以下操作
通过填写 DEVICE_DESCRIPTION结构并 调用 IoGetDmaAdapter为设备的 DMA 功能设置适配器对象。保存 IoGetDmaAdapter 返回的适配器对象指针和 NumberOfMapRegisters。IoGetDmaAdapter 返回的平台特定最大 NumberOfMapRegisters 或驱动程序设备的传输功能以限制性更强者为准确定驱动程序是否必须拆分给定的传输请求并在其设备上执行多个 DMA 操作来满足该 IRP。
返回的适配器对象指针、驱动程序的 AdapterControl 例程的入口点、表示当前 IRP 的目标设备的 DeviceObject 指针、指向已为 AdapterControl 例程设置的区域的上下文指针以及 NumberOfMapRegisters 值可能小于较小传输请求的最大可能数目必须在调用中传递给 AllocateAdapterChannel。 通常驱动程序的 StartIo (或可能是 ControllerControl) 例程在调用 AllocateAdapterChannel 之前在 Context 处设置区域。
在系统中可能以两种不同的方式使用DMA基于数据包的系统DMA、基于公用缓冲区的系统DMA。