hwproxy
版本信息
| 项目 | 内容 |
|---|---|
| 组件版本 | 1.130.22 |
| 首发版本 | openUBMC 26.09 |
| 文档作者 | openUBMC 社区 |
| 最后更新 | 2026-09-15 |
| 许可证 | Mulan PSL v2 |
1. 组件概述
1.1 组件简介
hwproxy 是 openUBMC 的硬件代理组件,属于基础框架子系统的南向硬件访问层。它以独立 Skynet 应用运行,D-Bus 服务名为 bmc.kepler.hwproxy。BMC 启动后,hwdiscovery 将 CSR/SR 解析出的对象与拓扑写入资源树;hwproxy 订阅对象增删,按总线创建 work 工作服务,把 Chip / Bus / Accessor / Scanner 上树,并通过 runtime_accessor 调用用户态驱动完成硬件读写。
组件类型为 application(见 mds/service.json),deployConfig 为 framework.service。systemd 单元 hwproxy.service 在 mdb_mgmt.service 之后启动,依赖 mdb_mgmt.service 与 persistence.service,工作目录 /opt/bmc/apps/hwproxy,进程入口为 /opt/bmc/skynet/skynet /opt/bmc/apps/hwproxy/config.cfg。
仓库中没有 mds/ipmi.json,不提供 IPMI 命令。器件级 read / write 实现来自 runtime_accessor,底层总线 ioctl 来自 libsoc_adapter;本文只记录 hwproxy 对外发布的资源协作接口。
1.2 解决什么问题
业务组件需要访问温度传感器、GPIO 扩展器、EEPROM、SMC、CPLD、SPI Flash 等外围器件,但总线拓扑、Mux 切通道、扫描周期和实时读写各不相同。若每个组件各自封装驱动,会出现重复实现、访问冲突和机型适配成本高的问题。
hwproxy 把硬件访问收敛到统一服务:
- 按 CSR 建立 Chip / Bus / Mux 拓扑,对外暴露块读写、位读写、Flash 和 JTAG 接口。
- 用 Scanner 周期性扫描只读属性,用 Accessor 在属性读写时实时访问硬件。
- 用
PluginRequest让业务插件在独占总线通道内执行自定义协议。 - 将高优先级实时请求与低优先级扫描任务排队,避免互相打断。
1.3 核心功能
核心功能一:Chip 块/位访问
bmc.kepler.Chip.BlockIO/bmc.kepler.Chip.BitIO提供 Read、Write、WriteRead、ComboWriteRead、BatchWrite、PluginRequest 等接口。具体方法是否注册取决于器件class_name(见 2.1)。核心功能二:Scanner / Accessor
Scanner 在 work 服务内按
Period扫描并更新资源树只读属性;Accessor 监听property_read/property_before_change,在业务读/写属性时实时访问硬件。核心功能三:插件与诊断
PluginRequest/PluginRequestEx加载hwproxy.plugins.<PluginName>;TraceChip、TraceDebounce、一键 Dump 和 Debug Mock 用于跟踪读写与复现故障。
1.4 关键术语表
| 术语 | 解释 |
|---|---|
| hwproxy | 硬件代理服务,D-Bus 服务名 bmc.kepler.hwproxy。 |
| CSR / SR | Component Self-Description Record,描述芯片地址、总线、Mux、Scanner/Accessor 等。 |
| Chip | 器件对象。路径形如 /bmc/kepler/Chip/<ClassName>/<Id>。 |
| Bus | 总线对象。路径形如 /bmc/kepler/Bus/I2c/<Id>。 |
| Scanner | 周期性扫描对象,Value 只读,由内部扫描任务更新。 |
| Accessor | 实时访问对象,读 Value 触发硬件读,写 Value 触发硬件写。 |
| Mux | 多路复用器(如 PCA9545),访问下级 Chip 前切通道。 |
| PluginRequest | 在 Chip 队列中独占通道执行业务插件命令。 |
| runtime_accessor | 随 hwproxy 部署的器件/总线 Lua 驱动库。 |
| SMC | Server Management Channel;Smc 器件的 Offset 为命令字。 |
1.5 外部交互边界图
构建测试依赖见 mds/service.json:hwdiscovery、libmc4lua、mdb_interface、maca、persistence、dtframeforlua、runtime_accessor、libmgmt_protocol。运行时日志默认 /var/log/framework/hwproxy.log。组件自身没有独立监听端口。
2. API 使用说明与示例
对外发布的 API 为资源协作接口,服务名 bmc.kepler.hwproxy。对象路径中的 :Id 来自 CSR 对象名(含 GroupPosition 后缀,如 Eeprom_BCU_010101)。均可通过 busctl / mdbctl 调试。
方法首参 a{ss} 为框架调用上下文;命令行调试可传空字典 0。上下文可带 Timeout(秒,默认 120;小于等于 0 表示不设定时器)。权限取自 MDS / mdb_interface(TraceChip / TraceDebounce 为 DiagnoseMgmt;FlashIO 方法为 BasicSetting)。
# 查看资源协作接口
busctl --user tree bmc.kepler.hwproxy仓库无 mds/ipmi.json,以下接口均不能通过 ipmitool 调用。
不同 Chip 类注册的方法不同,以 src/lualib/object_defs.lua 为准:
class_name | 路径前缀 | BlockIO | BitIO | 其他方法 |
|---|---|---|---|---|
Eeprom / Rtc / Cpld | /bmc/kepler/Chip/<Class>/:Id | 是 | 否 | Cpld 另有 JtagTarget |
Smc / Pca9555 / Lm75 / Vrd / CpldChip / Ina / CanbusChip | 见 mds/model.json | 是 | 是 | Ina 另有 PowerMeter 属性 |
Chip(Complex) | /bmc/kepler/Chip/Complex/:Id | 是 | 否 | WriteRead、ComboWriteRead、WriteReadByProtocol |
SPIFlash | /bmc/kepler/Chip/SPIFlash/:Id | 是 | 否 | FlashIO |
Pca9545 / Pca9544 / Ads78 / CpldRegister | /bmc/kepler/Chip/<Class>/:Id | 否 | 否 | TraceChip |
上表中 “BlockIO 是” 同时注册 Read / Write / BatchWrite / PluginRequest / PluginRequestEx。WriteRead 仅 Chip 与 CanbusChip;ComboWriteRead 与 WriteReadByProtocol 仅 Chip。
2.1 bmc.kepler.Chip.BlockIO
功能说明
按字节对 Chip 做块读、块写、先写后读、批量写和插件访问。接口定义见 mdb_interface 的 json/intf/mdb/bmc/kepler/Chip/BlockIO.json。
路径:/bmc/kepler/Chip/<ClassName>/<Id>,例如 /bmc/kepler/Chip/Eeprom/Eeprom_BCU_010101。
参数说明
| 方法 | 入参(不含上下文) | 出参 | D-Bus 签名(含 a{ss}) | 说明 |
|---|---|---|---|---|
Read | Offset u、Length u | OutData ay | a{ss}uu → ay | 从偏移读取指定长度。 |
Write | Offset u、InData ay | 无 | a{ss}uay | 向偏移写入。 |
WriteRead | InData ay、ReadLength u | OutData ay | a{ss}ayu → ay | 扩展读:写入请求后再读;内部偏移为 0xFFFFFFFF。仅部分 Chip 类注册。 |
ComboWriteRead | WriteOffset u、InData ay、ReadOffset u、ReadLength u | OutData ay | a{ss}uayuu → ay | 先写后读,合并为一次原子操作。仅 Chip。 |
BatchWrite | WriteData a(uay) | 无 | a{ss}a(uay) | 多帧偏移+数据一次写入。 |
PluginRequest | PluginName s、Cmd s、Params ay | OutData ay | a{ss}ssay → ay | 加载并执行插件,见 2.9。 |
PluginRequestEx | 同上,另加 ControlParams a{ss} | OutData ay | a{ss}ssaya{ss} → ay | 扩展插件请求;Priority 可为 High 或 Secondary。 |
WriteReadByProtocol | InData ay、ReadLength u、Protocol y | OutData ay | a{ss}ayuy → ay | 指定协议写读。当前仅支持 0x02(SMBus/I2C)。仅 Chip。 |
bmc.kepler.Release.Chip.Read 与 BlockIO Read 绑定同一实现,入参同样是 Offset / Length。
返回值与异常
成功时读类方法返回字节数组;写类方法无返回值。失败时抛 D-Bus 错误,常见名称见 5.2。队列超限抛 ChipRequestLimitExceeded。器件不在拓扑中抛 kepler.hwproxy.ChipNotExistError。等待超时抛 kepler.hwproxy.RequestTimeout。
应用场景
- 业务通过 CSR 引用 Chip(如
StorageChip: "#/Eeprom_1")后调用chip:Read/chip:Write。 - 升级等多帧写入使用
BatchWrite,减少 D-Bus 往返。 - 需要写后立刻读且不能被其他写插入时使用
ComboWriteRead。
限制条件
- 拓扑未分发完成(
AddObjectComplete之前)访问会失败,启动阶段应重试。 - 单 Chip 各队列长度默认上限 500(环境变量
CHIP_REQUEST_QUEUE_MAX_LEN,实现会限制在 100~1000)。 WriteRead/ComboWriteRead/WriteReadByProtocol未在对应class_name上注册时,introspect 看不到该方法。- Cpld 的请求超时在
object_defs.lua中为-1(不设定时器)。
调试示例
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Eeprom/Eeprom_BCU_010101 \
bmc.kepler.Chip.BlockIO Read a{ss}uu 0 100 24
# 响应 ay 24 ...
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Eeprom/Eeprom_BCU_010101 \
bmc.kepler.Chip.BlockIO Write a{ss}uay 0 0 10 0 0 0 0 0 0 0 0 90 165-- 组件 service.json 声明对 Chip 接口的依赖,bingo gen 后通过代理对象访问
local data = chip:Read(ctx, offset, length)
chip:Write(ctx, offset, in_data)2.2 bmc.kepler.Chip.BitIO
功能说明
按位读写。位操作由对应器件的 runtime_accessor 驱动实现;I2C 总线上的数据仍以字节为单位传输。接口定义见 json/intf/mdb/bmc/kepler/Chip/BitIO.json。
路径:与对应 Chip 相同,例如 /bmc/kepler/Chip/Smc/Smc_CpuBrdSMC_010101。
参数说明
| 方法 | 入参(不含上下文) | 出参 | D-Bus 签名 | 说明 |
|---|---|---|---|---|
Read | Offset u、Length y、Mask u | OutData ay | a{ss}uyu → ay | 读取后与掩码按位与。 |
Write | Offset u、Length y、Mask u、InData ay | 无 | a{ss}uyuay | 先读再按掩码改写。 |
返回值与异常
与 BlockIO 相同:成功返回数据或无返回值;失败抛 5.2 节错误。器件驱动不支持位操作时,行为由 runtime_accessor 对应 class_name 决定。
应用场景
读取或修改寄存器中的若干 bit,例如 SMC 状态位。
限制条件
仅 object_defs.lua 中 support_bit_io = true 的类注册该方法。块读场景 Mask 无效,可置 0。
调试示例
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Smc/Smc_CpuBrdSMC_010101 \
bmc.kepler.Chip.BitIO Read a{ss}uyu 0 0x2100 1 0x0f
# 响应 ay 1 10
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Smc/Smc_CpuBrdSMC_010101 \
bmc.kepler.Chip.BitIO Write a{ss}uyuay 0 0x2200 1 0x0f 1 0x022.3 bmc.kepler.Chip.FlashIO
功能说明
SPI Flash 器件的封装读写、擦除和原始帧收发。Read / Write 与 BlockIO 使用同一套块读写实现;RawRead / RawWrite 下发自定义帧;Erase 按类型擦除。仅 SPIFlash 注册。接口定义见 json/intf/mdb/bmc/kepler/Chip/FlashIO.json。
路径:/bmc/kepler/Chip/SPIFlash/:Id
参数说明
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
Read | Offset u、Length u | OutData ay | 与 BlockIO Read 相同。 |
Write | Offset u、InData ay | 无 | 与 BlockIO Write 相同。 |
Erase | Offset u、Type y | 无 | 0 扇区、1 32K 块、2 64K 块、3 芯片擦除。 |
RawRead | Length u、InData ay | OutData ay | 自定义读帧(含命令字)。 |
RawWrite | InData ay | 无 | 自定义写帧(含命令字)。 |
权限均为 BasicSetting。CSR 还需配置 ChipSelect、BytesPerPage(默认 256)、CommandSet。
返回值与异常
与 BlockIO 相同。擦除类型必须为 0~3。
应用场景
固件分区擦除、按页编程,或按器件手册下发非标准 SPI 帧。
限制条件
仅 SPIFlash 对象。Raw* 要求调用方自行组命令字与负载,错误帧会导致总线 IO 失败。
调试示例
busctl --user introspect bmc.kepler.hwproxy \
/bmc/kepler/Chip/SPIFlash/SPIFlash_1_01012.4 bmc.kepler.Chip.JtagTarget
功能说明
Cpld 的 JTAG 目标操作:读取链上 IDCODE、Bypass 模式升级、采集与自检。方法在 hwproxy_app.lua 中注册为 ImplCpldJtagTarget*。完整方法表以 mdb_interface 的 json/intf/mdb/bmc/kepler/Chip/JtagTarget.json 为准(mds/model.json 的 Cpld 段仅列出 Upgrade / Collect / Verify)。
路径:/bmc/kepler/Chip/Cpld/:Id
参数说明
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
GetChipIdcode | 无(仅上下文) | DeviceId au | JTAG 链上器件 IDCODE。 |
SetTargetNumber | Num u | 无 | Bypass 模式下选择待升级器件。 |
SetBypassMode | Enable b | 无 | 是否使用 Bypass 升级。 |
BypassChannelTest | Id y、Channel y | ResultCode b | JTAG 链路测试。 |
Upgrade | FilePath s、FileType y | 无 | FileType:0 VME,1 SVF。 |
Collect | FilePath s、FileType y、OutputFilePath s | 无 | 采集寄存器到文件。 |
Verify | FilePath s、FileType y | 无 | 安全自检。 |
Upgrade / Collect / Verify / BypassChannelTest 权限为 BasicSetting。Cpld 访问不设默认 120 秒超时。
返回值与异常
GetChipIdcode 返回 IDCODE 数组。BypassChannelTest 返回 true/false。升级类方法失败时抛 IO / 超时类错误。链切换常配合 Accessor(如 Accessor_JtagSwitch_*)先写链路选择。
应用场景
CPLD 固件升级、读取 IDCODE 确认链路、Bypass 通道测试。
限制条件
仅 Cpld 对象。升级前需保证 JTAG 总线与 Switch Accessor 指向正确板卡(Position 与 CSR FirmwareRoute 一致)。
调试示例
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Cpld/Cpld_1_0101 \
bmc.kepler.Chip.JtagTarget GetChipIdcode a{ss} 02.5 bmc.kepler.Accessor / bmc.kepler.Scanner
功能说明
Accessor 在业务读/写 Value 时实时访问硬件;Scanner 由 hwproxy 按 Period(毫秒)扫描,业务读 Value 不会再次访问硬件。接口定义见 json/intf/mdb/bmc/kepler/Accessor.json 与 Scanner.json。
路径:
- Accessor:
/bmc/kepler/Accessor/:Id - Scanner:
/bmc/kepler/Scanner/:Id
参数说明
接口属性
| 对象 | 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| Accessor | Value | t(U64) | 可读写 | 读触发硬件读,写触发硬件写。 |
| Accessor | Status | y | 只读 | 0 正常,1 失败,2 预失败(防抖中),3 无效,4 初始。 |
| Accessor | PrintableValue | s | 只读 | 块读成功后的可打印 ASCII;含不可见字符时不更新;不能用于写硬件。 |
| Scanner | Value | t | 只读 | 扫描缓存值。 |
| Scanner | Status | y | 只读 | 含义与 Accessor 相同;4 表示尚未开始扫描。 |
CSR 配置字段(mds/model.json,不全部出现在 D-Bus 接口上):
| 字段 | 对象 | 说明 |
|---|---|---|
Chip | 二者 | 关联器件,如 "#/Smc_2"。 |
Offset / Size / Mask / Type | 二者 | 偏移、长度(Byte)、掩码、0 位访问 / 1 块访问。Accessor Size 最大 64。 |
WriteOffset | Accessor | 写偏移;默认 4294967295(0xFFFFFFFF)表示与读偏移相同。 |
Period | Scanner | 扫描周期,单位 ms。 |
ScanEnabled | Scanner | 0 禁用,1 使能。禁用后可使用 NominalValue。 |
Debounce | Scanner | 防抖对象名:None / MidAvg / Median / Cont / ContBin。 |
FailureDebounceCount / SuccessDebounceCount | 二者 | 默认 10。 |
Scanner 另有 bmc.kepler.Scanner.Aggregate(AggregateOffset、AggregateStatus)以及 bmc.kepler.Release.Scanner.TraceDebounce(Action 为 start / stop,权限 DiagnoseMgmt)。
返回值与异常
属性读写失败时抛 IO / 超时 / Chip 不存在等错误。Status 经防抖后才从预失败变为失败。
应用场景
- 在位、温度、告警类只读量用 Scanner,业务监听
PropertiesChanged或读Value。 - 按钮、锁定、JTAG 切换等需要写入的量用 Accessor。
- 既要周期刷新又要写入时,配置一对参数相同的 Scanner + Accessor。
限制条件
- 同一处多次读 Accessor
Value会多次访问硬件,应先赋给局部变量。 - Scanner 的
Value只读;需要写入时不要改 Scanner,应增加 Accessor。 - 调用方须在
mds/service.json中声明对 Accessor/Scanner 的弱依赖,并require生成的 client。 - 同步语法
<=/Scanner_x.Value不能依赖成环。
调试示例
busctl --user get-property bmc.kepler.hwproxy \
/bmc/kepler/Accessor/Accessor_JtagSwitch_010101 \
bmc.kepler.Accessor Value
busctl --user set-property bmc.kepler.hwproxy \
/bmc/kepler/Accessor/Accessor_JtagSwitch_010101 \
bmc.kepler.Accessor Value t 1
busctl --user get-property bmc.kepler.hwproxy \
/bmc/kepler/Scanner/Scanner_PSU_1 \
bmc.kepler.Scanner Valuelocal lock = FruCtrl.PwrButtonLock -- 引用 Accessor.Value,每次读取都会访问硬件
FruCtrl.PwrButtonLock = 1 -- 写入硬件CSR 示例(Scanner,支持 // 注释的 CSR 语法):
"Scanner_PSU_1": {
"Chip": "#/Smc_2",
"Offset": 469765888,
"Size": 1,
"Mask": 255,
"Type": 0,
"Period": 100,
"Debounce": "None",
"Value": 0
}2.6 bmc.kepler.Bus / bmc.kepler.Bus.BlockIO
功能说明
bmc.kepler.Bus 提供总线访问使能控制。bmc.kepler.Bus.BlockIO 按从地址直接读写总线,不经过 Chip 驱动封装;object_defs.lua 中仅 I2c 设置 support_bus_block_io。接口定义见 json/intf/mdb/bmc/kepler/Bus.json 与 Bus/BlockIO.json。
路径:/bmc/kepler/Bus/I2c/:Id,例如 /bmc/kepler/Bus/I2c/I2c_7。
参数说明
| 属性/方法 | 类型 | 读写 | 说明 |
|---|---|---|---|
AccessEnabled | b | 只读 | 链路是否允许访问。 |
Timeout | q | 只读 | 命令超时,单位秒。 |
SetAccessibility | Status b、DisableDuration q | 方法 | Status=false 时禁止访问,DisableDuration 范围 1~1800 秒,到期自动恢复。 |
| BlockIO 方法 | 入参 | 出参 | D-Bus 签名 | 说明 |
|---|---|---|---|---|
Read | SlaveAddress y、ReadLength u | OutData ay | a{ss}yu → ay | 按从地址读。 |
Write | SlaveAddress y、InData ay | 无 | a{ss}yay | 按从地址写;InData 前若干字节通常为器件偏移。 |
WriteRead | SlaveAddress y、InData ay、ReadLength y | OutData ay | a{ss}yayy → ay | 先写后读。 |
返回值与异常
与 Chip 访问相同。禁止访问期间对总线上 Chip 的请求会失败。
应用场景
类似 i2ctool 的调试读写;需要先切 PCA9545 通道时,连续下发 Write 与 WriteRead,避免被 Scanner 打断通道。
限制条件
- 当前仅 I2c 注册 Bus.BlockIO。
- 经过 Mux 的器件必须自行发切通道命令,且两条命令之间不能插入扫描任务。
mdbctl不支持一行多条命令时,请用busctl连续发送。
调试示例
# 切 PCA9545 通道后再读 EEPROM(地址与 CSR Address 一致)
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Bus/I2c/I2c_7 \
bmc.kepler.Bus.BlockIO Write a{ss}yay 0 0xe0 2 0x00 0x01
busctl --user call bmc.kepler.hwproxy /bmc/kepler/Bus/I2c/I2c_7 \
bmc.kepler.Bus.BlockIO WriteRead a{ss}yayy 0 0xae 2 0x00 0x05 102.7 bmc.kepler.Chip 器件状态与访问控制
功能说明
各 Chip 对象均带 bmc.kepler.Chip 接口:健康/上电/自检/锁定状态,以及禁止访问、锁定通道。接口定义见 json/intf/mdb/bmc/kepler/Chip.json。
路径:与具体 Chip 相同。
参数说明
| 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|
HealthStatus | y | 可写 | 0 访问正常,1 访问失败。 |
HealthStatusValidity | b | 只读 | HealthStatus 是否有效。 |
PowerStatus | y | 只读 | 上电状态。 |
SelfTestResult | y | 只读 | 自检结果。 |
LockStatus | y | 只读 | 0 未锁定,1 已锁定。 |
ChipType | s | 只读 | 器件类型字符串;Complex Chip 由 CSR 配置。 |
| 方法 | 入参 | 出参 | 说明 |
|---|---|---|---|
SetAccessibility | Status b、DisableDuration q | 无 | false 禁止该 Chip 访问;时长 1~1800 秒,到期自动恢复。实现会同时启停该 Chip 上的 Scanner。 |
SetLockStatus | OpType y、LockTime u | ResultCode y | OpType:0 解锁,1 加锁。LockTime 仅加锁时有效,上限 30 分钟。 |
SetLockStatus 的 ResultCode:0 OK,1 InvalidParameter,2 UnlockedError,3 RequestorMismatchedError,4 ChipMismatchedError,5 ChannelMismatchedError。
部分 Chip 另有 CSR 属性(Address、OffsetWidth、WriteRetryTimes、ReadRetryTimes、DrvWriteDelay、SwitchSupported、RegisterConfig 等),用于构造驱动,不都作为运行时可写接口暴露。
返回值与异常
SetLockStatus 返回枚举码,不抛该枚举对应的业务错误。禁止访问后对该 Chip 的读写会报访问已关闭。
应用场景
升级或复位期间临时关闭扫描/访问;多组件互斥占用同一通道时加锁。
限制条件
同通道或同总线不同 Chip 加锁会返回 Chip/Channel 不匹配。续锁要求请求者一致。
调试示例
busctl --user get-property bmc.kepler.hwproxy \
/bmc/kepler/Chip/Smc/Smc_CpuBrdSMC_010101 \
bmc.kepler.Chip HealthStatus
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Smc/Smc_CpuBrdSMC_010101 \
bmc.kepler.Chip SetAccessibility a{ss}bq 0 false 602.8 bmc.kepler.Release.TraceChip
功能说明
跟踪指定 Chip 的实时读写,结果通过 mdbctl/调试日志输出(十六进制,超过 1024 字节截断)。权限 DiagnoseMgmt。
路径:带 bmc.kepler.Release.TraceChip 的 Chip 对象。
参数说明
| 方法 | 入参 | 说明 |
|---|---|---|
TraceChip | Action s:start / stop | 开始或停止跟踪。 |
返回值与异常
非法 Action 由参数校验拒绝。跟踪开启后,读写日志含 requestor、bit/block、addr、offset、数据。
应用场景
对照总线波形或业务请求,确认 hwproxy 实际下发的偏移与数据。
限制条件
仅 support_trace = true 的 Chip 类注册。生产环境用完应 stop。
调试示例
busctl --user call bmc.kepler.hwproxy \
/bmc/kepler/Chip/Eeprom/Eeprom_BCU_010101 \
bmc.kepler.Release.TraceChip TraceChip a{ss}s 0 start2.9 PluginRequest 与插件加载
功能说明
PluginRequest / PluginRequestEx 属于 BlockIO。work 服务执行 require('hwproxy.plugins.' .. plugin_name),缓存插件实例,校验 has_cmd(cmd) 后在 Chip 访问队列中调用 run_cmd(chip, cmd, ...),插件执行期间占用该 Chip 通道。
插件通常由业务组件安装到 /opt/bmc/lualib/hwproxy/plugins/<PluginName>/(源码常见位置 include/hwproxy/plugins/<name>/init.lua)。hwproxy 仓库本身不内置业务插件命令。
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
PluginName | string | 与 require('hwproxy.plugins.' .. name) 模块名一致。 |
Cmd | string | 插件已实现的命令名。 |
Params | ay | 用 skynet.pack / skynet.packstring 序列化的参数;空数组表示无额外参数。 |
ControlParams.Priority | string | 仅 Ex:High 或 Secondary。 |
返回的 OutData 需用 skynet.unpack 还原。
返回值与异常
未知命令抛 unknown plugin cmd <name>.<cmd>。模块不存在时 require 失败。硬件失败按 Chip 错误返回。
应用场景
SMBus mailbox、厂商私有帧等无法用通用 BlockIO 表达的访问。
限制条件
插件必须提供 has_cmd / run_cmd。执行期间独占通道,长时间阻塞会拖慢同 Chip 上的 Scanner 与其他请求。
调试示例
local skynet = require('skynet')
local ctx = require('mc.context').new()
ctx.Timeout = 30
local params = skynet.packstring(arg1, arg2)
local out = chip:PluginRequest(ctx, 'compute', 'some_cmd', {string.byte(params, 1, #params)})集成测试中对不存在的插件名会加载失败,对未知 Cmd 会得到 unknown plugin cmd。
2.10 bmc.kepler.Debug.Mock
功能说明
调试用单例对象,用于模拟 Scanner 故障和总线挂死。启动时 create_singleton_objects 调用 CreateMock。
路径:/bmc/kepler/Debug/Mock
参数说明
| 方法 | 入参 | 说明 |
|---|---|---|
MockScannerFailure | ScannerName s、FailureDuration u(1~1800 秒) | 模拟指定 Scanner 故障。 |
MockBusCtrl | BusName s、Action s(suspend / resume) | 模拟总线挂死或恢复。 |
返回值与异常
Scanner 不在拓扑中时抛 ChipNotExistError。FailureDuration 越界由模型校验拒绝。
应用场景
集成测试与故障注入,不要在生产业务路径调用。
限制条件
仅调试/测试构建使用。suspend 后须 resume,否则该总线访问会一直失败。
调试示例
busctl --user introspect bmc.kepler.hwproxy /bmc/kepler/Debug/Mock2.11 其他已建模对象
以下对象由 CSR 上树,本文不展开未在源码中单独实现为对外方法的细节:
| 对象 | 路径 | 说明 |
|---|---|---|
I2cMux | /bmc/kepler/Mux/I2cMux/:Id | Mux 通道,CSR ChannelId。 |
Ina | /bmc/kepler/Chip/PowerMeter/Ina/:Id | 功率计;ChipModel 仅 Ina238 / Ina226 / Ina220。 |
Chip.Aggregate | Complex Chip | CSR:Supported、BaseOffset、Length、Period。 |
Dft* | /bmc/kepler/Manufacture/SelfTest/... | 制造自检;main.lua 在存在 hwproxy_manufacture_app 时加载。 |
SmcDfxInfo | CSR 引用 Smc | Dump 时写入 smc_dfx_info.txt。 |
| MicroComponent | /bmc/kepler/hwproxy/MicroComponent | 框架标准健康检查、Dump、平滑重启。 |
3. 组件扩展案例
3.1 扩展能力概述
hwproxy 支持三类扩展,均不改变现有 BlockIO 返回约定:
- CSR 配置:新增 Scanner / Accessor / Chip,无需改 hwproxy 代码。
- 业务插件:在其他组件中实现
hwproxy.plugins.<name>,经PluginRequest调用。 - 新器件类型:在
mds/model.json、object_defs.lua增加类,并在 runtime_accessor 中实现对应class_name驱动。
3.2 扩展点说明
| 扩展点 | 文件 | 触发时机 |
|---|---|---|
| 对象能力开关 | src/lualib/object_defs.lua | 启动时 method_register。 |
| BlockIO/BitIO/FlashIO 绑定 | src/lualib/hwproxy_app.lua | 同上。 |
| 插件加载 | src/lualib/hwproxy_objects/work_objects.lua 的 plugin_request | 调用 PluginRequest 时。 |
| 驱动/Stream/Mux | runtime_accessor 的 driver / stream / mux | 构造 Chip / Bus 时按 class_name 选择。 |
| Dump | src/lualib/log_dump.lua | MicroComponent on_dump。 |
3.3 二次开发指导
3.3.1 业务侧增加 Scanner / Accessor
- 在机型 CSR 中增加
Scanner_*或Accessor_*,填写Chip、Offset、Size、Type等。 - 在使用方组件的属性上用同步
<=/Scanner_x.Value或引用#/Accessor_x.Value。 - 在使用方
mds/service.json声明弱依赖,bingo gen后requireclient。 - 用
busctl先直接读写 hwproxy 树上的 Accessor/Scanner,再查业务属性。
3.3.2 新增插件
插件模块需能被 require('hwproxy.plugins.<PluginName>'),并提供:
local class = require('mc.class')
local plugin = class()
function plugin:ctor(work_objects)
self.work_objects = work_objects
end
function plugin:has_cmd(cmd)
return cmd == 'ping'
end
function plugin:run_cmd(chip, cmd, ...)
-- 通过 chip:read / chip:write 访问硬件,独占通道
return '\x00'
end
return plugin验证:对已注册 BlockIO 的 Chip 调用 PluginRequest,未知 Cmd 应报 unknown plugin cmd;成功路径返回插件 OutData。
注意事项:不要在插件中做无超时的长循环;日志不要打印敏感载荷;Params 必须与 skynet.pack 格式一致。
3.3.3 新增 Chip 类
- 在
mds/model.json增加类、path 和接口列表。 - 在
object_defs.lua设置type = 'Chip'及support_block_io等开关。 - 在 runtime_accessor 注册同名 driver。
- 同步更新本文第 2 章能力表与示例。
验证:bingo gen 后跑 test/unit/test.lua 与 test/integration/test_hwproxy.lua 中相关用例。
4. 日志说明
4.1 一键日志收集
模块名在 src/service/main.lua / work.lua / monitor.lua 中设为 hwproxy。默认日志文件 /var/log/framework/hwproxy.log(dist/config.cfg 的 logger)。
通过 mc.mdb.micro_component.debug.on_dump 注册 log_dump.on_dump。一键收集时在 Dump 目录生成:
| 文件 | 内容 |
|---|---|
topology.txt | 各总线 Chip 拓扑及 Chip 别名(合并对象名 → 主对象名)。 |
snapshot.csv | Accessor/Scanner 的周期、状态、成功/失败计数、Value。 |
smc_dfx_info.txt | 聚合 / SMC DFX 信息。 |
chips_access_statistic.csv | 非 Release 构建才生成:各 Chip 读写成功/失败计数与耗时。 |
4.2 关键日志信息
| 日志片段 | 日志级别 | 含义解读 | 建议处理动作 |
|---|---|---|---|
hwproxy load patches successfully | NOTICE | 热补丁加载成功。 | 无。 |
Not support object, class name | ERROR | object_defs 无该 class_name。 | 检查 CSR 类型名与 hwproxy 版本。 |
Not support chip model | ERROR | Ina 等 ChipModel 不在支持列表。 | 仅使用 Ina238 / Ina226 / Ina220。 |
the %s queue len of %s is over limit | ERROR | Chip 请求队列超上限。 | 降频访问或增大 CHIP_REQUEST_QUEUE_MAX_LEN(不超过 1000)。 |
the chip %s access has been closed | ERROR | 访问被 SetAccessibility 或重启流程关闭。 | 等待恢复或手动重新打开。 |
chip: ... times out / The request is timeout. | ERROR/DEBUG | 等待硬件完成超时。 | 查总线挂死、Mux 通道、Timeout 上下文。 |
Unable to find chip in the topology link. | DEBUG | Chip 不在当前 work 拓扑中。 | 等 AddObjectComplete,或核对 Position/总线。 |
topology dump success / snapshot dump success | NOTICE | Dump 完成。 | 到收集目录查看对应文件。 |
set hwproxy service health status need to restart | NOTICE | work 异常,健康状态为需立即重启。 | 查 monitor 与对应 bus_name。 |
The bus (%s) access has been opened | NOTICE | 总线访问已重新使能。 | 无。 |
总线超时日志在 hw_utils.hw_log 中按约 1 分钟限流,避免刷屏。
5. 问题定界指南
5.1 典型问题定界
| 问题描述 | 是否为本组件问题 | 判断依据 | 关键证据收集方法 |
|---|---|---|---|
busctl tree bmc.kepler.hwproxy 无服务 | 可能是 | 进程未起或会话总线未就绪。 | systemctl status hwproxy;查 mdb_mgmt / persistence 依赖。 |
| 启动后立刻 Read/Write 失败,稍后成功 | 通常是时序 | 拓扑未 AddObjectComplete。 | 启动日志;业务侧加重试。 |
| 接口不存在 / 找不到服务 | 可能是调用方依赖 | 未声明弱依赖或对象未上树。 | busctl introspect 目标路径;核对 CSR 与 service.json。 |
Scanner Value 与硬件不符 | 可能是 | 读的是缓存;或防抖/聚合未就绪。 | 对照 snapshot.csv 的 Status/Scan_status;用 Accessor 或 BlockIO 实时读。 |
| Accessor 写入无效 | 可能是 | Type/Mask/WriteOffset 配置错误,或器件不支持位写。 | 先 busctl set-property Accessor,再 BlockIO/BitIO 对照。 |
PluginRequest 失败 | 可能是 | 插件未安装或 Cmd 未知。 | 日志中的 unknown plugin cmd 或 module not found。 |
| 总线读写偶发失败 | 可能是 | Mux 通道被扫描任务切走。 | 连续 busctl;或改用 Chip 接口让 hwproxy 切通道。 |
| 管理站/业务超时但硬件有响应 | 可能是 | 默认 120 秒内队列过长或驱动阻塞。 | 查队列超限日志、chips_access_statistic.csv。 |
5.2 错误码速查表
hwproxy 的 Lua API 通过 D-Bus 错误对象返回,不使用 IPMI 完成码作为业务接口(mds/errors.json 中的 ipmi_response 字段为框架映射,值为 0xFF)。
| 错误名 | 含义 | 可能原因 | 排查建议 |
|---|---|---|---|
kepler.hwproxy.RequestTimeout | 请求超时 | 硬件无响应、总线挂死、Timeout 过短。 | 查 times out 日志;Dump 拓扑;MockBusCtrl 是否误 suspend。 |
kepler.hwproxy.IOError | 输入输出错误 | 驱动/总线读写失败。 | 结合 runtime_accessor / libsoc_adapter 与硬件在位。 |
kepler.hwproxy.ChipNotExistError | 拓扑中找不到 Chip | 对象已删、Position 不匹配、work 未创建。 | topology.txt;等自发现完成。 |
kepler.hwproxy.Unknown | 未知错误 | 未分类失败。 | 保存完整错误与前后日志。 |
ChipRequestLimitExceeded | 队列达到上限 | 突发请求过多。 | 等待重试;检查是否有死循环访问 Accessor。 |
SetLockStatus 返回 1~5 | 加解锁未成功 | 参数、请求者或通道不匹配。 | 按 2.7 节枚举核对 OpType/LockTime/调用方。 |
5.3 最小化复现与证据收集
- 记录 Chip/Accessor 路径、Offset、Length、Mask、Type 和返回错误名。
busctl --user introspect确认接口已注册。- 执行一键收集,保存
topology.txt、snapshot.csv和/var/log/framework/hwproxy.log。 - 对实时访问问题,用 TraceChip 抓一次成功/失败对照。
- 复现步骤应包含是否在
AddObjectComplete之后调用。
5.4 调试方法
busctl --user tree bmc.kepler.hwproxy
busctl --user introspect bmc.kepler.hwproxy /bmc/kepler/Chip/Smc/Smc_CpuBrdSMC_010101- 单元测试:
test/unit/test.lua。 - 集成测试:
test/integration/test_hwproxy.lua。 - 不要为排障在生产环境长期开启 TraceChip 或 Mock 挂死总线。
5.5 错误对象解读
资源协作方法失败时抛结构化错误,name 为 kepler.hwproxy.* 或 ChipRequestLimitExceeded。SetLockStatus 用整型 ResultCode 表示结果,成功为 0。Scanner/Accessor 的 Status 不是 D-Bus 错误,而是对象属性。
6. 常见问题解答
Q1:组件刚启动就读写硬件失败?
- 问题描述:对象已在资源树上,但 BlockIO / Accessor 立刻失败,稍后又成功。
- 一句话答案:hwproxy 要等整份 SR 分发完成并建立拓扑后才能访问。
- 根因说明:
AddObject之后、AddObjectComplete之前存在窗口期。 - 解决方案:业务启动访问增加重试;确认 hwdiscovery 与 hwproxy 均已完成对象上树。
- 规避方案:在依赖 Chip 的组件中等待对象就绪信号后再访问。
- 适用版本:1.130.22。
Q2:Scanner 需要写入怎么办?
- 问题描述:Scanner 的
Value只读,无法下发配置。 - 一句话答案:再定义一个相同 Offset/Size/Type 的 Accessor 用于写入。
- 根因说明:Scanner 只服务周期扫描;写路径由 Accessor 的
property_before_change触发。 - 解决方案:CSR 增加 Accessor,业务写引用属性。
- 规避方案:不要对 Scanner 做 set-property。
- 适用版本:1.130.22。
Q3:报错找不到服务或 interface 不存在?
- 问题描述:Lua 代理或
busctl提示无接口。 - 一句话答案:检查弱依赖、生成 client,以及目标对象是否已上树。
- 根因说明:未在
service.json声明 Accessor/Scanner/Chip 依赖时不会生成代理;CSR 未加载则路径不存在。 - 解决方案:声明依赖并
bingo gen;用busctl tree确认路径。 - 规避方案:通过正式构建安装 hwproxy,不要只拷贝单个 Lua 文件。
- 适用版本:1.130.22。
Q4:PluginRequest 报 unknown plugin cmd 或模块找不到?
- 问题描述:插件调用失败。
- 一句话答案:确认插件已安装到
hwproxy.plugins.<name>,且has_cmd包含该 Cmd。 - 根因说明:work 服务按模块名动态
require,命令名必须与插件实现一致。 - 解决方案:检查
/opt/bmc/lualib/hwproxy/plugins/与has_cmd;Params 使用skynet.pack。 - 规避方案:先在 IT/隔离环境用最小插件验证加载路径。
- 适用版本:1.130.22。
Q5:引用/同步的属性与预期不符?
- 问题描述:业务对象上的同步值不是硬件真实值。
- 一句话答案:先在 hwproxy 树上直接操作 Accessor/Scanner,再查同步配置。
- 根因说明:失败可能在 hwproxy 访问,也可能在启动时同步/引用配置错误。
- 解决方案:
busctl读写 hwproxy 对象;查看启动日志中的同步/引用错误;核对snapshot.csv。 - 规避方案:改 CSR 后做一次 Dump,确认拓扑与 Scanner 状态。
- 适用版本:1.130.22。