1. 1. Win10 Storport DmaRemappingCompatible 阻塞问题调试记录
    1. 1.1. 目录
      1. 1.1.1. PART 1:驱动分析
      2. 1.1.2. PART 2:调试过程记录
      3. 1.1.3. PART 3:调试方法
  2. 2. PART 1:驱动分析
    1. 2.1. 1.1 卡死时机分析
      1. 2.1.1. 1.1.1 结论更新(基于 Win10/Win11 日志对比)
      2. 2.1.2. 1.1.2 日志对比分析
        1. 2.1.2.1. Win10 日志(卡住)
        2. 2.1.2.2. Win11 日志(正常)
      3. 2.1.3. 1.1.3 时序对比图
      4. 2.1.4. 1.1.4 结论
    2. 2.2. 1.2 驱动中潜在的卡死点
      1. 2.2.1. 1.2.1 驱动加载时序图
      2. 2.2.2. 1.2.2 验证方案
        1. 2.2.2.1. 方案 1:在 os_alloc_dma_buffer 入口添加调试打印
      3. 2.2.3. 1.2.3 StorPortGetUncachedExtension 与 Win10 DMAR 兼容性分析
        1. 2.2.3.1. 问题背景
        2. 2.2.3.2. Win10 vs Win11 差异
        3. 2.2.3.3. 可能的卡死原因
        4. 2.2.3.4. 验证方法
      4. 2.2.4. 1.2.4 潜在卡死点详细分析
        1. 2.2.4.1. 卡死点 A:os_alloc_dma_buffer 中的 StorPortGetUncachedExtension(高优先级)
        2. 2.2.4.2. 卡死点 B:StorHwPassiveInitialize 中的 PowerFx 初始化(中优先级)
        3. 2.2.4.3. 卡死点 C:Storport 框架的 DMA Remapping 初始化(根本原因)
      5. 2.2.5. 1.2.5 为什么 Win11 不卡死?
      6. 2.2.6. 1.2.6 建议的调试方向
        1. 2.2.6.1. 步骤1:添加调试打印(最优先)
        2. 2.2.6.2. 步骤2:临时禁用 DmaRemappingCompatible
        3. 2.2.6.3. 步骤3:使用 WinDbg 内核调试
      7. 2.2.7. 1.3 代码位置速查表
      8. 2.2.8. 1.3.1 驱动加载相关函数
      9. 2.2.9. 1.3.2 DMA 相关 API
      10. 2.2.10. 1.3.3 关键代码片段
    3. 2.3. 1.4 调试过程记录(2026-03-19)
      1. 2.3.1. 1.4.1 阶段一:DIFx 日志对比分析
      2. 2.3.2. 1.4.2 阶段二:添加超时机制解决安装 Hang
      3. 2.3.3. 1.4.3 阶段三:WinDbg 日志确认 API 失败
      4. 2.3.4. 1.4.4 阶段四:改用 StorPortAllocateDmaMemory API
      5. 2.3.5. 1.4.5 调试流程总结
      6. 2.3.6. 1.4.6 调试结果分析(2026-03-20)
        1. 2.3.6.1. WinDbg 日志关键发现
        2. 2.3.6.2. 状态码分析
        3. 2.3.6.3. 问题根因分析
        4. 2.3.6.4. Win10 系统 IOMMU 状态验证
        5. 2.3.6.5. 可能的问题根因
        6. 2.3.6.6. 关键发现
        7. 2.3.6.7. 验证步骤
        8. 2.3.6.8. 总结
      7. 2.3.7. 1.4.7 阶段五:检查 MapBuffers 设置(2026-03-19)
      8. 2.3.8. 1.4.8 阶段六:MapBuffers 修改无效,确认 Storport 框架问题(2026-03-19)
      9. 2.3.9. 1.4.9 阶段七:DmaRemappingCompatible=2 测试(2026-03-20)
      10. 2.3.10. 1.4.10 阶段八:Win10 vs Win11 日志对比分析(2026-03-20)
      11. 2.3.11. 1.4.12 阶段九:IRP_MN_START_DEVICE 深入分析(2026-03-19)
        1. 2.3.11.1. 方案 1:禁用 DMA Remapping 兼容性(测试用)
        2. 2.3.11.2. 方案 2:驱动层捕获并覆盖错误
      12. 2.3.12. 1.4.11 阶段十:最终结论(2026-03-20)
  3. 3. PART 2:调试方法
    1. 3.1. 方法 1:启用 Driver Install Framework (DIFx) 日志
      1. 3.1.1. 1.1 启用 DIFx 日志
      2. 3.1.2. 1.2 查看安装日志
      3. 3.1.3. 1.3 日志内容解读
    2. 3.2. 方法 2:启用 Storport 驱动日志
      1. 3.2.1. 2.1 启用 Storport 日志
      2. 3.2.2. 2.2 使用 tracelog 捕获
      3. 3.2.3. 2.3 查看事件日志
    3. 3.3. 方法 3:内核调试 (Kernel Debugging)
      1. 3.3.1. 3.1 设置双机调试环境
        1. 3.3.1.1. 目标机 (Win10) 设置
        2. 3.3.1.2. 主机 (WinDbg) 设置
      2. 3.3.2. 3.2 加载符号
      3. 3.3.3. 3.3 关键断点位置
        1. 3.3.3.1. 注册表读取相关
        2. 3.3.3.2. DMA Remapping 初始化
        3. 3.3.3.3. PnP 安装相关
        4. 3.3.3.4. 可能阻塞的位置
        5. 3.3.3.5. DMAR/IOMMU 相关
      4. 3.3.4. 3.4 诊断命令
        1. 3.3.4.1. 查看卡住的线程和进程
        2. 3.3.4.2. 查看 IRP
        3. 3.3.4.3. 查看 DMA 信息
      5. 3.3.5. 3.5 使用脚本自动设置断点
    4. 3.4. 方法 4:ETW 跟踪
      1. 3.4.1. 4.1 使用 tracelog
      2. 3.4.2. 4.2 使用 WPR (Windows Performance Recorder)
      3. 3.4.3. 4.3 分析 ETW 跟踪
      4. 3.4.4. 4.4 使用 TraceView
    5. 3.5. 方法 5:Process Monitor 监控 INF 处理
      1. 3.5.1. 5.1 下载和设置
      2. 3.5.2. 5.2 过滤器设置
      3. 3.5.3. 5.3 观察要点
      4. 3.5.4. 5.4 导出日志
    6. 3.6. 方法 6:检查 Storport 与 ACPI/DMAR 表的交互
      1. 3.6.1. 6.1 检查 DMAR 表
      2. 3.6.2. 6.2 查看 ACPI 表内容
      3. 3.6.3. 6.3 WinDbg 中检查 DMA remapping 状态
      4. 3.6.4. 6.4 检查 _DMA 方法
    7. 3.7. 推荐调试顺序
    8. 3.8. 常见问题排查清单
      1. 3.8.1. 安装阶段卡死
      2. 3.8.2. 内核调试无响应
      3. 3.8.3. 符号加载失败
      4. 3.8.4. ETW 跟踪为空
    9. 3.9. 获取帮助
      1. 3.9.1. 相关文档
      2. 3.9.2. 工具下载

Windows存储驱动开发(三):Win10 Storport DmaRemappingCompatible阻塞问题调试

Win10 Storport DmaRemappingCompatible 阻塞问题调试记录

日期: 2026-03-08
项目: Bayhub SD Host Controller Storport 驱动
目的: 调试 Bayhub 驱动在 Win10 上因 DmaRemappingCompatible 导致安装卡死的问题
适用: Windows 10 + Kernel DMA Protection + Storport Miniport


目录

PART 1:驱动分析

  1. 1.1 卡死时机分析
  2. 1.2 驱动中潜在的卡死点
  3. 1.3 代码位置速查表

PART 2:调试过程记录

1.4. 1.4 调试过程记录(2026-03-19)

PART 3:调试方法

  1. 2.1 启用 DIFx 日志
  2. 2.2 启用 Storport 驱动日志
  3. 2.3 内核调试 (Kernel Debugging)
  4. 2.4 ETW 跟踪
  5. 2.5 Process Monitor 监控
  6. 2.6 检查 ACPI/DMAR 表
  7. 推荐调试顺序
  8. WinDbg 关键断点脚本

