UEFI 关闭USB唤醒的原理

UEFI 关闭USB唤醒的原理

概述

USB唤醒(USB Wake)指系统进入睡眠状态(S3 Suspend-to-RAM)后,通过USB设备(鼠标移动、键盘按键等)将系统唤醒。UEFI固件中提供"USB唤醒"开关,关闭该选项后USB设备不再能唤醒系统。

本文从ACPI、PCI电源管理、芯片组GPIO路由三个层面解释其工作原理。


1. 相关技术栈

复制代码
用户操作 → UEFI Setup (关闭 USB Wake)
              ↓
        UEFI 固件修改以下内容之一或多个:
              ↓
    ┌───────┼───────────────┐
    ↓       ↓               ↓
 ACPI表   PCI配置空间    芯片组寄存器
(_PRW)   (PMCSR)       (GPIO/PME路由)
层级 组件 作用
ACPI _PRW (Power Resource for Wake) 向OS描述设备是否支持唤醒以及从哪个睡眠状态唤醒
PCI PM PMCSR (Power Management Control/Status) PCI设备的PME#使能位,控制设备能否发出唤醒信号
芯片组 GPIO路由 / PMC (Power Management Controller) 物理层面将USB控制器的唤醒信号连接到PCH的唤醒逻辑

2. ACPI 层:_PRW 方法

每个USB控制器(xHCI/EHCI)在ACPI命名空间(DSDTSSDT)中都有一个设备对象,其中包含 _PRW 方法。

开启USB唤醒时的 _PRW 示例

asl 复制代码
Device (XHC)                    // xHCI USB 3.0 Controller
{
    Name (_PRW, Package () {
        0x6D,                   // GPE (General Purpose Event) 编号
        3                       // 可从 S3 唤醒
    })
    ...
}
  • 第一个参数:GPE(General Purpose Event)编号 --- 当USB控制器触发PME时,芯片组产生该GPE中断
  • 第二个参数:支持的唤醒睡眠状态(3 表示S3)

关闭USB唤醒时UEFI的做法

固件有多种策略移除该能力:

策略A:将 _PRW 改为 Package(Zero, Zero)

asl 复制代码
Name (_PRW, Package () {
    0,      // GPE = 0 → 无唤醒能力
    0
})

操作系统在设备初始化时调用 _PRW,发现返回值为零,判定该设备不支持唤醒,不会为其注册唤醒回调。

策略B:从DSDT中移除 _PRW 方法

直接删除 _PRW 定义,OS根本不会尝试将该设备设置为唤醒源。

策略C:修改 _PRW 的返回值为不支持的状态

asl 复制代码
Name (_PRW, Package () {
    0x6D,
    0       // 返回 0 表示不支持任何睡眠状态唤醒
})

3. PCI 电源管理:PMCSR 寄存器

USB控制器作为PCIe设备,其PCI配置空间Power Management Capability结构中包含PMCSR(Power Management Control/Status)寄存器:

PMCSR 位定义

名称 说明
15 PME_Status 只读,PME已触发,写1清零
8 PME_Enable 1=允许设备发出PME唤醒信号
1:0 PowerState 电源状态 (D0/D1/D2/D3hot)

UEFI 关闭唤醒时的操作

UEFI固件在启动时(或S3准备阶段)写入USB控制器的PCI配置空间:

复制代码
PMCSR[8] (PME_Enable) = 0

清除PME使能位,设备在D3状态时不会断言PME#引脚。

固件执行时机

复制代码
S3 入睡前(UEFI runtime 或 OS 通过ACPI调用):
  固件 S3 Boot Script 中包含一条配置空间写入:
  PCI_CFG_WRITE(Bus:Dev:Func, PMCSR_offset, 0x00)

这些操作被记录为 S3 Boot Script,系统恢复时由固件重放。


4. 芯片组层:GPIO / GPE 路由

当USB控制器的PME#被触发,信号需要经过芯片组(PCH)路由到CPU的唤醒逻辑。

硬件信号路径

复制代码
USB设备插拔 → xHCI控制器 → PME#断言 → PCH GPIO Pad
                                          ↓
                                     GPE Status Bit 置位
                                          ↓
                                    ACPI PM1 寄存器
                                          ↓
                                    SLP_EN → SLP_S3# 释放
                                          ↓
                                    系统恢复

UEFI 关闭唤醒时的操作

