X5 eFuse 介绍
以下关于开启secure boot要烧写secure bank13-20,non secure bank10的bit0的介绍,仅针对于由地瓜key对BL2加密签名的芯片,如果是由客户key签名BL2的芯片(X5 Customer root rsa key hash烧录及使用),可以忽略对应部分
概述
eFuse(电子熔丝)是一种可编程的非易失性存储技术,广泛用于各种硬件平台上,如微控制器( MCU)、处理器、嵌入式设备、 SoC(系统级芯片)等。 eFuse 通过电子方式进行编程,能够存储和保护敏感信息,且具有在编程后不可更改的特性。
eFuse 通常用于存储设备的安全密钥、配置参数、设备标识符、校准数据等重要信息。
X5 eFuse 特性
X5 eFuse 分为 secure bank 和 non-secure bank,每个 region 有 32 个 bank,每个 bank 是 32bit,即每个 region 有 128Byte。其布局如下

支持特性如下
eFuse 比特位默认均为 0,可以从 0 写为 1 ,但不能从 1 写为 0 (eFuse 硬件特性)
用户可烧写的区域
| 区域 | bank | 用途 | 备注 |
|---|---|---|---|
| secure | 13 - 20 | 公钥hash 对应文件 bl2_rot_prikey.pem |
当使用客户的 key 签名 BL2,这些 bank 由客户自由定义 考虑到安全问题,这些 bank 写过数据不为0后,不论是否 lock,都不允许再次写入了 |
| secure | 25 - 28 | 用户的 user root aes key | |
| non-secure | 10 | 配置开启 secure boot 和 关闭 JTAG | 当使用客户的 key 签名 BL2,bit0 由客户自由定义 |
| non-secure | 11 - 13 | 用户自定义数据 | 在没有 lock 的情况下,这些 bank 中未更新为1的 bit,仍然可以继续更新 |
特殊 bank 说明
secure 和 non-secure region 的 bank0 的每个 bit 表示对应的 bank 是否被 lock, 1 表示 lock, 0 表示没有 lock.
non-secure bank10 用于设置 secure boot 和 JTAG 使能开关,其定义如下
| 比特位 | 功能描述 | 定义 | 默认值 |
|---|---|---|---|
| bit0 | enable secure boot | 0 : 关闭 secure boot 1 : 开启 secure boot | 0 |
| bit1 | disable debug port | 0 : 开启 JTAG 1 : 关闭 JTAG | 0 |
eFuse 的烧录(读写),可通过以下三个阶段
BL2 烧录 eFuse
eFuse 配置文件
eFuse 的配置信息位于 BL2 CFG 文件中,文件路径为 device/horizon/x5/board_cfg/soc/bl2_cfg/bl2_cfg.json。
其内容如下所示:
{
"bl2_cfg": {
...
},
"efuse_cfg": {
"bypass": 1,
"secure_boot": "false",
"debug_disable": "false",
"burn_user_rot_key": "false",
...
},
"nonsecure_bank": {
"bank11":["0x0"],
"bank12":["0x0"],
"bank13":["0x0"]
},
}
参数说明
bypass: bl2 是否烧录 eFuse1 : 表示 bypass
0 : 表示 bl2 将烧录 eFuse
secure_boot: 是否开启 secure boot,对应 eFuse 的 non-secure bank10 bit0false : 表示不开启 secure boot
true : 表示开启 secure boot,开启会将 Uboot 公钥的 hash 烧写到 eFuse secure region bank13~20
debug_disable: 是否禁止 debug port,对应 eFuse 的 non-secure bank10 bit1false : 表示开启 debug port
true : 表示禁止 debug port
burn_user_rot_key: 是否要烧写 user root aes key。对应的 key 文件位于device/horizon/x5/board_cfg/soc/bl2_cfg/user_root.key,同时注意为小端格式nonsecure_bank: 要烧写的 non-secure bank11/12/13 的值
注意:
在烧写 eFuse 之后,相应的 bank 都会被 lock
BL2 CFG 会被打包到镜像中,如果要烧录 user root aes key,直接将 key 保存到外部 storage,如 eMMC 中并不安全,推荐使用以下方法:
在 Linux 下调用接口的形式更新 key
通过 UART/USB 形式下载 miniboot 更新 key,路径位于
out/product/uart_usb,并妥善保存该文件夹。
eFuse 电源控制与烧录状态
eFuse 烧录状态
BL2 可以通过一个 GPIO 指示烧录成功或失败的状态。如烧写成功拉高该 GPIO,烧写失败保持为低,在硬件上可通过外接 LED 用于显示 eFuse 烧录状态。
以 device/horizon/x5/board_cfg/soc/bl2_cfg/bl2_cfg.json 为例,通过 efuse_cfg 配置 :
{
"bl2_cfg": {
...
},
"efuse_cfg": {
"bypass": 1,
"secure_boot": "false",
"debug_disable": "false",
"burn_user_rot_key": "false",
"status_gpio" : {
"gpio_sub": "none",
"gpio_group": 0,
"gpio_num": 0
},
"delay_before_efuse": 0,
"delay_after_efuse": 0
},
...
}
status_gpio字段表示用于指示 eFuse 烧写状态的 GPIO 信息,其可配置参数如下gpio_sub: 表示 GPIO 所在的 subsystem,包括aon,hsio,lsio,dspgpio_group: 表示 GPIO 的 groupgpio_num: 表示 GPIO 号polarity:可选参数,表示 GPIO 的默认值, default_low 默认为低, default_high 默认为高,该字段不写时,选择为 default_low
delay_before_efuse: 烧写前操作power_gpio后到真正烧写 eFuse 的延迟时间,单位 ms,目的是为了保证在烧写之前 eFuse 电源是稳定的默认配置为 0 时,延迟时间为 1s
这个时间只有在真正烧写 eFuse 时才会起作用。例如在产线烧录固件后第一次启动, BL2 将要烧录 eFuse,此时延时时间起作用,之后再次启动由于不会重复烧写 eFuse,因此这个延时时间也就失效了
delay_after_efuse: 表示烧写完成之后的动作,其定义如下
| delay_after_efuse | 烧写完成之后的行为 |
|---|---|
| 0 | 烧写成功代码继续执行,烧写失败停止 |
| -1 | 烧写成功与否,代码都停止 |
| 正值 | 烧写失败代码停止,成功则 delay 一段时间,单位 ms |
| 负值(不包括 -1 ) | 烧写成功失败都 delay 一段时间,单位 ms |
eFuse 电源控制
在硬件设计时 eFuse 默认电源关闭,只有在烧写 eFuse 的阶段才上电, BL2 在烧录 eFuse 之前会操作一个 GPIO(如拉高电平)来通知外部给 eFuse 上电,烧录完成后再次操作一次(如拉低)来通知烧录完毕, eFuse 应下电。
注意: X5 默认使用的是 aon gpio0_7 控制 eFuse 电源,如果使用其他 GPIO,则需要添加特殊字段 power_gpio 描述该信息
如下所示,使用方法和 status_gpio 字段类似。
{
"bl2_cfg": {
...
},
"efuse_cfg": {
...
"power_gpio" : {
"gpio_sub": "none",
"gpio_group": 0,
"gpio_num": 0
},
...
},
...
}
使用示例
示例 : 以 aon gpio0_7 为 power GPIO,hsio1_1 为 state GPIO ,两个 GPIO 默认值都是低,则最终的状态如下
| power GPIO | status | 描述 |
|---|---|---|
| 先拉高再拉低 | 拉高 | 烧写成功 |
| 先拉高再拉低 | 拉低 | 烧写失败 |
| 一直未拉高 | x | 未进入烧写 eFuse 流程,如上电失败 |
uboot 读写 eFuse
在 uboot 命令支持读写 eFuse,支持三个 eFuse 命令 dump, read 和 write。
读取 eFuse
uboot 读取 eFuse 信息命令 efuse dump
该命令用于读取 socid, public key hash 和 non-secure 区域的值

