5.5.2.4.4. 声明IPMI运营区域
本节介绍智能平台管理接口 (IPMI) 地址空间以及如何使用该地址空间与 AML 中的底板管理控制器 (BMC) 硬件进行通信。
与 SMBus 类似,IPMI操作区域是基于命令的,其中IPMI地址空间内的每个偏移量代表一个IPMI命令和响应对。鉴于这种独特性,IPMI操作区域对其字段定义进行了限制,并要求所有事务使用IPMI特定的数据缓冲区。本节中介绍的IPMI接口旨在与任何与IPMI规范兼容的硬件实现一起使用,无论系统接口类型如何。
与ACPI兼容的操作系统对IPMI通用地址空间的支持是可选的,并且取决于ACPI、IPMI设备的存在,即具有IPI0001即插即用ID的设备。如果存在,OSPM应根据设备下的_IFT(IPMI接口类型)控制方法指定的系统接口类型加载必要的驱动程序软件,并注册用于访问IPMI操作区域空间的处理程序。
如需了解更多信息,请参阅IPMI规范。
每个IPMI操作区域定义标识一个IPMI网络功能。仅针对需要从AML访问的IPMI网络功能定义操作区域。与其他区域一样,IPMI操作区域只能通过“字段”术语访问(请参阅声明IPMI字段)。
该接口将每个IPMI网络功能建模为具有 256 字节线性地址范围。此范围内的每个字节偏移对应一个命令值(例如,字节偏移 0xC1 等于命令值 0xC1),最多 256 个命令值。通过这样做,IPMI地址空间看起来是线性的,并且可以按照与其他地址空间类型类似的方式进行处理。
OperationRegion 术语的语法(来自 OperationRegion(声明操作区域))如下所述:
操作区域( RegionName, // NameString RegionSpace, // RegionSpaceKeyword Offset, // TermArg=>Integer Length // TermArg=>Integer )
其中:
RegionName 指定此 IPMI 网络功能的名称(例如,“POWR”)。
RegionSpace必须设置为IPMI(操作区域类型值0x07)。
偏移量是一个字大小的值,指定目标设备的网络功能和初始命令值偏移量。高字节存储网络功能地址,低字节存储命令值偏移。例如,值 0x3000 将用于网络功能为 0x06 且初始命令值偏移为零 (0) 的设备。
对于初始命令值偏移为零 (0) 的区域,长度设置为 0x100 (256),表示可能的命令值的最大数量。这两个值的差用于具有非零偏移的区域。例如,偏移值为 0x3010 的区域的相应长度将为 0xF0(0x100 减去 0x10)。
例如,底板管理控制器将支持网络功能 0x30 处的电能计量功能,以及用于查询网络功能 0x06 处BMC设备信息的IPMI命令。
以下ASL代码显示了如何使用OperationRegion术语来描述这些IPMI函数:
Device (IPMI)
{
Name (_HID, "IPI0001") // IPMI device
Name (_IFT, 0x1) // KCS system interface type
OperationRegion (DEVC, IPMI, 0x0600, 0x100) // Device info network function
OperationRegion (POWR, IPMI, 0x3000, 0x100) // Power network function
}
请注意,本例中的这些操作区域是在“拥有”IPMI设备的直接上下文中定义的。这可确保根据 _IFT 对象返回的值使用正确的操作区域处理程序。每个定义对应一个单独的网络功能,并且恰好使用零 (0) 的初始命令值偏移。
5.5.2.4.4.1. 声明IPMI字段
与其他区域一样,IPMI操作区域只能通过“字段”术语访问。每个字段元素都分配有一个唯一的命令值,并代表目标网络功能的虚拟命令。
字段术语(来自 Event(声明事件同步对象))的语法如下所述:
Field(
RegionName, // NameString=>OperationRegion
AccessType, // AccessTypeKeyword - BufferAcc
LockRule, // LockRuleKeyword
UpdateRule // UpdateRuleKeyword - ignored
) {FieldUnitList}
其中:
RegionName 指定之前为网络功能定义的操作区域名称。
AccessType 必须设置为 BufferAcc。这表明对字段元素的访问将使用区域特定的数据缓冲区来完成。对于这种访问类型,字段处理程序不知道数据缓冲区的内容可能是任何大小。当这种类型的字段用作操作中的源参数时,它的计算结果只是一个缓冲区。然而,当用作目标时,缓冲区会双向传递,以允许从写入操作返回数据。修改后的缓冲区将成为该命令的响应消息。这与执行结果与写入目标的值相同的正常情况略有不同。请注意,源永远不会改变,因为它仅代表特定IPMI命令的虚拟寄存器。
LockRule 指示访问该操作区域是否需要获取全局锁以进行同步。该字段应设置为锁定系统,其固件可以通过IPMI访问BMC,否则设置为“NoLock”。
UpdateRule 不适用于IPMI操作区域,因为每个虚拟寄存器都是完整访问的。所有 IPMI 字段定义都会忽略此字段。
IPMI操作区域要求所有字段元素都以命令值粒度声明。这意味着每个虚拟寄存器不能分解为字段定义中的各个位。
对虚拟寄存器的子部分的访问只能在字段定义之外进行。施加此限制既是为了简化IPMI接口,也是为了保持与IPMI规范定义的物理模型的一致性。
由于用于IPMI通信的系统接口由IPMI设备下的_IFT 对象确定,因此无需在字段定义中使用AccessAs 术语。事实上,它的使用将被操作处理程序忽略。
例如,电表网络功能的命令值 0xC1 处的寄存器可能表示设置BMC强制功率限制的命令,而同一网络功能的命令值 0xC2 处的寄存器可能表示当前配置的功率限制。同时,命令值 0xC8 处的寄存器可能代表最新的功率计测量结果。
以下ASL代码显示了使用OperationRegion、Field 和Offset 术语来表示这些虚拟寄存器:
OperationRegion(POWR, IPMI, 0x3000, 0x100) // Power network function
Field(POWR, BufferAcc, NoLock, Preserve)
{
Offset(0xC1), // Skip to command value 0xC1
SPWL, 8, // Set power limit [command value 0xC1]
GPWL, 8, // Get power limit [command value 0xC2]
Offset(0xC8), // Skip to command value 0xC8
GPMM, 8 // Get power meter measurement [command value 0xC8]
}
请注意,命令值相当于字段元素的字节偏移量(例如,SPWL=0xC1、GPWL=0xC2、GPMM=0xC8)。
5.5.2.4.4.2. 声明和使用IPMI请求和响应缓冲区
由于IPMI操作区域中的每个虚拟寄存器代表一个单独的IPMI命令,并且该操作依赖于双向缓冲区的使用,因此需要一个公共缓冲区结构来表示请求和响应消息。使用IPMI事务的数据缓冲区允许AML接收状态和数据长度值。
IPMI数据缓冲区被定义为固定长度的 66 字节缓冲区,如果使用“C”样式声明表示,则将建模如下:
typedef struct
{
BYTE Status; // Byte 0 of the data buffer
BYTE Length; // Byte 1 of the data buffer
BYTE[64] Data; // Bytes 2 through 65 of the data buffer
}
其中:
状态(字节 0)表示给定IPMI命令的状态代码。有关详细信息,请参阅IPMI 状态代码。
长度(字节1)指定数据缓冲区中存在的有效数据的字节数。有效长度值为 0 到 64。在执行操作之前,该值表示请求数据缓冲区的长度。之后,该值代表结果响应数据缓冲区的长度。
Data(字节65-2)代表一个64字节的缓冲区,是实际数据存储的位置。在执行操作之前,这代表实际的请求消息负载。此后,这表示IPMI命令返回的响应消息有效负载。
例如,以下ASL显示了如何使用IPMI数据缓冲区来执行幂函数命令。此代码基于声明IPMI字段中提供的示例ASL,其中列出了相关IPMI电能计量命令的操作区域和字段定义。
/* Create the IPMI data buffer */
Name(BUFF, Buffer(66){}) // Create IPMI data buffer as BUFF
CreateByteField(BUFF, 0x00, STAT) // STAT = Status (Byte)
CreateByteField(BUFF, 0x01, LENG) // LENG = Length (Byte)
CreateByteField(BUFF, 0x02, MODE) // MODE = Mode (Byte)
CreateByteField(BUFF, 0x03, RESV) // RESV = Reserved (Byte)
LENG = 0x2 // Request message is 2 bytes long
MODE = 0x1 // Set Mode to 1
BUFF = (GPMM = BUFF) // Write the request into the GPMM command,
// then read the results
CreateByteField (BUFF, 0x02, CMPC) // CMPC = Completion code (Byte)
CreateWordField (BUFF, 0x03, APOW) // APOW = Average power measurement (Word)
If ((STAT == 0x0) && (CMPC == 0x0)) // Successful?
{
Return (APOW) // Return the average power measurement
}
Else
{
Return (Ones) // Return invalid
}
请注意使用 CreateField 原语来访问数据缓冲区的子元素(状态、长度和数据),其中数据(字节 65-2)被“类型转换”到不同的字段(包括结果完成代码)。
上面的示例演示了如何使用 Store() 运算符和双向数据缓冲区来调用由虚拟寄存器表示的实际IPMI命令。内部Store()将请求消息数据缓冲区写入IPMI操作区域处理程序,并调用命令。外部 Store() 获取该命令的结果并将其写回数据缓冲区,这次代表响应消息。
5.5.2.4.4.3. IPMI 状态代码
每个IPMI命令都会产生一个状态代码,作为响应消息的第一个字节返回,包含在双向数据缓冲区中。此状态代码可以指示IPMI操作处理程序的成功、各种错误以及可能的超时。这是必要的,因为某些 IPMI 命令可能需要长达 5 秒的时间来执行,并且由于 AML Store() 操作本质上是同步的,因此必须确保 IPMI 操作及时返回,以免阻塞 OSPM 中的 AML 解释器。
- 此状态代码与IPMI完成代码不同,后者作为数据缓冲区有效负载中响应消息的第一个字节返回。完整的IPMI规范中描述了完成代码。
| 表 5.150 IPMI 状态代码 状态代码 | 姓名 | 描述 |
|---|---|---|
| 00 点 | IPMI OK | 表示命令已成功完成。 |
| 07 点 | IPMI 未知故障 | 表示由于未知IPMI错误而失败。 |
| 10 小时 | IPMI 命令操作超时 | 表示操作超时。 |