UEFI固件可以通过芯片组特定的寄存器屏蔽GPIO Pad的唤醒能力

  • PCH GPIO社区(Community)配置寄存器 :每个GPIO pad有对应的 PADCFG 寄存器

  • PADCFG0.RxWake / PADCFG0.RxConfig:控制该pad能否产生GPE

  • UEFI将其置为 DISABLE,使USB控制器产生的PME无法转换为GPE

    GPIO PADCFG0 (偏移 0x100 + index * 8) // 示例地址
    bit 11: RxWake → 0 (Disable)
    bit 10: RxConfig → 0 (GPIO mode, 非native)


5. 固件配置流程(完整链路)

复制代码
┌──────────────────────────────────────────────────────────┐
│ UEFI Setup 用户关闭 "USB Wake"                           │
│                                                          │
│   UEFI 固件读取 Setup Variable ("UsbWakeSupport", 0x00)  │
│                                                          │
│   策略决策 (以下全部或部分执行):                          │
│                                                          │
│   ① ACPI 表修补:                                         │
│      - 运行时修改 DSDT/SSDT 中 USB 设备的 _PRW            │
│      - 或加载 SSDT override 覆盖原 _PRW                   │
│                                                          │
│   ② 生成 S3 Boot Script:                                 │
│      - PCI PMCSR.PME_EN = 0                              │
│      - GPIO PADCFG.RxWake = 0                            │
│                                                          │
│   ③ Runtime 调用:                                        │
│      在 ExitBootServices 前的最后时刻                     │
│      或通过 SMM 在 OS 写入 PMCSR 后进行拦截                │
└──────────────────────────────────────────────────────────┘

6. 操作系统层面的影响

固件层面关闭USB唤醒后,OS(Windows/Linux)的行为:

工具/机制 关闭前 关闭后
powercfg /devicequery wake_armed 列出USB设备 USB设备消失
cat /proc/acpi/wakeup USB控制器为 enabled USB控制器为 disabled
Windows 设备管理器 "允许此设备唤醒计算机" 可选且有效 灰显或勾选无效
echo DEV > /proc/acpi/wakeup 可以重新启用 重新启用后仍无效(硬件屏蔽)

7. 不同固件实现方式对比

方式 影响范围 能否被OS覆盖 安全性
仅清除 PMCSR.PME_EN 仅当前会话,S3恢复时可能被固件重置 是(OS可重新置位)
修改 ACPI _PRW 设备枚举阶段,持久 是(echo 到 /proc/acpi/wakeup)
GPIO Pad 级别屏蔽 物理信号层面,最彻底 (OS无法绕过) 最强
三者组合 三重保障 无法绕过 最强

8. 常见问题

Q: 为什么关闭USB唤醒后,某些USB设备仍能唤醒?

  • 设备连接在不同控制器(如USB 2.0 EHCI vs USB 3.0 xHCI),固件只关闭了其中一个
  • 固件Bug:Setup Variable读取失败,默认保持开启
  • 使用了USB Wake from S5(关机充电功能),与S3唤醒是独立控制通道

Q: S4 (Hibernate) 和 S5 (Soft Off) 的USB唤醒?

S4/S5的USB唤醒(如"USB充电"、"开机功能")由独立于PME的电路控制,通常位于EC(Embedded Controller)或PCH的always-on域中。关闭UEFI中的"USB Wake"通常只影响S3,不影响S4/S5的USB唤醒功能。

Q: Linux 下绕过限制?

bash 复制代码
# 即使固件关闭了PME_EN,OS仍可以尝试重新开启
echo enabled > /sys/bus/pci/devices/0000:00:14.0/power/wakeup

但如果固件在GPIO层面做了屏蔽,物理信号无法到达PCH,OS层面无法绕过。


参考

相关推荐
yao0003714 天前
【7】UEFI固件存储格式
uefi·bios·固件
spencer_tseng22 天前
Thinkpad T440p BIOS F1
bios·thinkpad·f1·t440p
郭老二1 个月前
【经验】工控机上电自启动设置
bios
深念Y1 个月前
从CH341A编程器、SPI Flash到Linux+STM32理解
linux·stm32·flash·bios·固件·编程器·闪存
BestOrNothing_20152 个月前
(2)联想拯救者安装 Ubuntu 双系统前的 BIOS 设置全过程
linux·bios·拯救者·ubuntu22.04·联想lenovo
yao000373 个月前
基于QEMU+OpenSBI+edk2的riscv启动流程解析
qemu·riscv·uefi·bios·固件·opensbi
seasonsyy4 个月前
如何快速进入BIOS(绕过键盘按键识别难题)
bios
love530love5 个月前
【笔记】华硕 ROG MAXIMUS Z890 HERO 主板 BIOS 更新完整操作实录
运维·人工智能·windows·笔记·单片机·嵌入式硬件·bios
REDcker5 个月前
UEFI BIOS深度解析:现代固件架构的革命性突破
架构·操作系统·uefi·bios