记一次雷电显卡坞的“折腾”历程
前言
- 购买了一块SGWZONE家的4080M显卡坞,其使用的是7440芯片,看重它的点是可更换模块(雷电 & OCUlink),因为是考研前购买的,没有时间折腾,接在了零刻的12900hH上,只是装了驱动低负载使用,并没有暴露出兼容性问题,但切换到了Ultra258V后暴露了问题,抱着不甘和侥幸心理,于是开始了为期3天的折腾。
为什么购买
-
之前使用过6340、ASM2464的显卡坞,分别来自GPD和天钡家,但由于性能其实并没有强到哪里,新鲜劲过了就挂了闲鱼,这次的目的是能够让笔记本和掌机共享一张显卡,从而在极致便携性(方便过年回家)的同时,尽可能的做到“物尽其用”,同时显卡坞上挂满所需外设和仓库盘,切换设备只需要把下行线从A取下插到B上即可。
-
但其实兼容性问题确实不小。
与惠普X14 Ultra 258V的连接
问题出现
- 在刚到手,折腾这台电脑时,怀着对Win10“短平快”的执念,尝试安装了21h2 LTSC IOT,当时是有几个设备没驱动感叹号 + NPU开启后任务管理器性能页直接闪退(问了AI说是前端渲染架构的问题,没办法通过注册表魔改,属于无解),于是还是选择了Win11 LTSC 24h2。
- 然而,在使用Offical出场系统通过DISM备份的驱动后,会出现,WHEA(17),通过HWINFO排查,发现是PCIE下联的ThunderBolt控制器频繁报错,查询资料主要原因是Host和GPU存在NAK帧,就会触发重传,如果重传率过高或次数太多,就会报WHEA。
故障分析
- 为最小化复现故障,选择重装Win11 LTSC 24h2原版,仅打NV驱动,使用FurMark,通过HWINFO检测WHEA,计数上来后,不定时出发WHEA蓝屏,dump日志分析为USB4Router和NV相关dll的异常ret,可以基本确定是这代Lunar Lake架构的特点,Gemini的解释是:
Lunar Lake 内部有一个非常激进的节能机制叫 “Graphics Standby” (RC6) 和 “Deep Link Power Management”。这些机制在 24H2 下极易触发 eGPU 的 WHEA 错误。
原理推导
- 对于PCIE设备,会大量使用DMA进行内存IO,WHEA17, PCIE下行TB控制器的Erro反映了传输过程中存在错误写存,或数据变化,最终的结果是NAK的返回帧,WHEA计数器会将NAK的次数和频率进行记录,蓝屏的发生本质是对系统的保护,即,发生了大量的不可恢复错误,强行终止。
- 在Host和Egpu数据传输过程中,显卡的工作贷款在pcie4.0 X 3,但实际的传输速率,以雷电4为例,分给显卡部分的数据传输大概是2.88G(3DMark带宽测试结果),因此在这个传输过程中存在着较大的延迟,但为什么在这台Lunar Lake上造成了如此严重的WHEA不得而知,但可以确定的是,这个“WHEA的错误“,并不是真的错误,只是高重传的报警,并不影响数据的可靠性,最多表现为画面突然卡住或掉帧一下,然后继续正常,但如果在卡顿和掉帧发生时Windows误以为是真的不可恢复错误,那么就进入了蓝屏阶段,即从宏观角度来说,这种”错误“本身并不是真的错误,如果能够让Windows的WHEA计数器不那么敏感,或者提高容忍度或Threshold,应该可以曲线救国,不蓝屏,而最多是卡顿。
Reddit和Youtube上的一个解决方案
- 在搜寻过程中,得到了一个看起来能解决问题的方案Fix AMD eGPU PCIe Bus Errors (WHEA) on Rog Ally X, Legion Go, and More:
Registry Editor (RUN AS ADMINISTRATOR) Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\GraphicsDrivers Click on Graphics Driver Folder
- Inside folder Right-Click “New” DWORD (32-bit) VALUE and name TdrDelay - Right-Click TdrDelay - Modify - switch to Decimal - Enter Value of 10 and click OK
- Inside folder Right-Click “New” DWORD (32-bit) VALUE and name TdrDelay - Right-Click TdrDdiDelay - Modify - switch to Decimal - Enter Value of 20 and click OK
- Command Prompt (RUN AS ADMINISTRATOR) Copy and Paste this text exact as it is: bcdedit /set {current} pciexpress forcedisable Press ENTER It will say Complete Successfully then you can close the window.
- RESTART your PC and you should be all set.
- 上述的操作的原理是:
TdrDelay:让显卡在卡顿或掉线时,系统多等几秒再放弃,减少直接死机。forcedisable:强制系统接管 PCIe 管理,不再听从 BIOS PCIE PM逻辑。
- 将上述方法在原版系统 + NV驱动下进行实践,HWINDO不出意外的再没有抓取到过因为PCIE下行TB控制器的WHEA,于是恢复到驱动完整的系统中,应用上述方案后重启,不出意外的出现了新的意外:DRIVER_VERIFIER_DMA_VIOLATION。
DMA Erro
- 在现代计算机体系中,PCIE设备内存的非法访问检测主要通过DMA控制器来把关,DMA的作用是接收对应PCIE设备的IO请求 + 指明对应IOMMU Group内存地址,在这里的PCIE设备应为设备信任链上的设备,而EGPU并不在该范畴中,因此在开机时,EGPU驱动注册时的DMA请求被判定为了非法,导致了DMA Erro(禁用 PCIe 原生管理(
forcedisable)时,系统底层的 DMA 分配逻辑发生了变化。而 Windows 为了防止雷电/USB4 接口遭受恶意硬件攻击,开启了 DMA 保护) - 而这一切的硬件实现是Intel VTD或AMD IOMMU来实现的,windows的内核 DMA 保护(Kernel DMA Protection)模块会直接调用该部件,实现DMA保护。VTD何IOMMU的初衷是为了将PCIE能够不冲突地提供给虚拟机直通使用,这也是ESXI,PVE等系统要求PCIE直通时开启该功能的原因,而对于个人计算机来说,其实开启后反而会增加延迟略微影响性能(PCIE 的DMA IO操作需要再过一层该模块)。
- 于是我们的第一个解决方案也是公认的DMA结果方案是:
- 关闭BIOS中的VTD
- 安全模式重置驱动程序校验器
verifier /reset - 关闭 Windows 内部的“内核 DMA 保护”
- 但如上方案并没有解决问题,个人推测是直接DISM导出的驱动包和NV驱动存在冲突(这个后文会有验证),于是只能进入安全模式,先恢复PCIE管理默认。
bcdedit /set {current} pciexpress default
排除驱动的冲突问题
- DISM导出的原理是将封装在
riverStore中的.inf、.sys和.cat文件提取,但这个可能会受到不同目标系统,导致缺失非INF安装项的问题,或存储控制器冲突,还有可能老旧驱动一并导出,造成强制签名检测等问题,最终导致无法进入系统。 - 因此,DISM的备份驱动方式虽然底层,但并不是万能的,造成DMA Error的驱动主要可能是芯片组驱动、SerierIO,Intel 管理引擎 ME驱动和使用PCIE总线设备驱动,我们需要一些体力劳动来完成排查。
- 首先在安装NV驱动并开启forcedisable后,使用dism++进行系统备份,依次安装上述驱动,并适当进行备份便于快速复原。
- 然而,在我们安装了所有的驱动后,我们惊奇的发现,之前的DMA Error问题消失了,这也证明了DISM备份时确实备份了一些潜在造成冲突的驱动,只是大多是情况下我们并不会涉及到如此苛刻的使用场景(EGPU),因此并不会影响系统的整体运行。
尾声的新插曲
-
最后,我们会发现,有两个设备会代码43,分别是核显驱动和NPU驱动。
- Gemini的解释是:
在大多数电脑(尤其是笔记本)中,核显驱动不仅负责显示,还深度参与了 CPU 系统代理(System Agent) 的电源管理和 PCIe 根复用器 的调度。 当你安装了官方核显驱动(Intel UHD/Iris Xe 或 AMD Radeon),它会激活硬件级别的 DMA 重映射(DMA Remapping) 功能。而你的
forcedisable指令强行关掉了 PCIe 的原生控制,核显驱动在尝试接管内存地址时发现逻辑对不上,可能触发蓝屏或者回退到代码43。 -
大胆猜测,如果我们改回default,这些设备应该能正常工作,验证后,果不其然。
-
这里Gemini提供了一些去改注册表,让核显和NPU不进行 DMA 保护和策略限制的方式,但是尝试无果。
-
看起来是二者是无法兼得的,首先必须保留
forcedisable(为了 eGPU 稳定),而这又导致了 Lunar Lake 这种高度依赖电源管理的 SoC(核显+NPU)出现 代码 43,我们实际上是在让现代硬件运行在“远古”的 PCIe 管理模式下。
曲线救国
- 我对笔记的两种使用场景其实正好对应了上述的两种情况
- 外出使用核显
- 固定场景外接屏幕使用独显
- 那么,我只需要写两个Bat脚本,在不同的场景下切换使用核显还是独显即可,大概就折腾到这里吧,毕竟找到了一个看起来的平衡点。这让我想起来极客湾“云飞”对雷电外接显卡坞的评价,“不好用,很吃厂商适配和生态“,现有的显卡坞都是在公版基础上的产品,因此兼容性非常的”因机而异“,为了追求所谓的”便携”和“一卡多用”,必然是需要付出时间和精力的。
更进一步,因祸得福
-
查了一些资料,热插拔设备的注册流程是首先BIOS介入,更新ACPI Table,随后将变更“通告”PnP(即插即用)模块,开启Forcedisable后实际是让操作系统对PnP设备的控制失效。
-
在Win10(22H2及之前),PnP保留了向后兼容性,开启Forcedisable后系统会照搬BIOS给到操作系统的ACPI设备内存分配表,而Win11 24H2后资源分配权做了重构,24H2 引入了极强的重平衡机制,WDDM驱动在初始化时会向系统请求高级电源管理接口,而forcedisable切断了OSPM接口,于是导致了代码43。
-
Gemini的说法是:
Windows 11 24H2 (零信任模型): Win11 强制实施 Kernel DMA Protection (内核 DMA 保护)。它要求驱动程序和 PCIe 总线必须随时汇报状态,以防止外接设备(eGPU)读取内存。
forcedisable= 屏蔽了汇报通道。- 结果: 系统认为这是一种安全风险,或者驱动发现无法建立安全握手,于是核显(作为系统代理的一部分)被强制挂起(代码 43),或者直接蓝屏(DMA_VIOLATION)。
Windows 10 (信任模型): Win10 虽然也有 DMA 保护,但默认策略是宽容的。如果它发现 PCIe 总线处于 Legacy 模式(即开启了
forcedisable),它会自动降级安全策略,允许驱动在没有严格 DMA 隔离的情况下加载。 -
在切换至Win10并开启Forcedisable后,核显驱动果然恢复了,即驱动成功加载,虽然安全性降低了,但设备能用。
-
Lunar Lake 核显在 Win10 上跑的是一种“兼容模式”: 虽然装的是官方驱动,但在 Win10 上,它无法激活 WDDM 3.0/3.1/3.2 的新特性(如硬件加速调度 HWS 的某些高级电源功能、NPU 与 GPU 的联合调度)。
-
正是因为这些复杂的、需要 OS 深度介入的功能在 Win10 下被禁用了,驱动反而变得简单纯粹了。它不需要和 PCIe 总线进行复杂的电源握手,所以
forcedisable不会“卡住”它。
最后接近完美的方案
-
使用Win10 22H2 Pro(时代的眼泪),21H2 LTSC也可以,正常打驱动
-
发现有一个小Bug,如果仅开启外屏时,会异常的卡顿,这里修改一下PCIE的链接状态电源管理 ,如果电源管理没有,可以直接在注册表中修改该 GUID 对应的
Attributes值:- 按
Win + R键,输入regedit并回车。 - 导航至以下路径(可直接复制到地址栏):
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\501a4d13-42af-4429-9fd1-a8218c268e20\ee12f906-d277-404b-b6da-e5fa1a576df5 - 在右侧窗格找到 Attributes,双击将其数值数据修改为 2(显示选项)。
- 按
-
还有一种办法可以不去改PCIE PM,写一个disable 在enable核显的脚本即可:
-
@echo off setlocal :: Check for Administrator privileges net session >nul 2>&1 if %errorLevel% neq 0 ( echo ========================================== echo ERROR: Please Right-click and "Run as Administrator" echo ========================================== pause exit ) :: Use the specific VEN and DEV code :: We use the ^ to escape the & symbol in Batch set "TARGET_ID=PCI\VEN_8086^&DEV_64A0" echo Now trying to flash IGPU... echo [1/3] Disabling IGPU (ID: %TARGET_ID%)... powershell -Command "Get-PnpDevice -InstanceId '*VEN_8086&DEV_64A0*' | Disable-PnpDevice -Confirm:$false" echo [2/3] Waiting for 5 seconds... timeout /t 5 /nobreak >nul echo [3/3] Enabling IGPU... powershell -Command "Get-PnpDevice -InstanceId '*VEN_8086&DEV_64A0*' | Enable-PnpDevice -Confirm:$false" echo ------------------------------------------ echo Task completed! pause
-
评论区