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),deployConfigframework.service。systemd 单元 hwproxy.servicemdb_mgmt.service 之后启动,依赖 mdb_mgmt.servicepersistence.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>TraceChipTraceDebounce、一键 Dump 和 Debug Mock 用于跟踪读写与复现故障。

1.4 关键术语表

术语解释
hwproxy硬件代理服务,D-Bus 服务名 bmc.kepler.hwproxy
CSR / SRComponent 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 驱动库。
SMCServer Management Channel;Smc 器件的 Offset 为命令字。

1.5 外部交互边界图

构建测试依赖见 mds/service.jsonhwdiscoverylibmc4luamdb_interfacemacapersistencedtframeforluaruntime_accessorlibmgmt_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 / TraceDebounceDiagnoseMgmt;FlashIO 方法为 BasicSetting)。

bash
# 查看资源协作接口
busctl --user tree bmc.kepler.hwproxy

仓库无 mds/ipmi.json,以下接口均不能通过 ipmitool 调用。

不同 Chip 类注册的方法不同,以 src/lualib/object_defs.lua 为准:

class_name路径前缀BlockIOBitIO其他方法
Eeprom / Rtc / Cpld/bmc/kepler/Chip/<Class>/:IdCpld 另有 JtagTarget
Smc / Pca9555 / Lm75 / Vrd / CpldChip / Ina / CanbusChipmds/model.jsonIna 另有 PowerMeter 属性
Chip(Complex)/bmc/kepler/Chip/Complex/:IdWriteRead、ComboWriteRead、WriteReadByProtocol
SPIFlash/bmc/kepler/Chip/SPIFlash/:IdFlashIO
Pca9545 / Pca9544 / Ads78 / CpldRegister/bmc/kepler/Chip/<Class>/:IdTraceChip

上表中 “BlockIO 是” 同时注册 Read / Write / BatchWrite / PluginRequest / PluginRequestEx。WriteReadChipCanbusChipComboWriteReadWriteReadByProtocolChip

2.1 bmc.kepler.Chip.BlockIO

功能说明

按字节对 Chip 做块读、块写、先写后读、批量写和插件访问。接口定义见 mdb_interfacejson/intf/mdb/bmc/kepler/Chip/BlockIO.json

路径/bmc/kepler/Chip/<ClassName>/<Id>,例如 /bmc/kepler/Chip/Eeprom/Eeprom_BCU_010101

参数说明

方法入参(不含上下文)出参D-Bus 签名(含 a{ss}说明
ReadOffset uLength uOutData aya{ss}uuay从偏移读取指定长度。
WriteOffset uInData aya{ss}uay向偏移写入。
WriteReadInData ayReadLength uOutData aya{ss}ayuay扩展读:写入请求后再读;内部偏移为 0xFFFFFFFF。仅部分 Chip 类注册。
ComboWriteReadWriteOffset uInData ayReadOffset uReadLength uOutData aya{ss}uayuuay先写后读,合并为一次原子操作。仅 Chip
BatchWriteWriteData a(uay)a{ss}a(uay)多帧偏移+数据一次写入。
PluginRequestPluginName sCmd sParams ayOutData aya{ss}ssayay加载并执行插件,见 2.9。
PluginRequestEx同上,另加 ControlParams a{ss}OutData aya{ss}ssaya{ss}ay扩展插件请求;Priority 可为 HighSecondary
WriteReadByProtocolInData ayReadLength uProtocol yOutData aya{ss}ayuyay指定协议写读。当前仅支持 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(不设定时器)。

调试示例

bash
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
lua
-- 组件 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 签名说明
ReadOffset uLength yMask uOutData aya{ss}uyuay读取后与掩码按位与。
WriteOffset uLength yMask uInData aya{ss}uyuay先读再按掩码改写。

返回值与异常

与 BlockIO 相同:成功返回数据或无返回值;失败抛 5.2 节错误。器件驱动不支持位操作时,行为由 runtime_accessor 对应 class_name 决定。

应用场景

读取或修改寄存器中的若干 bit,例如 SMC 状态位。

限制条件

object_defs.luasupport_bit_io = true 的类注册该方法。块读场景 Mask 无效,可置 0。

调试示例

bash
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 0x02

2.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

参数说明

方法入参出参说明
ReadOffset uLength uOutData ay与 BlockIO Read 相同。
WriteOffset uInData ay与 BlockIO Write 相同。
EraseOffset uType y0 扇区、1 32K 块、2 64K 块、3 芯片擦除。
RawReadLength uInData ayOutData ay自定义读帧(含命令字)。
RawWriteInData ay自定义写帧(含命令字)。

权限均为 BasicSetting。CSR 还需配置 ChipSelectBytesPerPage(默认 256)、CommandSet

返回值与异常

与 BlockIO 相同。擦除类型必须为 0~3。

应用场景

固件分区擦除、按页编程,或按器件手册下发非标准 SPI 帧。

限制条件

仅 SPIFlash 对象。Raw* 要求调用方自行组命令字与负载,错误帧会导致总线 IO 失败。

调试示例

bash
busctl --user introspect bmc.kepler.hwproxy \
    /bmc/kepler/Chip/SPIFlash/SPIFlash_1_0101

2.4 bmc.kepler.Chip.JtagTarget

功能说明

Cpld 的 JTAG 目标操作:读取链上 IDCODE、Bypass 模式升级、采集与自检。方法在 hwproxy_app.lua 中注册为 ImplCpldJtagTarget*。完整方法表以 mdb_interfacejson/intf/mdb/bmc/kepler/Chip/JtagTarget.json 为准(mds/model.json 的 Cpld 段仅列出 Upgrade / Collect / Verify)。

路径/bmc/kepler/Chip/Cpld/:Id

参数说明

方法入参出参说明
GetChipIdcode无(仅上下文)DeviceId auJTAG 链上器件 IDCODE。
SetTargetNumberNum uBypass 模式下选择待升级器件。
SetBypassModeEnable b是否使用 Bypass 升级。
BypassChannelTestId yChannel yResultCode bJTAG 链路测试。
UpgradeFilePath sFileType yFileType0 VME,1 SVF。
CollectFilePath sFileType yOutputFilePath s采集寄存器到文件。
VerifyFilePath sFileType 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 一致)。

