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.json 或 ipmi.json)。运行时代码位于调用方进程内。
编译产物主要包括:
libbcal.so:驱动工厂与 BCAL 公共框架,安装到/usr/lib64。libsoc_adapter.so:Lua 绑定集合(CMake 目标名为libsoc_adapter且PREFIX为空),安装到/usr/lib64。libsoc_adapter_c.so:部分 C 封装(如 TRNG / MCTP / USB C wrapper),安装到/usr/lib64。lib{driver}.so:各 BCAL 驱动实现,安装到/opt/bmc/bcal(例如libi2c.so、libgpio.so、libuart.so)。- Mock 库:安装到
/usr/lib64/mock,用于无硬件测试。 - 可选内核模块:
bmc_hisport_drv.ko;在chipv2_enable=true时还会构建bmc_i2c_over_localbus_drv.ko、bmc_i3c_over_localbus_drv.ko、bmc_uart_over_localbus_drv.ko,安装到lib/modules/ko。
Lua 业务通过 require 'libsoc_adapter.{driver}' 加载对应绑定,导出符号为 luaopen_libsoc_adapter_{driver}。
1.2 解决什么问题
上层微组件(如 runtime_accessor、hwproxy、bmc_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_info、hiss、boot_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 关键术语表
| 术语 | 解释 |
|---|---|
| BCAL | Board 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::SysInfo、hal::Hiss。 |
| Hisport | 本仓库提供的内核驱动与用户态接口,用于特定片内高速通道。 |
1.5 外部交互边界图
构建依赖见 mds/service.json:huawei_secure_c、skynet、libsomp;测试依赖 test_data。组件自身没有常驻进程、监听端口或资源协作接口。
2. API 使用说明与示例
本章 C++ 接口以 include/bcal/*.h 为准。仓库内 docs/v1/*.md、docs/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"。
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_name、success、error_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句柄;最后一个引用释放后才会卸载动态库。
调试示例
#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 |
| 废弃状态 | 正常可用 |
参数说明
| 方法名 | 入参 | 出参 / 返回值 | 描述 |
|---|---|---|---|
init | void* args, uint32_t size | void | 初始化。args 一般为各驱动配置结构体指针,size 为该结构体字节数。 |
lock / unlock | 无 | void | 对当前实例加锁 / 解锁,保护多线程下的硬件独占访问,不用于保护实现内部状态。 |
get_version | 无 | string_t | 驱动版本字符串。 |
get_driver_name | 无 | string_t | 驱动名,对应 lib{name}.so。 |
control | uint32_t cmd, void* args_in, void* args_out | int32_t | 扩展控制口。0 成功,-1 失败。头文件标明仅用于不变更 BCAL 版本时由业务与驱动实现自行协商的命令。 |
返回值与异常
init / lock / unlock 无返回值;具体实现可能抛出 std::runtime_error(例如设备节点打开失败)。control 约定 0 / -1。
应用场景
所有 BCAL 读写操作之前需要 init;多线程访问同一实例时应成对调用 lock / unlock。
限制条件
- 当前
IDriver没有config()方法;配置通过init(args, size)传入。 control的cmd与参数结构由各驱动头文件定义,不能跨驱动混用。
调试示例
见 2.5 GPIO:GpioConfig 通过 init 传入方向。
2.3 BCAL 驱动接口概览
以下类均继承 bcal::IDriver。命名空间、头文件和关键方法来自 include/bcal/。
| 驱动 | 头文件 | 命名空间 | 类 | 关键方法 |
|---|---|---|---|---|
| ADC | bcal/adc.h | BCAL_DRIVER_ADC | Adc | read(chan_id),返回 mV |
| BT | bcal/bt.h | BCAL_DRIVER_BT | Bt | read / write / setatn |
| CANBUS | bcal/canbus.h | BCAL_DRIVER_CANBUS | Canbus | read / write / set_speed / set_filter / reset |
| EDMA | bcal/edma.h | BCAL_DRIVER_EDMA | Edma | poll / read / write |
| EFUSE | bcal/efuse.h | BCAL_DRIVER_EFUSE | Efuse | get_domain_cnt / read / write |
| GPIO | bcal/gpio.h | BCAL_DRIVER_GPIO | Gpio | read / write / set_interrupt / get_interrupt |
| I2C | bcal/i2c.h | BCAL_DRIVER_I2C | I2c | read / write / slave_cache_read / slave_cache_write / reset |
| IPMB | bcal/ipmb.h | BCAL_DRIVER_IPMB | Ipmb | read / write / reset / set_addr / check_readable / set_enable |
| JTAG | bcal/jtag.h | BCAL_DRIVER_JTAG | Jtag | write / set_target_num / set_bypass_mode / get_cpld_idcode / reset |
| KCS | bcal/kcs.h | BCAL_DRIVER_KCS | Kcs | read / write / setatn |
| Localbus | bcal/localbus.h | BCAL_DRIVER_LOCALBUS | Localbus | read / write / set_timing / set_bitwidth_and_offset |
| MCTP | bcal/mctp.h | BCAL_DRIVER_MCTP | Mctp | write / read / reset |
| MDIO | bcal/mdio.h | BCAL_DRIVER_MDIO | Mdio | read / write |
| MEM | bcal/mem.h | BCAL_DRIVER_MEM | Mem | import |
| MMC | bcal/mmc.h | BCAL_DRIVER_MMC | Mmc | read_reg / get_health_report / get_write_stat / read / write / set_write_protect |
| PECI | bcal/peci.h | BCAL_DRIVER_PECI | Peci | reset / read |
| PWM | bcal/pwm.h | BCAL_DRIVER_PWM | Pwm | read / write / rst_hold |
| SOL | bcal/sol.h | BCAL_DRIVER_SOL | Sol | enable / read / get_pos / get_length / set_log_size |
| SPI | bcal/spi.h | BCAL_DRIVER_SPI | Spi | read / write |
| TRNG | bcal/trng.h | BCAL_DRIVER_TRNG | Trng | reset / read |
| UART | bcal/uart.h | BCAL_DRIVER_UART | Uart | open / close / read / select_read / write / set_baud_rate 等 |
| UART 互连 | bcal/uart.h | BCAL_DRIVER_UART | UartConnect | uart_connect_uart / uart_connect_port / port_connect_port / query_* |
| USB DRD | bcal/usb_drd.h | BCAL_DRIVER_USB_DRD | UsbDrd | set_role / get_role |
| USB 复合 | bcal/usb_driver.h | BCAL_DRIVER_USB | Usb 及 UsbMouse / UsbKeyboard / UsbCdrom / UsbFloppy / UsbFlashDrive / UsbLcd | connect / disconnect / is_connected 及各子类 write/read |
| WDT | bcal/wdt.h | BCAL_DRIVER_WDT | Wdt | clear / 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 使用点分模块名加载:
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.adc | luaopen_libsoc_adapter_adc | adc |
libsoc_adapter.bt | luaopen_libsoc_adapter_bt | bt |
libsoc_adapter.canbus | luaopen_libsoc_adapter_canbus | canbus |
libsoc_adapter.edma | luaopen_libsoc_adapter_edma | edma |
libsoc_adapter.efuse | luaopen_libsoc_adapter_efuse | efuse |
libsoc_adapter.gpio | luaopen_libsoc_adapter_gpio | gpio |
libsoc_adapter.i2c | luaopen_libsoc_adapter_i2c | i2c |
libsoc_adapter.ipmb | luaopen_libsoc_adapter_ipmb | ipmb |
libsoc_adapter.jtag | luaopen_libsoc_adapter_jtag | jtag |
libsoc_adapter.kcs | luaopen_libsoc_adapter_kcs | kcs |
libsoc_adapter.localbus | luaopen_libsoc_adapter_localbus | localbus |
libsoc_adapter.mctp | luaopen_libsoc_adapter_mctp | mctp |
libsoc_adapter.mdio | luaopen_libsoc_adapter_mdio | mdio |
libsoc_adapter.mem | luaopen_libsoc_adapter_mem | mem |
libsoc_adapter.mmc | luaopen_libsoc_adapter_mmc | mmc |
libsoc_adapter.peci | luaopen_libsoc_adapter_peci | peci |
libsoc_adapter.pwm | luaopen_libsoc_adapter_pwm | pwm |
libsoc_adapter.sol | luaopen_libsoc_adapter_sol | sol |
libsoc_adapter.spi | luaopen_libsoc_adapter_spi | spi |
libsoc_adapter.trng | luaopen_libsoc_adapter_trng | trng |
libsoc_adapter.uart | luaopen_libsoc_adapter_uart | uart + uart_connect |
libsoc_adapter.usb_drd | luaopen_libsoc_adapter_usb_drd | usb_drd |
libsoc_adapter.wdt | luaopen_libsoc_adapter_wdt | wdt |
libsoc_adapter.usb_driver | luaopen_libsoc_adapter_usb_driver | USB 复合 |
libsoc_adapter.mouse / keyboard / cdrom / floppy / flash / lcd | 对应 luaopen_libsoc_adapter_* | USB 子功能 |
芯片 HAL Lua 绑定(随 v1/v2 编入同一 libsoc_adapter.so)还包括 sys_info、hiss、boot_loader、scm3、hisport、innerbus、comm 等,以对应 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 路。
调试示例
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++ I2cConfig(init 参数)
| 成员 | 类型 | 描述 |
|---|---|---|
speed | uint32_t | 总线速率,枚举 100 / 400 / 3400,单位 kbps。 |
mode | uint32_t | 0 master,1 slave。 |
addr | uint32_t | slave 地址,mode 为 1 时有效。 |
use_smbus | uint32_t | 1 表示初始化为 SMBus 模式。 |
C++ 方法
| 方法名 | 入参 | 返回值 | 描述 |
|---|---|---|---|
read | length, time_out(ms), retry, in_data | tuple<int32_t, optional<string>> | 读数据;in_data 格式见 I2cWriteMsg(7 位地址 + 数据)。成功时第一项为 0,第二项为读出数据。 |
write | in_data, time_out(ms), write_delay(ms) | int32_t | 写数据。0 成功,其他为失败。 |
slave_cache_read | offset, size | std::string | 读从设备缓存。 |
slave_cache_write | offset, val | int32_t | 写从设备缓存。0 成功。 |
reset | 无 | void | 复位当前 I2C 实例。 |
Lua 方法(src/luawrapper/l_i2c.cpp)
| 方法 | 参数 | 返回值 | 说明 |
|---|---|---|---|
init(bus_id, speed, mode, addr) | 总线号、速率、主从、地址 | 0 | 切换到 bus_id 并 init(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_write | drv_id, offset, … | 同 C++ | 先 switch_index(drv_id)。 |
reset(bus_id) | 总线号 | 无 | 切换后复位。 |
lock / unlock / close | 无 | 无 | 加锁或 release_driver。 |
deploy(deploy) | DEV_I2C_DEPLOY | control 返回值 | 通过 control(I2C_CMD_DEPLOY, …) 下发时序参数。 |
Lua 还注册了 I2C_READ_S、I2C_SLAVE_CACHE_RDWR_S、DEV_I2C_DEPLOY、DEV_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++ 调试
#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 调试
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.direction | 0 输入,1 输出。 |
read() | 返回 uint8_t,1 高电平,0 低电平。 |
write(gpio_level) | int32_t,0 成功,-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 | 串口参数。parity:O/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_PORT、CMD_UPDATE_BAUD、CMD_UPDATE_BAUD_V2 以及 v2 的 RX/TX 直连命令。参数结构见同一头文件。
Lua 常用方法
open、read、write、select_read、set_baud_rate、set_parity、set_data_bits、set_stop_bits、uart_connect_uart、query_uart_connection 等。v2 额外导出 get_baud_from_reg、uart_rx_from_uart_tx 等。部分方法是别名,例如 get_current_baud 与 get_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,不能由调用方传入。
调试示例
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_info(SYS_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_t | DDR 自检结果。 |
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 头文件需分别核对。
调试示例
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_presence | TPCM 操作 |
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_decode | KMC 主密钥 |
get_dice_csr / import_dice_cert0 / export_dice_cert_n 等 | DICE 证书与挑战 |
各命令字枚举见 include/hiss.h 中 SEC_FW_MSG_A55_SUB_CMD_TYPE_E 等。完整参数约束源码未在独立规格中逐项列出的,请对照头文件与安全核协议,不要臆测取值范围。
返回值与异常
打开 /dev/sec_module 失败或 ioctl 失败时由实现抛出异常或返回错误码。具体 errno 映射源码未覆盖为统一错误表。
应用场景
安全启动、BIOS 校验、Efuse 电源控制、TPCM 度量、证书与密钥管理。
限制条件
- 仅在具备安全核 /
sec_module设备的芯片上可用。 - 涉及证书、密钥的接口不得在日志中打印明文。
- Lua 导出名称
export_nonce_chanllenge等与头文件拼写保持一致(含chanllenge)。
调试示例
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.h(ENV_AREA_OFFSET、ENV_AREA_SIZE)。set_uboot_env / get_uboot_env 为私有方法,Lua 未导出。
返回值与异常
设备打开或分区校验失败时由 hal::Driver / 实现抛错。set_pcie_bar_8M 返回 int8_t,取值含义源码未覆盖为公开枚举。
应用场景
BMC 启动后同步 PCIe 控制器使能状态。
限制条件
- 依赖指定 eMMC 分区布局,分区号写死在头文件中。
- 不适用于没有该分区的机型。
调试示例
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_enable、enable_qemu、enable_luajit、chip、module_symvers。
3.2 扩展点说明
| 扩展位置 | 作用 | 触发时机 |
|---|---|---|
include/bcal/xxx.h | 定义纯虚接口与配置结构。 | 编译期。 |
include/bcal_extend/xxx_extend.h | 声明厂商实现类。 | 编译期。 |
vendor/huawei/xxx/ 或 v1//v2/ | ioctl 实现,导出 create_driver / destroy_driver。 | get_driver("xxx", index) 时 dlopen。 |
src/luawrapper/l_xxx.cpp | 注册 luaopen_libsoc_adapter_xxx。 | require '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
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)。
示例代码
local xxx = require 'libsoc_adapter.xxx'
xxx:init(...)
xxx:close()验证方法
- 交叉编译后确认
/opt/bmc/bcal/libxxx.so与/usr/lib64/libsoc_adapter.so已安装。 require 'libsoc_adapter.xxx'成功。- 覆盖成功路径、非法
index、设备节点缺失。 - 同步更新本文档第 2 章接口表。
注意事项
- v1/v2 若行为不同,需同时维护两套实现,并用
chipv2_enable切换。 - 每个新驱动应提供 Mock。
- 保持
luaopen符号与require模块名的对应关系。 control只用于紧急扩展,正式能力应加到 BCAL 纯虚接口中。
4. 日志说明
4.1 一键日志收集
libsoc_adapter 是动态库,不创建独立日志文件,也没有仓库内声明的 on_dump 或一键日志项。工厂把加载失败写入内存中的 driver_load_info.error_msg;驱动实现普遍通过抛出 std::runtime_error(format(...))把错误交给调用方。是否出现在系统一键日志中,取决于宿主组件的日志配置。
| 文件路径 | 内容说明 |
|---|---|
| 不适用(宿主进程日志) | 排障时应先确定调用进程(如 hwproxy、bmc_soc、runtime_accessor),再收集该进程日志。 |
get_driver_load_info() | 进程内查询最近一次 dlopen/符号解析结果,不是落盘日志。 |
4.2 关键日志信息
组件没有统一的日志级别宏。下列字符串来自工厂与 Lua 绑定中的异常 / error_msg,会出现在宿主日志或 Lua traceback 中。
| 日志片段 | 日志级别 | 含义解读 | 建议处理动作 |
|---|---|---|---|
Failed to load library: | 宿主 ERROR / Lua error | dlopen 失败。 | 检查 /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 closed | Lua error | 已 close 后继续调用。 | 避免在 __gc/close 后再用同一 userdata。 |
uart id is invalid | Lua error | UART 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/xxx,dmesg,确认内核模块已加载。 |
| 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_driver。 | get_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 driver、ioctl、libsoc_adapter 等关键字。
复现问题方法
- 确认
/usr/lib64/libsoc_adapter.so、/usr/lib64/libbcal.so、/opt/bmc/bcal/lib<drv>.so存在。 - 确认对应
/dev/*与内核模块(Hisport 为bmc_hisport_drv.ko)。 - 用第 2 章最小 Lua 示例先验证工厂加载,再验证业务参数。
- C++ 调用方打印
get_driver_list()与get_driver_load_info()。
没有 busctl 调试面。
5.4 错误对象解读
Lua API 要么返回整数/tuple,要么抛出异常字符串。C++ BCAL 写接口普遍使用 0/-1,读接口返回数据或 tuple。将 -1、errno 和 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.json的type为library,required为空。 - 解决方案:使用 Lua 示例或 C++ 工厂 API;业务对象在
bmc_soc等组件上。 - 规避方案:无。
- 适用版本:1.130.70。