高级配置和电源接口(ACPI)简介

译者:陈浩


版权声明

本文译者是一位开源理念的坚定支持者,所以本文虽然不是软件,但是遵照开源的精神发布。

联系方式

由于译者水平有限,因此不能保证译文内容准确无误。如果你发现了译文中的错误(哪怕是错别字也好),请来信指出,任何提高译文质量的建议我都将虚心接纳。


原始英文版 https://acpica.org/sites/acpica/files/ACPI-Introduction.pdf (1.4版[2016年4月26日])

本文提供高级配置和电源接口(ACPI)的高级概述。为了更容易理解ACPI,本文重点介绍有关ACPI的一般性描述,而不讨论有关ACPI的所有异常或细节。如果ACPI开发人员想了解有关ACPI内部工作的更多细节,建议阅读ACPI规范的其他部分(例如《ACPI源语言(ASL)教程》)。

ACPI的历史

ACPI是在1990年代中期通过英特尔、微软、东芝、惠普、Phoenix 之间的合作开发的。在ACPI出现之前,操作系统主要使用BIOS(基本输入输出系统)接口进行电源管理以及设备的发现和配置。这种电源管理方法利用操作系统调用系统BIOS的能力来进行电源管理。BIOS还用于发现系统设备并基于探测输入/输出(I/O)尝试将正确的驱动程序匹配到正确的设备(即插即用)来加载驱动程序。设备的位置也可以在BIOS中硬编码,因为平台本身是不可枚举的。

这些解决方案在三个关键方面存在问题。首先,操作系统应用程序的行为可能会受到BIOS配置的电源管理设置的负面影响,导致系统在演示期间或其他不方便的时间进入睡眠状态。其次,电源管理接口在每个系统上都是专有的,这要求开发人员学习如何为每个单独的系统配置电源管理。最后,各种设备的默认设置也可能相互冲突,导致设备崩溃、行为不正常或无法发现。

开发ACPI就是为了解决这些问题和其他问题。

什么是ACPI?

ACPI首先可以理解为一种独立于体系结构的电源管理和配置框架,它在主机操作系统内表现为一个子系统。该框架建立了一个硬件寄存器集来定义电源状态(睡眠、休眠、唤醒等),硬件寄存器集可以容纳对专用硬件和通用硬件的操作。

标准ACPI框架和硬件寄存器集的主要目的是启用电源管理和系统配置,而无需直接从操作系统本地调用固件。ACPI作为系统固件(BIOS)和操作系统之间的接口层,具有一定的限制和规则。如"图1"所示:
ACPI概览

从根本上说,ACPI定义了两种在系统固件和操作系统之间共享的数据结构:数据表(​data table)和定义块(definition block)。这些数据结构是固件和操作系统之间的主要通信机制,数据表存储原始数据并由设备驱动程序使用,定义块由解释器可执行的字节码组成。如"图2"所示:
ACPI结构

此定义块字节码是从 ASL(ACPI Source Language) 代码编译而来的。ASL是用于定义ACPI对象和编写控制方法的语言。ASL编译器将ASL翻译成 AML(ACPI机器语言) 字节码。AML是 ACPI AML 解释器处理的语言,如"图3"所示:
ASL与AML

AML解释器执行字节码并评估定义块中的对象,以允许字节码执行循环结构、条件评估、访问定义的地址空间以及执行应用程序所需的其他操作。AML解释器对定义的地址空间具有读/写访问权限,包括系统内存、I/O、PCI配置等。它通过定义称为"对象"的入口点来访问这些地址空间。对象要么有一个直接定义的值,要么能够由AML解释器执行。

这个可枚举对象的集合是一个称为"ACPI命名空间"的操作系统结构。命名空间是系统上ACPI设备的分层表示。系统总线是这些ACPI设备的枚举根。在其他总线上可枚举的设备(如PCI或USB设备)通常不会在命名空间中枚举。相反,它们自己的总线会枚举设备并加载驱动程序。但是,所有可枚举的总线都有一种编码技术,允许ACPI对设备的总线特定地址进行编码,以便可以在ACPI中找到它们,即使ACPI通常并不加载这些设备的驱动程序。

通常,具有 _HID 对象(硬件识别对象)的设备会被枚举并由ACPI加载其驱动程序。具有 _ADR 对象(物理地址对象)的设备通常不会被ACPI枚举,并且通常不会被ACPI加载其驱动程序。_ADR 设备通常可以在不涉及ACPI的情况下执行所有必要的功能,但是在设备驱动程序无法执行功能的情况下,或者如果驱动程序需要与系统固件通信,ACPI可以评估对象以执行所需的功能。

