DMA 验证

DMA 验证监视直接内存访问 (DMA) 的使用情况。 由于 DMA 例程随着 Windows 的发展而发生更改,因此许多驱动程序错误地使用 DMA 调用。 此外,某些驱动程序编写器会尝试完全绕过 HAL DMA 子系统。 这种做法可能会将隐性 bug 引入到驱动程序中。

驱动程序验证程序的 DMA 验证选项尝试捕获常见的 DMA 错误。 与 !dma 内核调试器扩展一起,它可用于验证驱动程序是否以正确的方式使用 DMA。

此驱动程序验证程序选项也称为 HAL 验证。 驱动程序验证程序生成的某些错误消息可能使用此术语。

不同类型的 DMA

DMA 是一种机制,通过该机制,硬件设备可以在不使用处理器的情况下向内存或从内存中传输数据。 需要处理器才能设置传输,设备将在完成传输后向处理器发出信号。 此系统的优点是处理器可以在执行 DMA 传输时执行其他任务。

Windows 2000 及更高版本中使用了多种类型的 DMA:

Common-buffer DMA
当系统可以分配一个可供硬件和软件访问的缓冲区时,将执行 Common-buffer DMA。 驱动程序负责同步对缓冲区的访问。 内存不会缓存,因此驱动程序可以更轻松地进行此同步。 设置公共缓冲区后,驱动程序和硬件都可以直接写入缓冲区中的地址,而无需 HAL 进行任何干预。

数据包 DMA
当存在必须映射以供硬件使用的现有缓冲区时,将执行数据包 DMA。 使用数据包 DMA 的一个示例是将文件从内存传输到磁盘。 在这种情况下使用公共缓冲区 DMA 是浪费的,因为必须先将文件传输到通用缓冲区,然后硬件才能将其传输到磁盘。 而是咨询 HAL;它为驱动程序提供帮助硬件在内存中查找实际缓冲区所需的信息。 由于涉及的例程需要跨不同的体系结构工作,因此此操作很复杂。

散点/收集 DMA
散点/收集 DMA 是一种快捷方式,可同时设置多个数据包 DMA 传输。 例如,如果要通过网络传输数据包,则网络堆栈的每个部分都会 (TCP、IP、以太网等) 添加自己的标头。 这些标头都从内存中的不同位置分配。 在这种情况下,散点/收集 DMA 通过向 HAL 发出批处理请求来映射每个标头和数据段供硬件访问,从而节省时间。 此方法无需在数据包的每个部分调用数据包 DMA 例程,而是调用每个例程一次,并允许 HAL 负责单独映射每个例程。

注意散点/收集功能 并不意味着设备可以使用散点/收集例程。 散点/收集功能是指设备说明中的标志,指示设备能够读取或写入内存中的任何区域,而不仅仅是特定范围。

系统 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。 有关 bug 检查参数的列表,请参阅 bug 检查0xE6 (DRIVER_VERIFIER_DMA_VIOLATION) 。

DMA 验证何时有用?

所有通过调用 HAL DMA 例程) 直接 (使用 DMA 的驱动程序都应使用 DMA 验证进行测试。

此外,还应测试微型端口驱动程序,因为它们通常通过调用使用 DMA) 的端口驱动程序间接使用 DMA (。

DMA 验证也是检测内存损坏的有效方法,因为它可以发现驱动程序或硬件设备何时超过 DMA 缓冲区。

监视 DMA 验证

内核调试器扩展 !dma 可用于显示大量 DMA 信息。 它可以显示有关每个 DMA 适配器行为的各种详细信息。 Windows 调试工具包的文档中提供了 !dma 扩展的详细示例,以及有关调试器扩展的一般信息。 有关详细信息 ,请参阅 Windows 调试

激活此选项

可以使用驱动程序验证程序管理器或Verifier.exe命令行激活一个或多个驱动程序的 DMA 验证功能。 有关详细信息,请参阅 选择驱动程序验证程序选项

  • 在命令行

    在命令行中,DMA 验证选项由 位 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
    
  • 使用驱动程序验证程序管理器

    1. 启动驱动程序验证程序管理器。 在命令提示符窗口中键入 验证程序
    2. 选择“ 为代码开发人员) 创建自定义设置 ( ”,然后单击“ 下一步”。
    3. 从完整列表中选择“选择单个设置”。
    4. 选择“ (检查) DMA 验证”。

    DMA 验证功能也包含在标准设置中。 若要使用此功能,请在驱动程序验证程序管理器中,单击“ 创建标准设置”。