18.6. 错误注入
本节概述一种名为 EINJ 的 ACPI 表机制,它提供一种通用接口机制,使 OSPM 可以在不需要平台特定的 OSPM 级软件的情况下向平台注入硬件错误。该机制的主要目标是通过启用硬件错误注入来支持 OSPM 错误处理栈的测试。借助此能力,OSPM 能够为系统上的错误处理实现一个简单的诊断与验证接口。
18.6.1. 错误注入表(EINJ)
错误注入(EINJ)表提供一种通用接口机制,使 OSPM 可以在不需要平台特定的 OSPM 软件的情况下向平台注入硬件错误。系统固件负责构建该表,它由注入指令条目组成。下表描述了 EINJ 所需的详细信息。
表 18.23 错误注入表(EINJ)
| 字段 | 字节长度 | 字节偏移 | 描述 |
|---|---|---|---|
| ACPI 标准头 | |||
| 头签名 | 4 | 0 | EINJ。错误注入表的签名。 |
| 长度 | 4 | 4 | 整个 EINJ 的长度,单位为字节。整个表必须是连续的。 |
| 修订版本 | 1 | 8 | 1 |
| 校验和 | 1 | 9 | 整个表求和必须为零。 |
| OEMID | 6 | 10 | OEM ID。 |
| OEM 表 ID | 8 | 16 | 制造商型号 ID。 |
| OEM 修订版本 | 4 | 24 | EINJ 的 OEM 修订版本。 |
| 创建者 ID | 4 | 28 | 创建该表的工具的供应商 ID。 |
| 创建者修订版本 | 4 | 32 | 创建该表的工具的修订版本。 |
| 注入头 | |||
| 注入头大小 | 4 | 36 | 注入接口头的字节长度。 |
| 注入标志 | 1 | 40 | 保留。必须为零 |
| Reserved | 3 | 41 | 必须为零。 |
| 注入条目计数 | 4 | 44 | 注入操作表中的指令条目数量 |
| 注入操作表 | |||
| 注入指令条目 | 48 | 一系列错误注入指令条目,数量由 Injection Entry Count 指定。见表 18.25。 |
下表标识了受支持的错误注入操作。
表 18.24 错误注入操作
| 值 | 名称 | 描述 |
|---|---|---|
| 0x0 | BEGIN_INJECTION_OPERATION | 表示向平台指示错误注入开始。这使平台能够设置其操作上下文。 |
| 0x1 | GET_TRIGGER_ERROR_ACTION-_TABLE | 返回一个 64 位物理内存指针,指向触发操作表。见表 18.32 |
| 0x2 | SET_ERROR_TYPE | 要注入的错误类型。任何给定时刻只能注入一种 ERROR_TYPE。如果同时请求多次注入,则平台将返回错误状态。见 18.6.4 节。 |
| 0x3 | GET_ERROR_TYPE | 返回平台的错误注入能力。 |
| 0x4 | END_OPERATION | 表示向平台指示当前注入操作已结束。这使平台能够清除其操作上下文。 |
| 0x5 | EXECUTE_OPERATION | 指示平台根据当前操作上下文执行当前操作。 |
| 0x6 | CHECK_BUSY_STATUS | 返回当前操作的状态。一旦通过 EXECUTE_OPERATION 操作执行了某个操作,平台必须返回该操作忙碌的指示,直到操作完成为止。这使软件可以通过反复执行 CHECK_BUSY_STATUS 操作来轮询完成状态,直到平台通过将状态设为非忙碌来指示操作已完成。返回值最低位(bit0)通过置 1 表示忙碌状态,通过置 0 表示非忙碌状态。 |
| 0x7 | GET_COMMAND_STATUS | 返回当前操作的状态。有效命令状态码列表见表 18.28。 |
| 0x8 | SET_ERROR_TYPE-_WITH_ADDRESS | 要注入的错误类型,以及要注入的地址。任何给定时刻只能注入一种错误类型。如果同时请求多次注入,则平台将返回错误状态。SET_ERROR_TYPE_WITH_ADDRESS 中的 RegisterRegion 字段(见表 18.25)指向一个数据结构,其格式定义见表 18.30。注意,在不指定地址的情况下执行 SET_ERROR_TYPE_WITH_ADDRESS 与执行 SET_ERROR_TYPE 的效果相同。见表 18.29,错误类型定义。 |
| 0x9 | GET_EXECUTE_OPERATION-_TIMINGS | 返回一个编码后的 QWORD: [63:32] 的值为平台预期执行并完成一次 EXECUTE_OPERATION 所需的最大时间,单位为微秒。[31:0] 的值为平台预期执行并完成一次 EXECUTE_OPERATION 所需的典型时间,单位为微秒。 |
| 0xFF | TRIGGER_ERROR | 此值保留给响应 GET_TRIGGER_ERROR_ACTION_TABLE 操作而返回的 Trigger Error Action Table 中声明的条目。返回的表由一系列操作组成,其中每一项都被设置为 TRIGGER_ERROR(见表 18.32)。当由软件执行时,这一系列 TRIGGER_ERROR 操作会触发因 EXECUTE_OPERATION 操作成功完成而产生的错误注入。 |
18.6.2. 注入指令条目
一次注入操作由一个或多个注入指令组成。注入指令表示对抽象硬件寄存器的原始操作,该寄存器由注入指令条目中定义的寄存器区域表示。
注入指令条目描述了注入硬件寄存器中的一个区域,以及要在该区域上执行的注入指令。
下表详细说明了注入指令条目的布局。
表 18.25 注入指令条目
| 字段 | 字节长度 | 字节偏移 | 描述 |
|---|---|---|---|
| Injection Action | 1 | 0 | 该指令所属的注入操作。受支持的注入操作见错误注入操作表。 |
| Instruction | 1 | 1 | 标识要执行的指令。有效指令列表见注入指令表。 |
| Flags | 1 | 2 | 修饰该指令的标志。 |
| Reserved | 1 | 3 | 必须为零。 |
| Register Region | 12 | 4 | 使用通用地址结构来描述地址和位。Address_Space_ID 必须为 0(系统内存)或 1(系统 IO)。此约束旨在确保在存在硬件错误条件时寄存器仍可访问。 |
| Value | 8 | 16 | 此值字段供 READ 或 WRITE_REGISTER_VALUE 指令使用。 |
| Mask | 8 | 24 | 在由寄存器区域定义的给定位范围内,获取与注入指令对应位所需的位掩码。 |
Register Region 以通用地址结构进行描述。该结构描述了寄存器的物理地址,以及与所需寄存器区域相对应的位范围。位范围定义为包含与注入指令相关联的寄存器中每一位的最小连续位集合。如果位 [6:5] 和位 [3:2] 都对应某个注入指令,则该指令的位范围为 [6:2]。
由于某个位范围可能包含不属于特定注入指令的位(即上例中的位 4),因此需要位掩码来区分区域中与该指令对应的所有位。Mask 字段定义为该位掩码:位范围(由寄存器区域定义)中每一个与注入指令对应的位都置为 ‘1’。注意,位掩码的 bit 0 对应位范围中的最低位。在上面的示例中,掩码将是 11011b 或 0x1B。
表 18.26 指令标志
| 值 | 名称 | 描述 |
|---|---|---|
| 0x01 | PRESERVE_REGISTER | 对于 WRITE_REGISTER 和 WRITE_REGISTER_VALUE 指令,此标志表示未被写入的寄存器位必须被保留而不是破坏。对于 READ_REGISTER 指令,此标志被忽略。 |
18.6.3. 注入指令
下表列出了注入指令条目所支持的注入指令。
表 18.27 注入指令
| 操作码 | 指令名称 | 描述 |
|---|---|---|
| 0x00 | READ_REGISTER | READ_REGISTER 指令从指定的寄存器区域读取值。 |
| 0x01 | READ_REGISTER_VALUE | READ_REGISTER_VALUE 指令从指定的寄存器区域读取指定信息,并将结果与 Value 字段的内容进行比较。如果读取的信息与 Value 字段的内容匹配,则返回 TRUE,否则返回 FALSE。 |
| 0x02 | WRITE_REGISTER | WRITE_REGISTER 指令将软件选择的值写入指定的寄存器区域。Value 字段被忽略。 |
| 0x03 | WRITE_REGISTER_VALUE | WRITE_REGISTER_VALUE 指令将 Value 字段的内容写入指定的寄存器区域。 |
| 0x04 | NOOP | 无操作。 |
下表定义了从 GET_COMMAND_STATUS 返回的错误注入状态码。
表 18.28 命令状态定义
| 值 | 说明 |
|---|---|
| 0x0 | 成功 |
| 0x1 | 未知失败 |
| 0x2 | 无效访问 |
18.6.4. 错误类型
下表定义了从 GET_ERROR_TYPE 返回的错误类型代码,以及由 SET_ERROR_TYPE 设置的错误类型和由 SET_ERROR_TYPE_WITH_ADDRESS 设置的错误类型字段(见表 18.30)。
SET_ERROR_TYPE 和 SET_ERROR_TYPE_WITH_ADDRESS 这两个动作都必须作为 EINJ 动作表的一部分存在。OSPM 可以自由选择这两个动作中的任意一个来注入错误类型。平台将优先采用 SET_ERROR_TYPE_WITH_ADDRESS。也就是说,如果 SET_ERROR_TYPE_WITH_ADDRESS 设置了一个非零的错误类型值,那么由 SET_ERROR_TYPE 设置的任何错误类型值都将被忽略。但如果 SET_ERROR_TYPE_WITH_ADDRESS 未指定错误类型,则平台将使用 SET_ERROR_TYPE 来标识要注入的错误类型。
表 18.29 错误类型定义
| 位 | 说明 |
|---|---|
| 0 | 处理器可纠正 |
| 1 | 处理器不可纠正非致命 |
| 2 | 处理器不可纠正致命 |
| 3 | 内存可纠正 |
| 4 | 内存不可纠正非致命 |
| 5 | 内存不可纠正致命 |
| 6 | PCI Express 可纠正错误 |
| 7 | PCI Express 不可纠正非致命错误 |
| 8 | PCI Express 不可纠正致命错误 |
| 9 | 平台可纠正 |
| 10 | 平台不可纠正非致命 |
| 11 | 平台不可纠正致命 |
| 12:30 | 保留 |
| 31 | 厂商定义错误类型。如果设置了该位,则错误类型和相关数据结构由厂商定义,如厂商错误类型扩展结构中所示 |
表 18.30 SET_ERROR_TYPE_WITH_ADDRESS 数据结构
| 字段 | 字节长度 | 字节偏移 | 说明 |
|---|---|---|---|
| Error Type | 4 | 0x0 | 要注入的错误类型位图。参见错误类型定义。该字段在被平台使用后会被清除。 |
| Vendor Error Type Extension Structure Offset | 4 | 4 | 指定从表起始位置到厂商错误类型扩展结构的偏移量。如果不存在厂商错误类型扩展,则 error type 中的 bit31 必须清零,且该字段必须设为 0。 |
| Flags | 4 | 0x8 | Bit [0] - 处理器标识字段有效 Bit [1]- 内存地址和内存地址掩码字段有效 Bit [2] - PCIe SBDF 字段有效 Bit [31:3] - 保留 该字段在被平台使用后会被清除。 |
| Processor Error | |||
| Processor Identification | 4 | 0x0C | 可选字段:在非 ARM 架构上,这是作为注入目标的处理器的物理 APIC ID 或 X2APIC ID;在 ARM 系统上,这是 MADT 中使用的 ACPI Processor UID 值。 |
| Memory Error | |||
| Memory Address | 8 | 0x10 | 可选字段,指定作为注入目标的内存物理地址。当 Flags 字段的 Bit [1] 被置位时有效。 |
| Memory Address Range | 8 | 0x18 | 可选字段,为地址字段提供范围掩码。当 Flags 字段的 Bit [1] 被置位时有效。如果 OSPM 不想提供地址范围,则该字段应为零。 |
| PCIe SBDF | 4 | 0x20 | Byte 3 - PCIe Segment Byte 2 - Bus Number Byte 1: Bits [7:3] Device Number Bits [2:0] Function Number Byte 0 - 保留 |
表 18.31 厂商错误类型扩展结构
| 字段 | 字节长度 | 字节偏移 | 属性 | 说明 |
|---|---|---|---|---|
| Length | 4 | 0x0 | 由平台设置。对软件为 RO。 | 整个厂商错误类型扩展结构的长度(以字节为单位)。 |
| SBDF | 4 | 0x04 | 由平台设置。对软件为 RO | 该字段提供 PCIe Segment、Bus、Device 和 Function 编号,可用于读取 Vendor ID、Device ID 和 Rev ID,以便软件能够出于错误注入目的识别系统。该字段由平台设置,并且对软件为 RO。 |
| Vendor ID | 2 | 0x08 | 由平台设置。对软件为 RO | 用于标识设备制造商的厂商 ID。它与 PCI SIG 定义的 Vendor ID 相同。该字段由平台设置,并且对软件为 RO |
| Device ID | 2 | 0x0A | 由平台设置。对软件为 RO | 该 16 位 ID 由制造商分配,用于标识此设备。该字段由平台设置,并且对软件为 RO |
| Rev ID | 1 | 0x0C | 由平台设置。对软件为 RO | 该 8 位值由制造商分配,用于标识设备的修订号。该字段由平台设置,并且对软件为 RO |
| Reserved | 3 | 0x0D | 由平台设置。对软件为 RO | 保留 |
| OEM Defined structure | N | 0x10 | 其余字段由 OEM 定义。 |
18.6.5. 触发动作表
错误注入操作是一个两步过程:先将错误注入平台,随后再触发该错误。软件使用 EXECUTE_OPERATION 动作将错误注入平台后,接下来需要触发该错误。为了触发错误,软件执行 GET_TRIGGER_ERROR_ACTION_TABLE 动作,该动作返回一个指向 Trigger Error Action 表的指针。该表的格式如下表所示。然后软件执行 Trigger Error Action Table 中指定的指令项,以触发已注入的错误。
表 18.32 Trigger Error Action
| TRIGGER_ERROR 头 | 字节长度 | 字节偏移 | 说明 |
|---|---|---|---|
| Header Size | 4 | 0 | 此头的长度(以字节为单位)。 |
| Revision | 4 | 4 | |
| Table Size | 4 | 8 | 整个表的大小(以字节为单位)。 |
| Entry Count | 4 | 12 | TRIGGER_ERROR 动作序列中的指令项数量 —— 见下方注释 (1)。 |
| 动作表 | |||
| TRIGGER_ERROR Instruction Entries - 见下方注释 (2) | 16 | 一系列错误注入指令项,定义见表 18-405。 |
注
(1) 如果上述 “Entry Count” 字段为 ZERO,则 TRIGGER_ERROR 动作表中没有动作结构。在不需要 TRIGGER_ERROR 动作的情况下(例如,错误注入动作既播种错误又消耗错误的情况),平台可以将该字段设为 ZERO。
注
(2) TRIGGER_ERROR 指令项的格式与表 18-407 中描述的注入指令项相同。
18.6.6. 错误注入操作
在 OSPM 可以使用该机制注入错误之前,它必须通过执行 GET_ERROR_TYPE 来发现平台的错误注入能力。有关错误类型的定义,请参见错误类型定义。
在发现错误注入能力之后,OSPM 可以按照下面描述的顺序注入并触发一个错误。
请注意,将错误注入平台并不会自动消耗该错误。作为对错误注入的响应,平台会返回一个触发错误动作表。注入错误的软件必须执行触发错误动作表中的动作,才能消耗该错误。如果某种特定错误类型在注入时会被自动消耗,则平台将返回一个由 NO_OP 组成的触发错误动作表。
执行 BEGIN_INJECTION_OPERATION 动作,以通知平台错误注入操作即将开始。
执行 GET_ERROR_TYPE 动作,以确定系统的错误注入能力。该动作返回一个 DWORD 位图,表示平台支持的错误类型(见表 18.29)。
如果 GET_ERROR_TYPE 返回的 DWORD 中 Bit [31] 被置位,则表示除标准错误类型外,还存在厂商定义的错误类型(见表 18.29)。
OSPM 通过执行 SET_ERROR_TYPE 或 SET_ERROR_TYPE_WITH_ADDRESS _WITH_ADDRESS 动作来选择要注入的错误类型(见第 18.6.4 节)。
如果 OSPM 选择注入某个受支持的标准错误类型,则它在错误类型位图中设置相应的位。例如,如果 OSPM 选择注入 “内存可纠正” 错误,则 OSPM 在错误类型位图中设置值 0x0000_0080。
如果 OSPM 选择注入某个厂商定义的错误类型,则它在错误类型位图中设置 bit[31]。
- OSPM 执行 SET_ERROR_TYPE_WITH_ADDRESS_WITH_ADDRESS 动作,以检索 “SET_ERROR_TYPE_WITH_ADDRESS 数据结构” 的位置,然后通过读取 “Vendor Error Type Extension Structure Offset” 来获取 “Vendor Error Type Extension Structure” 的位置(见表 18.31)。
- OSPM 从 PCI 配置空间读取 Vendor ID、Device ID 和 Rev ID,其路径(PCIe Segment/Device/Function)由 Vendor Error Type Extension Structure 的 “SBDF” 字段提供。
- 如果 Vendor ID/Device ID 和 Rev ID 相匹配,则 OSPM 可以识别其正在运行的平台,并且会知道该平台支持哪些厂商错误类型。
- OSPM 将要注入的厂商错误类型写入 “OEM Defined Structure” 字段(见表 18.31)。
可选地,对于标准错误类型或厂商定义错误类型,OSPM 可以选择注入目标,例如内存范围、PCIe Segment/Device/Function 或处理器 APIC ID,具体取决于错误类型。OSPM 通过执行 SET_ERROR_TYPE_WITH_ADDRESS 动作来填写 “SET_ERROR_TYPE_WITH_ADDRESS 数据结构” 的相应字段(见表 18.30)。
执行 EXECUTE_OPERATION 动作,以指示平台开始注入操作。
通过持续执行 CHECK_BUSY_STATUS 动作进行忙等待,直到平台通过清除抽象 Busy 位来指示操作已完成。
执行 GET_COMMAND_STATUS 动作,以确定已完成操作的状态。
如果状态指示平台无法注入错误,则停止。
执行 GET_TRIGGER_ERROR_ACTION_TABLE 操作,以获取指向 TRIGGER_ERROR 动作表的物理指针。这为错误注入是两步(或更多步)过程的系统提供了灵活性。
执行 TRIGGER_ERROR 动作表中指定的动作。
执行 END_OPERATION,以通知平台错误注入操作已完成。