读取 eFuse 指定 bank 值
uboot 读取 eFuse 指定 bank 值命令格式 efuse read [type] [bank_index]
参数说明
type: secure 表示是读取 secure region, nonsecure 表示读取 non-secure regionbank_index: 表示要读取的 bank 的 index, 16 进制形式
注意: 可读区域
secure region 的 bank0 , bank13~bank20 可以读
non secure region 的所有 bank 均可读
执行命令后,将返回相应 bank 的值以及它的 lock 状态
Hobot>efuse read nonsecure 0xc
value:0xabcdef12
lock:true
Hobot>efuse read secure 0x13
value:0xed3137
lock:true
写入 eFuse
该命令用于写入 eFuse 相应 bank,命令格式如下
efuse write [type] [bank_index] [bank_value] [lock_status]
type: secure 表示写 secure region, nonsecure 表示写 non-secure regionbank_index: 表示要写的 bank 的 index, 16 进制形式bank_value: 表示要写的 bank 的 value, 16 进制形式lock_status: 烧写之后是否要 lock, 取值范围 lock/unlock
注意: 可读区域
secure region 的 bank13~bank20 , bank25~bank28 可写
non-secure region 的 bank10/11/12/13 可写。
示例: 将 0x1eff5f0d 写入 secure region bank20
Hobot>efuse write secure 0x14 0x1eff5f0d lock
write SECURE bank:0x14 success
注意事项
执行 efuse write 命令之后,需要在重启之后才能读到正确的数据
eFuse 电源默认是关闭状态,通过
aon gpio0_7来控制,在 efuse write 命令中,其控制时序如下 :先将该
aon gpio0_7拉高,给 eFuse 上电等待 1S,待 eFuse 电源稳定之后,再写 eFuse
写 eFuse 完成,控制 GPIO 下电
示例: 将 user root aes key 写入 secure bank 25 - 28
烧录 user root aes key,对应的 key 文件位于 device/horizon/x5/board_cfg/soc/bl2_cfg/user_root.key,同时注意为小端格式
$ hexdump user_root.key -C
00000000 78 56 34 12 89 67 45 23 9a 78 56 34 ab 89 67 45 |xV4..gE#.xV4..gE|
00000010
user root aes key 的内容如上,则对应烧录
secure bank[25]=0x12345678
secure bank[26]=0x23456789
secure bank[27]=0x3456789a
secure bank[28]=0x456789ab
Linux 读写 eFuse
在 Linux 中提供了接口用于读写 eFuse,动态库是 libefuse.so,头文件是 drobot_efuse.h
API 参考
drobot_efuse_read : 读 eFuse 接口
drobot_efuse_write : 写 eFuse 接口
数据结构
efuse_type
enum efuse_type 表示 efuse 的类型
| 名称 | 含义 |
|---|---|
| EFUSE_SECURE | secure region |
| EFUSE_NONSECURE | non-secure region |
efuse_info
struct efuse_info 是描述 efuse 某个 bank 信息的结构体
| 名称 | 类型 | 最小值 | 最大值 | 默认值 | 含义 |
|---|---|---|---|---|---|
| type | efuse_type | - | - | - | efuse 的类型 |
| bank | uint32_t | - | - | - | bank 的 index 值 |
| value | uint32_t | - | - | - | bank 的 value 值 |
| lock | bool | - | - | - | 该 bank 是否 lock |
接口说明
drobot_efuse_read
【函数声明】
int drobot_efuse_read(struct efuse_info *efuse);
【功能描述】
用于读 eFuse 某个 bank 的值
【参数描述】
[IN] struct efuse_info *efuse : 要读取的 efuse bank 属性结构体指针, efuse bank 属性结构体为 efuse_info
【返回值】
成功,返回 0
失败:异常为负值
drobot_efuse_write
【函数声明】
int drobot_efuse_write(struct efuse_info *efuse);
【功能描述】
用于写 eFuse 某个 bank 的值
【参数描述】
[IN] struct efuse_info *efuse : 要写入的 efuse bank 属性结构体指针, efuse bank 属性结构体为 efuse_info
【返回值】
成功,返回 0
失败:异常为负值
示例: 将 user root aes key 写入 secure bank 25 - 28
烧录 user root aes key,对应的 key 文件位于 device/horizon/x5/board_cfg/soc/bl2_cfg/user_root.key,同时注意为小端格式
$ hexdump user_root.key -C
00000000 78 56 34 12 89 67 45 23 9a 78 56 34 ab 89 67 45 |xV4..gE#.xV4..gE|
00000010
user root aes key 的内容如上,则对应烧录
secure bank[25]=0x12345678
secure bank[26]=0x23456789
secure bank[27]=0x3456789a
secure bank[28]=0x456789ab
注意事项
开启 secure boot 的操作顺序
以下仅针对于烧了地瓜KEY的芯片,如果是烧的是客户自己的KEY,请跳过
non secure bank10 的 bit0 用于开启 secure boot,开启后启动阶段将验证各个阶段镜像。如果没有烧写公钥 hash (即 secure region bank13~20 ),将导致验证失败。所以开启 secure boot 之前要先烧写公钥 hash。
公钥的 hash 数据保存在 BSP 路径
out/deploy/uboot/pubkey-hash.txt,可以在 uboot 阶段烧入 secure region bank13~20 。
强制开启 debug port
non secure bank10 的 bit1 用于关闭 debug port,若烧写 eFuse 将其关闭之后,仍然需要开启 debug,可通过 BL2 CFG 的 socid 白名单机制进行开启。
注意: 最多支持100个 socid 白名单
通过以下命令获取 socid
hrut_socuid
将 socid 填充到 BL2 CFG 文件中
{
"bl2_cfg": {
"feature": {
...
},
"efuse_cfg": {
.....
},
"socid":["0x12345678123456781234567812345678","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0",
"0x0","0x0", "0x0", "0x0", "0x0","0x0", "0x0", "0x0", "0x0", "0x0"]
}
}
编译之后,再次烧写镜像,将会开启 debug port