4.3.27. boardinfo 调试指南
4.3.27.1. 概述
boardinfo 驱动为上层软件提供了获取板级信息的接口。本文档将详细介绍 boardinfo 驱动的功能,并提供 sysfs 和 userspace API 两种访问方式。
4.3.27.2. 功能描述
boardinfo 驱动具备以下主要功能:
读取关键硬件信息,包括芯片型号、名称、版本号、启动方式、SOC ID 及 DDR 信息等。
配置下次启动时使用的 BAK slot,以便在系统启动时切换到指定的备份状态。
通过以上功能,boardinfo 驱动能够为系统提供实时和准确的板级信息,确保系统运行的稳定性和可靠性。
接口名称统一命名与 userspace API 返回值跟踪表(X5为例)
| 接口名称 | 接口功能 | 接口权限 | userspace API 结果类型 | 返回值 |
|---|---|---|---|---|
| soc_gen | 查看芯片型号 | RO | 字符串 | X5 |
| soc_name | 查看芯片名称,包括子型号 | RO | 字符串 | X5M X5H UKNOWN |
| hw_name | 查看硬件板子名称 | RO | 字符串 | x5-fpga x5-soc x5-svb x5-evb |
| board_version | 查看硬件板子版本号 | RO | 字符串 | v1 v2 v3 |
| hw_info | 查看硬件板子全名称 (由<hw_name>-<board_version>-<ddr_vendor>-<ddr_size>-<ddr_freq>组成) |
RO | 字符串 | x5-evb-v2-cxmt-2048MB-4266 ... |
| bootdevice_name | 查看启动方式 | RO | 字符串 | emmc sd nand |
| soc_uid | 查看 SOC 的 ID 号 | RO | 字符串 | soc唯一id |
| ddr_vendor | 查看 DDR 厂商 | RO | 字符串 | DDR厂商 |
| ddr_type | 查看 DDR类型,如LPDDR4或LPDDR4X | RO | 字符串 | LPDDR4 LPDDR4X |
| ddr_freq | 查看 DDR最高速率,单位Mbps | RO | 字符串 | 3200 Mbps 3733 Mbps 4266 Mbps |
| ddr_size | 查看 DDR容量,单位MB | RO | 字符串 | 1024MB 2048MB 4096MB 8192MB |
| board_id | 查看硬件板子 ID | RO | 字符串 | 当前board_id,以十六进制形式打印 |
| sec_chip | 查看是否是secure芯片 | RO | 字符串 | 未烧key的芯片: nosec_chip 烧地瓜key的芯片: sec_chip1 烧客户自己public key hash的芯片: sec_chip2 |
| sec_boot | 查看是否开启AVB和dm-verity校验 | RO | 字符串 | enable disable |
| bak_slot | 读:当前启动的 BAK slot; 写:设置下次启动的 BAK slot |
R/W | 字符串 | 0 1 |
如何烧客户自己的public key hash,请参考X5 Customer root rsa key hash烧录及使用
4.3.27.3. 驱动代码
socinfo 驱动代码位于 kernel/drivers/soc/hobot/socinfo/socinfo.c,主要功能如下:
读取 DTS 配置文件中配置的板级信息,并保存到对应变量中。
if (read_from_property(pdev, "soc_gen", &soc_gen) ||
read_from_property(pdev, "soc_name", &soc_name) ||
read_from_property(pdev, "hw_name", &hw_name) ||
read_from_property(pdev, "board_version", &board_version) ||
read_from_property(pdev, "hw_info", &hw_info) ||
read_from_property(pdev, "bootdevice_name", &bootdevice_name) ||
read_from_property(pdev, "soc_uid", &soc_uid) ||
read_from_property(pdev, "board_id", &board_id) ||
read_from_property(pdev, "sec_chip", &sec_chip) ||
read_from_property(pdev, "sec_boot", &sec_boot)) {
return -1;
}
实现 sysfs 接口,提供上层软件获取板级信息的接口。
static struct class_attribute soc_gen_attribute =
__ATTR(soc_gen, 0444, soc_gen_show, NULL);
static struct class_attribute soc_name_attribute =
__ATTR(soc_name, 0444, soc_name_show, NULL);
static struct class_attribute hw_name_attribute =
__ATTR(hw_name, 0444, hw_name_show, NULL);
static struct class_attribute board_version_attribute =
__ATTR(board_version, 0444, board_version_show, NULL);
static struct class_attribute hw_info_attribute =
__ATTR(hw_info, 0444, hw_info_show, NULL);
static struct class_attribute bootdevice_name_attribute =
__ATTR(bootdevice_name, 0444, bootdevice_name_show, NULL);
static struct class_attribute soc_uid_attribute =
__ATTR(soc_uid, 0444, soc_uid_show, NULL);
static struct class_attribute ddr_vender_attribute =
__ATTR(ddr_vendor, 0444, ddr_vender_show, NULL);
static struct class_attribute ddr_type_attribute =
__ATTR(ddr_type, 0444, ddr_type_show, NULL);
static struct class_attribute ddr_freq_attribute =
__ATTR(ddr_freq, 0444, ddr_freq_show, NULL);
static struct class_attribute ddr_size_attribute =
__ATTR(ddr_size, 0444, ddr_size_show, NULL);
static struct class_attribute board_id_attribute =
__ATTR(board_id, 0444, board_id_show, NULL);
static struct class_attribute sec_chip_attribute =
__ATTR(sec_chip, 0444, sec_chip_show, NULL);
static struct class_attribute sec_boot_attribute =
__ATTR(sec_boot, 0444, sec_boot_show, NULL);
static struct class_attribute bak_slot_attribute =
__ATTR(bak_slot, 0644, bak_slot_show, bak_slot_store);
“soc_gen” 和 “soc_name” 需要在 Kernel DTS 文件中配置,路径是kernel/arch/arm64/boot/dts/hobot/x5.dtsi,节点名为 “socinfo”。
当前在 kernel dts 中 "hw_name" 和 "board_version" 的占位符长度为16字节,"hw_info" 的占位符长度为32字节,如果对应的字段超出了占位符的长度,将会导致 socinfo 此驱动初始化失败。

