APEI(ACPI Platform Error Interfaces)为硬件平台提供了一种将故障信息传递给OS的方法。APEI扩展了现有的硬件故障上报机制(e.g. Intel MCA, PCIe AER etc),并将他们组合到一起以提供统一的硬件故障上报框架。由于固件离硬件更近,访问硬件设备更为方便,APEI中固件的作用也更为明显,提出了Firmware First机制。
硬件故障源(Hardware error source)
APEI的核心概念是硬件故障源(Hardware error source),硬件故障源是OS感知到硬件故障的先决条件,典型的硬件故障源包含以下几个方面:
- 一个或多个硬件故障状态寄存器(Hardware error status registers)
- 一个或多个硬件故障配置/控制寄存器(Hardware error configuration or control registers)
- 通知OS当前硬件发生硬件故障的通知机制
由此可见,硬件故障源指的是硬件中记录硬件故障信息、配置硬件故障部分以及通知OS当前硬件发生硬件故障的通知机制。了解Intel MCA(Machine Check Architecture)机制的朋友可以将上面三点对应上。如下图所示,左侧是全局的硬件故障配置/控制寄存器,右侧是记录硬件故障信息的寄存器,硬件故障通过MCE异常通知OS:
如果是CE故障,硬件故障源可以不包括硬件故障通知机制,可以由OS自主轮询(poll)故障状态寄存器以检查是否存在硬件故障。轮询机制不适用于UCE故障,UCE故障需要立即处理,硬件需要立刻通知OS。Intel MCA机制中,CE故障是通过CMCI中断通知OS,当发生CE风暴时,为了降低大量CMCI中断对系统性能的影响,OS将中断通知机制转换为轮询机制进行CE风暴抑制。
APEI采用固件优先(Firmware First mode, FFM)的故障上报机制,即硬件单元出现故障,先通知BIOS(Firmware),BIOS进行预处理之后,然后将故障通知给OS。APEI中BIOS和OS合作进行故障处理,这种模式也给硬件平台供应商(Hardware platform vendor)很大的灵活性进行设计来确定是BIOS还是OS拥有关键的硬件错误资源。APEI允许BIOS将硬件错误源的控制权让渡给OS。一个典型的例子,Intel EMCA2即便采用FFM故障上报,OS进入MCE故障处理流程也是能够访问硬件故障状态寄存器、硬件故障控制寄存器;然而,ARM实现的FFM,OS无法拥有关键的硬件错误资源,所有的故障信息均来源于BIOS预处理之后的故障信息上报。
ACPI错误源(ACPI error source)
ACPI错误源指的是BIOS通过一种标准化的机制向OS描述硬件故障源。APEI通过一套标准化的表格描述硬件故障源,这是一种平台和处理器架构无关的接口。表格中不仅包含确定的硬件故障信息,还包括关于错误源的可操作参数(operational parameters),例如故障级别、masking bits、阈值,这些可操作参数可以视为BIOS和OS之间沟通过程中的可调节参数。ACPI规范定义了HEST表(Hardware Error Source Table)用于BIOS向OS描述硬件故障源。HEST表结构如下图所示:
我人为地将HEST表结构分为两部分:
- HEST header,包含ACPI表格头的常用信息,如表格头签名、表格长度,还包含OEM的些许信息,最重要的是“Error Source Count”,说明BIOS报告给OS的错误源个数
- 错误源结构,实际描述硬件故障错误源,上图中给出的是GHES错误源的结构
前面提到过ACPI错误源,相应的存在非ACPI错误源(Non-ACPI error source)。非ACPI错误源表示可以通过非ACPI标准化的表格描述硬件故障源,例如Intel MCA报告UCE故障的MCE异常使用上文提及的MSRs描述硬件故障以及配置/控制故障源,可以通过MCE异常直接通知OS。APEI定义了多种类型的错误源结构,可以将这些错误源结构可以总结为两类:
- 兼容非ACPI错误源,即便这些错误源能够直接通知OS,ACPI也支持标准化的表格描述该故障源,如x86架构通过MCE上报的UCE、x86架构通过MCE上报的Deferred error、x86架构通过correceted machine check上报的CE、x86架构通过NMI上报的UCE、PCIe root prot的AER故障、PCIe设备的AER故障、PCI Express/PCI-X Bridge的AER故障
- GHES(Generic Hardware Error Source),通用故障错误源,不受限于任何故障源类型,提供一种统一描述故障源的方法,若要实现架构无关的故障源描述,GHES是绝佳选择。平台支持多个通知类型的GHES故障源,例如使用SCI通知类型的GHES故障源处理异步错误;使用SEA/MCE通知类型处理同步错误。
兼容非ACPI错误源大概特征总结如下:
Error source structure | Flags | Max entry in HEST |
---|---|---|
IA-32 Architecture Machine Check Exception | FIRMWARE_FIRST|GHES_ASSIST | 1 |
IA-32 Architecture Deferred Machine Check | FIRMWARE_FIRST|GHES_ASSIST | 1 |
IA-32 Architecture Corrected Machine Check | FIRMWARE_FIRST|GHES_ASSIST | 1 |
IA-32 Architecture Non-Maskable Interrupt | N/A | 1 |
PCI Express Root Port AER Structure | FIRMWARE_FIRST|GLOBAL | >= 1 (none GLOBAL flag set); 1 (GLOBAL flag set) |
PCI Express Device AER Structure | FIRMWARE_FIRST|GLOBAL | >= 1 (none GLOBAL flag set); 1 (GLOBAL flag set) |
PCI Express/PCI-X Bridge AER Structure | FIRMWARE_FIRST|GLOBAL | >= 1 (none GLOBAL flag set); 1 (GLOBAL flag set) |
“Max entry in HEST”表示HEST表格中允许该类型的错误源的最大数目。”Flags”是错误源结构体中的一个字段,只有IA-32 Architecture Non-Maskable Interrupt
不存在该字段。直接引用APEI规范对Flags
字段的bit进行解释:
Bit [0] - FIRMWARE_FIRST: If set, this bit indicates to the OSPM that system firmware will handle errors from this source first.
Bit [1] - GLOBAL: If set, indicates that the settings contained in this structure apply globally to all PCI Express Devices
Bit [2] - GHES_ASSIST: If set, this bit indicates that although OSPM is responsible for directly handling the error (as expected when FIRMWARE_FIRST is not set), system firmware reports additional information in the context of an interrupt generated by the error. The additional information is reported in a Generic Hardware Error Source structure with a matching Related Source Id.
上述包含Flags
字段的错误源结构体,都包含FIRMWARE_FIRST
bit,该位如果设置,表示该类故障源采用Firmware First的故障处理模式。IA-32 MCA的CE/UCE/Deferred错误源还使用了GHES_ASSIST
bit,如果该位设置了,即便是OS直接处理故障(FIRMWARE_FIRST
不设置,非FFM),也可以让BIOS生成中断,通过GHES报告故障信息,GHES结构体中的Related Source Id
可以将二者关联起来。PCIe AER故障还会使用GLOBAL
bit,该位与FIRMWARE_FIRST
bit互斥。如果GLOBAL
bit设置,表示此故障源的所有设置适用于系统中的所有PCIe设备,若设置FIRMWARE_FIRST
bit,则可以为每个PCIe设备进行故障源配置。
GHES(Generic Hardware Error Source)
GHES作为通用故障源,可以做到平台无关地描述故障源,因此被会被多个架构用来描述故障。我接触到的ARM服务器基本上都使用GHES(v2 or higher)故障源描述硬件故障。GHES结构体中最重要的字段是Error Status Address
,其指定了一个寄存器的位置,该寄存器保存了该错误源的(Generic) Error Status Block
的起始物理地址。Error Status Block Length
指定了(Generic) Error Status Block
的长度,两者构成了(Generic) Error Status Block
的实际物理地址空间,该物理地址空间位于BIOS预留的地址区间(由于BIOS需要对该区间进行读/写操作),OS为了读取该错误源的故障信息,需要先将该预留地址空间映射到OS的系统地址空间。
(Generic) Error Status Block
包含错误源的实际错误状态信息(error status information),HEST、GHES故障源、error status block的关联关系如下图所示,在图中标明了相应的Linux kernel数据结构。
Generic Error Status Block
(Generic) Error Status Block
包含两级信息,顶级是Generic Error Status Block
结构,随后的是Generic Error Data Entry
结构,可以将顶级信息理解为(Generic) Error Status Block
头部信息。Generic Error Data Entry
实际保存硬件故障信息,(Generic) Error Status Block
可能包含多个Generic Error Data Entry
以保存与同一硬件故障相关的多个硬件组件信息。例如,使用GHES故障源描述发生在PCI Express/PCI-X bridge的次级设备上的硬件故障,则可以使用两个Generic Error Data Entry
分别描述PCI Express Bridge的硬件故障信息和PCI-X设备上的硬件故障信息。Generic Error Data Entry
在整个HEST、GHES层级结构的位置如下图所示:
Generic Error Status Block
结构中最重要的域是Error Severity
,表示的是硬件故障事件整体的故障级别。Generic Error Status Block
之后是连续的一个或多个Generic Error Data Entry
。其中的Section Type
字段可以区分出硬件故障的硬件类型[1],Error Severity
表示硬件故障事件中的该硬件组件的故障级别,该故障级别不能超过整体的故障级别,Generic error data
是实际保存硬件故障的字段,根据不同的硬件类型(Section Type
),其采用UEFI规范中“Common Platform Error Record(CPER)”的相应硬件类型表格记录硬件故障信息。
GHESv2(Generic Hardware Error Source version 2)
上报GHES故障源的固件可能会与OS并行运行(例如固件运行在单独/专有处理器上,或者固件运行在从处理器上(application processor))。为了防止固件和OS并发访问error status block,或者OS尚未读取error status block便被固件覆写了故障信息。GHESv2作为GHES的扩展解决了上述问题,GHESv2新增了”Read Ack Register”,仅在OS读取完error status block中的信息之后,回写Read Ack Register之后,固件才能写error status block,具体流程如下图所示:
GHESv2在GHES表格尾部新增了三个字段:
- Read Ack Register:保存Read Ack Register的GAS地址
- Read Ack Preserve:写Read Ack Register时,其中原有的内容的bit必须保留的mask bits
- Read Ack Write:写Read Ack Register时,必须设置的bit的mask bits
因此OS回写Read Ack Register分为两步:
- 读取Read Ack Register的值为X
- OS写入
(( X & ReadAckPreserve) | ReadAckWrite)
到Read Ack Register的值