PART 1:驱动分析

1.1 卡死时机分析

1.1.1 结论更新(基于 Win10/Win11 日志对比)

分析角度 最初假设 日志验证结论
卡死时机 安装阶段,驱动代码不执行 驱动代码执行,卡死在 PnP Start: 之后
卡死阶段 AddService 阶段 DriverEntry 加载后
日志表现 - Win10 日志在 Start: 后中断,乱码
根因位置 Storport 框架 Storport 框架或驱动的 DMA 初始化

1.1.2 日志对比分析

Win10 日志(卡住)

1
2
3
4
11:20:45.955  {Restarting Devices} 11:20:45.955
dvi: Query-remove: PCI\VEN_1217&DEV_9860&SUBSYS_232C17AA...
dvi: Start: PCI\VEN_1217&DEV_9860&SUBSYS_232C17AA...
<乱码/无响应>

关键发现

  • 日志在 Start: 之后完全中断
  • 之后是乱码,说明系统已卡死或崩溃
  • 驱动代码已执行(因为进入了 Start 阶段)

Win11 日志(正常)

1
2
3
19:55:15.259  Install Device: Starting device 'PCI\VEN_1217&DEV_9860...'
19:55:15.259 Install Device: Starting device completed.
19:55:15.259 !!! Device not started: Device has problem: 0x37 (CM_PROB_CONSOLE_LOCKED)

关键发现

  • Starting devicecompleted 在同一毫秒完成(0ms 耗时)
  • 问题代码 0x37CM_PROB_CONSOLE_LOCKED(会话锁定),不是驱动问题
  • Win11 驱动加载/初始化快速完成

1.1.3 时序对比图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
                    Win10                          Win11
│ │
INF解析 ─────────────┼───────────────────────────────┼────→ 正常
│ │
AddService ──────────┼───────────────────────────────┼────→ 正常
│ │
Starting device ─────┼───────────────────────────────┼────→ 正常
│ │
Start: ──────────────┼───────────────────────────────┼────→ completed (0ms)
│ │
│ ★ 卡死发生在这里 ★ │
│ (DriverEntry 执行 │
│ scsi_HwFindAdapter │
│ → os_alloc_dma_buffer) │
│ │
↓ ↓
卡死/无响应 CM_PROB_CONSOLE_LOCKED
(setupapi.log中断) (会话锁定,非驱动问题)

1.1.4 结论

确认:驱动代码会执行,卡死发生在驱动加载的 DMA 缓冲区分配阶段。


1.2 驱动中潜在的卡死点

基于 Win10/Win11 日志对比,确认卡死发生在驱动加载阶段。

1.2.1 驱动加载时序图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PnP Manager (Start:)

Storport 框架加载 bhtsddr.sys 到内存

DriverEntry (line 2675, winscsientry.c)

StorPortInitialize (line 2908, winscsientry.c)

scsi_HwFindAdapter (line 989, winscsientry.c) ← 第一个被调用的 Hw 函数

os_alloc_dma_buffer (line 1208, winscsientry.c) ← ★ 最可能的卡死点

StorPortGetUncachedExtension ← 关键 API(winapi.c:2020)

(卡死发生在这里)

1.2.2 验证方案

方案 1:在 os_alloc_dma_buffer 入口添加调试打印

目的:验证卡死确实在这个函数内部

修改文件SDSTORDriver/sdstor/windows_os/winapi.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool os_alloc_dma_buffer(void * pdx, void * ctx, u32 nbytes, dma_desc_buf_t * pdma)
{
// 添加调试打印 - 验证函数是否被调用
DbgInfo(MODULE_OS_API, FEATURE_DRIVER_INIT, NOT_TO_RAM,
"[DEBUG] Enter os_alloc_dma_buffer, size=0x%x, retry=%d\n",
nbytes, pdma->retry_count);

for(retry = 1; retry < 10; retry++)
{
pdma->va = (OS_PortSetGetUncacheedExtension(pdx, ConfigInfo, pdma->len));

// 添加调试打印 - 验证 GetUncachedExtension 是否返回
if(pdma->va == NULL) {
DbgInfo(MODULE_OS_API, FEATURE_DRIVER_INIT, NOT_TO_RAM,
"[DEBUG] GetUncachedExtension() returned NULL, retry %d\n", retry);
}
else {
DbgInfo(MODULE_OS_API, FEATURE_DRIVER_INIT, NOT_TO_RAM,
"[DEBUG] GetUncachedExtension() succeeded!\n");
break;
}
}
// ...
}

预期结果

  • 如果打印了 Enter os_alloc_dma_buffer 但没有 GetUncachedExtension() returned NULL/succeeded → 确认卡死在 GetUncachedExtension 调用中
  • 如果连 Enter 都没有打印 → 卡死在 os_alloc_dma_buffer 之前

1.2.3 StorPortGetUncachedExtension 与 Win10 DMAR 兼容性分析

问题背景

当 INF 中设置 DmaRemappingCompatible=1 时,Storport 框架会以 DMA Remapping 兼容模式 初始化 DMA 子系统。

Win10 vs Win11 差异

方面 Win10 Win11
Storport 版本 较旧 (19041+) 较新 (22000+)
DMA Remapping 框架 2018-2020 版本 2021+ 版本
GetUncachedExtension 行为 可能同步阻塞 异步处理
IOMMU 超时机制 可能不完善 已修复

可能的卡死原因

1
2
3
4
5
6
7
8
9
10
11
12
13
DmaRemappingCompatible=1

Storport 调用 StorPortGetUncachedExtension

Storport 框架检查 IOMMU/DMAR 表

Win10: 同步等待 IOMMU 响应 ──────────────────→ 卡死

├── DMAR 表解析超时
├── IOMMU 无响应
└── 死锁 (IOMMU 锁 vs 系统锁)

Win11: 异步处理或超时机制完善 ───────────────→ 正常完成

验证方法

方法 A:检查 Win10 Storport 版本

1
2
# 查看 storport.sys 版本
Get-FileHash C:\Windows\System32\drivers\storport.sys

方法 B:检查 DMA remapping 状态

1
2
# 在 WinDbg 中检查
!ioctldma

方法 C:临时禁用 DmaRemappingCompatible 测试

修改 INF 文件:

1
2
3
4
5
; 原始设置
HKLM,...\Parameters\DmaRemappingCompatible = 0x00010001 ; DWORD = 1

; 临时禁用
HKLM,...\Parameters\DmaRemappingCompatible = 0x00010001 ; DWORD = 0

如果禁用后安装正常 → 确认是 DmaRemappingCompatible 相关问题

1.2.4 潜在卡死点详细分析

卡死点 A:os_alloc_dma_buffer 中的 StorPortGetUncachedExtension(高优先级)

文件位置SDSTORDriver/sdstor/windows_os/winapi.c:2004-2030

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bool os_alloc_dma_buffer(void * pdx, void * ctx, u32 nbytes, dma_desc_buf_t * pdma)
{
for(retry = 1; retry < 10; retry++)
{
pdma->va = (OS_PortSetGetUncacheedExtension(pdx, ConfigInfo, pdma->len));
// ↑
// 这个宏在不同 OS 版本可能映射到:
// - ScsiPortGetUncachedExtension (ScsiPort模式)
// - StorPortGetUncachedExtension (Storport模式)
if(pdma->va == NULL) {
DbgInfo(..., "GetUncachedExtension() failed!!!,retry %d\n", retry);
}
else break;
}
if(pdma->va == NULL) {
DbgErr("GetUncachedExtension(%xh) failed!!!\n", pdma->len);
return FALSE;
}
}

卡死原因

  • 当 INF 声明了 DmaRemappingCompatible=1
  • StorPortGetUncachedExtension 尝试分配符合 IOMMU/DMAR 要求的缓冲区
  • 在 Win10 上,这个过程可能触发同步等待(等待 IOMMU/DMAR 表解析)
  • 如果 IOMMU 无响应或超时机制不完善 → 整个调用卡死

卡死点 B:StorHwPassiveInitialize 中的 PowerFx 初始化(中优先级)

