4.6. ACPI 硬件模型
ACPI 硬件模型的定义是为了允许 OSPM 通过操纵已定义的接口,按照下图所示在各种全局系统状态(G0-G3)之间对平台进行时序控制。首次上电时,平台处于全局系统状态 G3,即“机械关闭”。该状态被定义为功耗非常接近于零的状态——电源插头已被拔掉;然而,实时时钟设备仍由电池供电运行。G3 状态会在任何电源故障时进入,这被定义为意外或用户发起的断电。
G3 状态会根据平台所支持的内容转换到 G0 工作状态或传统状态之一。如果平台是纯 ACPI 平台,则它通过始终返回状态位 SCI_EN 为置位(1)来允许直接引导进入 G0 工作状态(更多信息请参见 传统/ACPI 选择 和 SCI 中断)。如果平台同时支持传统和 ACPI 操作(这对于支持非 ACPI OS 是必要的),那么它将始终引导进入传统状态(表现为返回 SCI_EN 清零(0))。在任一种情况下,离开 G3 状态的转换都需要 OSPM 的完整引导。
传统系统状态是非 ACPI OS 执行时的全局状态。只有当硬件同时支持传统和 ACPI 模式时,才能从 G3“机械关闭”、G2“软关闭”或 G0“工作”状态进入该状态。在传统状态下,ACPI 事件模型被禁用(不会生成 SCI),硬件使用传统电源管理和配置机制。在传统状态下,符合 ACPI 的 OS 可以通过执行 ACPI 模式请求来请求转换到 G0 工作状态。OSPM 通过将 ACPI_ENABLE 值写入 SMI_CMD 来执行该转换,这会向硬件生成一个事件,以便将平台转换到 ACPI 模式。当硬件完成该转换后,它会置位 SCI_EN 位,并将控制权返回给 OSPM。在 G0“工作状态”下,OSPM 可以通过将 ACPI_DISABLE 值写入 SMI_CMD 寄存器来请求转换到传统模式,其结果是硬件进入传统模式并将 SCI_EN 位复位为低电平(有关更多信息,请参见 传统/ACPI 选择 和 SCI 中断)。
G0“工作”状态是 ACPI 系统的正常运行环境。在该状态下,不同设备会在各自的电源状态(D0、D1、D2、D3hot 或 D3)之间动态转换,而处理器会在各自的电源状态(C0、C1、C2 或 C3)之间动态转换。在该状态下,OSPM 可以作出策略决策,将平台置于系统 G1“睡眠”状态。平台一次只能进入一个睡眠状态(称为全局 G1 状态);但是,硬件最多可以提供四种系统睡眠状态,它们具有不同的功耗和退出延迟,分别由 S1、S2、S3 或 S4 状态表示。当 OSPM 决定进入某个睡眠状态时,它会选择硬件支持的最合适的睡眠状态(OS 策略会检查哪些设备已启用唤醒事件,以及这些设备支持哪些睡眠状态)。OSPM 通过启用适当的唤醒事件,然后用期望的睡眠状态对 SLP_TYPx 字段进行编程,并接着设置 SLP_ENx 位,来启动睡眠转换。随后系统将进入睡眠状态;当某个已启用的唤醒事件发生时,它将使系统转换回工作状态(有关更多信息,请参见 唤醒与睡眠)。
在 G0“工作”状态下,另一种全局状态转换选项是进入 G2“软关闭”或 G3“机械关闭”状态。这些转换表示一种受控转换,允许 OSPM 以有序方式关闭系统(卸载应用程序、关闭文件等等)。这些类型转换的策略可以与 ACPI 电源按钮相关联,当按下该按钮时,会向电源按钮驱动程序生成一个事件。当 OSPM 完成针对电源丢失的操作环境准备后,它将要么生成一个弹出消息,指示用户移除电源,以便进入 G3“机械关闭”状态;要么通过将 S5“软关闭”系统状态的值写入 SLP_TYPx 寄存器并设置 SLP_EN 位,来启动 G2“软关闭”转换。
G1 睡眠状态由硬件可支持的四种可能睡眠状态表示。每种睡眠状态都具有不同的功耗和唤醒延迟特性。睡眠状态不同于工作状态,因为用户的操作环境被冻结在低功耗状态中,直到被已启用的唤醒事件唤醒。在该状态下不会执行任何工作,也就是说,处理器不执行指令。每种系统睡眠状态对于谁负责系统上下文和唤醒时序都有要求(有关更多信息,请参见 唤醒与睡眠)。
G2“软关闭”状态是由 OS 发起的系统关机。该状态的启动方式类似于睡眠状态转换(将 SLP_TYPx 设置为 S5 值并设置 SLP_EN 位以启动该序列)。退出 G2 软关闭状态需要重新引导系统。在这种情况下,纯 ACPI 系统将直接重新进入 G0 状态(硬件返回 SCI_EN 位置位),而 ACPI/传统系统则转换到传统状态(SCI_EN 位为清零)。

