WavePci 微型端口驱动程序的可靠性问题

WavePci 微型端口驱动程序必须跟踪它从端口驱动程序接收的映射。 WavePci 微型端口驱动程序在驱动程序线程之间共享的数据结构中维护其映射列表。 驱动程序线程还必须共享对 DMA 通道的访问权限,以便向硬件队列添加新的映射,并从队列中删除已完成的映射。 为了防止数据损坏,微型端口驱动程序使用旋转锁序列化对共享数据结构和外围设备的访问。 旋转锁可保护共享数据和硬件队列免受两个或多个驱动程序线程的同时访问。

开发管理映射的驱动程序部分时,供应商应特别注意以下几点。

旋转锁

为了避免潜在的死锁,微型端口驱动程序在调用Portcls.sys获取或释放映射时不得保留自己的旋转锁。 Microsoft Windows 驱动程序工具包 (WDK) 中的 Ac97 示例驱动程序说明了这一原则。 在调用 IPortWavePciStream::GetMapping IPortWavePciStream::ReleaseMapping 之前,示例驱动程序调用 KeReleaseSpinLock 释放旋转锁。 GetMapping 或 ReleaseMapping 调用返回后,驱动程序调用 KeAcquireSpinLock 以再次获取旋转锁。 在调用释放和获取旋转锁之间,驱动程序线程不得假定它具有对映射列表的独占访问权限。 在此未受保护的时间间隔内访问共享数据是危险的。 如果释放和获取旋转锁之间的间隔很小,则两个驱动程序线程之间的争用条件损坏数据的可能性也很小。 这意味着生成的故障是间歇性的,因此难以跟踪。 释放和获取旋转锁后,编写良好的驱动程序应假定以前用于访问共享数据结构内容的任何临时指针或索引都不再有效。

IRP 取消

在处理播放或捕获流的过程中,取消 IRP 可能会导致操作系统撤销微型端口驱动程序获取的一个或多个映射。 发生这种情况时,端口驱动程序调用 IMiniportWavePciStream::RevokeMappings 方法以通知微型端口驱动程序。 为了避免播放数据或将数据捕获到撤销的映射中,微型端口驱动程序必须从其软件列表和 DMA 控制器的硬件队列中删除映射。 由于软件列表和硬件队列在驱动程序线程之间共享,因此需要一些谨慎才能可靠地执行这些操作。

例如,要撤销的一组映射可能包含刚刚或即将发布的映射。 在这种情况下,两个驱动程序线程可能会同时尝试从 DMA 队列中删除相同的映射。 如果驱动程序无法阻止同时访问,则结果可能会损坏管理队列的寄存器或内存结构中的数据。

有关工作代码示例,请参阅 Windows 驱动程序工具包 (WDK) 中的 Ac97 示例驱动程序。