butterfli的片上ROM包含一个安全引导加载 (bootloader),其特性有:
- UART下载
- 使用AES加密传输image文件,Flash上可保存加密image,由硬件实时解密执行,也支持明文image
- 加密保存image密钥,即使复制了加密image,也无法在一颗不同的butterfli芯片上执行
- 使用RSA数字签名验证image文件完整性,防止下载非法的image文件
- PingPong下载
- 安装Patch,修改Flash驱动
密钥
bootloader使用的密钥有:
- rootkey: 保存于efuse的不可读区域,用于加密image密钥
- image密钥: image加解密使用的密钥,经rootkey加密后保存于Flash
- 数字签名RSA公钥: 用于解密验证image身份和完整性
- UID: 芯片ID,保存于efuse的可读区域,作为nonce参数加密image密钥
image的加密下载过程:
- 将rootkey、数字签名公钥的hash和UID写入efuse (只需一次)
- 下载Flash配置表和数字签名公钥到Flash (只需一次)
- 使用image密钥对image进行加密,使用SHA256计算加密后数据的hash,使用数字签名私钥加密hash得到数字签名, image header(使用rootkey加密,包含image密钥等信息)、加密image和数字签名三者打包生成最终的加密image
- 传输加密image,bootloader从image header中提取image密钥对image进行解密,接收完成后比对数字签名确认来源并验证完整性,若合法则下载成功
启动模式
可以通过bootmode跳线设置bootloader的启动模式,若跳线接0,则为正常启动,bootloader读取flash判断是否可以引导用户程序,若跳线接1,则进入下载模式,等待PC发送下载命令, 在正常启动模式如果发现flash上没有有效的用户image,则自动进入下载模式
Memory规划
默认的Flash地址空间规划
| 名称 | 起始地址 | 结束地址 | 大小(字节) | 描述 |
| Flash配置表 | 0x10000000 | 0x10004FFF | 20*1024 | |
| 校准表 | 0x10005000 | 0x10006FFF | 8*1024 | |
| 保留 | 0x10007000 | 0x1000FFFF | 36*1024 | |
| bootrom patch | 0x10010000 | 0x1001FFFF | 64*1024 | |
| User Code | 0x10020000 | | | |
其中Flash配置表的位置和格式不可修改,其他表项的地址和大小由Flash配置表指定
Flash配置表格式
| 名称 | 起始偏移 | 结束偏移 | 大小(字节) | 描述 |
| MAGIC | 0x00000000 | 0x00000003 | 4 | 0x53454346 |
| Flash分区表 | 0x00000004 | 0x00000103 | 16*16 | 16个分区 |
| 数字签名公钥 | 0x00000104 | 0x00000229 | 294 | DER格式的RSA公钥 |
| 保留 | 0x0000022A | 0x00000FFF | 3542 | |
| image描述表 | 0x00001000 | 0x00002BFF | 14*512 | 14个image描述条目, |
| image索引表 | 0x00002C00 | 0x00002C0F | 4*4 | 指向激活(当前运行 )的image描述表条目 |
Flash分区表由16个分区信息组成,每个分区信息指定分区的起始地址和大小
分区表
| 索引 | 名称 | 描述 |
| 0 | Flash分区表 | |
| 1 | 校准表 | |
| 2 | LCPU image Ping区 | |
| 3 | BCPU image Ping区 | |
| 4 | HCPU image Ping区 | |
| 5 | Flash Boot patch区 | |
| 6 | LCPU image Pong区 | |
| 7 | BCPU image Pong区 | |
| 8 | HCPU image Pong区 | |
| 9 | RAM Boot patch区 | |
| 10 | HCPU image扩展区1 | |
| 11 | HCPU image扩展区2 | |
| 12 | LCPU image扩展区1 | |
| 13 | LCPU image扩展区2 | |
| 14 | 保留 | |
| 15 | 保留 | |
分区信息格式
| 名称 | 大小(字节) | 描述 |
| 分区起始地址 | 4 | 分区的起始地址 |
| 分区大小 | 4 | 分区大小 |
| 分区执行地址 | 4 | 对于image分区,指定该分区的执行地址 |
| 标志 | 4 | 未使用 |
下表为默认的Flash配置表,struct sec_configuration是Flash配置表的数据结构名
const struct sec_configuration sec_config =
{
.magic = SEC_CONFIG_MAGIC,
.ftab[0] = {.base = 0x10000000, .size = 20*1024, .xip_base = 0, .flags = 0},
.ftab[1] = {.base = 0x10005000, .size = 8*1024, .xip_base = 0, .flags = 0},
.ftab[4] = {.base = 0x10020000, .size = 0x80000, .xip_base = 0x10020000, .flags = 0},
.ftab[5] = {.base = 0x10010000, .size = 64*1024, .xip_base = 0x10010000, .flags = 0},
.ftab[8] = {.base = 0x10020000, .size = 0x80000, .xip_base = 0x10020000, .flags = 0},
.ftab[9] = {.base = 0x20050000, .size = 64*1024, .xip_base = 0x20050000, .flags = 0},
.imgs[0] = {.length = 0xFFFFFFFF},
.imgs[1] = {.length = 0xFFFFFFFF},
.imgs[2] = {.length = 0x80000, .blksize = 512, .flags = DFU_FLAG_AUTO},
.imgs[3] = {.length = 0xFFFFFFFF},
.imgs[4] = {.length = 0xFFFFFFFF},
.imgs[5] = {.length = 0xFFFFFFFF},
.imgs[6] = {.length = 0xFFFFFFFF},
.imgs[7] = {.length = 0xFFFFFFFF},
.imgs[8] = {.length = 0xFFFFFFFF},
.imgs[9] = {.length = 0xFFFFFFFF},
.imgs[10] = {.length = 0xFFFFFFFF},
.imgs[11] = {.length = 0xFFFFFFFF},
.imgs[12] = {.length = 0xFFFFFFFF},
.imgs[13] = {.length = 0xFFFFFFFF},
.running_imgs[0] = (struct image_header_enc *)0xFFFFFFFF,
.running_imgs[1] = (struct image_header_enc *)0xFFFFFFFF,
.running_imgs[2] = (struct image_header_enc *) &sec_config.imgs[2],
.running_imgs[3] = (struct image_header_enc *)0xFFFFFFFF,
};
Bootrom使用下表所示的RAM地址空间,当使用bootrom引导用户程序在RAM中执行时,需要避免地址空间冲突
bootloader RAM地址空间
| 名称 | 起始地址 | 结束地址 | 大小(字节) | 描述 |
| DATA | 0x20040000 | 0x2004FFFF | 64*1024 | Bootrom数据 |
| PATCH CODE | 0x20050000 | 0x2005FFFF | 64*1024 | Patch代码 |
| PATCH DATA | 0x20060000 | 0x2006FFFF | 64*1024 | Patch数据 |
加密image的生成与下载
不使用bootloader下载
使用JTAG下载SDK提供的默认Flash配置表到0x10000000地址,再下载未加密的用户image到地址0x10020000,复位后bootloader即可引导用户image运行,用户image使用0x10020000地址编译
使用bootloader下载
相关工具在$sdk_root/tools/secureboot下,bootloader使用芯片的UART4作为下载串口
生成密钥
执行脚本genkeys.bat生成UID、rootkey、数字签名密钥和公钥hash,
sifli01为生成密钥的路径,运行后会生成如下几个文件
| 名称 | 描述 |
| s01.bin | rootkey |
| uid.bin | rootkey |
| sig_hash.bin | 数字签名公钥hash |
| sig_pri.pem | 数字签名私钥 |
| sig_pub.pem | 数字签名公钥 |
| sig_pub.der | DER格式的数字签名公钥 |
烧写密钥
将密钥烧写到efuse中只能执行一次,烧写后无法再修改efuse中的密钥
- 将butterfli的bootmode跳线设为下载模式
- 复位后进入bootloader下载模式
- 运行脚本
program_efuse.bat烧写密钥,第一个参数为密钥所在路径,第二个参数为串口号 program_efuse.bat sifli01/ COM3
- 复位芯片,使得密钥被正确加载
下载Flash配置表
- 进入bootloader下载模式
- 运行脚本
factory_flash_default.bat下载flash配置表(ftab\ftab_flash_default.json)和数字签名公钥,第一个参数为密钥所在路径,第二个参数为串口号 factory_flash_default.bat sifli01/ COM3
如果Flash配置表没有变化,更新image时不需要再次下载
生成image
加密image
运行gen_sec_img.bat,第一个参数为密钥所在路径,第二个参数为待加密的image路径,生成的加密image名为image_sec.bin
gen_sec_img.bat sifli01/ example.bin
明文image
运行gen_plain_img.bat,第一个参数为密钥所在路径,第二个参数为待加密的image路径,生成的加密image名为image_plain.bin
gen_plain_img.bat sifli01/ example.bin
下载image
加密image
运行download_sec_image.bat, 指定的port为bootloader所使用的串口
download_sec_image.bat --port=COM3
明文image
运行download_plain_image.bat,指定的port为bootloader所使用的串口
download_plain_image.bat --port=COM3