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_banks

支持特性如下

  • 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 是否烧录 eFuse

    • 1 : 表示 bypass

    • 0 : 表示 bl2 将烧录 eFuse

  • secure_boot: 是否开启 secure boot,对应 eFuse 的 non-secure bank10 bit0

    • false : 表示不开启 secure boot

    • true : 表示开启 secure boot,开启会将 Uboot 公钥的 hash 烧写到 eFuse secure region bank13~20

  • debug_disable: 是否禁止 debug port,对应 eFuse 的 non-secure bank10 bit1

    • false : 表示开启 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,包括 aonhsiolsiodsp

    • gpio_group: 表示 GPIO 的 group

    • gpio_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_dump

读取 eFuse 指定 bank 值

uboot 读取 eFuse 指定 bank 值命令格式 efuse read [type] [bank_index] 参数说明

  • type: secure 表示是读取 secure region, nonsecure 表示读取 non-secure region

  • bank_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 region

  • bank_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 命令中,其控制时序如下 :

    1. 先将该 aon gpio0_7 拉高,给 eFuse 上电

    2. 等待 1S,待 eFuse 电源稳定之后,再写 eFuse

    3. 写 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 参考

数据结构

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