例如,PCI不支持本机热插拔。但是,PCI可以使用ACPI来评估对象并定义允许ACPI填充在PCI上执行热插拔所需功能的方法。

ACPI也是一个运行时模型,它处理系统运行期间发生的ACPI中断事件。ACPI继续根据需要评估对象以处理这些事件。这种基于中断的运行时模型在下面的运行时模型部分有更详细的讨论。

ACPI初始化

了解ACPI如何工作的最好方法是按时间顺序来了解。在用户启动系统的那一刻,系统固件完成其设置、初始化和自检。如"图4"所示:
ACPI初始化

然后,系统固件使用固件初始化期间获得的信息,根据需要使用各种平台配置和电源接口数据更新ACPI表,然后再将控制权传递给引导加载程序。扩展根系统描述表(XSDT)是ACPI子系统使用的第一个表,包含系统上大多数其他ACPI表的地址。XSDT指向固定的ACPI描述表(FADT)以及操作系统在初始化期间处理的其他主要表。操作系统初始化后,FADT将ACPI子系统引导到差异化系统描述表(DSDT),这是命名空间的开始,因为它是第一个包含定义块的表。

ACPI子系统然后处理DSDT并开始从ACPI定义块构建命名空间。XSDT还指向辅助系统描述表(SSDT)并将它们添加到命名空间。ACPI数据表提供有关系统硬件的操作系统原始数据。

操作系统从ACPI表构建命名空间后,它开始遍历命名空间并为它在命名空间中遇到的所有 _HID 设备加载设备驱动程序。

运行时模型

系统启动并运行后,ACPI与操作系统一起处理通过ACPI系统控制中断(SCI)处理程序发生的任何ACPI中断事件。此中断以两种通用方式之一调用ACPI事件:固定事件和通用事件(GPE)。SCI在整个系统中复用以管理ACPI中断事件。

固定事件是在ACPI规范中具有预定义含义的ACPI事件。这些固定事件包括按下电源按钮或ACPI计时器溢出等操作。这些事件由操作系统处理程序直接处理。

GPE是ACPI规范未预定义的ACPI事件。这些事件通常通过评估控制方法来处理,这些控制方法是命名空间中的对象,可以访问系统硬件。当ACPI子系统使用AML解释器评估控制方法时,GPE对象会根据操作系统的实现来处理事件。通常,这可能涉及向设备发出通知以调用设备驱动程序来执行功能。

我们将在下一节中讨论此运行时模型的通用示例。

热事件示例

ACPI包括一个热模型,允许系统主动(通过执行打开风扇等操作)或通过减少系统使用的电量(通过执行诸如节流处理器等操作)被动控制系统温度。下面是一个演示ACPI运行时模型工作原理的通用热事件示例,如"图5"所示:
运行时热事件

ACPI热区包括读取当前系统温度和跳闸点的控制方法。

  1. 当操作系统最初在命名空间中找到热区时,它会加载热区驱动程序,该驱动程序会评估热区以获取当前温度和跳变点。
  2. 当系统组件加热到足以触发跳闸点时,就会出现热区GPE。
  3. GPE通过SCI引起中断发生。当ACPI子系统收到中断时,它首先检查是否发生了任何固定事件。在这个例子中,热区事件是一个GPE,所以没有发生固定事件。
  4. 然后ACPI子系统在命名空间中搜索与中断的GPE编号匹配的控制方法。找到后,ACPI子系统会评估控制方法,然后可能会访问硬件和/或通知热区处理程序。
  5. 操作系统的热区处理程序然后采取任何必要的行动来处理事件,包括可能访问硬件。

ACPI是一个非常健壮的接口实现。热区跳闸点可以通知系统打开风扇、降低设备性能、读取温度、关闭系统,或者和其他操作的任意所需组合。

该运行时模型在整个系统中用于管理系统运行期间发生的所有ACPI事件。

总结

ACPI最好被描述为一个概念和接口的框架,并被实现为主机操作系统内的子系统。ACPI表、处理程序、解释器、命名空间、事件和中断模型共同构成了ACPI的实现(主机操作系统中创建的ACPI子系统)。从这个意义上说,ACPI是系统硬件/固件与操作系统和操作系统应用程序之间的接口,用于配置和电源管理。这为各种操作系统提供了一种通过ACPI命名空间支持电源管理和配置的标准化方法。

ACPI命名空间是系统上所有ACPI设备的可枚举、分层的表示,用于查找和加载系统上ACPI设备的驱动程序。通过实时评估对象和发送中断,命名空间可以是动态的,同时限制操作系统调用本机系统固件代码。这使设备制造商能够将他们自己的指令和事件编码到设备中。它还通过实施标准化的电源管理接口来减少不兼容性和不稳定性。