驱动诊断
概述
DarraRT 产品运行依赖三个内核态驱动: DarraRT.sys、DarraRT_Eth.sys、DarraRT_PLC.sys。
三者通过 GlobalIO Section 共享同一物理页, 实现零拷贝、零跨驱动调用的运行时协作。
驱动层一旦异常, 上层表现会非常多样: PDO 全零、WKC 恒错、Service 无法连接、 IOCTL 超时、Section 映射失败、系统崩溃 (BSOD)。本文档系统介绍驱动状态检查、 IOCTL 响应测试、DbgView 实时日志过滤、GlobalIO 映射验证、卸载/重装标准流程。
适用场景
- IDE/Service 报告
\\.\DarraRT*设备打开失败 - PDO 或 IO 显示全零 (Section 未映射)
- 系统启动后 DarraRT 服务进入"已启动但不工作"
- 升级驱动后功能异常
- 偶发 BSOD
三驱动矩阵
| 驱动文件 | 设备路径 | 职责 | 源码 |
|---|---|---|---|
DarraRT.sys | \\.\DarraRT | 核心隔离 / SMI 检测 / GlobalIO Section 创建者 / TSC 校准 | Darra_RT_Driver/Global/WDK/ |
DarraRT_Eth.sys | \\.\DarraRT_Eth | NDIS 协议驱动 / EtherCAT 帧 / PDO 线程 / 实例共享内存 | Darra_RT_Driver/Eth/WDK/ |
DarraRT_PLC.sys | \\.\DarraRT_PLC | PLC VM / IOMerge / Robot CyclicUpdate | Darra_RT_Driver/PLC/WDK/ |
三驱动依赖与启动顺序
1. DarraRT.sys (Boot Start, 系统启动前加载)
|
| IOCTL_DARRT_CALIBRATE → 获取 TSC
| IOCTL_DARRT_ISOLATE_CORE → 注册隔离核
| ZwCreateSection → GlobalIO Section
v
2. DarraRT_Eth.sys (System Start, 启动时加载)
|
| ZwOpenSection + MapViewOfSection → 映射 GlobalIO
| NdisRegisterProtocol → 绑定网卡
v
3. DarraRT_PLC.sys (Demand Start, Service 触发)
|
| ZwOpenSection + MapViewOfSection → 同一物理页
| 启动 PLC VM 线程
v
[运行时: 三驱动通过 Section 指针直接读写, 零 IOCTL]
关键点: 第 2 步若失败, PDO 即便帧收发正常, 也无法传到 PLC; 第 3 步若 Section 映射 到不同物理页, 所有 IO 为零但无错误日志。
前置条件与工具
| 工具 | 用途 | 来源 |
|---|---|---|
sc.exe | 服务管理 | Windows 自带 |
DbgView.exe | 内核日志捕获 | SysInternals |
devcon.exe | 设备管理 | WDK |
WinDbg Preview | 崩溃转储分析 | WDK |
poolmon.exe | 内存池监控 | WDK |
SDV (Static Driver Verifier) | 驱动验证 | WDK |
诊断步骤 (状态检查)
步骤 1: 服务管理器状态
# 查看三驱动服务状态
sc query DarraRT
sc query DarraRT_Eth
sc query DarraRT_PLC
预期输出:
SERVICE_NAME: DarraRT
TYPE : 1 KERNEL_DRIVER
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
...
判定规则:
STATE = 4 RUNNING→ 正常STATE = 1 STOPPED→ 未加载, 看WIN32_EXIT_CODE和ERROR_CODESTATE = 7 PAUSED→ 异常, 重启服务
步骤 2: 设备路径可达性
用 DarraDiag.exe (Service 附带的小工具) 测试:
DarraDiag.exe --device-test
预期输出:
Opening \\.\DarraRT ... OK, handle=0x254
Opening \\.\DarraRT_Eth ... OK, handle=0x258
Opening \\.\DarraRT_PLC ... OK, handle=0x25C
或者用 PowerShell 的 P/Invoke:
Add-Type -TypeDefinition @"
using System; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles;
public class K32 {
[DllImport("kernel32", SetLastError=true)]
public static extern SafeFileHandle CreateFile(string p, uint a, uint s, IntPtr x,
uint c, uint f, IntPtr t);
}
"@
[K32]::CreateFile("\\.\DarraRT", 0xC0000000, 3, 0, 3, 0, 0)
步骤 3: IOCTL 响应测试
DarraDiag.exe --ioctl-test 会对每个驱动发送一个已知 IOCTL 并校验返回值:
IOCTL_DARRT_QUERY_VERSION → 1.0.25200 OK (延迟 3μs)
IOCTL_DARRT_ETH_STATS → rx=12345 tx=12340 OK
IOCTL_DARRT_PLC_CYCLE_INFO → cycle=1000μs last=892μs OK
判定规则: 任一 IOCTL 超时 (>10ms) 或返回错误 → 看 DbgView 中对应驱动的异常日志。
步骤 4: GlobalIO Section 映射验证
三驱动必须映射到同一物理页, 否则零拷贝失效。
DarraDiag.exe --section-test
预期输出:
Global create section : virt=0xFFFFCA01B8900000 phys=0x00000001BA000000 size=4096
Eth map view of section : virt=0xFFFFCA01B8900000 phys=0x00000001BA000000 MATCH ✓
PLC map view of section : virt=0xFFFFCA01B8900000 phys=0x00000001BA000000 MATCH ✓
Writing test pattern 0xDEADBEEF via Global ...
Reading from Eth: 0xDEADBEEF MATCH ✓
Reading from PLC: 0xDEADBEEF MATCH ✓
判定规则:
phys三者相同 → 零拷贝 OKphys不同 → 严重问题, 通常是 Section 创建失败后, 每个驱动各自建了独立 Section- 写入校验失败 → Section 虚拟地址被改写, 看 Eth/PLC 的 Map 流程
步骤 5: DbgView 实时日志
以管理员权限启动 DbgView:
File → Capture Kernel (勾)
Edit → Filter/Highlight → Include: DarraRT;DarraRT_Eth;DarraRT_PLC
关注前缀:
| 前缀 | 驱动 | 说明 |
|---|---|---|
[DarraRT] | Global | 隔离核 / TSC / Section |
[DarraRT_Eth] | Eth | NDIS / PDO / WKC |
[DarraRT_PLC] | PLC | VM / IOMerge / Robot |
正常启动序列:
[DarraRT] driver entry, ver=25.2.0
[DarraRT] TSC CAL done, freq=3.6GHz skew=12
[DarraRT] Section created at 0xFFFFCA01B8900000
[DarraRT_Eth] driver entry, ver=25.2.0
[DarraRT_Eth] NDIS protocol registered: DarraRT_Eth
[DarraRT_Eth] Section mapped OK
[DarraRT_Eth] Bound to adapter {GUID}, linkspeed=1Gbps
[DarraRT_PLC] driver entry, ver=25.2.0
[DarraRT_PLC] Section mapped OK
[DarraRT_PLC] PLC VM thread started on isolated core 4
异常序列示例:
[DarraRT_Eth] Section map FAILED: STATUS_OBJECT_NAME_NOT_FOUND
→ 说明 DarraRT.sys 尚未创建 Section (顺序错) 或名字不匹配 (版本不一致)。
诊断步骤 (深度)
步骤 6: 非分页池使用
# 管理员
poolmon.exe -p -i -bDREC,DRRC,DRPC
输出:
Tag Type Allocs Frees Used Diff
DRRC Nonp 1 200 1 199 4 KB +1
DREC Nonp 8 200 8 100 64 KB +100 <-- 泄漏?
DRPC Nonp 1 500 1 500 8 KB 0
判定规则: Diff 持续增长 → 该驱动有内存泄漏, 定位到对应 Tag 的 ExAllocatePoolWithTag
调用处。
步骤 7: 查看是否进入过 BSOD
Get-WinEvent -LogName System -MaxEvents 50 |
Where-Object { $_.LevelDisplayName -eq "Error" -and $_.ProviderName -like "*BugCheck*" }
如果有 BSOD 记录, 崩溃转储默认在 %SystemRoot%\MEMORY.DMP 或
%SystemRoot%\Minidump\*.dmp。用 WinDbg 打开:
!analyze -v
关注:
MODULE_NAME是否为 DarraRT*STACK_TEXT是否穿过 DarraRT 驱动BUCKET_ID是否有已知缺陷
步骤 8: 核心隔离状态
DarraDiag.exe --core-status
输出:
Total logical cores: 8
Isolated mask: 0x30 (core 4, 5)
Core 0: OS general , CPU usage 18%
Core 1: OS general , CPU usage 22%
Core 2: OS general , CPU usage 15%
Core 3: OS general , CPU usage 12%
Core 4: ISOLATED-PLC , CPU usage 100% (busy wait, correct)
Core 5: ISOLATED-ECAT , CPU usage 100% (busy wait, correct)
Core 6: OS general , CPU usage 8%
Core 7: OS general , CPU usage 11%
判定规则: 隔离核 100% 是正确的; 非隔离核若某个长时间 > 80% → 有后台进程抢资源。
驱动卸载 / 重装标准流程
严格按顺序: 停 Service → 停 PLC 驱动 → 停 Eth 驱动 → 停 Global → 卸载 → 重装 → 反向启动。
步骤 1: 停止用户态
# 停 IDE / Panel
taskkill /IM Darra.PLC.IDE.exe /F
taskkill /IM Darra.PLC.Panel.exe /F
# 停 Service
sc stop "Darra.PLC.Service"
步骤 2: 按逆序停止驱动
sc stop DarraRT_PLC
sc stop DarraRT_Eth
sc stop DarraRT
验证: sc query <name> 全部 STOPPED。
步骤 3: 卸载
用官方卸载脚本 (绝对不要手动删 .sys, 会留下服务注册残留):
cd "C:\Program Files\DarraRT\Driver"
.\uninstall.ps1
步骤 4: 重装 (签名版本)
.\install.ps1 -InfPath .\DarraRT.inf
.\install.ps1 -InfPath .\DarraRT_Eth.inf
.\install.ps1 -InfPath .\DarraRT_PLC.inf
步骤 5: 按正序启动
sc start DarraRT
sc start DarraRT_Eth
sc start DarraRT_PLC
sc start "Darra.PLC.Service"
步骤 6: 验证
DarraDiag.exe --full-test
通过所有 6 项 → 可以投产。
异常模式速查表
| 现象 | 根因 | 定位方法 | 解决 |
|---|---|---|---|
\\.\DarraRT 打不开 | 驱动未加载 | sc query DarraRT | sc start DarraRT |
| Section map failed | 启动顺序错 | DbgView 启动序列 | 按序重启 |
| PDO 全零 | Section 物理页不一致 | --section-test | 重启三驱动 |
| IOCTL 超时 | 驱动死锁 | WinDbg !locks | 收集 dump 报 bug |
| 系统 BSOD | 驱动缺陷 | !analyze -v | 回退版本或报 bug |
| 非分页池泄漏 | 资源未释放 | poolmon Tag | 查对应 Tag 代码 |
| 隔离核 < 100% | 隔离失败 | --core-status | 检查 bcdedit |
| NDIS 未绑定 | 网卡 GUID 变了 | Get-NetAdapter | 重置 Eth Service |
| 签名失败 | 测试签名未开 | bcdedit /enum | testsigning on |
| 卸载后残留 | 非标准卸载 | devmgmt.msc | sc delete 清理 |
高级技巧
- 驱动版本强一致: 三驱动必须同一编译批次, 头文件
dx_version.h被三者共用, 版本号不一致时启动会报VERSION_MISMATCH拒绝映射 Section。 - 测试签名模式: 开发阶段用
bcdedit /set testsigning on, 生产阶段必须 EV 代码签名。 - WinDbg 实时附加:
Win+R → dbgview只看DbgPrint, 如需逐行调试内核代码, 用另一台机器 USB/Net 内核调试连接。 - Pool Tag 命名: DarraRT 内部约定
DRRC(Global) /DREC(Eth) /DRPC(PLC),poolmon按 tag 过滤一目了然。 - NDIS 双注册防护: Eth 用
"DarraRT_Eth"作为协议名, 不与旧 Global 驱动冲突; 升级时若先旧版再新版可能双注册蓝屏, 务必先卸载旧版再装新版。
相关文档