文件位置SDSTORDriver/sdstor/windows_os/winscsientry.c:370-453

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
BOOLEAN StorHwPassiveInitialize(IN PVOID DeviceExtension)
{
...
// line 396: 获取 D3Cold 支持
status = StorPortGetD3ColdSupport(DeviceExtension, NULL, &enableD3Cold);

...

// line 430: 初始化 PowerFx
status = StorPortInitializePoFxPower(DeviceExtension, NULL,
(PSTOR_POFX_DEVICE)(&(pdx->os.AdptPoFxDevice)), &enableD3Cold);

if(status != STOR_STATUS_SUCCESS)
{
pdx->os.StateFlags.PoFxEnabled = FALSE;
pdx->os.StateFlags.PoFxActive = FALSE;
goto Exit; // ← 失败时跳过后续
}

// register success
win_rtd3_req_wait_wake(pdx); // ← 注意这个函数

pdx->os.StateFlags.PoFxEnabled = TRUE;
pdx->os.StateFlags.PoFxActive = TRUE;
Exit:
return TRUE;
}

卡死原因分析

  • StorPortInitializePoFxPower 是 Power Management Framework 初始化
  • 在 Win10 上可能与 DMA remapping 初始化有依赖关系
  • 如果 DMA remapping 初始化未完成,PowerFx 可能等待

卡死点 C:Storport 框架的 DMA Remapping 初始化(根本原因)

这是最可能的根因位置

1
2
3
4
5
6
7
8
9
10
11
12
bayhub 驱动声明 DmaRemappingCompatible=1

Storport 框架读取该注册表键

Storport 尝试以 "DMA remapping 兼容" 模式初始化 DMA 子系统

在 Win10 上,这个初始化可能需要:
- 与 IOMMU/VT-d 进行 ACPI 表查询
- 验证 DMA 路径
- 建立 IOVA 映射

如果任何步骤在 Win10 上超时或死锁 → 整个驱动加载卡死

1.2.5 为什么 Win11 不卡死?

方面 Win10 Win11
Storport 版本 较旧 (19041+) 较新 (22000+)
DMA Remapping 框架 2018-2020 版本 2021+ 版本
GetUncachedExtension 行为 可能同步阻塞 异步处理
IOMMU 超时机制 可能不完善 已修复
IOMMU 集成 松散耦合 紧密集成

1.2.6 建议的调试方向

步骤1:添加调试打印(最优先)

os_alloc_dma_buffer 函数入口添加调试打印,验证卡死位置:

1
2
3
4
5
6
bool os_alloc_dma_buffer(void * pdx, void * ctx, u32 nbytes, dma_desc_buf_t * pdma)
{
DbgInfo(MODULE_OS_API, FEATURE_DRIVER_INIT, NOT_TO_RAM,
"[DEBUG] Enter os_alloc_dma_buffer, size=0x%x\n", nbytes);
// ... 原有代码 ...
}

验证结果:

  • 如果打印了 Enter 但没有后续日志 → 确认卡死在函数内部
  • 如果连 Enter 都没有 → 卡死在更早的位置

步骤2:临时禁用 DmaRemappingCompatible

修改 INF 文件,临时禁用:

1
2
; 临时禁用
HKLM,...\Parameters\DmaRemappingCompatible = 0x00010001 ; DWORD = 0

如果禁用后安装正常 → 确认是 DmaRemappingCompatible 相关问题

步骤3:使用 WinDbg 内核调试

在 WinDbg 中设置断点:

1
2
bp bhtsddr!os_alloc_dma_buffer "kv; g"
bp storport!StorPortGetUncachedExtension "kv; g"

1.3 代码位置速查表

1.3.1 驱动加载相关函数

函数名 文件:行号 功能 卡死风险
DriverEntry winscsientry.c:2675 驱动入口点
scsi_HwFindAdapter winscsientry.c:989 适配器查找和初始化
os_alloc_dma_buffer winapi.c:2004 DMA缓冲区分配 最高
StorHwPassiveInitialize winscsientry.c:370 被动初始化回调
scsi_HwInitialize winscsientry.c:488 硬件初始化

1.3.2 DMA 相关 API

API 说明 与DMAR的关系
StorPortGetUncachedExtension 分配公共缓冲区 关键:在DMAR环境下分配符合要求的缓冲区
StorPortAllocateDmaMemory 分配DMA内存 返回IOVA而非PA
StorPortMapDmaTransfer DMA映射传输 使用IOVA
StorPortGetD3ColdSupport 查询D3Cold支持 可能与DMAR交互
StorPortInitializePoFxPower PowerFx初始化 可能与DMAR有依赖

1.3.3 关键代码片段

关键点1:Dma64BitAddresses 配置 (winscsientry.c:1133-1148)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(SCSI_DMA64_SYSTEM_SUPPORTED == ConfigInfo->Dma64BitAddresses &&
(dma_address_range_mode) &&
((pdev_ext->host.chip_type == CHIP_SEAEAGLE2) ||
(pdev_ext->host.chip_type == CHIP_GG8) ||
(pdev_ext->host.chip_type == CHIP_ALBATROSS)) &&
(pdev_ext->dump_mode == FALSE))
{
ConfigInfo->Dma32BitAddresses = FALSE;
ConfigInfo->Dma64BitAddresses = SCSI_DMA64_MINIPORT_SUPPORTED;
DbgInfo(MODULE_OS_ENTRY, FEATURE_DRIVER_INIT, NOT_TO_RAM, "cfg 64bit address\n");
}
else
{
cfg_dma_addr_range_dec(pdev_ext->cfg, 0);
ConfigInfo->Dma32BitAddresses = TRUE;
DbgInfo(MODULE_OS_ENTRY, FEATURE_DRIVER_INIT, NOT_TO_RAM, "cfg 32bit address\n");
}

关键点2:MapBuffers 配置 (winscsientry.c:1255-1288)

原始逻辑(已修改):

1
2
3
4
5
6
7
if(FALSE == cfg_dma_need_sdma_like_buffer(pdev_ext->cfg->host_item.test_dma_mode_setting.dma_mode))
ConfigInfo->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
else
ConfigInfo->MapBuffers = STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE;

if(pdev_ext->dump_mode == TRUE)
ConfigInfo->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;

修改后逻辑(2026-03-19):

  • 在 DMA remapping 模式下(DmaRemappingCompatible=12),强制使用 STOR_MAP_NON_READ_WRITE_BUFFERS
  • 与 StorAHCI 示例驱动行为一致
  • 可能解决 Win10 上的 STATUS_INSUFFICIENT_RESOURCES 问题

详见 1.4.7 阶段五:检查 MapBuffers 设置


1.4 调试过程记录(2026-03-19)

1.4.1 阶段一:DIFx 日志对比分析

时间:2026-03-19 初始分析

方法:对比 Win10 和 Win11 的 setupapi.dev.log 安装日志

发现

  • Win10 日志:在 Start: PCI\VEN_1217&DEV_9860... 之后日志中断,出现乱码,系统卡死
  • Win11 日志Starting devicecompleted 在同一毫秒完成(0ms),问题代码为 CM_PROB_CONSOLE_LOCKED(会话锁定,非驱动问题)

