4. FADT详解:电源管理寄存器与中断配置

FADT(Fixed ACPI Description Table)是 ACPI 启动流程中仅次于 RSDP 的核心表。它承载了硬件平台与 OSPM(操作系统电源管理)之间的关键握手信息,包括电源管理寄存器的物理地址、SCI 中断路由策略以及 SMI 命令端口。本章将深入解析 FADT 中与电源性能调优直接相关的字段。

4.1 FADT 表头与核心结构

FADT 的起始部分遵循标准 ACPI 表头,随后是长度可变的固定布局字段。下表列出了与电源管理直接相关的关键字段及其偏移量:

偏移(字节) 字段名称 长度(字节) 描述
0 Signature 4 固定为 "FACP"
4 Length 4 表总长度,>= 244(ACPI 6.5)
40 SCI_INT 2 SCI 中断号(通常为 9)
44 SMI_CMD 4 SMI 命令端口 I/O 地址
48 ACPI_ENABLE 1 写入 SMI_CMD 以启用 ACPI 的值
49 ACPI_DISABLE 1 写入 SMI_CMD 以禁用 ACPI 的值
64 PM1a_EVT_BLK 4 PM1a 事件寄存器块基地址
68 PM1b_EVT_BLK 4 PM1b 事件寄存器块基地址(0 表示不存在)
72 PM1a_CNT_BLK 4 PM1a 控制寄存器块基地址
76 PM1b_CNT_BLK 4 PM1b 控制寄存器块基地址(0 表示不存在)
80 PM2_CNT_BLK 4 PM2 控制寄存器块基地址(0 表示不存在)
84 PM_TMR_BLK 4 PM 定时器寄存器块基地址
88 GPE0_BLK 4 GPE0 寄存器块基地址
92 GPE1_BLK 4 GPE1 寄存器块基地址(0 表示不存在)
调试提示: 在 Linux 下使用 acpidump 和 iasl 解析 FADT 时,重点关注 SCI_INT 是否与 IRQ 路由表匹配,以及 PM1a_EVT_BLK 的地址是否在 ACPI 驱动 IO 资源范围内。

4.2 电源管理寄存器详解

FADT 描述的电源管理寄存器块是 OSPM 直接操作硬件电源状态的窗口。这些寄存器通过 I/O 空间或内存映射空间访问,具体由 X_PM1a_EVT_BLK 等扩展地址字段中的地址空间 ID 决定。

4.2.1 PM1 事件与状态寄存器(PM1_EVT)

PM1_EVT 块包含两组寄存器:状态寄存器(PM1_STS)和使能寄存器(PM1_EN)。每组长度为 2 字节(16 位)。PM1a 是必须存在的,PM1b 为可选。当 PM1b 存在时,其寄存器与 PM1a 的对应寄存器在逻辑上拼接为 32 位宽。

  • PM1_STS(偏移 0x00): 记录电源管理事件,如电源按钮按下、唤醒事件、RTC 闹钟等。写 1 清零。
  • PM1_EN(偏移 0x02): 控制哪些事件可以触发 SCI。写 1 使能对应事件的中断。

4.2.2 PM1 控制寄存器(PM1_CNT)

PM1_CNT 块长度为 2 字节,用于控制系统睡眠状态转换(Sleep/ Wake)和 CPU 时钟调节。关键位域包括:

  • SCI_EN(Bit 0): ACPI 硬件使能标志。OSPM 通过写入 SMI_CMD 使能 ACPI 后,此位由硬件置 1。
  • SLP_TYPx(Bits 10-12): 睡眠类型,定义要进入的 S 状态(S1/S3/S4/S5)。
  • SLP_EN(Bit 13): 睡眠使能位。OSPM 写入此位后,硬件立即开始睡眠序列。

4.2.3 PM2 控制寄存器(PM2_CNT)

PM2_CNT 块长度为 1 字节,主要用于处理器性能状态(P-State)的硬件协调。其核心位域为:

  • ARB_DIS(Bit 0): 总线仲裁禁用位。在某些多处理器系统中,用于控制处理器对系统总线的访问优先级,以配合 P-State 切换。

4.2.4 GPE 寄存器块

GPE(General Purpose Event)寄存器块用于处理非固定功能的电源管理事件,例如设备唤醒、热插拔、电池状态变化等。每个 GPE 块包含状态寄存器和使能寄存器,长度由 FADT 中的 GPE0_BLK_LEN 和 GPE1_BLK_LEN 字段定义。

性能调优要点: 在低功耗嵌入式平台中,PM1 和 GPE 寄存器的访问延迟直接影响唤醒响应时间。建议通过 FADT 的 X_PM1a_EVT_BLK 等扩展字段确认寄存器是否映射到 MMIO 空间,MMIO 通常比 IO 空间具有更低的访问延迟。
FADT 电源管理寄存器架构 FADT 电源管理寄存器架构 FADT 表 PM1_EVT PM1_STS (16-bit) PM1_EN (16-bit) 基址: PM1a_EVT_BLK PM1_CNT SCI_EN (Bit 0) SLP_TYPx (Bits 10-12) 基址: PM1a_CNT_BLK PM2_CNT ARB_DIS (Bit 0) P-State 协调 基址: PM2_CNT_BLK GPE0_BLK GPE0_STS / GPE0_EN 设备唤醒、热插拔、电池事件 GPE1_BLK(可选) GPE1_STS / GPE1_EN 扩展事件源 说明 PM1a 必须存在,PM1b 和 PM2 可选。GPE0 用于固定功能之外的事件。 所有寄存器块基址由 FADT 中的 32 位或 64 位地址字段指定。

