ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

BIOS USB控制权误改导致键盘失灵?11天排查与修复实录

BIOS USB控制权误改导致键盘失灵?11天排查与修复实录 1. 一块键盘引发的血案我为什么要去动 BIOS 的 USB 控制权事情的起因其实特别简单甚至有点蠢。我手上有一台老机器主板是 B490 芯片组那一代的具体型号就不点名了反正 BIOS 界面还是那种蓝底白字的传统 AMI 风格。我本来只是想调一下 U 盘启动顺序结果手贱点进了 USB Configuration 里面看到有个选项叫 USB Legacy Support 和 XHCI Hand-off当时脑子一热想着反正都是老设备了干脆把 USB 控制权从 BIOS 的 SMI 手里抢过来让操作系统直接接管 EHCI/XHCI 控制器理论上能降低一点输入延迟。结果改完保存重启键盘当场就没了。不是那种灯不亮的没是连 BIOS 自检阶段都直接不认键盘了。PS/2 接口的键盘倒是还能用但我那台机器只有一个 PS/2 口而且我手头根本没有 PS/2 键盘。USB 键盘插上去主板连供电都正常NumLock 灯亮着但按键完全没反应。进系统之后更离谱Windows 能识别到 USB 控制器但键盘设备直接显示黄色感叹号错误代码 43。我当时的第一反应是完了BIOS 设置改坏了得清 CMOS。但清完 CMOS 之后发现问题更严重——默认设置下 USB Legacy Support 是开启的但我的键盘依然不工作。这说明问题不是出在设置本身而是我在改设置的过程中把 8042 控制器和 USB 控制器之间的某种握手逻辑给搞乱了。这里得先解释一下背景。传统 BIOS 对 USB 键盘的支持靠的是一套叫 SMI 重定向 的机制。简单说BIOS 在启动阶段会把 USB 键盘的输入事件通过 System Management Interrupt 转发给 8042 键盘控制器让操作系统以为自己在跟一个 PS/2 键盘说话。这套机制在 EHCI 时代还能凑合用但到了 XHCI 时代USB 控制器直接由操作系统接管BIOS 不再插手SMI 重定向就失效了。我当时的操作相当于把 BIOS 的 USB 控制权彻底交了出去但操作系统那边又没准备好接管结果就是两边都不管键盘成了孤儿。更麻烦的是这台机器的 BIOS 没有提供 恢复默认设置 的快捷键也没有双 BIOS 备份。我试过拔电池、跳线清 CMOS、甚至用镊子短接 BIOS 芯片的引脚都没用。因为问题不在 CMOS 数据而在 BIOS 固件本身——我在改设置的时候可能触发了某个隐藏的写操作把 USB 控制器的初始化代码给覆盖了。接下来的 11 天我几乎把能想到的办法都试了一遍。从最基础的换键盘、换 USB 口、换数据线到进阶的 USB 抓包分析、BIOS 固件反编译、甚至用 STM32 自己写了一个 USB 设备来模拟键盘。中间踩过的坑比我过去三年折腾硬件加起来都多。这篇文章就是把这 11 天的完整排查链路、原理分析和修复方案整理出来。如果你也遇到过类似的问题——比如改了 BIOS 设置之后键盘失灵、USB 设备在启动阶段不工作、或者想自己动手做 USB 设备但不知道从哪下手——那这篇内容应该能帮你省下不少时间。2. 从 8042 到 XHCIBIOS 到底怎么管 USB 键盘2.1 8042 控制器一个活了四十年的老古董要理解我遇到的问题得先搞清楚 BIOS 是怎么跟键盘打交道的。很多人以为键盘是直接插在主板上的其实不是。在 x86 体系里键盘和鼠标的输入最早是由一颗叫 8042 的微控制器来处理的。这颗芯片从 IBM PC/AT 时代就开始用了到现在已经四十多年但它的影子还在。8042 控制器有两个端口0x60 和 0x64。0x60 是数据端口0x64 是命令/状态端口。操作系统通过读写这两个端口来获取键盘扫描码、控制键盘 LED、甚至发送复位命令。PS/2 键盘就是直接连在 8042 上的所以它的驱动非常简单几乎不需要什么初始化。但 USB 键盘就不一样了。USB 是一个完全不同的协议栈它有自己的一套描述符、端点、传输类型。操作系统要通过 USB 主机控制器EHCI 或 XHCI来跟键盘通信而不是直接读写 0x60 端口。那问题来了在 BIOS 启动阶段操作系统还没加载 USB 驱动怎么用 USB 键盘答案就是 SMI 重定向。BIOS 在启动时会初始化 USB 控制器然后通过 SMI 中断把 USB 键盘的输入事件翻译成 8042 能理解的扫描码再写入 0x60 端口。这样操作系统不管是在 BIOS 里还是在 DOS 里都能像用 PS/2 键盘一样用 USB 键盘。这套机制在 EHCI 时代工作得很好因为 EHCI 控制器在操作系统接管之前BIOS 可以完全控制它。但到了 XHCI 时代情况变了。XHCI 控制器设计之初就考虑到了操作系统接管的问题它有一个叫 Hand-off 的机制允许 BIOS 在启动后期把控制权交给操作系统。一旦交接完成BIOS 就不再管 USB 控制器了SMI 重定向也就失效了。2.2 XHCI Hand-off交接没做好键盘就没了XHCI Hand-off 的流程大概是这样的BIOS 在 POST 阶段初始化 XHCI 控制器然后设置一个叫 OS Owned Semaphore 的标志位告诉操作系统我准备好了你可以接管了。操作系统加载 XHCI 驱动时会检查这个标志位如果发现 BIOS 已经准备好交接就会执行接管流程把控制权从 BIOS 手里拿过来。问题出在交接的时机上。如果 BIOS 在交接之前就把 USB Legacy Support 关掉了那操作系统在启动阶段就没有键盘可用。如果 BIOS 在交接之后还试图控制 USB 控制器那操作系统接管时就会冲突导致设备无法正常工作。我当时的操作相当于强制 BIOS 提前交接但操作系统那边还没准备好。结果就是 BIOS 以为操作系统已经接管了不再处理 USB 键盘输入操作系统以为 BIOS 还在管没有初始化 XHCI 控制器。两边互相甩锅键盘就成了牺牲品。更坑的是这种状态下即使你进系统之后手动安装 XHCI 驱动也不一定能恢复。因为 BIOS 在交接时可能已经把 XHCI 控制器置于一个奇怪的状态操作系统驱动初始化时无法正确复位。2.3 为什么清 CMOS 救不回来很多人遇到 BIOS 设置问题第一反应就是清 CMOS。这招在大多数情况下确实管用因为 CMOS 里存的是 BIOS 设置清掉之后 BIOS 会加载默认值问题通常就解决了。但我的情况不一样。清 CMOS 只能恢复设置不能恢复固件。我在改设置的时候可能触发了 BIOS 固件里的某个写操作把 USB 控制器的初始化代码给改了。这种修改是写在 BIOS 芯片里的清 CMOS 根本没用。怎么判断是设置问题还是固件问题有个简单的办法清完 CMOS 之后如果问题依然存在而且症状跟之前一模一样那大概率是固件问题。如果症状变了或者部分功能恢复了那可能只是设置问题。我当时清完 CMOS键盘依然不工作而且症状完全一样——NumLock 灯亮按键无反应系统里设备管理器显示错误代码 43。这就说明问题不在设置而在固件。3. 11 天排查实录从换键盘到 USB 抓包3.1 第一阶段排除硬件故障第 1-2 天最开始的两天我一直在怀疑是硬件坏了。毕竟键盘灯亮着但按键没反应听起来很像键盘本身的固件挂了。我换了三把键盘一把老式的 IBM Model MPS/2 接口一把罗技的 K120USB 接口还有一把杂牌的机械键盘。结果都一样——PS/2 键盘能用USB 键盘不能用。然后我怀疑是 USB 口的问题。这台机器有六个 USB 口我挨个试了一遍前后各两个加上两个 USB 3.0 的蓝色口。结果还是一样所有 USB 口都不认键盘。接着我怀疑是数据线的问题。我换了两根 Type-C 转 USB-A 的线一根是普通数据线一根是 OTG 线。这里插一句普通数据线和 OTG 线在引脚定义上是有区别的OTG 线会把 ID 引脚接地让设备进入主机模式。但我的键盘是标准 USB 设备不需要 OTG 线所以换线也没用。到第二天晚上我基本确认了不是键盘的问题不是 USB 口的问题也不是数据线的问题。问题出在主板上而且大概率是 BIOS 层面的。3.2 第二阶段尝试各种恢复手段第 3-5 天确认是 BIOS 问题之后我开始尝试各种恢复手段。最先试的是清 CMOS拔电池、短接跳线、甚至用镊子短接 BIOS 芯片的引脚都试过了。没用。然后我试了盲刷 BIOS。这台机器的 BIOS 是 AMI 的理论上可以用 U 盘盲刷。但盲刷需要键盘操作而我的键盘正好不工作这就成了一个死循环。我试过用 PS/2 键盘盲刷但手头没有 PS/2 键盘临时买了一个结果发现这台机器的 PS/2 口是坏的。接着我试了用编程器直接刷 BIOS 芯片。我把 BIOS 芯片拆下来用 CH341A 编程器读取固件发现固件确实被修改过。具体来说USB 控制器的初始化代码段有几个字节被改成了 0xFF这应该是导致键盘失灵的直接原因。但问题是我没有原始固件备份。这台机器是二手的买来的时候就没有 BIOS 备份。我在网上找了很久终于在一个叫 d大魔改bios论坛 的地方找到了同型号主板的 BIOS 固件。下载下来之后用编程器刷进去结果机器直接不亮了。后来我才知道那个固件是魔改版的跟我的主板型号不完全匹配。刷进去之后BIOS 自检都过不了直接黑屏。3.3 第三阶段USB 抓包分析第 6-8 天刷错固件之后机器彻底变砖了。我只好把原来的 BIOS 芯片焊回去至少还能亮机虽然键盘不工作。这时候我想到了一个办法用 USB 抓包分析仪看看 BIOS 在启动阶段到底发了什么 USB 包。如果我能搞清楚 BIOS 是怎么初始化 USB 控制器的也许就能找到修复的方法。我手头有一个 Teledyne LeCroy 的 USB Protocol Suite 分析仪这玩意儿平时用来调试 USB 设备驱动没想到这次派上了用场。我把分析仪串在键盘和主板之间然后开机抓取 BIOS 启动阶段的 USB 流量。抓到的数据很有意思。BIOS 在 POST 阶段确实发了 USB 控制器的初始化命令包括复位、设置地址、读取描述符等等。但在某个时间点之后USB 流量突然中断了键盘的端点被禁用控制器进入了一个奇怪的状态。对比正常的启动流程我发现问题出在 Set Configuration 这一步。正常情况下BIOS 会发送 Set Configuration 命令把键盘配置成工作状态。但在我的机器上这个命令没有发出去或者发出去了但被控制器拒绝了。这说明 BIOS 的 USB 初始化代码确实被破坏了它无法正确完成键盘的配置流程。3.4 第四阶段用 STM32 自己做一个 USB 键盘第 9-11 天既然 BIOS 的 USB 初始化代码坏了那我能不能自己做一个 USB 设备绕过 BIOS 的初始化流程直接跟操作系统通信这个想法听起来很疯狂但技术上可行。我手头有一块 STM32F103 的开发板这颗芯片自带 USB 外设可以配置成 HID 设备。我打算用 STM32 模拟一个 USB 键盘看看能不能在操作系统里正常工作。这里插一句STM32 做 USB 设备最麻烦的是描述符的配置。USB HID 设备需要提供设备描述符、配置描述符、接口描述符、HID 描述符和报告描述符。其中报告描述符最复杂它定义了键盘按键和 USB 数据包之间的映射关系。我参考了 RT-Thread 官方 USB 协议栈的示例代码把 STM32 配置成一个标准的 104 键盘。然后把它插到那台机器上开机。结果很有意思在 BIOS 阶段STM32 键盘依然不工作因为 BIOS 的 USB 控制器初始化代码是坏的任何 USB 设备都认不出来。但进了操作系统之后STM32 键盘居然能用了因为操作系统有自己的 XHCI 驱动不依赖 BIOS 的初始化代码。这就给了我一个思路如果我能用 STM32 键盘进操作系统那我就能在操作系统里刷 BIOS 固件而不需要依赖 BIOS 阶段的键盘操作。4. 修复方案从操作系统层面重刷 BIOS4.1 为什么操作系统能救回 BIOS很多人以为刷 BIOS 必须在 BIOS 阶段或者 DOS 环境下进行其实不是。现代操作系统都有直接访问 SPI 闪存的能力只要你有合适的工具和驱动就可以在 Windows 或 Linux 下直接读写 BIOS 芯片。我用的工具是 BIOS Backup Toolkit这是一个开源工具可以通过操作系统直接访问 SPI 控制器读取和写入 BIOS 固件。它的原理是利用芯片组的 SPI 控制器接口绕过 BIOS 的写保护机制直接操作闪存芯片。当然这个方法有风险。如果刷写过程中断电或者出错机器就彻底变砖了。所以我建议在操作之前先做好以下准备确保电源稳定最好接 UPS备份当前固件即使它是坏的准备好编程器万一刷坏了可以拆芯片恢复确认固件版本和主板型号完全匹配4.2 具体操作步骤第一步用 STM32 键盘进操作系统。这里要注意STM32 键盘必须在操作系统加载 XHCI 驱动之后才能工作所以你需要等系统完全启动听到登录提示音之后再插上 STM32 键盘。第二步安装 BIOS Backup Toolkit。这个工具需要管理员权限而且需要安装一个内核驱动。安装过程中可能会提示驱动签名问题需要临时禁用驱动签名强制。第三步读取当前 BIOS 固件。打开工具选择 Read BIOS它会自动识别 SPI 闪存芯片的型号和容量。读取过程大概需要几分钟取决于芯片容量。读取完成后保存为一个 .bin 文件。第四步验证固件完整性。用 UEFITool 打开读取的固件检查是否有明显的损坏。如果固件被修改过UEFITool 会显示一些异常比如无效的卷、缺失的模块等等。第五步写入正确的固件。如果你有原始固件备份直接写入即可。如果没有需要从主板厂商官网下载对应型号的 BIOS 更新文件然后用 UEFITool 提取固件部分再写入。第六步验证写入结果。写入完成后重新读取固件跟源文件做对比确保写入正确。第七步重启机器。如果一切顺利BIOS 应该能正常初始化 USB 控制器键盘也能在 BIOS 阶段工作了。4.3 刷写过程中的坑这里有几个坑我踩过你们就别踩了。第一个坑固件版本不匹配。我在网上找的那个固件虽然型号看起来一样但实际上是魔改版的刷进去直接黑屏。所以一定要从官方渠道下载固件或者确认固件来源可靠。第二个坑SPI 写保护。有些主板的 SPI 闪存有写保护机制BIOS Backup Toolkit 可能无法直接写入。这时候需要先解除写保护通常是通过修改芯片组的寄存器来实现。具体方法因主板而异需要查芯片组的数据手册。第三个坑刷写过程中断电。这个不用多说刷 BIOS 最怕的就是断电。我那次刷写的时候家里正好跳闸幸好我有 UPS不然机器就彻底废了。第四个坑驱动签名问题。BIOS Backup Toolkit 的内核驱动没有签名在 Windows 10/11 上需要临时禁用驱动签名强制。具体方法是按住 Shift 键重启进入高级启动选项选择 禁用驱动程序强制签名。5. 事后复盘BIOS USB 控制权的边界在哪里5.1 哪些 BIOS 设置可以动哪些不能动经过这次折腾我总结了一个原则BIOS 里跟 USB 相关的设置能不碰就不碰。具体来说USB Legacy Support这个设置控制 BIOS 是否在启动阶段支持 USB 键盘鼠标。如果你用的是 USB 键盘这个设置必须开启否则进 BIOS 都进不去。XHCI Hand-off这个设置控制 BIOS 是否在启动后期把 USB 控制器交给操作系统。一般来说开启这个设置能让操作系统更好地管理 USB 设备但如果你的操作系统比较老可能需要关闭。EHCI Hand-off类似 XHCI Hand-off但针对的是 EHCI 控制器。老机器上常见新机器上基本没有了。USB Mass Storage Support这个设置控制 BIOS 是否支持 USB 存储设备。如果你需要用 U 盘启动这个设置必须开启。我的建议是除非你明确知道自己在做什么否则不要动这些设置。默认值通常是经过厂商测试的最稳定。5.2 如果键盘已经失灵了怎么进 BIOS如果你已经改了设置键盘失灵了但又需要进 BIOS 改回来有几个办法用 PS/2 键盘这是最直接的办法。PS/2 键盘不依赖 USB 控制器只要 8042 控制器还在工作就能用。用串口控制台有些主板支持串口重定向可以通过串口连接另一台电脑用终端软件进 BIOS。用网络 KVM如果主板支持 IPMI 或 AMT可以通过网络远程进 BIOS。清 CMOS如果问题只是设置问题清 CMOS 通常能恢复默认值。但如果是固件问题清 CMOS 没用。5.3 关于 USB 抓包的一些经验USB 抓包是排查 USB 问题的利器但用起来有几个注意事项抓包点要选对最好在设备和主机之间抓不要在 Hub 后面抓否则会混入 Hub 的流量。过滤要设好USB 流量很大如果不设过滤抓到的数据会非常多。可以按设备地址、端点号、传输类型来过滤。分析要耐心USB 协议栈很复杂一个简单的键盘按键背后可能涉及几十个 USB 包。分析的时候要有耐心从设备枚举开始一步步往下看。我用的 Teledyne LeCroy USB Protocol Suite 是专业级的分析仪价格不菲。如果只是偶尔用可以考虑用软件方案比如 Wireshark 的 USBPcap 插件虽然功能弱一些但胜在免费。6. 给想折腾 USB 设备的人几句实在话如果你看到这里对 USB 设备开发产生了兴趣想自己动手做一个 USB 键盘或者 USB 转串口工具我有几个建议。第一从 STM32 或者 RT-Thread 的官方示例开始。STM32 的 USB 库很成熟RT-Thread 的 USB 协议栈也很完善照着示例改比自己从头写要快得多。我这次用 STM32 做键盘就是参考了 RT-Thread 的 HID 示例只改了几个描述符就搞定了。第二USB 描述符是核心一定要搞清楚。设备描述符、配置描述符、接口描述符、端点描述符、HID 描述符、报告描述符每一层都有它的作用。特别是报告描述符它定义了数据包和实际按键之间的映射关系写错了设备就不工作。第三USB 抓包工具是必备的。不管你是做 USB 设备还是调试 USB 问题抓包工具都能帮你省下大量时间。如果预算有限可以用 Wireshark USBPcap虽然不如专业分析仪好用但基本够用。第四注意 USB 协议的版本差异。USB 1.1、USB 2.0、USB 3.0 在协议上有很大区别特别是 XHCI 和 EHCI 的差异。如果你做的是 USB 3.0 设备一定要看 XHCI 规范不要拿 EHCI 的经验去套。第五做好心理准备。USB 协议栈很复杂调试起来很痛苦。我这次做 STM32 键盘光描述符就调了两天中间无数次想放弃。但当你看到键盘在操作系统里正常工作的那一刻那种成就感是值得的。最后再说一句如果你只是想让键盘在 BIOS 里能用千万别去动 USB Legacy Support 和 XHCI Hand-off 这两个设置。默认值就是最好的除非你有明确的理由否则不要改。我这次就是手贱结果硬肝了 11 天差点把主板废了。
返回列表