ACPI 简介

Peter 于 2020-10-14 发布

ACPI的定义

ACPI 全称是 Advanced Configuration Power Interface。它是由 Intel, Microsoft, Toshiba, HP, Phoenix 在90年代中期的时候一起合作开发和制定的标准。ACPI是为了解决APM的缺陷而问世的。在此过程中它定义了许多新的规范所以把现有的PNP BIOS Spec, MP Spec 也一并集合了进来形成了新的规范。 那么APM是什么呢,APM全称是 Advanced Power Management(高级电源管理)它是一种基于BIOS 的系统电源管理方案 (是由BIOS实现)提供CPU和外设的电源管理功能;当空闲的时候会被OS调用提供CPU的电源管理。这个做法有什么缺陷呢?

  1. 由于基于APM 的每家的BIOS都有它自己的实现,使得它成为了一个黑盒子,而且不同的计算机的实现之间缺乏一致性,每个 BIOS 开发者必须精心维护自己的APM BIOS代码和功能。

  2. 系统进入挂起的原因无法知晓。用户是否按了进入睡眠按钮,还是BIOS认为系统已进入了空闲状态,或者电池电压过低,这些信息APM都无法知道,但是Windows必须要知道挂起的原因,即使系统 没有进入空闲状态。

  3. BIOS 无法知道用户在干什么,只有通过监视中断和I/O端口来猜测用户的活动。有时,BIOS会使系统处于完全混乱的状态,当系统没有空闲时将系统挂起或者当系统处于空闲状态时,却不进入挂 起状态。

  4. 早期APM(1.0和1.1)不提供任何系统性能信息,系统是否支持睡眠状态就只有尝试将系统转入睡眠模式才知道。如果BIOS不支持睡眠模式,那将导致死机。BIOS APM 1.2解决了这个缺陷。

  5. BIOS对USB设备、加插的电脑配件卡和IEEE1394设备全然不知,导致当以上设备没有进入空闲状态,而BIOS却认为系统已经进入空闲状态,从而发生冲突,使这些设备无法正常使用或系统死机。 微软为了推动发展笔记本电脑,提供更好的电源管理体验,所以提出来ACPI解决混乱的电源管理问题。

ACPI的工作原理

ACPI怎么解决APM存在的问题的呢?我觉得主要是通过定义Interface,硬件Interface,软件Interface,以及ACPI 数据结构,并把它们汇报给OS,由OS统一控制管理这些设备并实现电源管理的算法,减少BIOS和OS之间的冲突增加可靠性。ACPI spec定义的部分在整个系统中的cover的部分如下图红色部分所示, ACPI包含了软件和硬件的元素,通过定义软硬件接口实现OS对系统的配置和电源管理。 ACPI Struct

1.   ACPI System Description Table是是整个实现的核心,它描述了硬件的接口,例如一些控制寄存器的定义通常实现在固定的模块或者表格中,被称为fixed ACPI description table (FADT)。另外一种table叫做Definition blocks,它是使用ACPI Source Langauge(ASL)定义object和control method,所有的object组成了ACPI namespace。

2.  ACPI Register Interface也是通过System Description Table汇报出去的。

3.  ACPI BIOS其实就是bootloader,它实现了少量的用于sleep, wake,restart的操作;这些操作很少会被调用。另外ACPI System Description Table也是由BIOS创建和提供的。ACPI
System Description Tabl本质上包含了两种类型的共享数据结构接口,并通过他们来架起OS和系统固件之间的桥梁,而且因为是接口,所以不同的平台可以按照自己的硬件定义来实现,从而可以做到架构独立,平台无关。这两种数据结构分别是Data Table 和 Definition Block. Data table里面是一些原始数据供OS和driver使用,Definition Block则包含了可以被解释器执行的字节码。 ACPI Table

通常ACPI的开发过程是, 我们根据平台以及芯片的spec 把硬件寄存器或者电源管理逻辑用ASL描述成ACPI table,这些table会被iASL编译器 build成AML 字节码,AML字节码会和BIOS/Bootloader一并打包生成一个Firmware Package。 ACPI Developing Flow

ACPI 软件编程模型

1.  Fixed ACPI Description Table FADT就是一个典型的Data Table, FADT包含了ACPI HW register 比如PM1a_EVT_BLK以及一些具体的平台配置信息。这些信息是由OEM设置的,主要包含如 下的Register: ACPI FADT Registers 不同的平台因为使用不同的Chipset或者不同的方法,会提供不同的FADT的实现。比如ACPI enable在下面的平台是通过写A0=》B0 port实现的,这是一个SWSMI, BIOS SMI handler会收到后会将SCI_EN bit设起来用来指示OSPM现在是ACPI 模式了。 另外一个例子就重启,通常X86 平台的重启是写06=》CF9, 但是有些平台的南桥是通过写一个mmio的寄存器,所以就需要override FADT里面的RESET_REG 和 RESET_VALUE。 Reset Register 2.  Definition Block 通常是指Differentiated System Description Table (DSDT)和Secondary System Description Table (SSDT),这些Table 包含了各种各样的系统feature。 AML build出来的table会被AML 解释器生成ACPI namespace 它是一个树状的结构,DSDT SSDT中定义的objects会被挂在这个树上。DSDT和SSDT都会被OSPM的在启动的时候加载,它们包含了电源管里,散热管理以及一些即插即用的设备的信息。SSDT 是DSDT的延续和扩充,SSDT依赖于DSDT,当OSPM将DSDT加载以createACPI Namespace时之后,后续的每个SSDT才会被加载。相当于DSDT提供了一个大部分的功能,SSDT作为一个比较小的辅助功能在BIOS启动过程中依据系统的配置决定是否创建以及包含哪些功能。其实我个人觉得SSDT的引入可以方便我们实现模块化,把不同部分的功能使用不同的SSDT实现。比如现在的BIOS通常会把CPU的Cstate,Pstate这些电源管理的功能通过SSDT实现。 CPU SSDT 下图是一个ACPI namespace的例子,SB是system bus的缩写,它是所有的ACPI devices的根。对于PCI, USB这种可以被自己的总线枚举的设备通常不会被ACPI 枚举,它们会被自己的总线driver枚举并加载驱动。对于声明了_HID(hardware identification)的object,通常会被ACPI枚举而且会被加载ACPI driver。但是对于声明了_ADR(Address) object通常不会被枚举,_ADR通常在PCI或者USB的device object中会被声明。 ACPI Namespace 3.  BIOS创建ACPI Table 并汇报给OSPM。BIOS在启动的过程根据平台的信息创建并更新ACPI table,比如FADT中的register的地址,以及某些电源管理的feature的实现方式等等。The extended root system description table(XSDT)是第一被ACPI子系统使用的table,它包含了其它的table的地址。通过XSDT,我们可以找到FADT,SSDT以及其它的table。FADT中又包含了DSDT table的地址。 ACPI Runtime 在OS开始启动以后,它的ACPI 子系统通过FADT找到DSDT 然后创建ACPI Namespace。接下来子系统会解析SSDT并把它的object也加载到ACPI Namespace。在ACPI namesapce创建好以后,OS可以通过内置的AML解释器分析namespace,解析出_HID并加载对应的ACPI driver。driver起来以后又可以通过AML解释器执行相应的control method。(AML是一个解释语言,与Java类似,它是跨平台的,可是ACPI是在BIOS中生成的,BIOS是平台密切相关的,每个平台都有自己的BIOS。不仅ARM和X86的 BIOS不能共用,就连X86平台下也都基本上不能共用。BIOS不能共用,AML作为解释执行的语言 跨平台实现的意义是什么呢?) AML Interpreter

Refer: