UE 挂起检测:步骤 1-14
下面介绍了 UE 挂起检测的步骤 1 到 14。 这些步骤对应于 UE 挂起检测和恢复流中显示的关系图。
此示例使用 OID_SET_POWER。
NDIS 接收系统电源 IRP 或 NIC 活动引用降至 0。
NDIS 为 WDI 驱动程序生成OID_SET_POWER D3。
WDI (M1) 设置 WDI 命令的计时器,包括将 WDI OID 向下发送到 LE 之前的任务。 如果命令是任务,则还会设置该任务的其他计时器。 这两个计时器都可以超时,但最多只能有一个计时器触发重置恢复。
WDI 将 WDI 命令发送到 LE。 如果 LE 需要固件命令来完成 OID,则建议在适配器结构中记住 WDI OID。 当固件完成 WDI OID 的作业时,LE 完成 OID 并将其从适配器结构中删除。 由于 WDI 将 OID 序列化为 LE,因此 LE 只需要一个槽来记住挂起的 WDI OID。 如果固件命令挂起,LE 可以随时返回 OID,但不得晚于意外删除 (当固件已禁用时,它可以在步骤 17 的意外删除) 上下文中返回 OID。 对于任何其他情况,LE 只是在固件完成相应的作业时完成 WDI OID,而不管它是在诊断回调之前还是之后。 如果 LE 在诊断后需要记住 WDI OID,则需要另一个槽来记住它。 但是,对于诊断后收到的 OID,LE 不应接触固件以避免级联挂起。
LE 向固件发送命令。
如果固件命令超时,可能是由于固件挂起或耗时过长。
- 如果固件在超时后只需花费太长时间才能完成命令,则 LE 可以完成 WDI 命令。 UE 会相应地处理它。
- 如果固件挂起,WDI 命令不会很快完成。 重置硬件后,LE 必须在步骤 16 中意外移除时完成,因此无需对潜在争用情况进行特殊处理即可安全完成。
触发 WDI 计时器以生成 WDI 诊断命令。 此 WDI 命令是调用 LE 驱动程序 MiniportWdiAdapterHangDiagnose,而不是 WDI OID。
LE 收集硬件控制寄存器状态,以及可选的完整固件状态。
- IHV 驱动程序应收集限制为 1KB 的硬件寄存器内容,并在函数返回中返回。 此外,在预生产环境中,LE 还应尝试将固件上下文转储到文件中,以便 IHV 可以彻底进行事后调试。 可以将开关实现为注册表项,以控制硬件寄存器和固件映像的集合。
- LE 还会标记要取消的当前命令。 如果命令完成争用以击败诊断,则如果 LE 对此命令不执行任何操作,则可以接受。
- 当此命令挂起时,UE 可能会发送进一步的 WDI 命令作为重置的结果。 这些是正在进行的命令或清理命令。 诊断调用后,LE 应在不接触固件的情况下处理它们。
WDI 接收控件寄存器状态。
WDI 标记挂起的 WDI 命令,以便稍后由 LE 指示。
WDI 返回 () 未完成 WDI 的 NDIS 命令。 这是安全的,因为 WDI 双缓冲区 NDIS 命令。
WDI 调用 NDIS 重置,并调用 NdisWriteErrorLogEntry,错误代码为 NDIS_ERROR_CODE_HARDWARE_FAILURE (0xc000138a) 。 这会导致系统事件日志中记录一个模块名称为 LE 的事件。 错误事件 ID 自动弹出为 (0xc000138a |0xffff) – 0n5002。 如果 LE 也使用相同的错误代码来写入错误日志,则数据的第一个 DWORD 应包含高位集 (0x80000000) ,以便通过 LE 轻松分隔事件。 WDI 使用 0x00000000 为第一个 DWORD 数据0x7fffffff。
调用返回。
NDIS 完成 IRP。
在此之后,NDIS 调用总线以意外删除并重新枚举我们。 请务必注意,WDI 对 NDIS 命令进行双重缓冲,以便它不必等待 WDI 命令返回以完成 NDIS 命令。 这样就无需 LE 执行取消逻辑,这些逻辑非常复杂。
若要避免 PnP 操作死锁,必须完成 NDIS OID_SET_POWER。 将序列化所有 PnP 和电源状态更改事件。 这意味着,如果设置电源 OID 不返回,NDIS 将无法返回设置电源 IRP,这意味着重置恢复锁定Surprise-Remove IRP。