libsoc_adapter

版本信息

项目内容
组件版本1.130.70
首发版本openUBMC 26.09
文档作者openUBMC 社区
最后更新2026-09-15
许可证Mulan PSL v2

1. 组件概述

1.1 组件简介

libsoc_adapter 是 openUBMC 的 BMC SOC 芯片适配库,属于用户态驱动层。它将 BMC SOC 各控制器的内核态 ioctl 接口封装为统一的用户态 API,并通过 BCAL(源码头文件注释为 Board Control Abstraction Layer)纯虚接口对上层微组件屏蔽芯片差异。

组件类型为 library(见 mds/service.json),不启动独立服务进程,也不注册 D-Bus / MDB 资源协作接口(required 为空,仓库中没有 model.jsonipmi.json)。运行时代码位于调用方进程内。

编译产物主要包括:

  • libbcal.so:驱动工厂与 BCAL 公共框架,安装到 /usr/lib64
  • libsoc_adapter.so:Lua 绑定集合(CMake 目标名为 libsoc_adapterPREFIX 为空),安装到 /usr/lib64
  • libsoc_adapter_c.so:部分 C 封装(如 TRNG / MCTP / USB C wrapper),安装到 /usr/lib64
  • lib{driver}.so:各 BCAL 驱动实现,安装到 /opt/bmc/bcal(例如 libi2c.solibgpio.solibuart.so)。
  • Mock 库:安装到 /usr/lib64/mock,用于无硬件测试。
  • 可选内核模块:bmc_hisport_drv.ko;在 chipv2_enable=true 时还会构建 bmc_i2c_over_localbus_drv.kobmc_i3c_over_localbus_drv.kobmc_uart_over_localbus_drv.ko,安装到 lib/modules/ko

Lua 业务通过 require 'libsoc_adapter.{driver}' 加载对应绑定,导出符号为 luaopen_libsoc_adapter_{driver}

1.2 解决什么问题

上层微组件(如 runtime_accessorhwproxybmc_soc)需要访问 I2C、GPIO、UART、eMMC、PECI 等片上控制器,但不同芯片代际的设备节点、ioctl 和能力集合不同。若业务直接调用内核接口,会把芯片差异扩散到各组件。

libsoc_adapter 通过以下方式隔离差异:

  • bcal::IDriver / bcal::IDriverFactory 统一驱动生命周期和加载路径。
  • 为每种控制器提供 BCAL 纯虚接口,厂商实现(*Extend)负责实际 ioctl。
  • 通过 vendor/huawei/v1/vendor/huawei/v2/ 以及 CMake 选项 chipv2_enable(对应 CONAN_DEFS_CHIPV2_ENABLE)选择芯片实现。
  • 为驱动提供 Lua 绑定,供 Lua 微组件在进程内访问硬件。
  • 提供 Mock 实现,支持无真实硬件的 UT/IT。

1.3 核心功能

  • 驱动工厂:按名称加载 /opt/bmc/bcal/lib{driver_name}.so,按 driver_name + index 管理实例引用计数。
  • BCAL 标准控制器接口:I2C、GPIO、UART / UART 互连、ADC、PWM、SPI、JTAG、Localbus、MDIO、MMC、PECI、MCTP、IPMB、BT、KCS、CANBUS、EDMA、EFUSE、SOL、TRNG、USB DRD、USB 复合设备、WDT、MEM。
  • Lua 绑定:BCAL 驱动绑定位于 src/luawrapper/;芯片相关 HAL(如 sys_infohissboot_loader、Hisport)绑定位于 vendor/huawei/v1/vendor/huawei/v2/
  • HAL 能力:hal::SysInfo(核温、复位原因、DDR 自检等)、hal::Hiss(安全模块 / TPCM / 安全启动)、hal::BootLoader(PCIe 控制器与 BAR 相关环境变量)。
  • Hisport:仓库自行实现的内核模块与用户态访问路径,提供初始化、读、写。
  • Mock:vendor/huawei/mock/ 下为各驱动提供无硬件实现。

1.4 关键术语表