结论

  • ✅ 确认卡死发生在驱动加载后(Start: 阶段之后)
  • ✅ 驱动代码确实在执行(DriverEntryscsi_HwFindAdapteros_alloc_dma_buffer
  • ✅ 卡死发生在 DMA 缓冲区分配阶段

相关文件

  • setupapi-win10.dev.log:Win10 卡死日志
  • setupapi-win11.dev.log:Win11 正常安装日志

1.4.2 阶段二:添加超时机制解决安装 Hang

时间:2026-03-19

问题scsi_HwFindAdapter 中的 while(1) 循环在 DMA 分配失败时导致无限循环,系统卡死

修改

  1. 文件SDSTORDriver/sdstor/windows_os/winscsientry.c

    • while(1) 改为 for(;;) 循环
    • 添加 10 秒总超时机制(使用 util_init_waitlooputil_is_timeout
    • 在每次 os_alloc_dma_buffer 调用前检查超时
  2. 文件SDSTORDriver/sdstor/windows_os/winapi.c

    • 简化 os_alloc_dma_buffer,移除内部 30 秒超时(由外层统一管理)

代码变更

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// winscsientry.c: 添加超时控制
loop_wait_t while_loop_wait;
util_init_waitloop(pdev_ext, 10000, 0, &while_loop_wait); // 10秒总超时

for(;;) // 禁止使用 while(1)
{
// 检查超时
if(util_is_timeout(&while_loop_wait))
{
DbgErr("[WHILE_TIMEOUT] DMA buffer allocation timeout after 10s total!\n");
ret = FALSE;
break;
}

ret = os_alloc_dma_buffer(pdev_ext, ConfigInfo, buf_size, &pdev_ext->dma_buff);
if(TRUE == ret) break;

buf_size = buf_size / 2; // 减半重试
}

结果

  • ✅ 解决了安装过程中的系统卡死问题
  • ✅ 驱动在 10 秒超时后优雅失败,不再 hang 系统
  • ⚠️ 但设备仍无法启动(DMA 分配失败)

1.4.3 阶段三:WinDbg 日志确认 API 失败

时间:2026-03-19

方法:使用 WinDbg 内核调试器抓取驱动加载日志

关键发现(WinDbg 日志片段):

1
2
3
4
5
6
7
8
9
10
行 594: BHT-OSAPI  : [DMA_ALLOC] Attempt 1/10, calling StorPortGetUncachedExtension(0x113eaa0)...
行 600: BHT-OSAPI : GetUncachedExtension() failed!!!,retry 1
行 601: BHT-OSAPI : [DMA_ALLOC] Attempt 2/10, calling StorPortGetUncachedExtension(0x113eaa0)...
行 607: BHT-OSAPI : GetUncachedExtension() failed!!!,retry 2
...
行 657: BHT-ERROR : GetUncachedExtension(113eaa0h) failed after 9 retries!!!
行 658: BHT-OSENTRY: os alloc dma buf len 8b2d50 (buf_size 减半)
行 659: BHT-OSAPI : Enter os_alloc_dma_buffer size=8b2d50h
...
(重复多次,直到 10 秒超时)

关键观察

  1. StorPortGetUncachedExtension 立即返回 NULL(非阻塞)
  2. ✅ 每次失败后触发 PnP IRP_MN_QUERY_INTERFACE 查询
  3. ✅ 重试 9 次后,buf_size 减半继续尝试(113eaa0 → 8b2d50 → 46cea8 → 249f54…)
  4. ✅ 所有尝试均失败,直到 10 秒超时
  5. ✅ 重启后设备无法启动,显示错误代码 10(系统资源不足)

结论

  • StorPortGetUncachedExtension 在 Win10 + DMAR compatible 环境下无法工作
  • ❌ API 立即返回 NULL,不是阻塞问题,而是不兼容 Win10 DMAR 模式
  • ✅ 之前的 while(1) 没有超时导致安装 hang 问题已解决
  • ⚠️ 根因:需要改用其他 Storport DMA 分配 API

设备管理器错误

  • 错误代码:10(STATUS_INSUFFICIENT_RESOURCES
  • 错误信息:”该设备无法启动。系统资源不够,无法完成 API。”

1.4.4 阶段四:改用 StorPortAllocateDmaMemory API

时间:2026-03-19

问题根因

  • StorPortGetUncachedExtension 在 Win10 DMAR 环境下不兼容
  • 需要改用 Microsoft 推荐的 DMA remapping 兼容 API

解决方案
参考 Microsoft StorAHCI 示例驱动(Windows-driver-samples/storage/miniports/storahci/src/common.h),使用 StorPortAllocateDmaMemory API。

API 对比

API 说明 Win10 DMAR 兼容性 返回值
StorPortGetUncachedExtension 旧式 DMA 缓冲区分配 不兼容(立即返回 NULL) 虚拟地址
StorPortAllocateDmaMemory Microsoft 推荐的 DMAR API 兼容 虚拟地址 + IOVA

关键差异

  • StorPortGetUncachedExtension:返回物理地址(PA),在 DMAR 环境下不适用
  • StorPortAllocateDmaMemory:返回 IOVA(IO Virtual Address),专为 DMA remapping 设计

代码修改

  1. 文件SDSTORDriver/sdstor/windows_os/winapi.c

    • 修改 os_alloc_dma_buffer:使用 BhtAllocateDmaBuffer(内部调用 StorPortAllocateDmaMemory)替代 StorPortGetUncachedExtension
    • 修改 os_free_dma_buffer:使用 BhtFreeDmaBuffer(内部调用 StorPortFreeDmaMemory)释放内存
  2. 已有函数

    • BhtAllocateDmaBufferwinapi.c:4096):已实现,基于 StorAHCI 模式
    • BhtFreeDmaBufferwinapi.c:4148):已实现,基于 StorAHCI 模式

修改后的 os_alloc_dma_buffer 逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool os_alloc_dma_buffer(void * pdx, void * ctx, u32 nbytes, dma_desc_buf_t * pdma)
{
ULONG status;
void* buffer_va = NULL;
phy_addr_t buffer_pa;

// DMAR Fix: Use StorPortAllocateDmaMemory instead of StorPortGetUncachedExtension
status = BhtAllocateDmaBuffer(pdx, pdma->len, &buffer_va, &buffer_pa);

if(status != STOR_STATUS_SUCCESS || buffer_va == NULL)
{
DbgErr("BhtAllocateDmaBuffer(StorPortAllocateDmaMemory) failed! status=0x%X\n", status);
return FALSE;
}

pdma->va = buffer_va;
pdma->pa = buffer_pa; // 注意:这是 IOVA,不是物理地址

// 对齐处理...
return TRUE;
}

预期效果

  • StorPortAllocateDmaMemory 在 Win10 DMAR 环境下应能正常工作
  • ✅ 返回的地址是 IOVA,符合 DMA remapping 要求
  • ✅ 设备应能正常启动

下一步调试

  • 重新编译驱动并测试
  • 使用 WinDbg 验证 StorPortAllocateDmaMemory 是否成功
  • 检查设备是否能正常启动

1.4.5 调试流程总结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
阶段一:DIFx 日志对比

确认:卡死发生在驱动加载后(Start: 之后)

阶段二:添加超时机制

解决:安装 hang 问题(while(1) 无限循环)

阶段三:WinDbg 日志分析

确认:StorPortGetUncachedExtension 在 Win10 DMAR 下失败

阶段四:改用 StorPortAllocateDmaMemory

**DMA 分配成功,但 START_DEVICE 返回 0xC000009A**

设备管理器:Code 10(STATUS_INSUFFICIENT_RESOURCES)

**根因:Win10 测试系统可能无 IOMMU 支持**

**建议:使用原生 Win10 系统(有 IOMMU)进行测试**

1.4.6 调试结果分析(2026-03-20)

WinDbg 日志关键发现

DMA 分配成功(✅):

1
2
3
行 264:  BHT-ERROR  : DMAR_DIAG: BhtAllocateDmaBuffer: VA=FFFFEF7B80C00000 IOVA=0x000000007224B000 len=18082464
行 265: BHT-OSAPI : BhtAllocateDmaBuffer succeeded: VA=FFFFEF7B80C00000, IOVA=0x7224B000, len=0x113eaa0
行 269: BHT-OSAPI : Exit os_alloc_dma_buffer

驱动初始化完成(✅):

1
行 905:  BHT-OSENTRY: Exit StorHwPassiveInitialize

PnP START_DEVICE 失败(❌):

1
行 2911: BHT-OSENTRY: Exit BHTDispatchPnp, status=0xC000009A

设备被移除

1
行 2913: BHT-OSENTRY: Enter BHTDispatchPnp - MinorFunction: (IRP_MN_REMOVE_DEVICE)

状态码分析

状态码 含义 来源
0xC000009A STATUS_INSUFFICIENT_RESOURCES Storport 框架返回
Code 10 “该设备无法启动。系统资源不够,无法完成 API。” 设备管理器

问题根因分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Win10 测试系统(无 IOMMU):
├── 驱动声明 DmaRemappingCompatible=1
├── 驱动调用 StorPortAllocateDmaMemory
├── DMA 缓冲区分配成功(返回 IOVA)
├── Storport 尝试验证 DMA 路径
├── Storport 检查 IOMMU 状态
├── 发现 IOMMU 不存在或被禁用
└── Storport 返回 STATUS_INSUFFICIENT_RESOURCES

OEM Win10 系统(有 IOMMU):
├── 驱动声明 DmaRemappingCompatible=1
├── 驱动分配 DMA 缓冲区(成功)
├── Storport 验证 DMA 路径(通过)
└── 设备正常启动

Win10 系统 IOMMU 状态验证

更正:通过 msinfo32 确认 Kernel DMA Protection 已启用,说明:

  • ✅ IOMMU 硬件存在且已启用
  • ✅ BIOS 已正确配置 VT-d/IOMMU
  • ✅ Windows 已检测到并启用了 Kernel DMA Protection

因此,问题不是 IOMMU 不存在,而是其他原因。

可能的问题根因

可能原因 说明 可能性
Win10 Storport 版本问题 Win10 (19041) Storport 对 DMA remapping 支持不完善,在验证/使用 IOVA 时失败
IOVA 地址范围限制 虽然 IOVA 在 2GB 范围内(0x7224B000),但 Storport 可能对某些地址范围有特殊要求
DMA 缓冲区配置 缓冲区大小、对齐或缓存类型可能不符合 Storport 在 Win10 上的要求
Storport 框架 Bug Win10 Storport 在处理 DMA remapping 兼容驱动时的已知 bug

关键发现

从日志分析:

  • DMA 分配成功BhtAllocateDmaBuffer 成功返回 IOVA=0x7224B000
  • 驱动初始化完成:所有驱动初始化步骤成功
  • Storport 框架返回错误Exit BHTDispatchPnp, status=0xC000009A不是驱动代码返回的

结论:驱动代码已正确实现(使用 StorPortAllocateDmaMemory),但 Win10 Storport 框架在处理 DMA remapping 时返回 STATUS_INSUFFICIENT_RESOURCES

验证步骤

  1. 检查测试系统是否有 IOMMU

    1
    2
    3
    4
    5
    6
    7
    # 检查系统信息
    msinfo32.exe
    # 查找 "IOMMU" 或 "VT-d" 或 "AMD-Vi"

    # 或在 WinDbg 中
    !amddeviceinfo # AMD
    !intelinfo # Intel
  2. 检查 BIOS 设置

    • 进入 BIOS/UEFI
    • 查找 “Intel VT-d” 或 “AMD-Vi” 或 “IOMMU”
    • 确保已启用
  3. 尝试禁用 DmaRemappingCompatible 测试

    1
    2
    ; 在 INF 中临时禁用
    HKLM,...\Parameters\DmaRemappingCompatible = 0x00010001 ; DWORD = 0

    重要发现:根据 Microsoft 官方文档,DmaRemappingCompatible 值含义:

    含义 Windows 10 支持
    0 Opt-out
    1 Opt-in (完全) ⚠️ 可能导致问题
    2 Opt-in,仅外部设备或 Driver Verifier 推荐
    3 Opt-in (仅 Windows 11+) ❌ Windows 10 不支持

    建议:先尝试 值=0(禁用),确认是否是 DmaRemappingCompatible 导致的问题。然后尝试 值=2

  4. 尝试 DmaRemappingCompatible=2

    1
    2
    ; 值 2:在 Windows 10 上更安全
    HKLM,...\Parameters\DmaRemappingCompatible = 0x00010001 ; DWORD = 2
  5. 使用原生 Win10 系统测试

    • 使用 OEM 台式机或笔记本(通常有 IOMMU)
    • 或使用支持 VT-d 的服务器系统

总结

调试阶段 结果 说明
阶段一: DIFx 日志对比 ✅ 完成 确认卡死发生在驱动加载后
阶段二:添加超时机制 ✅ 完成 解决了安装 hang 问题
阶段三:WinDbg 日志分析 ✅ 完成 确认 StorPortGetUncachedExtension 在 Win10 DMAR 下失败
阶段四:改用 StorPortAllocateDmaMemory ✅ 完成 DMA 分配成功,但 START_DEVICE 失败
阶段五:验证 IOMMU 状态 ✅ 完成 确认 Kernel DMA Protection 已启用,IOMMU 存在
阶段六:检查 MapBuffers 设置 ✅ 完成 在 DMA remapping 模式下强制使用 STOR_MAP_NON_READ_WRITE_BUFFERS
阶段七:MapBuffers 修改无效 ❌ 失败 修改 MapBuffers 后仍出现 Code 10,重启时失败
阶段八:DmaRemappingCompatible=2 测试 ❌ 失败 同样返回 status=0xC000009A
阶段九:Win10 vs Win11 日志对比 ✅ 完成 确认问题在 Storport 框架,不是驱动代码

结论

  1. 驱动代码已修复:使用 StorPortAllocateDmaMemory 替代 StorPortGetUncachedExtension
  2. DMA 分配成功BhtAllocateDmaBuffer 成功返回 IOVA=0x7223B000
  3. IOMMU 已启用:通过 msinfo32 确认 Kernel DMA Protection 已启用
  4. Win10 vs Win11 对比
    • Win10:Storport 返回 status=0xC000009A,设备被移除
    • Win11:Storport 返回 status=0x00000000,设备正常工作
  5. DmaRemappingCompatible=2 也失败:与值=1 一样,返回 status=0xC000009A
  6. MapBuffers 修改无效:强制使用 STOR_MAP_NON_READ_WRITE_BUFFERS 后问题依然存在
  7. BHTDispatchPnp 代码不是问题来源0xC000009A 来自 SavedDispatchPnp(Storport 框架)

根因确认:这是 Windows 10 Storport 框架在处理 DMA remapping 兼容驱动时的已知问题,不是驱动代码问题。

建议的下一步调试步骤

  1. 尝试禁用 DmaRemappingCompatible(值=0):确认是否是 DMA remapping 导致的问题
  2. 尝试 DmaRemappingCompatible=2:仅在外部设备或 Driver Verifier 时启用,更安全
  3. 参考 Microsoft 文档StorPortAllocateDmaMemoryStorPortAllocateContiguousMemorySpecifyCacheNode 的扩展版本,底层相同
  4. 使用 Driver Verifier 测试:Microsoft 文档建议在测试 DMA remapping 时启用 Driver Verifier

1.4.7 阶段五:检查 MapBuffers 设置(2026-03-19)

时间:2026-03-19

问题:在 DMA remapping 模式下,STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE 可能与 Storport 的 DMA remapping 处理冲突,导致 STATUS_INSUFFICIENT_RESOURCES

分析

  1. StorAHCI 示例驱动行为

    • StorAHCI 使用 STOR_MAP_NON_READ_WRITE_BUFFERS
    • StorAHCI 未声明 DmaRemappingCompatible(使用默认值)
  2. 当前驱动行为

    • 根据 DMA 模式动态设置 MapBuffers
      • 非 SDMA-like 模式:STOR_MAP_NON_READ_WRITE_BUFFERS
      • SDMA-like 模式:STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE
    • 在 DMA remapping 模式下,STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE 可能不兼容
  3. 问题根因假设

    • STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE 要求 Storport 为所有缓冲区(包括 READ/WRITE)提供虚拟地址映射
    • 在 DMA remapping 模式下,Storport 需要处理 IOVA 映射
    • Win10 Storport 可能无法同时满足这两个要求,导致验证失败

修改

winscsientry.cscsi_HwFindAdapter 函数中,添加 DMA remapping 检测逻辑:

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
38
39
40
// DMAR Fix: Check DmaRemappingCompatible setting
// In DMA remapping mode, STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE may cause
// STATUS_INSUFFICIENT_RESOURCES on Win10. Force STOR_MAP_NON_READ_WRITE_BUFFERS.
ULONG dmaRemappingCompatible = 0;
ULONG dmaRemappingSize = sizeof(ULONG);
PUCHAR dmaRemappingBuf = StorPortAllocateRegistryBuffer(pdev_ext, &dmaRemappingSize);
PVOID dmaRemappingBufp = &dmaRemappingBuf;
CHAR dmaRemappingKeyName[256];
strcpy_s(&dmaRemappingKeyName[0], 256, "Parameters");
if(StorPortRegistryReadAdapterKey((PVOID)pdev_ext, (PUCHAR)&dmaRemappingKeyName,
"DmaRemappingCompatible", REG_DWORD,
dmaRemappingBufp, &dmaRemappingSize) == STOR_STATUS_SUCCESS)
{
dmaRemappingCompatible = *(PULONG)dmaRemappingBuf;
if(dmaRemappingCompatible == 1 || dmaRemappingCompatible == 2)
{
// DMA remapping enabled: force STOR_MAP_NON_READ_WRITE_BUFFERS
// This matches StorAHCI sample driver behavior
ConfigInfo->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
DbgInfo(MODULE_OS_ENTRY, FEATURE_DRIVER_INIT, NOT_TO_RAM,
"DMAR: DmaRemappingCompatible=%d, forcing MapBuffers=STOR_MAP_NON_READ_WRITE_BUFFERS\n",
dmaRemappingCompatible);
}
else
{
// No DMA remapping: use original logic
if(FALSE == cfg_dma_need_sdma_like_buffer(pdev_ext->cfg->host_item.test_dma_mode_setting.dma_mode))
ConfigInfo->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
else
ConfigInfo->MapBuffers = STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE;
}
}
else
{
// DmaRemappingCompatible not found: use original logic
if(FALSE == cfg_dma_need_sdma_like_buffer(pdev_ext->cfg->host_item.test_dma_mode_setting.dma_mode))
ConfigInfo->MapBuffers = STOR_MAP_NON_READ_WRITE_BUFFERS;
else
ConfigInfo->MapBuffers = STOR_MAP_ALL_BUFFERS_INCLUDING_READ_WRITE;
}

代码位置winscsientry.c:1255-1288

预期效果

  • DmaRemappingCompatible=12 时,强制使用 STOR_MAP_NON_READ_WRITE_BUFFERS
  • 与 StorAHCI 示例驱动行为一致
  • 可能解决 Win10 上的 STATUS_INSUFFICIENT_RESOURCES 问题

测试结果(2026-03-19):

  • 修改无效:强制使用 STOR_MAP_NON_READ_WRITE_BUFFERS 后,问题依然存在
  • 安装时:OK(不再 hang)
  • 重启后:Code 10 错误,设备无法启动
  • 日志显示:Exit BHTDispatchPnp, status=0xC00000BBSTATUS_NOT_SUPPORTED

结论MapBuffers 设置不是根本原因,问题在于 Storport 框架本身。


1.4.8 阶段六:MapBuffers 修改无效,确认 Storport 框架问题(2026-03-19)

时间:2026-03-19

问题:修改 MapBuffers 设置后,问题依然存在。安装时 OK,但重启后出现 Code 10 错误。

测试结果

测试项 结果 说明
安装时 ✅ OK 不再 hang,驱动安装成功
重启后 ❌ Code 10 设备无法启动
错误码 0xC000009A STATUS_INSUFFICIENT_RESOURCES(Storport 框架返回)
错误信息 “Insufficient system resources exist to complete the API.” 设备管理器显示

日志关键信息

1
Exit BHTDispatchPnp, status=0xC000009A

结论MapBuffers 设置不是根本原因,问题在于 Storport 框架本身。


1.4.9 阶段七:DmaRemappingCompatible=2 测试(2026-03-20)

时间:2026-03-20

问题:尝试 DmaRemappingCompatible=2(仅外部设备或 Driver Verifier 时兼容),看是否能解决问题。

测试结果

DmaRemappingCompatible 值 Win10 结果 说明
= 0 黄叹号 设备被策略拦截
= 1 ❌ Code 10 status=0xC000009A
= 2 ❌ Code 10 status=0xC000009A

结论DmaRemappingCompatible=2 同样失败,问题不是值的选择,而是 Win10 Storport 框架本身。


1.4.10 阶段八:Win10 vs Win11 日志对比分析(2026-03-20)

时间:2026-03-20

问题:对比 Win10 和 Win11 的 DbgView 日志,确认问题根源。

测试环境

  • Win10:OS Version 10.0.19045
  • Win11:OS Version 10.0.26200

Win10 失败日志关键序列

1
2
3
4
5
6
7
8
行 2910: BHT-OSENTRY: Exit StorHwPassiveInitialize
行 2911: BHT-OSENTRY: Enter BHTDispatchPnp - MinorFunction: (IRP_MN_QUERY_INTERFACE)
行 2912: BHT-OSENTRY: Enter DispatchPnpAdapter PNP=8
行 2913: BHT-OSENTRY: Exit DispatchPnpAdapter
行 2914: BHT-OSENTRY: Exit BHTDispatchPnp, status=0x00000000 ← 第一个 IRP_MN_QUERY_INTERFACE 成功
行 2915: BHT-OSENTRY: Exit BHTDispatchPnp, status=0xC000009A ← 第二个 IRP_MN_QUERY_INTERFACE 失败!
行 2916: BHT-OSENTRY: Enter BHTDispatchPnp - MinorFunction: (IRP_MN_REMOVE_DEVICE)
行 2917: BHT-OSENTRY: Enter DispatchPnpAdapter PNP=2 ← 设备被移除

Win11 成功日志关键序列

1
2
3
4
5
行 919: BHT-OSENTRY: Exit StorHwPassiveInitialize
行 920: BHT-OSENTRY: Enter BHTDispatchPnp - MinorFunction: (IRP_MN_QUERY_INTERFACE)
行 921-924: BHT-OSENTRY: Exit BHTDispatchPnp, status=0x00000000 ← 成功
行 925-947: 设备正常工作,处理 SCSI 命令
行 948: Exit BHTDispatchPnp, status=0x00000000

关键发现

  1. 驱动初始化都成功:两边的 StorHwPassiveInitialize 都正常退出

  2. DMA 分配都成功

    • Win10:BhtAllocateDmaBuffer succeeded: IOVA=0x7223B000
    • Win11:BhtAllocateDmaBuffer succeeded: IOVA=0x720C8000
  3. 区别在于 IRP_MN_QUERY_INTERFACE 处理

    • Win10:第二次 QUERY_INTERFACE 返回 0xC000009A
    • Win11:所有 QUERY_INTERFACE 都返回成功
  4. 设备后续行为

    • Win10:设备被移除(IRP_MN_REMOVE_DEVICE
    • Win11:设备正常工作

BHTDispatchPnp 代码分析

1
2
3
4
// DispatchPnpAdapter 中的 IRP_MN_QUERY_INTERFACE 处理
case IRP_MN_QUERY_INTERFACE:
default:
break; // 没有专门处理,走 default 分支
1
2
// BHTDispatchPnp 中返回实际状态
status = SavedDispatchPnp(DeviceObject, Irp); // ← 这里是返回 0xC000009A 的地方

结论

  1. 0xC000009A 来自 SavedDispatchPnp(Storport 框架),不是驱动代码返回的
  2. BHTDispatchPnp 代码不处理 IRP_MN_QUERY_INTERFACE,直接透传给下层驱动
  3. 问题在于 Win10 Storport 框架在处理 DMA remapping 兼容驱动时返回 STATUS_INSUFFICIENT_RESOURCES
  4. 驱动代码无需修改

1.4.12 阶段九:IRP_MN_START_DEVICE 深入分析(2026-03-19)

日期:2026-03-19

问题:进一步定位 0xC000009A 的来源

最新测试日志

1
2
3
4
5
6
7
行 806: IRP_MN_START_DEVICE: Calling SavedDispatchPnp
行 807: Enter BHTDispatchPnp - MinorFunction: (IRP_MN_QUERY_INTERFACE)
行 814: SavedDispatchPnp returned 0xC00000BB (STATUS_NOT_SUPPORTED)
行 815: SavedDispatchPnp returned 0xC00000BB
行 824: SavedDispatchPnp returned 0x00000103
行 955: IRP_MN_START_DEVICE: SavedDispatchPnp returned 0xC000009A
行 956: IRP_MN_REMOVE_DEVICE

关键发现

MinorFunction SavedDispatchPnp 返回值 含义
IRP_MN_QUERY_INTERFACE (第1次) 0xC00000BB STATUS_NOT_SUPPORTED
IRP_MN_QUERY_INTERFACE (第2次) 0xC00000BB STATUS_NOT_SUPPORTED
IRP_MN_QUERY_INTERFACE (第3次) 0x00000000 STATUS_SUCCESS
IRP_MN_QUERY_INTERFACE (第4次) 0x00000103 STATUS_PENDING
IRP_MN_START_DEVICE 0xC000009A STATUS_INSUFFICIENT_RESOURCES

错误码含义

  • 0xC000009A = STATUS_INSUFFICIENT_RESOURCES
  • 0xC00000BB = STATUS_NOT_SUPPORTED

根本原因

IRP_MN_START_DEVICE 期间,Storport 返回 STATUS_INSUFFICIENT_RESOURCES,可能原因:

  1. DMA Remapping 资源分配失败

    • INF 中 DmaRemappingCompatible=1 声明支持 DMA remapping
    • 但平台 IOMMU 未正确配置或不支持该设备
    • Storport 无法分配 DMA 映射资源
  2. INF 配置状态

    1
    2
    [DmaRemappingCompatible_AddReg]
    HKR,Parameters,DmaRemappingCompatible,0x00010001,1 ; 当前值 = 1

解决方案

方案 1:禁用 DMA Remapping 兼容性(测试用)

1
2
[DmaRemappingCompatible_AddReg]
HKR,Parameters,DmaRemappingCompatible,0x00010001,0 ; 改为 0

方案 2:驱动层捕获并覆盖错误

BHTDispatchPnp 中添加 IRP_MN_START_DEVICE 专门处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
else if (DeviceType == FILE_DEVICE_CONTROLLER && MinorFuncIndex == IRP_MN_START_DEVICE)
{
status = SavedDispatchPnp(DeviceObject, Irp);

DbgInfo(MODULE_OS_ENTRY, FEATURE_PNP_TRACE, NOT_TO_RAM,
"IRP_MN_START_DEVICE: SavedDispatchPnp returned 0x%08X\n", status);

// 强制返回 SUCCESS(测试用)
status = STATUS_SUCCESS;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
return status;
}

注意:驱动已实现方案 2,但问题仍然存在,说明问题可能不在驱动层。


1.4.11 阶段十:最终结论(2026-03-20)

问题根源:Windows 10 Storport 框架的已知问题/限制

证据链

  1. ✅ 驱动代码正确(使用 StorPortAllocateDmaMemory
  2. ✅ DMA 分配成功(IOVA 正确返回)
  3. ✅ IOMMU 已启用(Kernel DMA Protection 已启用)
  4. MapBuffers 设置正确(强制 STOR_MAP_NON_READ_WRITE_BUFFERS
  5. DmaRemappingCompatible=1=2 都失败
  6. ❌ Win10 Storport 返回 STATUS_INSUFFICIENT_RESOURCES (0xC000009A)
  7. ✅ Win11 Storport 正常工作

不是驱动代码问题的证据

  • BHTDispatchPnp 不处理 IRP_MN_QUERY_INTERFACE
  • 0xC000009A (资源不可获取)来自 SavedDispatchPnp(Storport 框架)处理IRP_MN_START_DEVICE返回
  • 所有驱动级别的初始化都成功
  • Win11 相同代码正常工作

建议的下一步

  1. 不修改miniport部分驱动代码(问题不在这里,在框架层storport)
  2. 向 Microsoft 报告此问题(使用 20260319_Microsoft_Storport_DMAR_Issue_Report.md
  3. 考虑条件安装:Win10 使用不同的 INF 配置,禁用DmaRemappingCompatible,Group Policy如果开启Enumeration policy,需选择Allow all避免Yellow-bang黄标

PART 2:调试方法

方法 1:启用 Driver Install Framework (DIFx) 日志

DIFx 是 Windows 处理驱动安装的组件,开启详细日志可以看到安装过程中每一步的状态。

1.1 启用 DIFx 日志

1
2
3
4
5
# 方法 A:设置全局 DIFx 日志
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\LogLevel" /v DIFxDebugSession /t REG_DWORD /d 1 /f

# 或者使用 WPP 日志
reg add "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter" /v DIFx /t REG_DWORD /d 0xFFFFFFFF /f

1.2 查看安装日志

1
2
3
4
5
6
# 找到 setupapi 日志
dir $env:SystemRoot\Inf\setupapi*.log

# 默认位置
# C:\Windows\Inf\setupapi.dev.log
# C:\Windows\Inf\setupapi.setup.log

1.3 日志内容解读

日志中搜索关键字:

1
2
3
>>>  [InstallHInfSection]
>>> [AddService]
>>> [DmaRemappingCompatible]

观察:

  • 哪个 AddReg 最后执行
  • 是否有错误代码
  • 卡在哪一步

方法 2:启用 Storport 驱动日志

Storport.sys 有内置的跟踪功能。

2.1 启用 Storport 日志

1
2
3
4
5
6
7
8
9
# 启用 Storport 日志(需要管理员权限)
reg add "HKLM\SYSTEM\CurrentControlSet\Services\Storport\Parameters" /v EnableTracing /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Services\Storport\Parameters" /v TraceLevel /t REG_DWORD /d 0xFF /f

# 设置日志缓冲区大小
reg add "HKLM\SYSTEM\CurrentControlSet\Services\Storport\Parameters" /v TraceFileSize /t REG_DWORD /d 0x100000 /f

# 重启生效
shutdown /r /t 0

2.2 使用 tracelog 捕获

1
2
3
4
5
6
7
8
9
10
11
# 创建跟踪会话
tracelog -start StorportTrace -guid #d836db6b-0e4f-440b-8e73-d5d0a8c3e81d -level 0xFF -flag 0xFF -f storport.etl

# 执行安装
pnputil -add-driver bhtsddr.inf -install

# 停止跟踪
tracelog -stop StorportTrace

# 转换格式
traceview storport.etl

2.3 查看事件日志

1
2
3
4
5
# 打开事件查看器并导航到
# 应用程序和服务日志 > Microsoft > Windows > PartDebug

# 或使用 PowerShell
Get-WinEvent -LogName "Microsoft-Windows-PartDebug/Operational" -MaxEvents 50

方法 3:内核调试 (Kernel Debugging)

这是最有效的方法,可以观察到卡死的具体位置和调用栈。

3.1 设置双机调试环境

目标机 (Win10) 设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 启用调试模式
bcdedit /debug on

# 串口调试(推荐)
bcdedit /dbgsettings serial debugport:1 baudrate:115200

# 或网络调试(Win10 1607+)
bcdedit /debug on
bcdedit /set debugtype network
bcdedit /set dbgtransport 1

# 验证设置
bcdedit /dbgsettings

# 重启
shutdown /r /t 0

主机 (WinDbg) 设置

1
2
3
4
5
# 串口连接
windbg -k com:port=COM1,baud=115200

# 网络连接(需要目标机 IP)
windbg -k net:port=50000,key=xxx.xxx.xxx.xxx

3.2 加载符号

1
2
3
4
5
6
7
8
// WinDbg 中设置符号路径
.sympath srv*c:\symbols*https://msdl.microsoft.com/download/symbols

// 重新加载
.reload

// 加载 Storport 符号
.reload /f storport.sys

3.3 关键断点位置

注册表读取相关

1
2
3
4
5
6
7
8
// DmaRemappingCompatible 被读取
bp storport!StorPortRegistryQueryDword

// 注册表查询入口
bp storport!StorPortReadRegistry

// 设置断点并输出信息
bp storport!StorPortRegistryQueryDword "kv;r;g"

DMA Remapping 初始化

1
2
3
4
5
6
7
8
9
10
11
// DMA setup 入口
bp storport!StorPortDmaSetup

// DMA 初始化
bp storport!StorPortInitializeDma

// DMA 分配
bp storport!StorPortAllocateDmaMemory

// 公共缓冲区和 DMA
bp storport!StorPortDmaMapTransfer

PnP 安装相关

1
2
3
4
5
6
7
8
9
10
11
// PnP 处理程序
bp storport!StorPortPnPHandler

// 设备添加
bp storport!StorPortDeviceAdd

// PnP dispatch
bp storport!StorPortDispatchPnp

// IRP 处理
bp storport!StorPortDispatch

可能阻塞的位置

1
2
3
4
5
6
7
8
9
10
11
12
// 等待相关
bp storport!KeWaitForSingleObject
bp storport!KeWaitForMutexObject
bp storport!KeWaitForMultipleObjects

// 同步对象
bp storport!ExAcquireFastMutex
bp storport!ExReleaseFastMutex

// 事件
bp storport!KeSetEvent
bp storport!KeClearEvent

DMAR/IOMMU 相关

1
2
3
4
5
6
7
8
9
// DMA remapping 设备
bp storport!StorPortDMARemapDevice

// DMA 对齐查询
bp storport!StorPortQueryDmaAlignment

// IOVA 相关
bp storport!StorPortMapDmaTransfer
bp storport!StorPortUnmapDmaTransfer

3.4 诊断命令

查看卡住的线程和进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 查看所有进程
!process 0 0

// 查看当前进程
!process

// 找到 pnputil 进程
!process pnputil.exe

// 查看所有线程
!thread

// 查看特定线程的调用栈
~* k

// 查看挂起的线程
!locks

// 查看 dispatcher 对象
!locks -v

查看 IRP

1
2
3
4
5
6
7
8
// 查看挂起的 IRP
!irpfind

// 查看特定进程的 IRP
!process <process address>

// 查看设备栈
!devstack <device object>

查看 DMA 信息

1
2
3
4
5
6
7
8
// DMA 相关 IOCTL
!ioctldma

// 查看设备扩展
!devobj <device address>

// 查看适配器
!adapters

3.5 使用脚本自动设置断点

创建一个 storport_debug.txt 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
.echo ========================================
.echo Storport DmaRemappingCompatible Debug
.echo ========================================

.echo Setting breakpoints...

bp storport!StorPortRegistryQueryDword ".echo Registry Query; kv; g"
bp storport!StorPortDmaSetup ".echo DMA Setup; kv; g"
bp storport!StorPortDeviceAdd ".echo Device Add; kv; g"
bp storport!StorPortDispatchPnp ".echo PnP Dispatch; kv; g"
bp storport!KeWaitForSingleObject ".echo Wait; kv; g"

.echo Breakpoints set. Run 'g' to start.

在 WinDbg 中加载:

1
$$>a< storport_debug.txt

方法 4:ETW 跟踪

使用 Windows 事件跟踪 (ETW) 捕获详细的安装过程。

4.1 使用 tracelog

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
# 创建 ETW 跟踪会话
$sessionName = "StorportDebug"
$tracePath = "$env:TEMP\storport_trace.etl"

# 删除旧的跟踪会话(如果存在)
logman stop -n $sessionName -ets -ErrorAction SilentlyContinue
logman delete -n $sessionName -ets -ErrorAction SilentlyContinue

# 创建跟踪
logman create trace -n $sessionName -o $tracePath -ets -f bin -max 100

# 添加 Storport 提供者 (Provider GUID)
$storportGuid = "{d836db6b-0e4f-440b-8e73-d5d0a8c3e81d}"
logman update trace -n $sessionName -p $storportGuid 0xFFFFFFFF 0xFF -ets

# 添加 Microsoft-Windows-Kernel-Storport 提供者
$kernelStorportGuid = "{c63a8d34-2a39-4b9d-9cf6-85bfd3f9221c}"
logman update trace -n $sessionName -p $kernelStorportGuid 0xFFFFFFFF 0xFF -ets

# 启动跟踪
logman start -n $sessionName -ets

Write-Host "ETW tracing started. Now run: pnputil -add-driver bhtsddr.inf -install"

# 等待安装完成或超时
Start-Sleep -Seconds 60

# 停止跟踪
logman stop -session $sessionName -ets

Write-Host "Tracing stopped. Output: $tracePath"

4.2 使用 WPR (Windows Performance Recorder)

1
2
3
4
5
6
7
8
9
10
11
# 使用 WPR 捕获
wpr -start GeneralProfile -filemode

# 执行安装
pnputil -add-driver bhtsddr.inf -install

# 等待
Start-Sleep -Seconds 30

# 停止
wpr -stop install_trace.etl

4.3 分析 ETW 跟踪

1
2
3
4
5
6
7
8
# 使用 tracerpt 转换
tracerpt $tracePath -o etw_output -all -f html

# 查看 CSV 格式
tracerpt $tracePath -of CSV -o events.csv

# 查看 XML 格式
tracerpt $tracePath -of XML -o events.xml

4.4 使用 TraceView

1
2
3
4
5
# 打开 TraceView
traceview $tracePath

# 或使用 tracefmt
tracefmt $tracePath -o formatted.txt

方法 5:Process Monitor 监控 INF 处理

使用 Process Monitor 监控注册表和文件操作。

5.1 下载和设置

  1. 下载 Process Monitor
  2. 以管理员身份运行

5.2 过滤器设置

设置以下过滤器:

过滤器类型 条件
Process Name is pnputil.exe
Operation begins with Registry
Operation begins with File

5.3 观察要点

  1. 最后写入的注册表键

    • 查找 DmaRemappingCompatible 相关键
    • 找到最后成功完成的操作
  2. 挂起的操作

    • 是否有状态为 “Pending” 或 “Timeout” 的操作
    • 查找长时间无响应的注册表查询
  3. 循环等待

    • 是否反复查询同一键
    • 是否有 “Name Not Found” 后重试

5.4 导出日志

1
File > Export > CSV

方法 6:检查 Storport 与 ACPI/DMAR 表的交互

问题可能出在 Storport 查询 DMAR 表时的超时。

6.1 检查 DMAR 表

1
2
3
4
5
# 使用 RWEverything 查看 ACPI 表
# 下载: http://rweverything.com/

# 或使用 acpiview (WDK 工具)
"C:\Program Files (x86)\Windows Kits\10\Tools\x64\acpiview\acpiview.exe"

6.2 查看 ACPI 表内容

1
2
3
4
5
6
# 查看 DMAR 表
# 使用 Intel System Debugger 或直接读取内存

# 检查 ACPI 表是否存在
# C:\Windows\System32\ACPI Tables\ 目录
dir "C:\Windows\System32\ACPI Tables\"

6.3 WinDbg 中检查 DMA remapping 状态

1
2
3
4
5
6
7
8
9
10
11
// 检查 IOMMU 状态
!ioctldma

// 查看 DMA remapping 引擎
!dx -r1 *(unsigned int*)0xFFFFF80004000000 // 地址需根据实际

// 查看设备扩展
!devobj bhtsddr

// 查看适配器对象
!adapters

6.4 检查 _DMA 方法

1
2
# 使用 ACPI_INFO 或 DeviceTree 工具
# 检查设备的 _DMA ACPI 方法是否返回正确值

推荐调试顺序

顺序 方法 难度 能获得的信息
1 DIFx 日志 安装卡在哪一步
2 Process Monitor 注册表操作卡在哪
3 ETW 跟踪 Storport 内部的调用序列
4 Storport 日志 驱动级别的详细信息
5 内核调试 (WinDbg) 最详细信息:调用栈、阻塞位置

常见问题排查清单

安装阶段卡死

  • DIFx 日志是否记录到最后一步
  • Process Monitor 显示最后访问的注册表键
  • 断点是否命中

内核调试无响应

  • 串口连接是否正常
  • 波特率是否匹配
  • 目标机是否正确进入调试模式

符号加载失败

  • 网络连接是否正常
  • 尝试使用本地缓存
  • 使用 .symfix.reload

ETW 跟踪为空

  • 检查 Provider GUID 是否正确
  • 使用 logman query -ets 查看活动会话
  • 确认管理员权限

获取帮助

相关文档

工具下载

工具 下载链接
WinDbg Windows SDK
Process Monitor Sysinternals
WPR/WPA Windows Assessment and Deployment Kit (ADK)

文档生成: 2026-03-19
适用版本: Windows 10 (所有版本)