前一阵子,软件组的同事向我提交了几个与电源管理请求相关的BSOD转储文件,由于手头积压了较多的BSOD DUMP FILE待分析, 所以起初并没有对这几个与电源请求相关的DUMP FILE有足够的重视,随着同事后续又提交了一系列该类型的转储文件,而该BSOD又是每天都发生,在达到近20多个该类型的BSOD DUMP FILE后,我决定先放开别的事情,对这个问题花时间去研究研究.
在前面的文章中,已经提及,无论USB设备还是USB主机的开发,均离不开USB-IF的GOLDEN TREE/INTEROP测试.
对于xhci host的测试要求,目前最近版本为<<xHCI_Interoperability_Testing_v1_58>>, 下图为一个完整的GOLDEN TREE.
简而言之,在被测试设备/device或者主机/host,还是USB集线器/hub,纳入该GOLDEN TREE的情况下,所有GOLDEN TREE中的USB3.0 host, USB3.0/2.0/1.1/1.0设备与HUB都要能够正常正确地工作.
而这一系列的BSOD均是在操作系统将要把整个系统带入S3的过程中发生的. 因为当OS系统发出ENTER S3的请求,在足够长的时间内,系统并未按要求进入S3.
该问题明显是由这个GOLDEN TREE所导致的,但该GOLDEN中包括了近30个单元,每个单元又加载了一个到多个不等的驱动程序,如何将怀疑对象的范围缩小,是我第一步需要做的当务之急.
在跳进去进行分析之前,查找了一些相关的文章:
包括:
张银奎 <<格蠹汇编>>中的第6章<<再解电源服务溢出崩溃>>
第7章<<三解电源服务溢出崩溃>>
第16章<<转储分析之探寻唤醒失败原因>>.
第31章<<在调试器中观察计算机的睡眠过程>>
其中,第16章<<转储分析之探寻唤醒失败原因>>确实给出了张银奎老师自己所碰到的关于电源管理导致的BSOD的一个案例具体分析过程,但问题是,与我所接收到一BSOD的问题正好相反.而且该文章,最后将系统无法唤醒的原因草草地归结为微软的USB3.0 HUB的usbhub驱动没有调用上层函数给出的完成例程,但却没有给出为什么上层函数给出的完成例程不被USBHUB驱动调用的原因. 实在有点遗憾.
之后,又查找到两篇相关文章:
http://www.yiiyee.cn/Blog/0x9f-2/
http://www.yiiyee.cn/Blog/fast_mutex/
在看完这两篇文章后,对电源管理BSOD的分析有了进一步的掌握与较多的收获,但离分析出结果还是征途漫漫,其根本原因是,都是电源管理的BSOD,但却是"形似神不似".
看来,要想从别人那里立马取得问题的解决方法,是不太可能的事情了,毕竟,人家出问题的环境与我们的GOLDEN TREE是不同的.
打开WINDBG,导入BSOD文件, 先进行初分析:
*************************************************************
DRIVER_POWER_STATE_FAILURE (9f)
A driver has failed to complete a power IRP within a specific time.
Arguments:
Arg1: 00000003, A device object has been blocking an Irp for too long a time
Arg2: 85be34c0, Physical Device Object of the stack
Arg3: 836c5a00, nt!TRIAGE_9F_POWER on Win7 and higher, otherwise the Functional Device Object of the stack
Arg4: bcd5eaa0, The blocked IRP
*************************************************************
对这个问题中文解释一下:
系统发给设备栈中的一个物理设备对象的IRP超时,导致了该BSOD.
于是问题就随之而来了:
1.这是什么类型的电源管理IRP,即他的MINOR FUNCTION是什么?
2.哪个物理设备对象是该IRP的接收者?
3.这种MAJOR/MINOR组合的IRP系统能够接收的处理时间范围是多少?
4.而这个IRP到底又被阻塞了多少时间?
5.为什么这个IRP会被阻塞?
第一个问题,这是什么具体类型的电源管理IRP?
是取得GET系统或者是设备的电源状态,还是设置SET?
电源管理方法,相关类型是指:
是系统还是针对于某个设备?
nt!_POWER_STATE_TYPE
SystemPowerState =0n0
DevicePowerState =0n1
如果是针对于系统的,该目标状态是多少?
nt!_SYSTEM_POWER_STATE
PowerSystemUnspecified = 0n0
PowerSystemWorking= 0n1
PowerSystemSleeping1 = 0n2
PowerSystemSleeping2 = 0n3
PowerSystemSleeping3 = 0n4
PowerSystemHibernate = 0n5
PowerSystemShutdown= 0n6
PowerSystemMaximum= 0n7
同样,如果针对于设备,它的目标状态又是多少?
nt!_DEVICE_POWER_STATE
PowerDeviceUnspecified = 0n0
PowerDeviceD0 = 0n1
PowerDeviceD1 = 0n2
PowerDeviceD2 = 0n3
PowerDeviceD3 = 0n4
PowerDeviceMaximum= 0n5
要得到这个答案,有两种方法,
方法一,
通过该IRP指针取得它当前栈的指针(Tail.Overlay.CurrentStackLocation )
然后通过这个栈的指针,取得该IRP的MajorFunction与MinorFunction类型
MajorFunction=0x16
MinorFunction=0x02
查找对应的WDM.H, 得出,这是一个设置SET类型的电源管理IRP.
IRP_MJ_POWER = 0x16
IRP_MN_SET_POWER = 0x2
再进一步:
通过该CurrentStackLocation的偏移为4的Parameters,取得上面所述的电源设置类型:
++++++++++++++++++++++++++++++++++++++
kd> dd 0xbcd5ef90+4 L4
bcd5ef94 00015400 00000001 00000004 00000003
++++++++++++++++++++++++++++++++++++++
我对以上一串数字进行一个注释:
bcd5ef94 地址
00015400 (System context,与该BSOD的分析无关)
00000001(DevicePowerState)
00000004(PowerDeviceD3)
00000003 (Shutdown Type, 与该BSOD的分析无关)
这就是要将指定的物理设备对象设置为D3的状态.
这个IRP类型,与我们要将系统置入S3,但在这个时候系统BSOD了,也是相符合的.
第二种方法:
通过微软未公开的WINDBG调试命令:
!poaction
一步到位:如下输出
而且这个方便的命令,还给出了更加有用的内容
1. 该SET DEVICE D3的IRP前面,还有一个SET System S4的IRP.
2. 发出该IRP的线程.
++++++++++++++++++++++++++++++++++++++++++++++++++++++
Allocated power irps (PopIrpList - 825fb560)
IRP: 8a90af48 (wait-wake/S3), PDO: 891050f0
IRP: 91da2f00 (wait-wake/S4), PDO: 890dba50
IRP: 80e7cc98 (wait-wake/S4), PDO: 86a54500
IRP: 80eb4d50 (wait-wake/S4), PDO: a805c650
IRP: 80fb8c30 (wait-wake/S4), PDO: a806a030
IRP: 80f9cce0 (wait-wake/S4), PDO: 86a1e4d0
IRP: 80eded70 (wait-wake/S4), PDO: 86a22620
IRP: 81b8a9f0 (wait-wake/S4), PDO: b6cda080
IRP: be9da9f0 (wait-wake/S4), PDO: b5186ce0
IRP: 80350aa0 (wait-wake/S4), PDO: b6df2878
IRP: b597c8a8 (wait-wake/S4), PDO: b5119ce0
IRP: be8b4960 (wait-wake/S4), PDO: b511a030
IRP: aed5a9f0 (wait-wake/S4), PDO: bae779e0
IRP: 814c8aa0 (wait-wake/S4), PDO: b6df2bd8
IRP: 80396b78 (wait-wake/S4), PDO: baf13490
IRP: ab7b4aa0 (set/S4), PDO: 85be34c0, CURRENT: baf54bf8, NOTIFY: 86a3e038
IRP: bcd5eaa0 (set/D3,), PDO: 85be34c0, CURRENT: baf54bf8
IRP: bb7fcb78 (wait-wake/S4), PDO: baf42ac8
IRP: aa70cde0 (wait-wake/S4), PDO: 85b81030
IRP: 815eaeb8 (wait-wake/S3), PDO: 890de030
IRP: 80ef0c50 (wait-wake/S4), PDO: 943aa148
IRP: bb754e48 (wait-wake/S4), PDO: 8e0d7028
IRP: ba774de0 (wait-wake/S4), PDO: 943b3650
IRP: b58e4eb8 (wait-wake/S3), PDO: 890dc030
IRP: bb7b6e48 (wait-wake/S4), PDO: 8e0ca028
IRP: 97512d28 (wait-wake/S4), PDO: 86a37178
Irp worker threads (PopIrpThreadList - 825fad88)
THREAD: 85ba55c0 (static)
THREAD: 85b6b640 (static)
THREAD: b745f500 (dynamic)
THREAD: 8904db00 (dynamic)
THREAD: 8bc34200 (dynamic), IRP: bcd5eaa0, DEVICE: 86a235e8
THREAD: b6d7e040 (dynamic)
THREAD: b514ad40 (dynamic)
THREAD: bae16d40 (dynamic)
***********************************************************************************************
第二个问题: 这个电源管理IRP的接收对象是谁?
我们已经知道这个物理设备对象的指针:PDO: 85be34c0
所以,要得到这个答案并非难事:
通过分析,我发现,这个物理设备对象,是GOLDEN TREE上的第四级的SS HUB(USB3.0 HUB), 即上图中的HUB SS4.
在更进一步分析,推测与下结论之前, 我要问的问题是, 是不是所有的BSOD存在相同的情况, 还是不同的情况?
于是,我打开所有近20个该类型的BOSD, 得出的结论是: 所有的超时IRP类型相同, 而且都是发给第四级的SS HUB.
这样一个暂时的结论,对于我们后续的分析反而变得简单了, 相反,如果这些IRP类型不同,接收者又是位于GOLDEN TREE中的不同设备,或者不同级的HUB,这个问题反而难度更高.
下一篇 ,我将给出进一步的分析,直至ROOT CAUSE.