术语解释
BCALBoard Control Abstraction Layer。include/bcal/ 中的纯虚驱动接口层。
IDriver所有 BCAL 驱动的公共基类,提供 init / lock / unlock / control 等生命周期接口。
IDriverFactory驱动工厂单例,动态加载 lib{driver_name}.so 并缓存实例。
index同一驱动的设备实例编号,例如 GPIO 的引脚号、UART 的端口号、I2C 的总线号。
*Extend继承 BCAL 接口的厂商实现类,位于 include/bcal_extend/vendor/huawei/
v1 / v2两代芯片实现目录;由构建选项 chipv2_enable 选择。
luawrap仓库内 C++ 到 Lua 的绑定框架,位于 include/luawrapper/
HAL未完全纳入 BCAL 工厂模型、直接封装 /dev/* 的用户态类,例如 hal::SysInfohal::Hiss
Hisport本仓库提供的内核驱动与用户态接口,用于特定片内高速通道。

1.5 外部交互边界图

构建依赖见 mds/service.jsonhuawei_secure_cskynetlibsomp;测试依赖 test_data。组件自身没有常驻进程、监听端口或资源协作接口。

2. API 使用说明与示例

本章 C++ 接口以 include/bcal/*.h 为准。仓库内 docs/v1/*.mddocs/v2/*.md 是各驱动的芯片 ioctl 规格,部分签名仍带 config() / index 参数,与当前 BCAL 头文件不一致时,以头文件为准。

本组件没有资源协作接口,不能通过 busctl 调用。

2.1 驱动工厂 bcal::IDriverFactory

功能说明

IDriverFactory 是全局单例,负责在指定目录加载 lib{driver_name}.so,并通过导出符号 create_driver / destroy_driver 创建、销毁驱动实例。同一 driver_name 的多个 index 共享动态库句柄,但各自持有独立实例。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

头文件:#include "bcal/driver.h"

cpp
bcal::IDriverFactory& factory = bcal::IDriverFactory::get_instance();
factory.set_driver_path("/opt/bmc/bcal");
bcal::IDriver* driver = factory.get_driver("gpio", 192);

参数说明

方法名方向类型描述取值范围
get_instance输出IDriverFactory&返回工厂单例。静态方法。
set_driver_path输入const string_t&设置 .so 搜索目录,默认 /opt/bmc/bcal可读目录。
get_driver输入driver_name, index加载并返回实例;已存在则增加引用计数。driver_name 不含 lib 前缀和 .so 后缀,例如 "i2c" 对应 libi2c.so
get_driver_list输出std::vector<string_t>扫描目录中合法的 lib*.so 名称(排除 libbcal.so)。目录不存在时返回空列表。
get_driver_load_info输出std::vector<driver_load_info>返回已尝试加载的驱动名、成功标志和 error_msg仅包含曾经调用过加载路径的项。
release_driver输入IDriver*引用计数减 1,减到 0 时销毁实例;动态库引用减到 0 时 dlclose必须是本工厂返回的指针。
destroy_driver输入IDriver*立即从工厂摘除该实例并按引用释放动态库。空指针直接返回。

driver_load_info 字段:driver_namesuccesserror_msg

返回值与异常

返回值含义触发条件处理建议
非空 IDriver*获取实例成功dlopen 成功且 create_driver 返回非空。使用完毕调用 release_driver
nullptr加载或创建失败.so 不存在、缺少 create_driver/destroy_driver,或 create_driver 返回空。调用 get_driver_load_info() 查看 error_msg
get_driver_list未扫描到驱动路径不是目录,或目录遍历抛出 filesystem_error检查 /opt/bmc/bcal 是否已安装驱动 .so

工厂实现本身不抛出异常;失败通过空指针和 error_msg 表达。error_msg 典型值:

  • Failed to load library: ...dlopen 失败,后接 dlerror()
  • Failed to find both create_driver and destroy_driver symbol

应用场景

  • C++ 组件按名称获取 GPIO / I2C / UART 等驱动实例。
  • Lua 绑定内部通过工厂取驱动,再转成具体 BCAL 类型。
  • 测试时将路径指到 Mock 库目录,替换真实驱动。

限制条件

  • 默认路径为 /opt/bmc/bcal,需在首次 get_driver 前按需调用 set_driver_path
  • get_driver_list 不把 libbcal.so 当作驱动。
  • release_driver / destroy_driver 传入非本工厂指针时会被忽略。
  • 同一 driver_name 的多个 index 共享 .so 句柄;最后一个引用释放后才会卸载动态库。

调试示例

cpp
#include "bcal/driver.h"
#include "bcal/gpio.h"

bcal::IDriverFactory& factory = bcal::IDriverFactory::get_instance();
bcal::IDriver* raw = factory.get_driver("gpio", 0);
if (raw == nullptr) {
    auto infos = factory.get_driver_load_info();
    // 根据 infos[].error_msg 定位 dlopen / 符号问题
    return;
}
auto* gpio = static_cast<BCAL_DRIVER_GPIO::Gpio*>(raw);
factory.release_driver(raw);

2.2 bcal::IDriver 公共接口

功能说明

所有 BCAL 驱动必须实现 IDriver。每个实例对应一个硬件对象,由 index 区分(例如一个 Gpio 实例对应一根 GPIO 引脚)。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

方法名入参出参 / 返回值描述
initvoid* args, uint32_t sizevoid初始化。args 一般为各驱动配置结构体指针,size 为该结构体字节数。
lock / unlockvoid对当前实例加锁 / 解锁,保护多线程下的硬件独占访问,不用于保护实现内部状态。
get_versionstring_t驱动版本字符串。
get_driver_namestring_t驱动名,对应 lib{name}.so
controluint32_t cmd, void* args_in, void* args_outint32_t扩展控制口。0 成功,-1 失败。头文件标明仅用于不变更 BCAL 版本时由业务与驱动实现自行协商的命令。

返回值与异常

init / lock / unlock 无返回值;具体实现可能抛出 std::runtime_error(例如设备节点打开失败)。control 约定 0 / -1

应用场景

所有 BCAL 读写操作之前需要 init;多线程访问同一实例时应成对调用 lock / unlock

限制条件

  • 当前 IDriver 没有 config() 方法;配置通过 init(args, size) 传入。
  • controlcmd 与参数结构由各驱动头文件定义,不能跨驱动混用。

调试示例

见 2.5 GPIO:GpioConfig 通过 init 传入方向。

2.3 BCAL 驱动接口概览

以下类均继承 bcal::IDriver。命名空间、头文件和关键方法来自 include/bcal/

驱动头文件命名空间关键方法
ADCbcal/adc.hBCAL_DRIVER_ADCAdcread(chan_id),返回 mV
BTbcal/bt.hBCAL_DRIVER_BTBtread / write / setatn
CANBUSbcal/canbus.hBCAL_DRIVER_CANBUSCanbusread / write / set_speed / set_filter / reset
EDMAbcal/edma.hBCAL_DRIVER_EDMAEdmapoll / read / write
EFUSEbcal/efuse.hBCAL_DRIVER_EFUSEEfuseget_domain_cnt / read / write
GPIObcal/gpio.hBCAL_DRIVER_GPIOGpioread / write / set_interrupt / get_interrupt
I2Cbcal/i2c.hBCAL_DRIVER_I2CI2cread / write / slave_cache_read / slave_cache_write / reset
IPMBbcal/ipmb.hBCAL_DRIVER_IPMBIpmbread / write / reset / set_addr / check_readable / set_enable
JTAGbcal/jtag.hBCAL_DRIVER_JTAGJtagwrite / set_target_num / set_bypass_mode / get_cpld_idcode / reset
KCSbcal/kcs.hBCAL_DRIVER_KCSKcsread / write / setatn
Localbusbcal/localbus.hBCAL_DRIVER_LOCALBUSLocalbusread / write / set_timing / set_bitwidth_and_offset
MCTPbcal/mctp.hBCAL_DRIVER_MCTPMctpwrite / read / reset
MDIObcal/mdio.hBCAL_DRIVER_MDIOMdioread / write
MEMbcal/mem.hBCAL_DRIVER_MEMMemimport
MMCbcal/mmc.hBCAL_DRIVER_MMCMmcread_reg / get_health_report / get_write_stat / read / write / set_write_protect
PECIbcal/peci.hBCAL_DRIVER_PECIPecireset / read
PWMbcal/pwm.hBCAL_DRIVER_PWMPwmread / write / rst_hold
SOLbcal/sol.hBCAL_DRIVER_SOLSolenable / read / get_pos / get_length / set_log_size
SPIbcal/spi.hBCAL_DRIVER_SPISpiread / write
TRNGbcal/trng.hBCAL_DRIVER_TRNGTrngreset / read
UARTbcal/uart.hBCAL_DRIVER_UARTUartopen / close / read / select_read / write / set_baud_rate
UART 互连bcal/uart.hBCAL_DRIVER_UARTUartConnectuart_connect_uart / uart_connect_port / port_connect_port / query_*
USB DRDbcal/usb_drd.hBCAL_DRIVER_USB_DRDUsbDrdset_role / get_role
USB 复合bcal/usb_driver.hBCAL_DRIVER_USBUsbUsbMouse / UsbKeyboard / UsbCdrom / UsbFloppy / UsbFlashDrive / UsbLcdconnect / disconnect / is_connected 及各子类 write/read
WDTbcal/wdt.hBCAL_DRIVER_WDTWdtclear / set_feed_mode / enable_wdt / abnormal_reset / wait_abnormal_reset

未在上表展开的结构体、枚举和 control 命令字,请直接阅读对应头文件。仓库 docs/bcal_interface_doc.md 有更长的接口说明,但其中部分命名空间仍写作 DRIVER_*,与当前头文件中的 BCAL_DRIVER_* 不一致,以头文件为准。

2.4 Lua 模块加载约定

功能说明

libsoc_adapter.so 将多个 luaopen_libsoc_adapter_* 导出到同一共享库。Lua 使用点分模块名加载:

lua
local i2c = require 'libsoc_adapter.i2c'
local gpio = require 'libsoc_adapter.gpio'
local sys_info = require 'libsoc_adapter.sys_info'
属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

BCAL Lua 绑定(src/luawrapper/)导出的模块名与 luaopen 后缀如下。

require 模块luaopen_*对应 BCAL 驱动名
libsoc_adapter.adcluaopen_libsoc_adapter_adcadc
libsoc_adapter.btluaopen_libsoc_adapter_btbt
libsoc_adapter.canbusluaopen_libsoc_adapter_canbuscanbus
libsoc_adapter.edmaluaopen_libsoc_adapter_edmaedma
libsoc_adapter.efuseluaopen_libsoc_adapter_efuseefuse
libsoc_adapter.gpioluaopen_libsoc_adapter_gpiogpio
libsoc_adapter.i2cluaopen_libsoc_adapter_i2ci2c
libsoc_adapter.ipmbluaopen_libsoc_adapter_ipmbipmb
libsoc_adapter.jtagluaopen_libsoc_adapter_jtagjtag
libsoc_adapter.kcsluaopen_libsoc_adapter_kcskcs
libsoc_adapter.localbusluaopen_libsoc_adapter_localbuslocalbus
libsoc_adapter.mctpluaopen_libsoc_adapter_mctpmctp
libsoc_adapter.mdioluaopen_libsoc_adapter_mdiomdio
libsoc_adapter.memluaopen_libsoc_adapter_memmem
libsoc_adapter.mmcluaopen_libsoc_adapter_mmcmmc
libsoc_adapter.peciluaopen_libsoc_adapter_pecipeci
libsoc_adapter.pwmluaopen_libsoc_adapter_pwmpwm
libsoc_adapter.solluaopen_libsoc_adapter_solsol
libsoc_adapter.spiluaopen_libsoc_adapter_spispi
libsoc_adapter.trngluaopen_libsoc_adapter_trngtrng
libsoc_adapter.uartluaopen_libsoc_adapter_uartuart + uart_connect
libsoc_adapter.usb_drdluaopen_libsoc_adapter_usb_drdusb_drd
libsoc_adapter.wdtluaopen_libsoc_adapter_wdtwdt
libsoc_adapter.usb_driverluaopen_libsoc_adapter_usb_driverUSB 复合
libsoc_adapter.mouse / keyboard / cdrom / floppy / flash / lcd对应 luaopen_libsoc_adapter_*USB 子功能

芯片 HAL Lua 绑定(随 v1/v2 编入同一 libsoc_adapter.so)还包括 sys_infohissboot_loaderscm3hisportinnerbuscomm 等,以对应 luaopen_libsoc_adapter_* 为准。部分 v1/v2 文件将 Mock 入口命名为 luaopen_libsoc_adapter_*_mock,与正式模块名不同,测试代码需要按实际导出符号加载。

返回值与异常

加载成功返回 Lua userdata(绑定类实例)。工厂取驱动失败时,绑定构造函数抛出 std::runtime_error,在 Lua 侧表现为错误,例如 Failed to get driver 'i2c'

应用场景

Lua 微组件、runtime_accessor 以及各业务仓中的 require 'libsoc_adapter.xxx'

限制条件

  • 需要 /usr/lib64/libsoc_adapter.so 可被 Lua C 搜索器找到(Lua 会把 libsoc_adapter.i2c 解析为库 libsoc_adapter 中的 luaopen_libsoc_adapter_i2c)。
  • 同时需要 /opt/bmc/bcal 下对应 lib{driver}.so,以及内核设备节点。
  • require 'libsoc_adapter.uart' 的构造函数会立即加载全部 UART 端口以及 uart_connect;任一失败即抛错。v1 最多 8 路,v2(CONAN_DEFS_CHIPV2_ENABLE)最多 16 路。

调试示例

lua
local gpio = require 'libsoc_adapter.gpio'
gpio:init(192, 1)          -- 引脚 192,方向输出
gpio:write(192, 1)
local level = gpio:read(192, 1)
gpio:close()

2.5 I2C

功能说明

C++ 接口 BCAL_DRIVER_I2C::I2c 提供 master/slave 读写、从设备缓存和复位。Lua 类 LI2c 在内部调用工厂 get_driver("i2c", bus_id),并在每次操作前按总线号切换实例。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

C++ I2cConfiginit 参数)

成员类型描述
speeduint32_t总线速率,枚举 100 / 400 / 3400,单位 kbps。
modeuint32_t0 master,1 slave。
addruint32_tslave 地址,mode 为 1 时有效。
use_smbusuint32_t1 表示初始化为 SMBus 模式。

C++ 方法

方法名入参返回值描述
readlength, time_out(ms), retry, in_datatuple<int32_t, optional<string>>读数据;in_data 格式见 I2cWriteMsg(7 位地址 + 数据)。成功时第一项为 0,第二项为读出数据。
writein_data, time_out(ms), write_delay(ms)int32_t写数据。0 成功,其他为失败。
slave_cache_readoffset, sizestd::string读从设备缓存。
slave_cache_writeoffset, valint32_t写从设备缓存。0 成功。
resetvoid复位当前 I2C 实例。

Lua 方法(src/luawrapper/l_i2c.cpp

方法参数返回值说明
init(bus_id, speed, mode, addr)总线号、速率、主从、地址0切换到 bus_idinit(I2cConfig)bus_id 对应工厂 index
read(read_data, in_data)I2C_READ_S、发送数据与 C++ read 相同使用 read_data.length / time_out_cnt / re_read_cnt
write(index, in_data, time_out, write_delay)总线号、数据、超时、写后延迟int32_t切换 index 后调用 C++ write
slave_cache_read / slave_cache_writedrv_id, offset, …同 C++switch_index(drv_id)
reset(bus_id)总线号切换后复位。
lock / unlock / close加锁或 release_driver
deploy(deploy)DEV_I2C_DEPLOYcontrol 返回值通过 control(I2C_CMD_DEPLOY, …) 下发时序参数。

Lua 还注册了 I2C_READ_SI2C_SLAVE_CACHE_RDWR_SDEV_I2C_DEPLOYDEV_I2C_MSG。其中 I2C_READ_S 的总线号字段在 Lua 侧注册名为 rv_id(绑定到 C++ 成员 drv_id)。

I2C_MAX_CHANEL 为 16,MAX_BYTE_READ_NUM 为 2048(include/bcal_extend/i2c_extend.h)。

返回值与异常

返回值 / 异常含义触发条件处理建议
read 第一项 0读成功ioctl 成功。使用 optional 中的数据。
read 第一项为 errno读失败ioctl 失败,实现把 errno 作为返回码。检查总线、地址、超时。
write 非 0写失败ioctl 失败。核对 in_data 与超时。
runtime_error参数或句柄非法Lua 侧驱动已 close,或 get_driver 失败。重新 require / 构造,并确认 libi2c.so

应用场景

访问板载 EEPROM、温度传感器、CPLD 等 I2C 器件;runtime_accessor 的 I2C 路径。

限制条件

  • C++ read/write 不再带 index 参数,总线号由工厂创建实例时的 index 决定。
  • Lua I2C_READ_S 请使用字段名 rv_id,不是 drv_id
  • 读长度超过 2048 时,厂商实现会抛出 runtime_error

调试示例

C++ 调试
cpp
#include "bcal/driver.h"
#include "bcal/i2c.h"

using namespace BCAL_DRIVER_I2C;
auto& factory = bcal::IDriverFactory::get_instance();
auto* raw = factory.get_driver("i2c", 0);
auto* i2c = static_cast<I2c*>(raw);
I2cConfig cfg{};
cfg.speed = 100;
cfg.mode = 0;
cfg.addr = 0;
cfg.use_smbus = 0;
i2c->init(&cfg, sizeof(cfg));
int32_t rc = i2c->write(addr_and_payload, 1000, 0);
factory.release_driver(raw);
Lua 调试
lua
local i2c = require 'libsoc_adapter.i2c'
assert(i2c:init(0, 100, 0, 0) == 0)
local req = i2c.I2C_READ_S()
req.rv_id = 0
req.length = 2
req.time_out_cnt = 1000
req.re_read_cnt = 3
local rc, data = i2c:read(req, string.char(0x50))
print(rc, data)
i2c:close()

2.6 GPIO

功能说明

每个 Gpio 实例对应一根引脚。Lua 绑定用第一个参数作为 index 切换实例。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

C++

方法 / 结构说明
GpioConfig.direction0 输入,1 输出。
read()返回 uint8_t1 高电平,0 低电平。
write(gpio_level)int32_t0 成功,-1 失败。
set_interrupt(int_level)中断极性;头文件注释:下降沿有效,1 为上升沿有效。
get_interrupt(timeout)timeout 单位 ms;返回 1 有中断,0 无中断。
control(CMD_GPIO_GET_IO_DRIVE_CONFIG / SET)驱动力配置,管脚序号范围注释为 0–126。

Lua(LGpio

方法参数说明
init(gpio_num, direction)引脚号、方向切换 index 后 init(GpioConfig)
read(gpio_num, direction)引脚号、方向切换后调用 C++ read()。Lua 的 direction 不会传给 C++ read
write(gpio_num, gpio_level)引脚号、电平切换后写电平。Lua 封装未返回 C++ 的 int32_t
set_interrupt(gpio_int_num, int_level)引脚号、极性配置中断。
get_interrupt(gpio_int_num, timeout, rsv)引脚号、超时、保留rsv 未使用。
get_io_drive_config(id) / set_io_drive_config(id, val)管脚序号、驱动力control 命令。

返回值与异常

C++ write 失败返回 -1。Lua 在 get_driver 失败或对象已 close 时抛出 runtime_error

应用场景

面板灯、在位检测、中断引脚、复位脚控制。

限制条件

  • 必须先 init 再读写。
  • 驱动力等级因管脚而异,头文件要求参见说明文档;源码未在本组件内给出完整管脚等级表。

调试示例

见 2.4 节 Lua 示例。

2.7 UART 与串口互连

功能说明

Uart 对应一个 UART 控制器;UartConnect 管理 UART 与 PORT 的互连。Lua LUart 把二者放在同一个 userdata 中:构造时加载全部 uart 实例和 uart_connect 实例。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

C++ Uart

方法说明
open / close打开 / 关闭通道。
read(len)len 字节,返回 string_t
select_read(len, timeout)阻塞读,timeout 单位 ms。
write(val)0 成功,-1 失败。
send_break(duration)发送 break,duration 单位 ms。
set_baud_rate / set_parity / set_data_bits / set_stop_bits串口参数。parityO/E/M/S/N
get_host_baud_rate返回 HOST 波特率。

C++ UartConnect

方法说明
uart_connect_uart / uart_connect_port / port_connect_port建立互连。
query_uart_connection / query_port_connection返回位域编码的连接关系,位定义见 bcal/uart.h 注释。

control 命令包括 CMD_OPEN_PORTCMD_UPDATE_BAUDCMD_UPDATE_BAUD_V2 以及 v2 的 RX/TX 直连命令。参数结构见同一头文件。

Lua 常用方法

openreadwriteselect_readset_baud_rateset_parityset_data_bitsset_stop_bitsuart_connect_uartquery_uart_connection 等。v2 额外导出 get_baud_from_reguart_rx_from_uart_tx 等。部分方法是别名,例如 get_current_baudget_host_baud_rate 绑定同一函数。

返回值与异常

Lua 构造失败抛出 Failed to get driver 'uart'Failed to get driver 'uart_connect'open/read 等在 index 越界时抛出 uart id is invalid:%d

应用场景

SOL、面板串口、HOST 串口互连;bmc_soc 的串口管理会间接依赖本库或 soctrl。

限制条件

  • Lua 构造即打开全部端口,缺少任意 libuart.so 实例或 libuart_connect.so 都会失败。
  • v1 / v2 的端口数量不同(8 / 16)。
  • Lua select_read(index, len) 的超时在绑定层固定为 1000 ms,不能由调用方传入。

调试示例

lua
local uart = require 'libsoc_adapter.uart'
uart:open(0)
uart:set_baud_rate(0, 115200)
uart:write(0, 'AT\r')
local data = uart:select_read(0, 64)  -- 超时在绑定层固定为 1000 ms
uart:close()

open / set_baud_rate / write / select_read 的首参均为 UART index。Lua select_read 只接受 (index, len),超时写死为 1000 ms,与 C++ Uart::select_read(len, timeout) 不同。

2.8 libsoc_adapter.sys_info

功能说明

hal::SysInfo 封装 /dev/sys_info,不属于 BCAL 工厂驱动,而是 HAL 类。Lua 模块 libsoc_adapter.sys_info 导出该类方法。bmc_soc 获取 BMC 核温、复位原因、DDR 自检等数据时会调用本库。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

设备节点:/dev/sys_infoSYS_INFO_DEVNAME)。

参数说明

方法签名来自 vendor/huawei/v2/luawrappers/sys_info.h(v1 对应文件同类)。Lua 通过 luaopen_libsoc_adapter_sys_info 导出下列方法。

方法返回值描述
get_core_temp()tuple<int32_t, int32_t, int32_t>BMC 芯片核心温度。
get_reset_type()int32_t复位原因。
get_sys_jiffies()uint32_t内核时钟。
get_startup_times()uint32_t系统启动次数。
clear_startup_times()清除启动失败次数。
get_sdk_ver()tuple<string, string>SDK 版本号与编译时间。
set_pcie1_flag(flag)设置 PCIe1 打开 / 关闭,flag:0 关闭,1 打开。
get_pcie_addr(id)tuple<uint32_t, uint32_t>PCIE 基地址与空间大小;v2 注释 PCIE_MAX_NUM = 2
get_ddr_self_test_result()uint32_tDDR 自检结果。
set_vga_display_status(status)0 关闭,1 打开 VGA。
get_rsvmem_free_support()int32_t保留内存是否支持释放:0 不支持,1 支持。
get_chip_name()uint32_t芯片名称。

C++ 另有 get_soc_board_cfg,当前 v2 的 luaopen_libsoc_adapter_sys_info 未导出该方法。

返回值与异常

打开 /dev/sys_info 失败时由 hal::Driver 基类处理(通常抛异常)。ioctl 语义以 sys_info.h 中的 SYS_INFO_* 命令为准。

应用场景

BMC 核温监控、复位原因记录、DDR 自检展示、PCIe / VGA 相关状态。

限制条件

  • 依赖内核 sys_info 设备,QEMU 或非配套内核上可能不可用。
  • 不同芯片 ioctl 编号可能不同,v1/v2 头文件需分别核对。

调试示例

lua
local sys = require 'libsoc_adapter.sys_info'
local t1, t2, t3 = sys:get_core_temp()
local reset = sys:get_reset_type()
local ddr = sys:get_ddr_self_test_result()
sys:close()

2.9 libsoc_adapter.hiss

功能说明

hal::Hiss 封装 /dev/sec_module,提供安全核通信、BIOS 校验、TPCM、DICE 证书、KMC 主密钥编解码等接口。Lua 模块名固定为 libsoc_adapter.hiss(源码注释:避免业务感知 1711/1712 差异)。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

下列签名来自 include/hiss.h,并已在 luaopen_libsoc_adapter_hiss 中注册。未列入的私有方法 send_recv_msg_with_hiss 不向 Lua 导出。

方法签名要点
sendrecv(string_view val, uint32_t read_length) -> string
boot_ok_notify无参
bmctime_notify(uint64_t timestamp)
efuse_pwr_set(uint32_t status) -> uint32_t
start_bios_verify(uint8_t bios_type)
get_bios_verify_result-> uint8_t
get_spi_mux_channel / set_spi_mux_channel获取 / 设置 uint8_t channel
notify_m3_following_a55_reset(uint8_t status)
export_custom_cert_hash / import_custom_cert_hash客户证书哈希导出 / 导入
import_repair_cert / export_repair_info维修凭证
disable_boot_verification失能安全核校验
tpcm_get_log / tpcm_get_pcr / tpcm_get_random / tpcm_get_sm3_hash / tpcm_get_presenceTPCM 操作
symkey_get_ras_public_key / symkey_import_keys对称密钥模块
get_sec_boot_info / get_secure_boot_mode / get_secure_boot_signatures安全启动信息
kmc_master_key_encode / kmc_master_key_decodeKMC 主密钥
get_dice_csr / import_dice_cert0 / export_dice_cert_nDICE 证书与挑战

各命令字枚举见 include/hiss.hSEC_FW_MSG_A55_SUB_CMD_TYPE_E 等。完整参数约束源码未在独立规格中逐项列出的,请对照头文件与安全核协议,不要臆测取值范围。

返回值与异常

打开 /dev/sec_module 失败或 ioctl 失败时由实现抛出异常或返回错误码。具体 errno 映射源码未覆盖为统一错误表。

应用场景

安全启动、BIOS 校验、Efuse 电源控制、TPCM 度量、证书与密钥管理。

限制条件

  • 仅在具备安全核 / sec_module 设备的芯片上可用。
  • 涉及证书、密钥的接口不得在日志中打印明文。
  • Lua 导出名称 export_nonce_chanllenge 等与头文件拼写保持一致(含 chanllenge)。

调试示例

lua
local hiss = require 'libsoc_adapter.hiss'
hiss:boot_ok_notify()
local mode = hiss:get_secure_boot_mode()
hiss:close()

2.10 libsoc_adapter.boot_loader

功能说明

hal::BootLoader 访问 U-Boot 环境变量分区(头文件中设备为 /dev/mmcblk0p8),并提供 PCIe 控制器状态与 BAR 相关接口。Lua 导出三个方法。

属性内容
首发版本openUBMC 26.09
废弃状态正常可用

参数说明

方法签名描述
get_pcie_controller_state(uint8_t id) -> bool查询 PCIe 控制器状态。
set_pcie_controller_state(uint8_t id, bool state)设置 PCIe 控制器状态。
set_pcie_bar_8M() -> int8_t设置 PCIe BAR 为 8M。

环境变量区偏移、大小见 include/boot_loader.hENV_AREA_OFFSETENV_AREA_SIZE)。set_uboot_env / get_uboot_env 为私有方法,Lua 未导出。

返回值与异常

设备打开或分区校验失败时由 hal::Driver / 实现抛错。set_pcie_bar_8M 返回 int8_t,取值含义源码未覆盖为公开枚举。

应用场景

BMC 启动后同步 PCIe 控制器使能状态。

限制条件

  • 依赖指定 eMMC 分区布局,分区号写死在头文件中。
  • 不适用于没有该分区的机型。

调试示例

lua
local bl = require 'libsoc_adapter.boot_loader'
local st = bl:get_pcie_controller_state(0)
bl:close()

3. 组件扩展案例

3.1 扩展能力概述

libsoc_adapter 不提供运行时插件 DSL,也不注册 MDB 接口。扩展方式是代码级二次开发:

  • 上层组件增加 Conan 依赖后调用现有 C++ / Lua API。
  • 新增 BCAL 驱动:定义接口、Extend 实现、create_driver/destroy_driver、Lua 绑定。
  • 通过 Mock 目录为新驱动提供无硬件实现。

构建选项(mds/service.json)包括 chipv2_enableenable_qemuenable_luajitchipmodule_symvers

3.2 扩展点说明

扩展位置作用触发时机
include/bcal/xxx.h定义纯虚接口与配置结构。编译期。
include/bcal_extend/xxx_extend.h声明厂商实现类。编译期。
vendor/huawei/xxx/v1//v2/ioctl 实现,导出 create_driver / destroy_driverget_driver("xxx", index)dlopen
src/luawrapper/l_xxx.cpp注册 luaopen_libsoc_adapter_xxxrequire 'libsoc_adapter.xxx'
vendor/huawei/mock/Mock 实现。测试构建。
src/driver.cpp工厂加载逻辑。一般不需要改;新驱动只要 .so 命名符合 lib{name}.so

仓库 docs/driver_adapter_guide.md 给出了逐步文件清单。

3.3 二次开发指导

步骤一:定义 BCAL 接口

include/bcal/xxx.h 中让 Xxx 继承 bcal::IDriver,并实现业务纯虚方法。配置结构通过 init(void* args, uint32_t size) 传入。

步骤二:实现驱动 .so

实现 create_driver(int32_t index)destroy_driver(IDriver*),CMake 将目标安装到 opt/bmc/bcal,生成 libxxx.so

步骤三:注册 Lua API

cpp
LUA_EXPORT int32_t luaopen_libsoc_adapter_xxx(lua_State* L)
{
    luaL_checkversion(L);
    luawrap::lua_class<LXxx>(L)
        .ctor<>()
        .def("init", c_func_wrap(L, LXxx::init))
        .def("close", c_func_wrap(L, LXxx::release));
    return 1;
}

构造函数内应调用 IDriverFactory::get_instance().get_driver("xxx", index)

示例代码

lua
local xxx = require 'libsoc_adapter.xxx'
xxx:init(...)
xxx:close()

验证方法

  1. 交叉编译后确认 /opt/bmc/bcal/libxxx.so/usr/lib64/libsoc_adapter.so 已安装。
  2. require 'libsoc_adapter.xxx' 成功。
  3. 覆盖成功路径、非法 index、设备节点缺失。
  4. 同步更新本文档第 2 章接口表。

注意事项

  • v1/v2 若行为不同,需同时维护两套实现,并用 chipv2_enable 切换。
  • 每个新驱动应提供 Mock。
  • 保持 luaopen 符号与 require 模块名的对应关系。
  • control 只用于紧急扩展,正式能力应加到 BCAL 纯虚接口中。

4. 日志说明

4.1 一键日志收集

libsoc_adapter 是动态库,不创建独立日志文件,也没有仓库内声明的 on_dump 或一键日志项。工厂把加载失败写入内存中的 driver_load_info.error_msg;驱动实现普遍通过抛出 std::runtime_errorformat(...))把错误交给调用方。是否出现在系统一键日志中,取决于宿主组件的日志配置。

文件路径内容说明
不适用(宿主进程日志)排障时应先确定调用进程(如 hwproxybmc_socruntime_accessor),再收集该进程日志。
get_driver_load_info()进程内查询最近一次 dlopen/符号解析结果,不是落盘日志。

4.2 关键日志信息

组件没有统一的日志级别宏。下列字符串来自工厂与 Lua 绑定中的异常 / error_msg,会出现在宿主日志或 Lua traceback 中。

日志片段日志级别含义解读建议处理动作
Failed to load library:宿主 ERROR / Lua errordlopen 失败。检查 /opt/bmc/bcal/lib{name}.so 及依赖库。
Failed to find both create_driver and destroy_driver symbol同上.so 未导出必需符号。核对驱动实现与链接脚本。
Failed to get driver 'xxx'Lua error工厂返回空指针。结合 get_driver_load_info 与设备节点。
I2c driver has been closed / Gpio driver has been closedLua errorclose 后继续调用。避免在 __gc/close 后再用同一 userdata。
uart id is invalidLua errorUART index 越界。按 v1/v2 端口上限传入。
request error, bus_id is invalid异常I2C 总线号 ≥ 16。bus_id 限制在 0–15。
i2c read length is too large异常读长度 > 2048。缩小 length

驱动 ioctl 失败时,部分实现把 strerror(errno) 拼进 runtime_error,关键字形如 ioctl(...) failed

5. 问题定界指南

5.1 典型问题定界

问题描述是否为本组件问题判断依据关键证据收集方法
require 'libsoc_adapter.i2c' 失败可能是libsoc_adapter.so 未安装或 package.cpath 不含 /usr/lib64/?.so检查文件是否存在、打印 package.cpath
Failed to get driver 'i2c'可能是libi2c.so 缺失、符号不全或 create_driver 失败。/opt/bmc/bcal,在 C++ 侧打印 get_driver_load_info
ioctl / runtime_error/dev/xxx通常是内核或硬件用户态只是转发 ioctl。ls -l /dev/xxxdmesg,确认内核模块已加载。
QEMU 上部分 HAL 不可用通常不是Mock 或 QEMU 未实现对应 /dev 节点。确认 enable_qemu 与 mock 路径;不要当芯片缺陷。
busctl 找不到 libsoc_adapter 对象本组件不注册 D-Bus。改用 Lua/IDriverFactory
bmc_soc 读不到核温 / DIEID可能是调用链bmc_soc 通过本库 sys_info 等接口取数。先单独 require 'libsoc_adapter.sys_info' 复现。

5.2 错误码速查表

错误码含义可能原因排查建议
IDriver* 为空工厂加载失败路径、.so、符号、create_driverget_driver_load_info
0多数写 / control 成功调用完成。对读接口还需检查返回数据。
-1通用失败ioctl 失败或 control 不支持。对照该驱动头文件中的 cmd 与 errno。
errno(I2C read 第一返回值)内核 I2C 错误NACK、超时、总线忙。结合 time_out/retry 与原理图地址。
std::runtime_error参数或状态非法index 越界、未 init、已 close、ioctl 失败被包装。阅读异常字符串,不要忽略 Lua traceback。

本组件没有 D-Bus 结构化错误对象。

5.3 调试方法

开启调试日志

没有独立日志开关。在宿主进程打开 DEBUG,并过滤 Failed to get driverioctllibsoc_adapter 等关键字。

复现问题方法

  1. 确认 /usr/lib64/libsoc_adapter.so/usr/lib64/libbcal.so/opt/bmc/bcal/lib<drv>.so 存在。
  2. 确认对应 /dev/* 与内核模块(Hisport 为 bmc_hisport_drv.ko)。
  3. 用第 2 章最小 Lua 示例先验证工厂加载,再验证业务参数。
  4. C++ 调用方打印 get_driver_list()get_driver_load_info()

没有 busctl 调试面。

5.4 错误对象解读

Lua API 要么返回整数/tuple,要么抛出异常字符串。C++ BCAL 写接口普遍使用 0/-1,读接口返回数据或 tuple。将 -1errno 和 Lua 异常视为不同层次,不要混成同一错误码。

6. 常见问题解答

Q1:为什么 require 'libsoc_adapter.gpio' 找不到模块?

  • 问题描述:Lua 报告 module not found 或无法加载共享库。
  • 一句话答案:检查 libsoc_adapter.so 是否在 Lua C 搜索路径中。
  • 根因说明:模块入口是 luaopen_libsoc_adapter_gpio,由无前缀目标 libsoc_adapter 安装为 /usr/lib64/libsoc_adapter.so
  • 解决方案:确认文件存在,将 /usr/lib64/?.so 纳入 package.cpath
  • 规避方案:通过组件包和正式构建流程部署,不要只拷贝单个 .so
  • 适用版本:1.130.70。

Q2:为什么已经能 require,仍提示 Failed to get driver

  • 问题描述:Lua 绑定构造成功前或构造中抛出获取驱动失败。
  • 一句话答案:BCAL 工厂还要再加载 /opt/bmc/bcal/lib{name}.so
  • 根因说明:libsoc_adapter.so 只是绑定层;真正 ioctl 实现在 libgpio.so 等驱动库。
  • 解决方案:安装对应驱动 .so,确认 create_driver/destroy_driver 已导出。
  • 规避方案:测试环境使用 /usr/lib64/mock 中的 Mock 库,并用 set_driver_path 指向该目录(C++)或按产品测试框架替换。
  • 适用版本:1.130.70。

Q3:IDriver 里有没有 config()

  • 问题描述:对照仓库 docs/v1 规格调用 config(index, …) 无法编译。
  • 一句话答案:当前公共接口只有 init(args, size),没有 config()
  • 根因说明:BCAL 头文件已将配置并入 init;v1/v2 规格文档部分尚未同步。
  • 解决方案:按 include/bcal/*.h 传配置结构体。
  • 规避方案:新增代码不要再依赖 docs/v1 中带 index 的旧签名。
  • 适用版本:以当前 include/bcal/driver.h 为准。

Q4:为什么 UART Lua 一加载就失败?

  • 问题描述:require 'libsoc_adapter.uart' 立即报错。
  • 一句话答案:构造函数会加载全部 UART 端口和 uart_connect
  • 根因说明:LUart 在构造时循环 get_driver("uart", i)get_driver("uart_connect", 0),任一为空即抛异常。
  • 解决方案:保证 libuart.so 能为每个 index 创建实例,且存在 libuart_connect.so
  • 规避方案:仅需单路 UART 的 C++ 代码应直接 get_driver("uart", n),不要走 Lua 全量加载。
  • 适用版本:1.130.70。

Q5:本组件能否用 mdbctl / busctl 调试?

  • 问题描述:在资源树上找不到 libsoc_adapter 对象。
  • 一句话答案:不能。它不是微组件服务,不注册资源协作接口。
  • 根因说明:mds/service.jsontypelibraryrequired 为空。
  • 解决方案:使用 Lua 示例或 C++ 工厂 API;业务对象在 bmc_soc 等组件上。
  • 规避方案:无。
  • 适用版本:1.130.70。