熟悉 x86 电脑的朋友估计对 ACPI 这个名词不会陌生,在如今的计算机市场上,ACPI 广泛应用于笔记本电脑、台式机、工作站以及服务器等产品上。新兴的 RISC-V 架构要进入桌面/服务器领域,不可避免地会与 ACPI 打上交道。
ACPI 全称是 Advanced Configuration and Power Interface(高级配置与电源接口),它是一套开放标准,可供操作系统用于发现和配置硬件、自动配置即插即用和热插拔设备、进行电源管理以及状态监控等 [1]
ACPI 的初版规范由英特尔(Intel)、微软(Microsoft)和东芝(Toshiba)共同制定,在 1996 年 12 月发布。随后越来越多的公司加入到 ACPI 规范的改进中。2013 年 10 月,ACPI 规范转交由 UEFI 论坛维护,一直至今。最新的 ACPI 规范已经演变到了 6.6 版本,在 2025 年 5 月发布。
在 ACPI 之前,计算机的电源管理几乎完全交由底层的 BIOS 固件来控制,这大大限制了操作系统在能耗控制上的功能。ACPI 的出现,取代了 APM(Advanced Power Management)、MPS(MultiProcessor Specification)、Legacy PnP(Plug and Play BIOS)等规范,让操作系统在电源管理和硬件配置上获得了更多的自主权,从而实现了 OSPM(Operating System-directed configuration and Power Management,操作系统导向的配置和电源管理)系统。
一个使用 ACPI 的系统的完整框图如下:
取自 ACPI specification v6.6 [2]
▲橙色部分是 ACPI 规范所覆盖的内容,因此 ACPI 定义的是一种软件和硬件组件的接口规范:
▲绿色部分是操作系统中的相关组件,其中:
▲蓝色部分是硬件或平台相关的组件,其中:
前面提到 ACPI 的 Definition Block Tables 由 AML 字节码组成,而 AML 字节码的生成流程通常如下图:工程师使用 ASL(ACPI Source Language)语言对硬件信息进行描述,随后通过 ASL 编译器(例如 iASL)将其编译为 AML 字节码,生成 Definition Block Tables,并打包进固件:
取自 Basic ACPI Source Language (ASL) Constructs Tutorial [4]
从固件中获取到 ACPI 表后,操作系统中的 AML Interpreter 会解析 AML 字节码,构造出硬件设备的树状层次结构,这种结构称为 ACPI namespace。操作系统从 ACPI namespace 中即可获取到硬件的各种信息:
取自 Basic ACPI Source Language (ASL) Constructs Tutorial [4]
在 ACPI 出现的场合,通常也能见到 UEFI 的身影。UEFI 全称是 Unified Extensible Firmware Interface(统一可扩展固件接口),它是计算机固件的一种规范,旨在替代 BIOS。
它的前身是英特尔于 1998 年提出的 Intel Boot Initiative,后改名为 EFI(Extensible Firmware Interface,可扩展固件接口),再于 2005 年改名为 UEFI 并转交由 UEFI 论坛维护发展至今 [5]。UEFI 规范的一个比较出名的实现是由 TianoCore 社区开源的 EDK II 工程 [6]。
虽然都是规范,但 ACPI 与 UEFI 关注的点不同:ACPI 是从硬件抽象的角度定义了操作系统发现、配置、管理硬件的规范接口,而 UEFI 定义的是固件与操作系统间软件层面的规范接口。从两者最初制定的目的也能看出差异:ACPI 是为了将 BIOS 固件的电源管理等功能以规范的接口交由操作系统来主导,而 UEFI 则是为了替代 BIOS 固件本身。
ACPI 与 UEFI 初版规范的提出都有英特尔的参与,并后面都交由 UEFI 论坛 [7]维护,两者间存在着诸多联系,但并非强绑定,其他 bootloader(如 U-Boot)也可以支持 ACPI,UEFI 也支持安装其他的配置表(如 Device Tree)供操作系统使用。不过在个人电脑/服务器领域,UEFI + ACPI 还是目前最常见、最成熟的使用组合。
在讨论 RISC-V 为什么需要支持 ACPI 之前,我们可以看一下发展路线十分相似的 ARM:同样都是起家于嵌入式领域,随后向个人电脑/服务器领域发起进攻。ARM 所经历过的挑战,在 RISC-V 上也同样存在。
嵌入式领域与个人电脑/服务器领域,两者的产品生态形式有较大的不同:
▲嵌入式领域的产品,通常会存在一个品牌厂商,整合上游厂商提供的软、硬件,做成一个高度定制化的最终产品,并对其负责。例如手机,普通用户通常接触到的只有苹果/华为/小米等最终的手机品牌厂商,无法轻易更换手机主板上的硬件,不同手机的固件/操作系统通常也互不通用。
▲个人电脑/服务器领域的产品,普通用户能直接接触到的厂商会多很多,CPU、主板、电源、硬盘、显卡等均可能来自不同的厂商,用户可选择合适的零部件产品,自行搭建出满足自身需求的机器。各零部件厂商也只对自身的零部件产品负责。软件操作系统的通用性也更强,一台机器可以运行 Windows、Ubuntu 等不同的操作系统,同一个操作系统通常也只需一个镜像就可适配不同的硬件机器。
(当然,目前市面上不乏很多集成化、定制化程度很高的个人电脑产品,例如苹果公司的 Mac 电脑,或其他一些笔记本电脑,它们的产品形态更接近于手机这样的嵌入式产品,普通用户无法轻易自行更换其软、硬件。不过从整体生态而言,这样的产品还是相对少数。)
个人电脑/服务器生态中如此多厂商的软、硬件能相互通用,不可或缺地会存在 “标准”。
在 20 世纪 70~80 年代,个人电脑(PC,Personal Computer)刚面向市场时,并不存在统一的标准,不同厂商间的个人电脑互不兼容。1981 年 8 月,IBM 推出了 IBM PC,并随后公布了上面除 BIOS 外的全部技术资料,并允许第三方公司生产与其兼容的硬件,即采用所谓的开放架构(open architecture)。
此举大大促进了整个个人电脑产业的发展,IBM PC 逐渐成为事实上的个人电脑 “开放标准”,与该标准兼容的机器都统称为 “IBM PC 兼容机”(IBM PC Compatible)[8]。
随着计算机技术的发展,到了 1990 年代,IBM 对个人电脑架构的影响力逐渐下降,取而代之的业界标准变成了 “Wintel” [9] :Windows + Intel,代指基于英特尔(Intel)的 x86 处理器、运行微软(Microsoft)的 Windows 操作系统的个人电脑。由英特尔和微软主导的行业联盟发布了诸多的软、硬件规范:UEFI、ACPI、PCI/PCIe 等,“IBM PC 兼容机” 的说法也逐渐被 “标准 PC”(standard PC)以及后续的 “ACPI PC” 所取代 [8]。
Wintel 架构在 x86 计算机中极具统治力,一直至今。除了台式机外,笔记本电脑或服务器产品也深受其影响,并且即使机器是基于其他厂商(如 AMD)的 x86 处理器,或运行其他的操作系统(如 Linux),也在很大程度上兼容该架构。
2000 年代的个人电脑主板结构框图 [10]
前面提到说 ACPI 的 ASL 语言可以通过 ACPI namespace 这样的硬件抽象结构来描述硬件信息,供操作系统使用,而嵌入式领域常用的另外一套技术方案 —— Device Tree,也能对硬件进行抽象。单论硬件抽象功能,两者并无孰优孰劣之分,那随着 ARM/RISC-V 进入个人电脑/服务器领域,Device Tree 是否有可能伴随 ARM/RISC-V 的使用惯性而带入进来,并成为与 ACPI 抗衡甚至取代 ACPI 的新行业标准?
目前来看暂无这样的趋势。因为在个人电脑/服务器领域,Device Tree 相比 ACPI 还是有以下两点不足:
▲一是规范的涉及范围:Device Tree 的规范 [11] 只涉及如何使用 DTS(Device Tree Source)语言来描述硬件信息,而 ACPI 规范涉及的范围更广:除了如何使用 ASL 语言描述硬件信息,ACPI 规范还规定了操作系统如何与底层固件、硬件交互的很多要求。这些规范的约束,是实现 “一个通用操作系统可运行在不同机器上” 的必要条件之一。
▲二是灵活性:ASL 语法上更加灵活,如下面的例子,它支持变量赋值、流程控制等运算符,可以让固件在无需修改操作系统的情况下,实现更加灵活的行为:
DefinitionBlock ("", "DSDT", 2, "", "", 0x0)
{
Name (INT1, 0x02)
Method (CTDW, 1) {
local0 = arg0
while (local0) {
printf ("%o",local0)
local0--
}
}
Method (CTUP, 1) {
local0 = arg0
while (local0 < 10) {
if (!(local0 % 2)) {
printf ("%o is even", local0)
} else {
printf ("%o is odd", local0)
}
local0++
}
}
}
因此,目前 Device Tree 有的,ACPI 有;Device Tree 没有的,ACPI 也有。并且在 ACPI 已经是个人电脑/服务器领域生态标准的前提下,要扩展 Device Tree 让它成为一个并没有明显优于 ACPI 的新标准,成为一件费力又不讨好的事情。自然而然地,在嵌入式领域使用更加轻量的 Device Tree,在个人电脑/服务器领域使用更符合行业生态标准的 ACPI,是更加合适的选择。
嵌入式领域高度定制化的产品特点,难以形成行业内通用的标准。在面对个人电脑/服务器这些有着几十年历史、涉及诸多零部件厂商、并且相互间遵循一定行业标准的 x86 传统生态领域时,ARM 嵌入式领域常用的 U-Boot、Device Tree 等技术方案也难以施展拳脚。那么 ARM 的选择自然不言而喻:在个人电脑/服务器也全面拥抱起了 x86 常用的 UEFI、ACPI、SMBIOS 等标准。
对此,ARM 于 2020 年发布了 Arm SystemReady 标准,对不同产品的软、硬件做出规范要求:
ARM SystemReady 对不同产品的要求。取自 arm-systemready-whitepaper.pdf [12]
在 2024 年 11 月 21 日发布的 Arm SystemReady Requirements Specification v3.0 [13]中,ARM 调整了 SystemReady 的分类:
取自 Arm SystemReady Requirements Specification v3.0 [13]
可见,对于个人电脑/服务器领域,ACPI 是十分重要的,它是实现操作系统通用化不可或缺的一环。
ACPI 诞生于 x86 架构,它的规范中也规定了需在硬件上实现的 ACPI 寄存器组,这些寄存器跟 x86 自然有着千丝万缕的关系。但 ARM/RISC-V 硬件上不一定实现有这些寄存器,那它们要如何支持 ACPI 呢?
ACPI 规范 v5.0 引入了一种新的方法,称为 hardware-reduced ACPI,它不再要求必须实现以下这些 ACPI 硬件特性 [14] :
相对应地,某些功能有了替代的实现手法。例如 ACPI 的事件通知模型,在传统 x86 上它是通过 SCI(System Control Interrupt)中断和 GPE(General-Purpose Event)寄存器实现,由 SCI 中断来触发 ACPI 事件的产生;而在 hardware-reduced ACPI 中,则变成可通过 GPIO-signaled ACPI Events 或 Interrupt-signaled ACPI Events 这两种机制实现,前者是由 GPIO 中断来触发 ACPI 事件,后者则可由任意中断来触发 ACPI 事件。
关于电源管理,ACPI 规范中为系统以及设备定义了以下状态(state):
取自 ACPI specification v6.6 [2]
▲系统的全局状态 Gx(Global System State)与睡眠状态 Sx(Sleeping State):
▲设备的电源状态 Dx(Device Power State):系统处于 G0/S0 状态时,设备可在以下电源状态之间切换(设备不一定会实现所有这些电源状态,实现的状态多寡会视设备类别而有所不同):
▲CPU 的电源状态 Cx(Processor Power State):系统处于 G0/S0 状态时,CPU 可在以下电源状态之间切换:
▲CPU 或设备的性能状态 Px(Device and Processor Performance State):当 CPU 或设备处于活跃状态时(C0/D0),可处于以下不同的性能状态:
传统 x86 ACPI 会借助硬件寄存器来实现 Sx 状态切换,而对于使用 hardware-reduced ACPI 的 ARM/RISC-V,通常也不与 x86 的 ACPI 方法兼容。但所幸,它们都定义有架构内通用的规范接口,并且也可使用 UEFI 的一些标准接口:
▲UEFI runtime service(运行时服务)ResetSystem() 可供操作系统调用来实现重启或关机的功能,从而实现 G0/S0 与 G2/S5 状态间的切换。通过 UEFI runtime service,与硬件平台相关的寄存器操作被下放到 UEFI 或更底层的固件中,对操作系统不可见,操作系统只需调用 UEFI 的标准接口即可实现重启和关机的功能。
▲ARM 定义有 SCMI(System Control and Management Interface)规范,可提供一套标准接口用于电源、性能以及系统管理 [18],从而实现 Sx 状态的切换。
▲RISC-V 定义 SBI(Supervisor Binary Interface)规范 [19],通过以下这些标准接口可实现 Sx 状态的切换:
设备的 Dx 电源状态不涉及 ACPI 硬件寄存器,ARM/RISC-V 也与 x86 相同,通过 ACPI 规范中定义的 ASL 对象(object)来实现,具体包含以下这些:
取自 ACPI specification v6.6 [2]
取自 ACPI specification v6.6 [2]
对于 CPU 的电源状态 Cx 与性能状态 Px,ACPI 规范中均提供了方法供实现 hardware-reduced ACPI 的平台使用:
▲LPI(Low Power Idle)States 机制:结合 FFH 规范,通过该指令集架构平台自身的方法实现 CPU 的 Cx 状态控制。
▲CPPC(Collaborative Processor Performance Control)机制:结合 FFH 规范,通过协处理器对主处理器的 Px 状态进行控制。
LPI States 和 CPPC 两套机制都要结合 FFH(Functional Fixed Hardware)规范使用,FFH 规范让 ACPI 规范可以对接到各指令集架构平台自身内部的、架构间各异的一些实现方法。x86/ARM/RISC-V 都分别定义有自己的 FFH 规范[20][21][22]。
例如 RISC-V,FFH 最终会对接到 SBI 扩展的实现中:
▲Cx 状态的控制由 “ACPI LPI States 机制 + RISC-V FFH 规范 + RISC-V SBI HSM(Hart State Management)Extension” 实现。
▲Px 状态的控制由 “ACPI CPPC 机制 + RISC-V FFH 规范 + RISC-V SBI CPPC Extension” 实现。
借 ARM 的 “他山之石”,RISC-V 社区早早地认识到了在个人电脑/服务器领域对接生态标准的重要性,因此十分积极地制定了一些相关规范,其中涉及 ACPI 的有:
▲RISC-V BRS(Boot and Runtime Services)Specification [23]:分别为通用系统和定制化系统提出了 BRS-I(Interoperable)和 BRS-B(Bespoke)两套标准,定义了它们在设备发现、系统管理等方面的软件要求(类似于 ARM 的 “SystemReady” 和 “SystemReady Devicetree”),其中也包括对 RISC-V ACPI 的一些新增定义与实现要求:
为 RISC-V 新增的 ACPI ID。取自 RISC-V BRS specification v0.91 [23]
RISC-V 必须实现的 ACPI 表。取自 RISC-V BRS specification v0.91[23]
RISC-V 可按需实现的 ACPI 表。取自 RISC-V BRS specification v0.91 [23]
▲ACPI 规范中一些原有内容也增加 RISC-V 的支持,例如新增了描述 RISC-V Hart 能力的 RHCT(RISC-V Hart Capabilities Table),在 MADT(Multiple APIC Description Table)中增加描述 RISC-V 中断控制器 AIA 和 PLIC 的结构,等等:
ACPI v6.6 的改动(截图中并没有囊括所有),其中包含很多 RISC-V 内容。取自 ACPI specification v6.6 [2]
▲RIMT(RISC-V IO Mapping Table)Specification [24]:定义了描述 RISC-V IOMMU 信息的 ACPI 表的规范。
▲RISC-V FFH(Functional Fixed Hardware)Specification [22]:定义了 RISC-V 的 ACPI FFH 规范,供 ACPI 的 LPI States 机制和 CPPC 机制使用,实现对 CPU Cx 状态和 Px 状态的控制。
目前进迭时空已经量产的 8 核 64 位 RISC-V AI CPU 芯片 K1,已经基于开源的 Tianocore EDK II [6],完成了对 UEFI 的适配,预计在不远的将来也会加入 ACPI 的支持,在终端领域适配更加通用、开放的生态。
另外进迭时空正在研发中的服务器芯片平台,基于自研的 X100 高性能处理器核,完整支持虚拟化、安全、RAS 等服务器特性,符合 RISC-V Server SoC Specification v1.0 [25]规范的要求,目前也已经完成了 UEFI + ACPI 的适配,可基于 ACPI 启动 Linux 内核:
进迭时空服务器芯片平台 Linux 内核启动日志
RISC-V 因 “开放” 的优势而发展迅猛,但 “碎片化” 的乌云也一直笼罩在其上空。为此 RISC-V 社区制定了各种软、硬件规范,也接受了源自于 x86 的 ACPI,让碎片化问题逐步得以改善。相信在不远将来的某一天,RISC-V 也能像 x86 那样,只需一个操作系统镜像就可在不同的机器上运行。