调试示例

bash
busctl --user call bmc.kepler.hwproxy \
    /bmc/kepler/Chip/Cpld/Cpld_1_0101 \
    bmc.kepler.Chip.JtagTarget GetChipIdcode a{ss} 0

2.5 bmc.kepler.Accessor / bmc.kepler.Scanner

功能说明

Accessor 在业务读/写 Value 时实时访问硬件;Scanner 由 hwproxy 按 Period(毫秒)扫描,业务读 Value 不会再次访问硬件。接口定义见 json/intf/mdb/bmc/kepler/Accessor.jsonScanner.json

路径

  • Accessor:/bmc/kepler/Accessor/:Id
  • Scanner:/bmc/kepler/Scanner/:Id

参数说明

接口属性
对象属性类型读写说明
AccessorValuet(U64)可读写读触发硬件读,写触发硬件写。
AccessorStatusy只读0 正常,1 失败,2 预失败(防抖中),3 无效,4 初始。
AccessorPrintableValues只读块读成功后的可打印 ASCII;含不可见字符时不更新;不能用于写硬件。
ScannerValuet只读扫描缓存值。
ScannerStatusy只读含义与 Accessor 相同;4 表示尚未开始扫描。

CSR 配置字段(mds/model.json,不全部出现在 D-Bus 接口上):

字段对象说明
Chip二者关联器件,如 "#/Smc_2"
Offset / Size / Mask / Type二者偏移、长度(Byte)、掩码、0 位访问 / 1 块访问。Accessor Size 最大 64。
WriteOffsetAccessor写偏移;默认 42949672950xFFFFFFFF)表示与读偏移相同。
PeriodScanner扫描周期,单位 ms。
ScanEnabledScanner0 禁用,1 使能。禁用后可使用 NominalValue
DebounceScanner防抖对象名:None / MidAvg / Median / Cont / ContBin
FailureDebounceCount / SuccessDebounceCount二者默认 10。

Scanner 另有 bmc.kepler.Scanner.AggregateAggregateOffsetAggregateStatus)以及 bmc.kepler.Release.Scanner.TraceDebounceActionstart / 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 不能依赖成环。

调试示例

bash
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 Value
lua
local lock = FruCtrl.PwrButtonLock   -- 引用 Accessor.Value,每次读取都会访问硬件
FruCtrl.PwrButtonLock = 1            -- 写入硬件