4.3 SCI 中断配置

SCI(System Control Interrupt)是 ACPI 硬件向 OSPM 发送事件通知的主要机制。FADT 中的 SCI_INT 字段定义了 SCI 使用的 IRQ 号。在 x86 平台上,这个值通常为 9,但也可以由平台固件配置为其他值。

4.3.1 SCI 中断路由

SCI 必须被配置为高电平触发(Level-Triggered, High Active)。OSPM 在启动阶段通过解析 MADT(Multiple APIC Description Table)和 FADT 来建立 SCI 的中断路由。如果 SCI_INT 与某个设备的中断号冲突,会导致中断风暴或功能异常。

常见陷阱: 某些固件在 FADT 中填写 SCI_INT = 0,这表示 SCI 未使用或通过其他方式配置。OSPM 在这种情况下应回退到默认 IRQ 9,并验证中断控制器是否已正确配置。

4.3.2 SCI 与 SMI 的协同

在系统从 SMM(System Management Mode)过渡到 ACPI 模式时,SCI 和 SMI 的切换是关键步骤。FADT 中的 SMI_CMD、ACPI_ENABLE 和 ACPI_DISABLE 字段定义了 OSPM 如何通过写入 I/O 端口来请求固件切换中断模式。

SCI 中断配置与 SMI 切换流程 SCI 中断配置与 SMI 切换流程 OSPM 读取 FADT 获取 SCI_INT & SMI_CMD 写入 SMI_CMD (ACPI_ENABLE) 固件: 切换 SCI 使能, 禁用 SMI OSPM 配置中断控制器 SCI 正常工作 SCI_INT 必须与 MADT 中的中断源匹配

4.4 SMI 命令端口

SMI_CMD 字段定义了 OSPM 用于与 SMM 通信的 I/O 端口地址。OSPM 通过向此端口写入 ACPI_ENABLE 或 ACPI_DISABLE 值,请求固件在 SMM 中执行 ACPI 模式的切换。

4.4.1 命令端口使用规范

  • ACPI_ENABLE: OSPM 写入此值后,固件应设置 SCI_EN 位,并将 SCI 中断路由到操作系统。
  • ACPI_DISABLE: OSPM 写入此值后,固件应清除 SCI_EN 位,并将控制权交还给 SMM。
  • 端口宽度: 通常为 8 位 I/O 端口,但 FADT 也支持通过 X_SMI_CMD 扩展字段定义 32 位或 64 位地址。
调试方法: 在 Linux 下,可以通过 cat /sys/firmware/acpi/tables/FACP 查看原始 FADT 内容。使用 iasl -d FACP.dat 反编译后,重点关注 SMI_CMD 和 ACPI_ENABLE 字段。如果系统无法进入 ACPI 模式,检查 SMI_CMD 端口是否被其他设备占用。

4.5 实战:解析 FADT 并验证电源管理配置

以下步骤演示了如何在 Linux 环境下解析 FADT 并验证关键电源管理配置:

  1. 获取 FADT 原始数据: acpidump > acpi.dat && acpixtract -a acpi.dat
  2. 反编译 FADT: iasl -d FACP.dat
  3. 查看反编译输出: 打开 FACP.dsl,定位到以下字段:
// FACP.dsl 关键字段示例
[0x02C] SCI_INT              : 9
[0x030] SMI_CMD              : 000000B2
[0x034] ACPI_ENABLE          : 01
[0x035] ACPI_DISABLE         : 00
[0x040] PM1a_EVT_BLK         : 00001000
[0x044] PM1b_EVT_BLK         : 00000000
[0x048] PM1a_CNT_BLK         : 00001004
[0x04C] PM1b_CNT_BLK         : 00000000
[0x050] PM2_CNT_BLK          : 00001050
[0x054] PM_TMR_BLK           : 00001008
[0x058] GPE0_BLK             : 00001020
[0x05C] GPE1_BLK             : 00000000
  1. 验证寄存器地址范围: 使用 cat /proc/ioports 检查上述 I/O 地址是否被正确声明。
  2. 检查 SCI 中断: cat /proc/interrupts | grep acpi 确认 SCI 中断号与 FADT 中的 SCI_INT 一致。
性能调优建议: 如果平台支持,优先使用 FADT 中的 X_PM1a_EVT_BLK 等 64 位扩展地址字段。这些字段允许寄存器映射到 MMIO 空间,从而减少 IO 指令的开销,提升电源管理事件的响应速度。

4.6 本章小结

FADT 是 ACPI 电源管理的硬件接口手册。通过本章的学习,你应该掌握:

  • PM1a/PM1b、PM2、GPE 寄存器块的布局与功能。
  • SCI 中断的配置方法及其与 SMI 的切换流程。
  • SMI 命令端口的使用规范与调试要点。
  • 如何通过 Linux 工具解析 FADT 并验证硬件配置的正确性。