图 4.2 全局状态及其转换
ACPI 体系结构定义了用于硬件生成事件以及实现此行为模型的控制逻辑的机制。事件用于通知 OSPM 需要执行某些操作,而控制逻辑由 OSPM 使用以引起某种状态转换。ACPI 定义的事件是“硬件”事件或“中断”事件。硬件事件是指导致硬件无条件执行某些操作的事件。例如,任何唤醒事件都会使系统从睡眠状态(全局 G1 状态中的 S1、S2、S3 和 S4)时序转换到 G0 工作状态(请参见 睡眠状态示例)。
中断事件会导致执行一个事件处理程序(AML 代码或 ACPI 感知驱动程序),从而允许软件基于该事件作出策略决策。对于 ACPI 固定功能事件,OSPM 或 ACPI 感知驱动程序充当事件处理程序。对于通用逻辑事件,OSPM 将调度执行与该事件关联的 OEM 提供的 AML 控制方法。
对于传统系统,一个事件通常会生成一个对 OS 透明的中断,例如系统管理中断,即 SMI。对于 ACPI 系统,中断事件需要生成一个对 OS 可见且可共享的中断;边沿触发中断将无法工作。希望同时支持传统操作系统和 ACPI 系统的硬件平台,需要支持在 ACPI 和传统模型之间切换时,在 SMI 和 SCI 之间重新映射中断事件的方法。如下方框图所示。

