最近做了一款pci的视频采集卡(H264压缩),由于数据传输量比较大,所有想采用dma来传输数据,刚开始感觉很简单,后来感觉还是困难重重。
DMA 验证监控直接内存访问 (DMA) 的使用。随着 Windows 的开发,DMA 例程已经发生改变,因此许多驱动程序错误地使用了 DMA 调用。而且,一些驱动程序作者尝试完全绕过 HAL DMA 子系统。这种做法可能将隐含的错误引入驱动程序。
驱动程序验证程序的 DMA 验证选项尝试捕获常见的 DMA 错误。与 !dma 内核调试程序扩展一起使用时,可以验证驱动程序是否在以适当的方式使用 DMA。
此驱动程序验证程序选项也称为“HAL 验证”。驱动程序验证程序生成的一些错误消息可能使用此术语。
此驱动程序验证程序选项仅在 Windows XP 及更高版本中提供。
不同类型的 DMA
DMA 是一种机制,硬件设备通过该机制可以与内存互传数据,而无需使用处理器。设置传输需要使用处理器,并且在设备完成传输时会向处理器发送信号。此系统的优势在于,在执行 DMA 传输时处理器可以执行其他任务。
Windows 2000 及更高版本中使用了若干类型的 DMA。
- 通用缓冲区 DMA
-
当系统可以分配硬件和软件都能访问的单个缓冲区时,将执行通用缓冲区 DMA。驱动程序负责对缓冲区的同步访问。不缓存内存,这使得驱动程序执行此同步更方便。在设置通用缓冲区之后,驱动程序和硬件都可以直接写入缓冲区中的地址,而无需 HAL 的任何干预。
- 数据包 DMA
-
如果存在一个现有的单一缓冲区,并且必须映射该缓冲区才能供硬件使用,将执行数据包 DMA。使用数据包 DMA 的示例是从内存到磁盘传输文件。在此情况下使用通用缓冲区 DMA 是一种浪费,因为需要将文件传输到通用缓冲区,硬件才能将其传输到磁盘。这时可借助 HAL;它可以为驱动程序提供所需的信息,帮助硬件查找内存中的实际缓冲区。此操作比较复杂,因为需要涉及一些例程跨不同体系结构执行操作。
- 分散/集中 DMA
-
分散/集中 DMA 是一次设置若干数据包 DMA 传输的快捷方法。例如,如果通过网络传输数据包,网络数据包的每部分都会添加自己的标头(TCP、IP、以太网等)。这些标头都从内存中的不同位置分配。在此情况下,使用分散/集中 DMA 可以节省时间,该方法通过将批处理请求发送到 HAL 来映射每个标头和数据段以供硬件访问。此方法无需在数据包的每个部分上调用数据包 DMA 例程,而是对每个例程调用一次,并让 HAL 负责分别映射它们。
Note 分散/集中功能并不意味着设备可以使用分散/集中例程。分散/集中功能在设备描述中引用一个标志,该标志指示设备可以从内存中的任何区域读写,而不只是特定范围。
- 系统 DMA
-
系统 DMA 的执行方式是在主板上对系统 DMA 控制器进行编程以直接执行传输。只有 ISA 卡可以使用系统 DMA。
DMA 验证的效果
当 DMA 验证处于活动状态时,驱动程序验证程序检测 DMA 例程的错误使用情况,其中包括:
-
DMA 内存缓冲区过载或不足(这些错误可能由硬件或驱动程序造成)。
-
双重释放通用缓冲区、适配器通道、映射注册表或分散/集中列表。
-
由于不释放通用缓冲区、适配器通道、映射注册表、分散/集中列表或适配器而导致内存泄漏。
-
一次对一个适配器提供多个适配器通道。
-
尝试使用已被释放且不复存在的适配器。
-
不刷新适配器缓冲区。
-
一个适配器的未处理引用计数太多。
-
在可分页缓冲区上执行 DMA(在开始 DMA 传输之前应锁定所有缓冲区)。
-
在具有已损坏标志的 MDL 上执行 DMA。
-
在第一个 MDL 之前或第一个 MDL 结束之后引用无效的系统地址,或者使用的传输长度超过 MDL 缓冲区并超过 MDL 中的页面边界。
-
一次分配的映射注册表太多,或者分配的映射注册表超过允许的最大数。
-
对映射注册表进行双重映射。
-
注册表仍在映射时就尝试释放映射注册表。
-
尝试刷新尚未映射的映射注册表。
-
在映射注册表文件末尾尝试刷新的字节数太多。
-
在不正确的 IRQL 上调用 DMA 例程。
-
将 Null 值 DMA_ADAPTER 传递到 HAL 例程。
-
在地址未包含在 MDL 中时,将该地址和 MDL 传递到 HAL 例程。
-
尝试映射已经映射的地址范围。
-
尝试刷新尚未映射的缓冲区。
-
尝试为传输映射零长度缓冲区。
-
调用过时函数 HalGetAdapter(所有驱动程序必须改用 IoGetDmaAdapter)。
驱动程序验证程序监控驱动程序的行为,如果发生其中的任意冲突,将发送错误检查 0xE6。有关错误检查参数列表,请参阅 Bug Check 0xE6 (DRIVER_VERIFIER_DMA_VIOLATION)。
何时使用 DMA 验证?
直接使用 DMA 的所有驱动程序(通过调用 HAL DMA 例程)都应使用 DMA 验证测试。
此外,还应测试微型端口驱动程序,因为它们通常间接使用 DMA(通过调用使用 DMA 的端口驱动程序)。
DMA 验证还可以作为检测内存损坏的有效方法,因为它可以检测到是驱动程序还是硬件设备造成了 DMA 缓冲区溢出。
监控 DMA 验证
内核调试程序扩展 !dma 可用于显示大量的 DMA 信息。它可以显示有关每个 DMA 适配器行为的各种详情。Windows 程序包的调试工具文档中提供了 !dma 扩展的详细示例以及有关调试程序扩展的常规信息。有关详细信息,请参阅 Windows 调试。
激活此选项
通过使用驱动程序验证程序管理器或 Verifier.exe 命令行,可以为一个或多个驱动程序激活 DMA 验证功能。使用命令行
-
在命令行,DMA 验证选项由 Bit 7 (0x80) 表示。要激活 DMA 验证,请使用标志值 0x80 或将 0x80 添加到该标志值。例如:
- verifier /flags 0x80 /driver MyDriver.sys
该功能将在下次启动时激活。
在 Windows Vista 及更高版本的 Windows 上,还可以通过将 /volatile 参数添加到此命令激活和停用 DMA 验证而不用重启计算机。例如:
- verifier /volatile /flags 0x80 /adddriver MyDriver.sys
此设置将立即生效,但在关闭或重启计算机时将丢失。有关详细信息,请参阅 使用易失性设置。
DMA 验证功能还包括在标准设置中。例如:
- verifier /standard /driver MyDriver.sys
- 使用驱动程序验证程序管理器
- 启动驱动程序验证程序管理器。在“命令提示符”窗口中键入 Verifier。
- 选择“创建自定义设置(供程序开发人员使用)”,然后单击“下一步”。
- 选择“从一个完整的列表选择单个设置”。
- 选择(选中)“DMA 验证”。
DMA 验证功能还包括在标准设置中。要使用此功能,请在驱动程序验证程序管理器中单击“创建标准设置”。
版权声明:本文为博主原创文章,未经博主允许不得转载。