Windows 驱动调试(一):BSOD 0xA IRQL_NOT_LESS_OR_EQUAL 问题分析报告 日期 : 2026-03-21问题编号 : BSOD 0xA0 (BH202)影响产品 : Bayhub SD Host Controller (BH202)复现概率 : 1/50 machines × 1/3000 S4 cycles (WP# 开启时 <20%)状态 : ✅ 已解决
1. 问题概述 1.1 问题现象 在 Qualcomm + BH202 SD chip 平台上进行大量老化测试时,系统出现蓝屏死机 (BSOD) ,错误码为 0xA (IRQL_NOT_LESS_OR_EQUAL) 。
1.2 复现环境
环境配置
描述
复现概率
环境 1
BH202 V10039 驱动 + BIOS 开启 SD Write Protection Pin (WP#)
< 20%
环境 2
BH202 V10039 驱动 + BIOS 关闭 SD Write Protection Pin (WP#)
< 0.1%
1.3 核心结论
根本原因 : BH202 driver V10039 代码中的 notify 线程创建时间早于 notify 事件初始化时间 ,导致有概率发生空指针访问,进而触发 BSOD 0xA。
2. 错误码分析 2.1 BSOD 0xA 错误信息 1 2 3 4 IRQL_NOT_LESS_OR_EQUAL (a) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high. This is usually caused by drivers using improper addresses.
2.2 参数解析
参数
值
含义
Arg1
0x0000000000000000
访问的内存地址 (NULL)
Arg2
0x0000000000000002
发生访问时的 IRQL 级别
Arg3
0x0000000000000000
bit0=0 表示读操作,bit3=0 表示非执行操作
Arg4
fffff803a0459c94
触发访问的代码地址
2.3 错误解读 根据 Microsoft 官方文档 (Bug Check 0xA ):
Arg1 = 0 < 0x1000,符合 “the issue is likely a NULL pointer dereference “ 的描述
访问的地址为 0 (NULL) ,确认是空指针访问 导致的 BSOD
3. 内核堆栈分析 3.1 完整调用堆栈 1 2 3 4 5 6 7 8 9 10 11 12 STACK_TEXT: fffff684`a8609fb0 fffff803`a04b18f4 : nt!KeBugCheck2+0x2e8 fffff684`a860a5c0 fffff803`a082af24 : nt!KiAbortException+0x1d4 fffff684`a860a600 fffff803`a0803c5c : nt!KisSynchronousException+0x3791a4 fffff684`a860a6f0 fffff803`a080285c : nt!KzSynchronousException+0x24 fffff684`a860a750 fffff803`a0459c94 : nt!KeWaitForSingleObject+0x214 fffff684`a860ab70 fffff803`9e296108 : storport!StorPortExtendedFunction+0x2ab0 fffff684`a860acb0 fffff803`a0865f9c : bhtsdhubdr!thread_polling_notify+0xa8 [thread.c @ 768] fffff684`a860ad00 fffff803`a04e9c5c : nt!IopThreadStart+0x3c fffff684`a860ad30 fffff803`a0800bfc : nt!PspSystemThreadStartup+0x7c fffff684`a860ad90 00000000`00000000 : nt!KiStartSystemThread+0x24
3.2 堆栈解析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 KiStartSystemThread ↓ PspSystemThreadStartup ↓ IopThreadStart ↓ bhtsdhubdr!thread_polling_notify ← BSOD 发生点 ↓ storport!StorPortExtendedFunction ↓ nt!KeWaitForSingleObject ← 等待未初始化的事件对象 ↓ nt!KzSynchronousException ← 同步异常 ↓ nt!KiAbortException ↓ nt!KeBugCheck2 ← 系统蓝屏
3.3 故障点定位
项目
值
故障文件
F:\AE\bh202-arm-win\SDSTORDriver\sdstor\main\thread.c
故障行号
768
故障函数
bhtsdhubdr!thread_polling_notify+0xa8
故障原因
在 KeWaitForSingleObject 中访问 NULL 指针
4. 根因分析 4.1 问题本质 Driver 代码执行顺序错误 :
Notify 线程 先被创建
Notify Event 后才初始化
如果 Notify 线程在 Event 初始化前执行,就会访问 NULL 指针
4.2 触发条件分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌─────────────────────────────────────────────────────────────────────┐ │ Notify 线程调度时机问题 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ 场景: 主线程执行时间过长 │ │ │ │ │ ├── BIOS 开启 WP# → 主线程等待 IOCTL → CPU 占用时间长 │ │ │ │ │ └── BIOS 关闭 WP# → 主线程快速释放 → CPU 占用时间短 │ │ │ │ │ ▼ │ │ CPU 调度策略 │ │ │ │ │ ├── 主线程占用 CPU 很久 → Notify 线程被调度概率高 │ │ │ │ │ └── 主线程占用 CPU 很短 → Notify 线程被调度概率低 │ │ │ │ │ ▼ │ │ Notify 线程创建后立即执行 → Event 未初始化 → NULL 访问 → BSOD │ │ │ └─────────────────────────────────────────────────────────────────────┘
4.3 概率分析
因素
影响
WP# 开启
主线程需要等待 IOCTL 完成才释放 CPU,占用时间长,Notify 线程被立即调度概率高
WP# 关闭
主线程快速释放 CPU,占用时间短,Notify 线程被调度概率低
CPU 调度状态
取决于 Notify 线程创建时,CPU 是否处于”待调度”状态
4.4 OS 调度原理
根据操作系统原理,同级别 (IRQL) 的多个线程是分时复用 CPU 的。如果某线程已经占用 CPU 很长时间,CPU 就即将执行其他同级别线程。
5. 代码问题定位 5.1 问题代码流程 1 2 3 4 5 6 7 8 9 10 11 12 13 DriverEntry / StorHwPassiveInitialize │ ├── (1) os_create_thread() ← 线程在此创建 │ ↓ │ CPU 可能立即调度线程 │ ↓ │ thread_polling_notify() 执行 │ ↓ │ KeWaitForSingleObject(p->evt) ← evt 未初始化 = NULL! │ └── (2) win_init_event_mgr() ← 事件在后续才初始化 │ └── win_init_event() → StorPortInitializeEvent()
5.2 关键代码位置
文件
函数
行号
说明
winscsientry.c
StorHwPassiveInitialize
348
os_create_thread() 调用
winscsientry.c
scsi_HwInitialize
386
初始化入口
winapi.c
win_init_event_mgr
477+
Event 初始化
winapi.c
win_init_event
436
StorPortInitializeEvent
thread.c
thread_polling_notify
768
Notify 线程函数
5.3 时序图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ┌─────────────────────────────────────────────────────────────────────┐ │ V10039 驱动初始化时序 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ [主线程] [Notify 线程] │ │ │ │ │ │ │ ① DriverEntry │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ② scsi_HwInitialize │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ③ StorHwPassiveInitialize │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ④ os_create_thread() │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ │ │ CPU 调度 │ │ │ │ ▼ ▼ │ │ │ ⑤ thread 运行 │ │ │ ⚠ KeWaitForSingleObject(NULL) │ │ │ 💥 BSOD! │ │ │ │ │ │ │ ⑥ win_init_event_mgr() │ │ │ │──────────────────────────────► (如果还没崩溃) │ │ │ │ │ │ │ ⑦ win_init_event() │ │ │ │──────────────────────────────► │ │ │ │ │ │ ▼ ▼ │ │ │ └─────────────────────────────────────────────────────────────────────┘
6. 解决方案 6.1 推荐方案:代码修复 (V10040) 核心修改 : 保证 Notify Event 初始化早于 Notify 线程创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ┌─────────────────────────────────────────────────────────────────────┐ │ V10040 驱动初始化时序 (已修复) │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ [主线程] [Notify 线程] │ │ │ │ │ │ │ ① DriverEntry │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ② scsi_HwInitialize │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ③ StorHwPassiveInitialize │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ④ win_init_event_mgr() │ ✅ 先初始化所有事件 │ │ │──────────────────────────────► │ │ │ │ │ │ │ ⑤ win_init_event() │ │ │ │──────────────────────────────► │ │ │ │ │ │ │ ⑥ os_create_thread() │ ✅ 然后才创建线程 │ │ │──────────────────────────────► │ │ │ │ │ │ │ │ │ │ │ │ │ CPU 调度 │ │ │ │ ▼ ▼ │ │ │ ⑦ thread 运行 │ │ │ │ │ │ │ ✅ KeWaitForSingleObject(valid_evt) │ │ │ │ │ │ │ ▼ │ │ │ 正常工作 │ │ │ │ │ │ ▼ ▼ │ │ │ └─────────────────────────────────────────────────────────────────────┘
6.2 代码修改 修改位置 : winscsientry.c - StorHwPassiveInitialize
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 BOOLEAN StorHwPassiveInitialize (IN PVOID DeviceExtension) { os_create_thread(pdx, &pdx->os.thread[0 ], pdx, thread_main); return TRUE; } BOOLEAN StorHwPassiveInitialize (IN PVOID DeviceExtension) { win_init_event_mgr(pdx, &pdx->os.evt_mgr); os_create_thread(pdx, &pdx->os.thread[0 ], pdx, thread_main); return TRUE; }
6.3 Workaround 方案 如果不修改驱动代码,可通过 BIOS 设置 降低复现概率:
设置
效果
关闭 SD Write Protection Pin (WP#)
减少主线程占用 CPU 时间,降低 Notify 线程被立即调度的概率
注意 : 此方案仅能降低概率 ,无法根本解决问题 。
7. 影响范围评估 7.1 风险场景
场景
风险等级
说明
系统冷启动
中
驱动加载时可能触发
设备管理器 Disable/Enable
中
驱动重新初始化
S4 休眠唤醒
中
系统从休眠状态恢复
运行时热插拔
低
驱动已完全初始化
7.2 平台差异
平台
复现概率
原因
BIOS 开启 WP#
< 20%
主线程等待时间长
BIOS 关闭 WP#
< 0.1%
主线程等待时间短
AMD + Qualcomm
中
CPU 调度策略差异
8. 测试验证 8.1 验证计划
测试项
验证方法
预期结果
冷启动测试
100 次冷启动
0 次 BSOD
S4 循环测试
3000 次 S4
0 次 BSOD
Disable/Enable
50 次操作
0 次 BSOD
热插拔测试
100 次插拔
0 次 BSOD
8.2 回归测试 修复后需要验证:
✅ 正常读写功能不受影响
✅ 电源管理功能正常
✅ 性能无明显下降
9. 总结 9.1 问题回顾
项目
说明
问题现象
系统蓝屏 BSOD 0xA
根本原因
线程创建早于事件初始化,导致空指针访问
触发条件
CPU 调度策略 + 主线程执行时间
复现概率
1/50 machines × 1/3000 S4 cycles (WP# 开)
9.2 解决方案
方案
效果
推荐度
V10040 驱动修复
✅ 根本解决
⭐⭐⭐⭐⭐
关闭 BIOS WP#
⚠️ 降低概率
⭐⭐
9.3 经验教训
初始化顺序至关重要 : 驱动初始化时,必须保证资源在被使用前已完成初始化
线程创建风险 : 创建线程后应立即检查是否有竞态条件
系统调度不确定性 : 不能假设线程创建后不会立即执行
参考资料
Bug Check 0xA: IRQL_NOT_LESS_OR_EQUAL
KeWaitForSingleObject function
StorPortInitializeEvent
Thread Creation in Kernel Mode
文档生成日期: 2026-03-21 问题编号: BH202 BSOD 0xA0 驱动版本: V10039 → V10040