一次真实的 7B 蓝屏:挂上调试器之后,我是怎么找到那个设备的
这篇是上一篇的一次实际应用。没看过的建议先看那篇 —— 系统已经进不去的时候,得先用那套办法把调试器挂上,这里才有的看。
现场
用户的系统是绑着硬件跑的,在它自己的机器上一切正常。
出问题之后,我们把镜像拷回本地,打进虚拟机 —— 起不来了,开机就是 0x0000007B INACCESSIBLE_BOOT_DEVICE。
注意这里有个关键区别:系统本身没坏,坏的是"它现在住的房子"。所以 7B 报的不是"驱动崩溃",是"找不到它熟悉的设备"。
网上那些办法为什么不一定管用
搜 7B 蓝屏,答案基本就那几样:进 BIOS 改硬盘模式(IDE/AHCI)、用工具注入存储驱动、上 P2V 转换工具。
这些是猜着试。它们针对的是"存储控制器驱动不匹配"这一种情况 —— 而 7B 的原因不止一种。像这次是整套硬件都换了,缺什么得一个一个查出来,猜不出来。
第一步:先让自己能调试
系统已经起不来,常规的附加调试器挂不上。用上一篇那套办法,手工把 virtualKD 注入进去,断在启动早期。
第二步:看设备树
kd> !devnode 0 1
这会 dump 整棵设备树,输出很长。要找的是带 Problem = 的那些节点:
DevNode 0xa265a660 for PDO 0xa26431d8
InstancePath is "ACPI\PNP0200\4&25ee97c0&0"
State = DeviceNodeInitialized (0x302)
Previous State = DeviceNodeUninitialized (0x301)
Problem = CM_PROB_NOT_CONFIGURED
Problem Status = 0x00000000
CM_PROB_NOT_CONFIGURED = 这个设备没有找到驱动。
小技巧:
!devnode 0 1是全量 dump,翻起来累。可以先跑!devnode 0 21—— 它只列有 Problem 的设备,直接就是你要找的那批。
第三步:搞清楚为什么是它
Windows 把「设备」和「驱动」分开记在两个地方:
Enum\<总线>\<硬件ID>\<实例ID>—— 设备实例,总线枚举出来的Class\{ClassGUID}\<编号>—— 驱动配置,里面的MatchingDeviceId说明它服务哪个硬件
两者之间靠设备实例里的 Driver 值连起来。
硬件一变,枚举出来的实例 ID 就变了。 这次遇到的就是这个:
- 用户的物理机上,这个设备是
ACPI\PNP0200\4&36e0039d&0 - 搬到虚拟机后,枚举出来的是
ACPI\PNP0200\4&25ee97c0&0 - 而注册表里记着的还是老的那个
链条断了,设备就"没有驱动"了 —— 7B 就是这么来的。
第四步:进 PE 修注册表
- 用 PE 启动,挂载目标系统的
system注册表 - 找一台硬件相同的正常机器,对照它的注册表看 —— 这是关键,别凭记忆改
- 把缺的项补上。这次是:在
Class下增加0128这一项(正常机器上是{4d36e97d-e325-11ce-bfc1-08002be10318}\0128,MatchingDeviceId = *pnp0200) - 所有报
CM_PROB_NOT_CONFIGURED的设备都要照此处理,别只修一个 —— 它们是一批一起坏的
第五步:可能会冒出第二个错误
修完前面那批,重启再看,可能又会出现新的:
DevNode 0xa2a03e78 for PDO 0xa2a9a690
InstancePath is "PCI\VEN_15AD&DEV_0740&SUBSYS_074015AD&REV_10\3&18d45aa6&0&3F"
State = DeviceNodeInitialized (0x302)
Previous State = DeviceNodeUninitialized (0x301)
Problem = CM_PROB_REGISTRY
Problem Status = 0x00000000
CM_PROB_REGISTRY 的意思是:这个设备对应的驱动服务没有在注册表里注册。
修法是去它的硬件注册表项里看它用哪个服务(这次是 vmci),然后把它在 services 下补上。
修完接着 !devnode 看,还会有没有别的 —— 一批批往下清,直到设备树干净。
小结
不猜、不试偏方。挂上调试器 → 看设备树 → 找到具体是哪个设备 → 对照一台正常机器把差异补齐。
7B 只是表象。设备树会告诉你到底是哪个设备、出的哪一种问题。
这套做法我用过很多次,每次都能把问题落到一个具体的设备上 —— 比对着错误码挨个试,是两个效率量级。