“board_id”、”hw_name”、”board_version” 等信息需要在 Uboot DTS 文件中配置,路径是uboot/arch/arm/dts/x5.dtsi,节点名为 “board_type”。
DTS 中的 board_type_array 字段对应 “board_id”,board_id 相关修改请参考修改 Board ID 的宏定义。
hardward_array 字段对应 “hw_name”,board_version 字段对应 “board_version”。

4.3.27.4. 功能使用
sysfs 接口
sysfs 接口路径位于 /sys/class/socinfo/,目前支持以下信息的获取:
例如要查看板级接口信息,可在命令行执行以下命令:
#查看芯片型号
root@buildroot:~# cat /sys/class/socinfo/soc_gen
x5
#查看芯片名称
root@buildroot:~# cat /sys/class/socinfo/soc_name
X5M
#查看硬件板子名称
root@buildroot:~# cat /sys/class/socinfo/hw_name
X5_EVB_LP4
#查看硬件板子版本号
root@buildroot:~# cat /sys/class/socinfo/board_version
1_B
#查看硬件板子全名称
root@buildroot:~# cat /sys/class/socinfo/hw_info
X5_EVB_LP4_1_B_cxmt_4096MB_4266
#查看启动方式
root@buildroot:~# cat /sys/class/socinfo/bootdevice_name
emmc
#查看SOC的ID号
root@buildroot:~# cat /sys/class/socinfo/soc_uid
0x308064960e31499301f0822400000000
#查看DDR厂商
root@buildroot:~# cat /sys/class/socinfo/ddr_vendor
cxmt
#查看DDR类型
root@buildroot:~# cat /sys/class/socinfo/ddr_type
LPDDR4
#查看DDR最高速率
root@buildroot:~# cat /sys/class/socinfo/ddr_freq
4266 Mbps
#查看DDR容量
root@buildroot:~# cat /sys/class/socinfo/ddr_size
4096MB
#查看硬件板子 ID
root@buildroot:~# cat /sys/class/socinfo/board_id
0x0202
#查看芯片secure类型
root@buildroot:~# cat /sys/class/socinfo/sec_chip
sec_chip1
#查看是否开启secure boot
root@buildroot:~# cat /sys/class/socinfo/sec_boot
enable
#查看当前启动的 BAK slot
root@buildroot:~# cat /sys/class/socinfo/bak_slot
0
#设置下次启动的 BAK slot
root@buildroot:~# echo 1 > /sys/class/socinfo/bak_slot
root@buildroot:~# reboot
root@buildroot:~# cat /sys/class/socinfo/bak_slot
1
注意:如果芯片名称 soc_name 是 UKNOWN,则属于是早期出厂芯片,未在eFUSE中烧写对应bit,需要根据芯片丝印区分芯片类型。
hw_info 由 <hw_name>-<board_version>-<ddr_vendor>-<ddr_size>-<ddr_freq> 组成:
hw_name: X5_EVB_LP4
board_version: 1_B
ddr_vendor: cxmt
ddr_size: 4096MB
ddr_freq: 4266
userspace API 接口
源码路径:hbre/hbutils/boardinfo
头文件: boardinfo.h
链接库: libboardinfo.so.1
接口定义
hb_get_boardinfo
【函数声明】
int32_t hb_get_boardinfo(char *key, void *dst, uint32_t len);
【参数描述】
[OUT] key: 要获取的板级信息
[OUT] dst: 接收结果的缓存空间
[IN] len: 缓存空间最大长度
【返回值】
HB_BINFO_SUCCESS:成功
HB_BINFO_INVALID_PARAM: 非法参数,如空指针
HB_BINFO_SHORT_BUF: 缓存空间过小
HB_BINFO_PLAT_NOT_SUPPORT: 本平台不支持的板级信息
【功能描述】
获取板级信息 key,结果将存入 dst,并返回错误代码。
动态库接口返回的错误类型
动态库错误值定义如下:
enum hb_binfo_retval {
HB_BINFO_SUCCESS,
HB_BINFO_INVALID_PARAM,
HB_BINFO_SHORT_BUF,
HB_BINFO_PLAT_NOT_SUPPORT,
};
示例代码
调用 userspace API 接口时,需先链接动态库,示例代码如下:
#include <stdio.h>
#include <stdint.h>
#include "boardinfo.h"
int main(void) {
int32_t ret;
char buf[1024];
ret = hb_get_boardinfo("soc_gen", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("soc_gen:%s\n", buf);
}
ret = hb_get_boardinfo("soc_name", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("soc_name:%s\n", buf);
}
ret = hb_get_boardinfo("hw_name", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("hw_name:%s\n", buf);
}
ret = hb_get_boardinfo("board_version", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("board_version:%s\n", buf);
}
ret = hb_get_boardinfo("hw_info", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("hw_info:%s\n", buf);
}
ret = hb_get_boardinfo("bootdevice_name", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("bootdevice_name:%s\n", buf);
}
ret = hb_get_boardinfo("soc_uid", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("soc_uid:%s\n", buf);
}
ret = hb_get_boardinfo("ddr_type", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("ddr_type:%s\n", buf);
}
ret = hb_get_boardinfo("ddr_size", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("ddr_size:%s\n", buf);
}
ret = hb_get_boardinfo("ddr_vendor", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("ddr_vendor:%s\n", buf);
}
ret = hb_get_boardinfo("ddr_freq", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("ddr_freq:%s\n", buf);
}
ret = hb_get_boardinfo("board_id", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("board_id:%s\n", buf);
}
ret = hb_get_boardinfo("sec_chip", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("sec_chip:%s\n", buf);
}
ret = hb_get_boardinfo("sec_boot", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("sec_boot:%s\n", buf);
}
ret = hb_get_boardinfo("board_id", buf, 2);
if (ret == 0) {
printf("hb_get_boardinfo test HB_BINFO_SHORT_BUF failed\n");
} else {
printf("hb_get_boardinfo test HB_BINFO_SHORT_BUF pass\n");
}
ret = hb_get_boardinfo("bak_slot", buf, 1024);
if (ret) {
printf("hb_get_boardinfo failed, ret:%d\n", ret);
} else {
printf("bak_slot:%s\n", buf);
}
ret = hb_get_boardinfo(NULL, buf, 1024);
if (ret == 0) {
printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM failed\n");
} else {
printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM pass\n");
}
ret = hb_get_boardinfo("xx", buf, 1024);
if (ret == 0) {
printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM failed\n");
} else {
printf("hb_get_boardinfo test HB_BINFO_INVALID_PARAM pass\n");
}
return 0;
}
4.3.27.5. 常见问题
使用 userspace API 接口时,如果传入的 key 值不存在,则返回 HB_BINFO_INVALID_PARAM 错误,此时 dst 指针不会被修改,需要检查返回值是否为 0。