图 4.3 传统/ACPI 兼容事件模型的示例事件结构
此示例逻辑说明了一个同时支持传统和 ACPI 事件模型的示例平台的事件模型。该示例平台支持若干与电源相关的外部事件(电源按钮、LID 打开/关闭、热、振铃指示)或与即插即用相关的事件(扩展坞、状态变化)。该逻辑表示三种不同类型的事件:
OS 透明事件
这些事件表示 OEM 特定的功能,它们没有 OS 支持,并使用能够以 OS 透明方式运行的软件(即 SMI)。
中断事件
这些事件表示由兼容 ACPI 的操作系统支持、但不受传统操作系统支持的功能。当加载传统 OS 时,这些事件被映射到透明中断(在本示例中为 SMI#);而当处于 ACPI 模式时,它们被映射到 OS 可见的可共享中断(SCI#)。该逻辑通过将事件逻辑路由经过解码器来表示:当 SCI_EN 位被清除时,将事件路由到 SMI# 仲裁器;当 SCI_EN 位被置位时,将事件路由到 SCI# 仲裁器。
硬件事件
这些事件用于触发硬件启动某些硬件序列,例如无条件地唤醒、复位,或使系统进入睡眠状态。
在此示例中,传统电源管理事件逻辑用于基于设备空闲计时器、设备陷阱以及全局待机计时器来确定设备/系统活动或空闲状态。传统电源管理模型使用空闲计时器来确定设备何时应因空闲而进入低功耗状态——也就是说,该设备在设定的时间内未被访问。设备陷阱用于指示处于低功耗状态的设备何时正被 OSPM 访问。全局待机计时器用于确定系统何时应被允许进入睡眠状态,因为其处于空闲——也就是说,用户界面在设定的时间内未被使用。
在 ACPI 模式下,这些传统空闲计时器、陷阱监视器和全局待机计时器不被 OSPM 使用。这项工作由兼容 ACPI 的 OS 中不同的软件结构来处理。例如,兼容 ACPI 的 OS 的驱动程序模型负责将其设备置于低功耗状态(D1、D2、D3hot 或 D3),并在需要时将其转换回开启状态(D0)。而 OSPM 负责通过对系统进行分析(使用电源管理计时器)以及利用其通过操作系统环境获得的其他信息(这会因 OS 而异)来判断系统何时处于空闲状态。当系统被置于 ACPI 模式时,这些事件不再生成 SMI,因为 OSPM 处理此功能。这些事件通过某种 OEM 专有方法被禁用。
另一方面,许多硬件事件由 ACPI 和传统模型共享(扩展坞、电源按钮等等),并且当为 ACPI 启用时,这类中断事件会变为 SCI 事件。ACPI OS 将生成一个请求,要求平台运行时固件进入 ACPI 模式。固件设置 SCI_EN 位以表明系统已成功进入 ACPI 模式,因此这是一种方便的机制,用于为这些事件映射所需的中断(SMI 或 SCI)(如图 4-3 所示)。
ACPI 架构规定了一些传统硬件模型中不存在的专用硬件:电源管理计时器(PM Timer)。这是一个自由运行计时器,ACPI OS 使用它来分析系统活动。该计时器的频率在本规范中被明确定义,并且必须按所述方式实现。
尽管 ACPI 架构原样复用了大多数传统硬件,但它确实对编程模型的生成位置和方式施加了限制。如果使用,所有固定硬件功能都应按本规范所述方式实现,以便 OSPM 能够直接访问固定硬件功能寄存器。
通用硬件功能通过驻留在 ACPI Namespace 中的 ACPI 控制方法来操作。这些接口可以非常灵活;但是,它们的使用受到已定义 ACPI 控制方法的限制(更多信息,请参见ACPI 定义的设备和设备特定对象)。通用硬件通常控制电源平面、缓冲隔离和设备复位资源。此外,“子”中断状态位可通过通用硬件接口访问;但是,它们在 GP_STS 寄存器中具有一个“父”中断状态位。ACPI 定义了八种可由通用硬件实现访问的地址空间。其中包括:
系统 I/O 空间
系统内存空间
PCI 配置空间
嵌入式控制器空间
系统管理总线(SMBus)空间
CMOS
PCI BAR 目标
IPMI 空间
平台通信通道
通用硬件电源管理功能可以通过访问位于这些地址空间中的任一地址空间的空闲 I/O 端口来实现。ACPI 规范定义了一个可选的嵌入式控制器和 SMBus 接口,用于与这些相关联的地址空间通信。
4.6.1. 硬件保留位
ACPI 硬件寄存器的设计使得保留位总是返回零,并且对其进行数据写入不会产生副作用。OSPM 实现必须在使能和状态寄存器中向保留位写入零,并在控制寄存器中保留这些位,同时会将这些位视为被忽略。
4.6.2. 硬件忽略位
ACPI 硬件寄存器的设计使得被忽略位是未定义的,并且会被软件忽略。被硬件忽略的位可以返回零或一。当软件读取带有被忽略位的寄存器时,它会在对结果进行操作之前屏蔽掉被忽略位。当软件向带有被忽略位字段的寄存器写入时,它会保留这些被忽略位字段。
4.6.3. 硬件只写位
ACPI 硬件定义了若干只写控制位。软件通过向这些位位置写入 1 来激活这些位。读取只写位位置会产生未定义结果。读取带有只写位的寄存器时,软件会屏蔽掉所有只写位。
4.6.4. 跨设备依赖关系
跨设备依赖关系是一种情况,其中对某个设备的操作会干扰其他无关设备的运行,或者允许其他无关设备干扰其行为。这种情况不受支持,并且可能导致平台故障。ACPI 不为跨设备依赖关系提供支持,并建议将设备设计为不表现出此类行为。以下两个示例描述了跨设备依赖关系:
4.6.4.1. 示例 1:相关设备干扰
此示例说明了一种跨设备依赖关系,其中某个设备会干扰其他无关设备的正常运行。设备 A 具有这样一种依赖关系:当其正在被配置时,它会阻止所有原本应发送到设备 B 的访问。因此,当设备 A 正在被配置时,设备 B 的设备驱动程序无法访问设备 B;因此,它需要与设备 A 的驱动程序同步访问。高性能、多线程操作系统无法在不严重影响性能的情况下执行这种同步。
为进一步说明这一点,假设设备 A 是串行端口,而设备 B 是硬盘驱动控制器。如果这些设备表现出这种行为,那么当某个软件驱动程序配置串行端口时,对硬盘的访问就需要被阻塞。只有当硬盘驱动程序将对磁盘控制器的访问与串行驱动程序同步时,才能做到这一点。没有这种同步,在配置串行端口时,硬盘数据将会丢失。
4.6.4.2. 示例 2:无关设备干扰
此示例说明了一种跨设备依赖关系,其中某个设备表现出一种行为,允许其他无关设备干扰其正常运行。设备 A 表现出一种编程行为:需要原子性的背靠背写访问才能成功写入其寄存器;如果任何其他平台访问能够插入到这两个背靠背访问之间,那么对设备 A 的写入就会失败。如果设备 A 的驱动程序无法对其设备生成原子性的背靠背访问,那么它就依赖软件将对其设备的访问与系统中的每一个其他驱动程序同步;这样便形成了设备跨依赖关系,平台也更容易发生设备 A 故障。