数据损坏,无需特殊处理传输

本文可帮助你解决数据损坏可能发生的问题,而无需对传输进行特殊处理。

原始产品版本: 直接内存访问
原始 KB 数: 2714876

现象

在启用了 PAE 的 x86 Windows 版本上,支持访问超过 4 GB 的内存的设备驱动程序,将 32 位直接内存访问(DMA)设备与对同一传输缓冲区的虚拟地址的写入进行混合,可能会导致数据损坏,而无需特殊处理传输。

原因

启用了 PAE 的 x86 Windows 版本支持访问超过 4 GB 的内存,对报告无法使用 32 位 DMA 地址的设备实施特殊处理。 这种特殊处理是在操作系统的硬件抽象层(HAL)中使用映射寄存器实现的,有时称为弹跳缓冲区。

当设备驱动程序开始对支持 32 位的设备执行 DMA 操作时, DmaOperations 函数 HalGetScatterGatherList 必须确定描述传输的任何物理地址是否驻留在 4 GB 以上。 然后,HAL 会将驻留在 4 GB 以上的传输缓冲区物理地址替换为驻留在 4 GB 以下的映射寄存器,设备能够寻址。

如果执行了替换,生成的散点收集列表(SGL)将由物理地址组成,其中一些地址不同于描述传输的原始内存描述符列表(MDL)。 当驱动程序指示 DMA 传输完成时,HAL 将确定是否使用映射寄存器来支持传输。 如果确实如此,并且操作是从设备读取到系统内存的,HAL 会将用于原始数据缓冲区的任何映射寄存器的内容复制到其中。 因此,在请求完成之前由驱动程序直接写入传输缓冲区虚拟地址的数据将在请求完成后被 HAL 替换的映射寄存器的内容覆盖。

如果映射寄存器中包含的数据与驱动程序直接写入传输缓冲区的数据不匹配,则传输缓冲区中的数据可能不一致。

解决方法

需要将 32 位 DMA 读取操作与写入到传输缓冲区的虚拟地址混合的设备驱动程序必须使用 DmaOperations 函数 HalBuildMdlFromScatterGatherList

如果映射寄存器替换由 HAL 完成,将创建一个新的 MDL, HalBuildMdlFromScatterGatherList 该 MDL 由非替换的传输缓冲区物理地址和替换的 HAL 映射寄存器的物理地址组成。 可以通过调用 MmGetSystemAddressForMdlSafe来获取新 MDL 的虚拟地址映射。 如果 HalBuildMdlFromScatterGatherList 返回原始 MDL,则不执行映射寄存器替换。

必须取消映射和释放由 HalBuildMdlFromScatterGatherList 调用 MmUnmapLockedPagesIoFreeMdl 函数创建的新 MDL。

详细信息