CSR 示例(Scanner,支持 // 注释的 CSR 语法):

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.jsonBus/BlockIO.json

路径/bmc/kepler/Bus/I2c/:Id,例如 /bmc/kepler/Bus/I2c/I2c_7

参数说明

属性/方法类型读写说明
AccessEnabledb只读链路是否允许访问。
Timeoutq只读命令超时,单位秒。
SetAccessibilityStatus bDisableDuration q方法Status=false 时禁止访问,DisableDuration 范围 1~1800 秒,到期自动恢复。
BlockIO 方法入参出参D-Bus 签名说明
ReadSlaveAddress yReadLength uOutData aya{ss}yuay按从地址读。
WriteSlaveAddress yInData aya{ss}yay按从地址写;InData 前若干字节通常为器件偏移。
WriteReadSlaveAddress yInData ayReadLength yOutData aya{ss}yayyay先写后读。

返回值与异常

与 Chip 访问相同。禁止访问期间对总线上 Chip 的请求会失败。

应用场景

类似 i2ctool 的调试读写;需要先切 PCA9545 通道时,连续下发 Write 与 WriteRead,避免被 Scanner 打断通道。

限制条件

  • 当前仅 I2c 注册 Bus.BlockIO。
  • 经过 Mux 的器件必须自行发切通道命令,且两条命令之间不能插入扫描任务。
  • mdbctl 不支持一行多条命令时,请用 busctl 连续发送。

调试示例

bash
# 切 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 10

2.7 bmc.kepler.Chip 器件状态与访问控制

功能说明

各 Chip 对象均带 bmc.kepler.Chip 接口:健康/上电/自检/锁定状态,以及禁止访问、锁定通道。接口定义见 json/intf/mdb/bmc/kepler/Chip.json

路径:与具体 Chip 相同。

参数说明

属性类型读写说明
HealthStatusy可写0 访问正常,1 访问失败。
HealthStatusValidityb只读HealthStatus 是否有效。
PowerStatusy只读上电状态。
SelfTestResulty只读自检结果。
LockStatusy只读0 未锁定,1 已锁定。
ChipTypes只读器件类型字符串;Complex Chip 由 CSR 配置。
方法入参出参说明
SetAccessibilityStatus bDisableDuration qfalse 禁止该 Chip 访问;时长 1~1800 秒,到期自动恢复。实现会同时启停该 Chip 上的 Scanner。
SetLockStatusOpType yLockTime uResultCode yOpType0 解锁,1 加锁。LockTime 仅加锁时有效,上限 30 分钟。

SetLockStatusResultCode0 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 不匹配。续锁要求请求者一致。

调试示例

bash
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 60

2.8 bmc.kepler.Release.TraceChip

功能说明

跟踪指定 Chip 的实时读写,结果通过 mdbctl/调试日志输出(十六进制,超过 1024 字节截断)。权限 DiagnoseMgmt

路径:带 bmc.kepler.Release.TraceChip 的 Chip 对象。

参数说明

方法入参说明
TraceChipAction sstart / stop开始或停止跟踪。

返回值与异常

非法 Action 由参数校验拒绝。跟踪开启后,读写日志含 requestor、bit/block、addr、offset、数据。

应用场景

对照总线波形或业务请求,确认 hwproxy 实际下发的偏移与数据。

限制条件

support_trace = true 的 Chip 类注册。生产环境用完应 stop

调试示例

bash
busctl --user call bmc.kepler.hwproxy \
    /bmc/kepler/Chip/Eeprom/Eeprom_BCU_010101 \
    bmc.kepler.Release.TraceChip TraceChip a{ss}s 0 start

2.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 仓库本身不内置业务插件命令。

参数说明

参数类型说明
PluginNamestringrequire('hwproxy.plugins.' .. name) 模块名一致。
Cmdstring插件已实现的命令名。
Paramsayskynet.pack / skynet.packstring 序列化的参数;空数组表示无额外参数。
ControlParams.Prioritystring仅 Ex:HighSecondary

返回的 OutData 需用 skynet.unpack 还原。

返回值与异常

未知命令抛 unknown plugin cmd <name>.<cmd>。模块不存在时 require 失败。硬件失败按 Chip 错误返回。

应用场景

SMBus mailbox、厂商私有帧等无法用通用 BlockIO 表达的访问。

限制条件

插件必须提供 has_cmd / run_cmd。执行期间独占通道,长时间阻塞会拖慢同 Chip 上的 Scanner 与其他请求。

调试示例

lua
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

参数说明

方法入参说明
MockScannerFailureScannerName sFailureDuration u(1~1800 秒)模拟指定 Scanner 故障。
MockBusCtrlBusName sAction ssuspend / resume模拟总线挂死或恢复。

返回值与异常

Scanner 不在拓扑中时抛 ChipNotExistErrorFailureDuration 越界由模型校验拒绝。

应用场景

集成测试与故障注入,不要在生产业务路径调用。

限制条件

仅调试/测试构建使用。suspend 后须 resume,否则该总线访问会一直失败。

调试示例

bash
busctl --user introspect bmc.kepler.hwproxy /bmc/kepler/Debug/Mock

2.11 其他已建模对象

以下对象由 CSR 上树,本文不展开未在源码中单独实现为对外方法的细节:

对象路径说明
I2cMux/bmc/kepler/Mux/I2cMux/:IdMux 通道,CSR ChannelId
Ina/bmc/kepler/Chip/PowerMeter/Ina/:Id功率计;ChipModelIna238 / Ina226 / Ina220
Chip.AggregateComplex ChipCSR:SupportedBaseOffsetLengthPeriod
Dft*/bmc/kepler/Manufacture/SelfTest/...制造自检;main.lua 在存在 hwproxy_manufacture_app 时加载。
SmcDfxInfoCSR 引用 SmcDump 时写入 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.jsonobject_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.luaplugin_request调用 PluginRequest 时。
驱动/Stream/Muxruntime_accessor 的 driver / stream / mux构造 Chip / Bus 时按 class_name 选择。
Dumpsrc/lualib/log_dump.luaMicroComponent on_dump

3.3 二次开发指导

3.3.1 业务侧增加 Scanner / Accessor

  1. 在机型 CSR 中增加 Scanner_*Accessor_*,填写 ChipOffsetSizeType 等。
  2. 在使用方组件的属性上用同步 <=/Scanner_x.Value 或引用 #/Accessor_x.Value
  3. 在使用方 mds/service.json 声明弱依赖,bingo genrequire client。
  4. busctl 先直接读写 hwproxy 树上的 Accessor/Scanner,再查业务属性。

3.3.2 新增插件

插件模块需能被 require('hwproxy.plugins.<PluginName>'),并提供:

lua
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 类

  1. mds/model.json 增加类、path 和接口列表。
  2. object_defs.lua 设置 type = 'Chip'support_block_io 等开关。
  3. 在 runtime_accessor 注册同名 driver。
  4. 同步更新本文第 2 章能力表与示例。

验证:bingo gen 后跑 test/unit/test.luatest/integration/test_hwproxy.lua 中相关用例。


4. 日志说明

4.1 一键日志收集

模块名在 src/service/main.lua / work.lua / monitor.lua 中设为 hwproxy。默认日志文件 /var/log/framework/hwproxy.logdist/config.cfglogger)。

