熟悉 x86 电脑的朋友估计对 ACPI 这个名词不会陌生,在如今的计算机市场上,ACPI广泛应用于笔记本电脑、台式机、工作站以及服务器等产品上。新兴的 RISC-V 架构要进入桌面/服务器领域,不可避免地会与 ACPI 打上交道。
什么是 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 的系统的完整框图如下:
取自 ACPI specification v6.6[2]
▲
橙色部分是 ACPI 规范所覆盖的内容,因此 ACPI 定义的是一种软件和硬件组件的接口规范:
硬件上:
ACPI Register Set:在硬件上实现的 ACPI 寄存器组,为 x86 架构特有。ARM 和 RISC-V 通常用的是 hardware-reduced ACPI,可无需在硬件上实现这些寄存器。
软件上,定义了多个 ACPI 表(Table),这些表整体可分为两种类型:
Static Tables:又称为Data Tables,由裸数据组成,ACPI Driver 可直接读取表中的内容。
Definition Block Tables:由AML(ACPI Machine Language)字节码(byte code)组成,它的内容要经AML Interpreter(解释器)解释后才能被 ACPI Driver 读取到。
▲
绿色部分是操作系统中的相关组件,其中:
ACPI Driver:操作系统用于对接 ACPI 的驱动,AML Interpreter 也是属于其中的一部分。其中有一个比较出名的开源工程ACPICA(ACPI Component Architecture)[3],它提供了与操作系统无关的一些 ACPI 相关代码实现,也包括一个 AML Interpreter 的实现。目前 ACPICA 的代码被用于 Linux、FreeBSD 等系统中,作为 ACPI Driver 的一部分。
OSPM(Operating System-directed configuration and Power Management):以 ACPI 为核心、由操作系统主导的电源管理子系统的统称。
▲
蓝色部分是硬件或平台相关的组件,其中:
Platform Firmware是负责启动机器、实现休眠/唤醒/重启等接口的固件,通常指 BIOS/UEFI。它也负责生成各个 ACPI 表并提供给操作系统。
ACPI Namespace
前面提到 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 的关系
在 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?
在讨论 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]
Device Tree vs ACPI
前面提到说 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(local010) {? ? ? ? ? ? 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,是更加合适的选择。
ARM 的选择
嵌入式领域高度定制化的产品特点,难以形成行业内通用的标准。在面对个人电脑/服务器这些有着几十年历史、涉及诸多零部件厂商、并且相互间遵循一定行业标准的 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 的分类:
SystemReady LS 被弃用
SystemReady ES 和 SR 统称为新的 “SystemReady”,用于那些可运行一个无需定制化修改的、通用的操作系统的产品,它要求 ACPI 是必须实现的。
SystemReady IR 则改名为 “SystemReady Devicetree”,用于那些运行嵌入式 Linux/BSD 操作系统的产品。
取自 Arm SystemReady Requirements Specification v3.0[13]
可见,对于个人电脑/服务器领域,ACPI 是十分重要的,它是实现操作系统通用化不可或缺的一环。
Hardware-reduced ACPI
ACPI 诞生于 x86 架构,它的规范中也规定了需在硬件上实现的 ACPI 寄存器组,这些寄存器跟 x86 自然有着千丝万缕的关系。但 ARM/RISC-V 硬件上不一定实现有这些寄存器,那它们要如何支持 ACPI 呢?
ACPI 规范 v5.0 引入了一种新的方法,称为hardware-reduced ACPI,它不再要求必须实现以下这些 ACPI 硬件特性[14]:
Power Management (PM) timer
Real Time Clock (RTC) wake alarm
System Control Interrupt (SCI)
Fixed Hardware register set (PMx_* event/control/status registers)
GPE block registers (GPEx_* event/control/status registers)
Embedded controller
相对应地,某些功能有了替代的实现手法。例如 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 电源管理
ACPI 电源管理相关状态分类
关于电源管理,ACPI 规范中为系统以及设备定义了以下状态(state):
取自 ACPI specification v6.6[2]
▲
系统的全局状态Gx(Global System State)与睡眠状态 Sx(Sleeping State):
G0(S0)- Working:正常工作状态。
G1 - Sleeping:以较低功耗运行的状态。从用户角度 “看起来” 系统像是关闭的,但无需重启操作系统就可回到 G0/S0 状态。G1 又细分为 S1~S4 四种传统状态,以及一种相对较近新提出的 S0ix 状态:
S1 - POS(Power on Suspend):最耗电的睡眠状态。该状态下会维持 CPU 和内存的供电,操作系统的上下文不会丢失。
S2:一种比 S1 更深的睡眠状态。该状态下 CPU 会断电。
S3 - STR(Suspend to RAM)/ Standby / Sleep:该状态下只有内存被供电,除了内存外的其他上下文都不会保留。
S4 - STD(Suspend to Disk)/ Hibernation / Non-Volatile Sleep:该状态允许主板断电,操作系统会将上下文保存在非易失存储介质(Non-Volatile Storage)中。
S0ix- 该状态有多种名称:ACPI 规范中称之为Low Power S0 Idle[2],英特尔称之为S0ix[15],微软称之为Modern Standby[16],Linux 内核称之为Suspend o Idle 或 S2Idle[17]该睡眠状态的功耗接近甚至低于传统的S3 状态,并且能更快地恢复到 G0/S0 状态。该状态还可以继续细分为 S0i1、S0i2、S0i3 等子状态。
G2(S5)- Soft Off:以最低功耗运行的状态。硬件不保留操作系统的上下文,操作系统经重启后才能回到 G0/S0 状态。该状态下并不一定能安全地移除硬件。
G3 - Mechanical Off:机械上的断电状态。不保留硬件上下文,可安全移除硬件。操作系统经重启后才能回到 G0/S0 状态。该状态下除了 RTC(real-time clock)外,功耗为零。
Legacy:如果系统不支持 ACPI,则运行在该状态。该状态下的电源管理通过 APM、Legacy PnP 等规范实现。
▲
设备的电源状态Dx(Device Power State):系统处于 G0/S0 状态时,设备可在以下电源状态之间切换(设备不一定会实现所有这些电源状态,实现的状态多寡会视设备类别而有所不同):
D0 - Fully-On:功耗最高的状态。设备完全活跃并能持续保持所有相关上下文。
D1:其含义视设备类别而定。通常会被定义为相比 D2 功耗更高、保留的上下文更多的状态。很多设备都没有定义该状态。
D2:其含义视设备类别而定。通常会被定义为相比 D1 或 D0 功耗更低、保留的上下文更少的状态。很多设备都没有定义该状态。
D3hot:其含义视设备类别而定。通常会被定义为在不影响设备枚举的情况下功耗尽可能低的状态。
D3(D3cold)- Off:设备完全断电。该设备所有上下文都会丢失。在软件上无法被枚举到。
▲
CPU 的电源状态Cx(Processor Power State):系统处于 G0/S0 状态时,CPU 可在以下电源状态之间切换:
C0:该状态下 CPU 会正常执行指令。
C1 - Halt:拥有最短唤醒延迟的状态。该状态下 CPU 不执行指令。
C2 - Stop Clock:比 C1 功耗更低,但唤醒延迟更长。该状态下 CPU 不执行指令。
C3 - Sleep:比 C2 功耗更低,但唤醒延迟更长。该状态下 CPU 不执行指令。
▲
CPU 或设备的性能状态Px(Device and Processor Performance State):当 CPU 或设备处于活跃状态时(C0/D0),可处于以下不同的性能状态:
P0:性能最高,功耗最大。
P1 ~ Pn:随着 n 增大,性能降低,功耗也降低。n 的大小视实际 CPU 和设备而定,最大不超过 255。
Hardware-reduced ACPI 的电源管理实现
系统级睡眠状态 Sx
传统 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 状态的切换:
SBISRST(System Reset)Extension:可用于实现重启/关机功能。
SBISUSP(System Suspend)Extension:可用于实现休眠功能。
设备电源状态 Dx
设备的 Dx 电源状态不涉及 ACPI 硬件寄存器,ARM/RISC-V 也与 x86 相同,通过 ACPI 规范中定义的 ASL 对象(object)来实现,具体包含以下这些:
取自 ACPI specification v6.6[2]
取自 ACPI specification v6.6[2]
CPU 电源状态 Cx 与性能状态 Px
对于 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” 实现。
RISC-V ACPI 的相关规范
借 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 状态的控制。
进迭时空芯片对 ACPI 的支持
目前进迭时空已经量产的 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 那样,只需一个操作系统镜像就可在不同的机器上运行。
-
ACPI
+关注
关注
1文章
14浏览量
9171 -
电源接口
+关注
关注
0文章
68浏览量
18698 -
RISC-V
+关注
关注
46文章
2660浏览量
49643
发布评论请先 登录
关于RISC-V的二三事
浅谈RISC-V
为什么选择RISC-V?
RISC-V你了解多少?
【转载】RISC-V 能打 50 年!risc-v 现在和未来的发展
RISC-V 发展
RISC-V规范的演进 RISC-V何时爆发?
RISC-V学习笔记【1】RISC-V概述
openEuler加入RISC-V Landscape
聊一聊RISC-V处理器的二三事

RISC-V Summit China 2024 青稞RISC-V+接口PHY,赋能RISC-V高效落地

加入全球 RISC-V Advocate 行列,共筑 RISC-V 的未来 !

评论