通过 mc.mdb.micro_component.debug.on_dump 注册 log_dump.on_dump。一键收集时在 Dump 目录生成:

文件内容
topology.txt各总线 Chip 拓扑及 Chip 别名(合并对象名 → 主对象名)。
snapshot.csvAccessor/Scanner 的周期、状态、成功/失败计数、Value。
smc_dfx_info.txt聚合 / SMC DFX 信息。
chips_access_statistic.csv非 Release 构建才生成:各 Chip 读写成功/失败计数与耗时。

4.2 关键日志信息

日志片段日志级别含义解读建议处理动作
hwproxy load patches successfullyNOTICE热补丁加载成功。无。
Not support object, class nameERRORobject_defs 无该 class_name检查 CSR 类型名与 hwproxy 版本。
Not support chip modelERRORIna 等 ChipModel 不在支持列表。仅使用 Ina238 / Ina226 / Ina220
the %s queue len of %s is over limitERRORChip 请求队列超上限。降频访问或增大 CHIP_REQUEST_QUEUE_MAX_LEN(不超过 1000)。
the chip %s access has been closedERROR访问被 SetAccessibility 或重启流程关闭。等待恢复或手动重新打开。
chip: ... times out / The request is timeout.ERROR/DEBUG等待硬件完成超时。查总线挂死、Mux 通道、Timeout 上下文。
Unable to find chip in the topology link.DEBUGChip 不在当前 work 拓扑中。AddObjectComplete,或核对 Position/总线。
topology dump success / snapshot dump successNOTICEDump 完成。到收集目录查看对应文件。
set hwproxy service health status need to restartNOTICEwork 异常,健康状态为需立即重启。查 monitor 与对应 bus_name
The bus (%s) access has been openedNOTICE总线访问已重新使能。无。

总线超时日志在 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 cmdmodule 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 最小化复现与证据收集

  1. 记录 Chip/Accessor 路径、Offset、Length、Mask、Type 和返回错误名。
  2. busctl --user introspect 确认接口已注册。
  3. 执行一键收集,保存 topology.txtsnapshot.csv/var/log/framework/hwproxy.log
  4. 对实时访问问题,用 TraceChip 抓一次成功/失败对照。
  5. 复现步骤应包含是否在 AddObjectComplete 之后调用。

5.4 调试方法

bash
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 错误对象解读

资源协作方法失败时抛结构化错误,namekepler.hwproxy.*ChipRequestLimitExceededSetLockStatus 用整型 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:PluginRequestunknown 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。