编辑语:
芯片开放社区(OCC)面向开发者推出RISC-V系列内容,通过多角度、全方位解读RISC-V,系统性梳理总结相关理论知识,构建RISC-V知识图谱,促进开发者对RISC-V生态全貌的了解。
YoC基础软件平台具有丰富的IoT组件,可有效支持RISC-V生态应用开发。前几期内容中,我们已经陆续介绍了YoC的CSI组件、AT组件和AV(多媒体)组件。本期内容,我们将为大家介绍YoC的PARTITION组件,从分区表介绍、配置与接口、配置示例三方面带大家详细了解该组件。
01 概述
PARTITION组件是一个分区管理的组件。基于分区表(MTB)的分区信息来统一管理Flash分区,对分区进行统一的读写、擦除、以及验签的操作。
下面就来介绍下分区表的定义以及组件提供的一些API接口。
02 分区表介绍
分区表简称为MTB(manifest table)。保存系统镜像的基本信息以及签名值。MTB分为两类。
名称 |
说明 |
BMTB |
bootloader manifest table,记录bootloader镜像的信息,给bootrom使用 |
IMTB |
images manifest table,记录除bootloader以外的其他镜像的信息,给bootloader使用 |
其中IMTB是必须的,而BMTB则取决于芯片bootrom的设计,是否需要这张BMTB表,使用BMTB的优势是可以灵活的配置boot的地址信息,避免固化在bootrom里。这2张表本身就是以分区的形式存储在Flash中的,在定义分区的时候要预留出来。分区名字也是固定为"bmtb"和"imtb"。
分区的信息存储在一个叫config.yaml的文件中,一般放在工程的board或者solution目录下,在打包镜像的时候通过工具自动生成bmtb/imtb两个镜像。
一个典型的分区表如下:
mtb_version: 4 chip: pangu # cb2201 / cb6501 / pangu diff: fota_version: 0 ram_buf: 50 #DEC KB ( max ram need) flash_buf: 16 #DEC KB ( buffer size) flash_sector: 4096 #DEC byte ( flash sector) diff_mode: 010 #BIN double_control: 1 #DEC (1--use 2 sector for diff restore,0--1 sector) flash: base_address: 0x8000000 # the base address of flash run_base_address: 0x18000000 # the run address, maybe sdram address sector: 4096 # Bytes size: 16777216 # Bytes, $(sector count) * sector partitions: - { name: bmtb, address: 0x8000000, size: 0x001000 } - { name: boot, address: 0x8001000, size: 0x020000 } - { name: tee, address: 0x8021000, load_addr: 0x18000000, size: 0x010000 } - { name: imtb, address: 0x8031000, size: 0x002000 } - { name: prim, address: 0x8033000, load_addr: 0x18010000, size: 0x300000, verify: true, update: FULL} - { name: kv, address: 0x8633000, size: 0x004000 } - { name: lpm, address: 0x8637000, size: 0x020000 } - { name: misc, address: 0x8657000, size: 0x400000 }
下面介绍下各个字段的意思。
2.1 一级字段说明
字段 |
说明 |
mtb_version |
MTB格式版本号,默认填4即可 |
chip |
芯片类型 |
diff |
用于差分升级相关的配置参数 |
flash |
flash信息相关参数 |
partitions |
分区表相关参数 |
2.2 diff字段说明
字段 |
是否必选 |
说明 |
ram_buf |
是 |
差分还原时所需的ram空间,单位KB; 大于2.3倍flash缓存大小;建议配置为设备系统最大可用内存,以提高差分效率; 大致计算公式: ram_buf = 2.2 * <flash_buf> + 2 * <flash_sector> + 1024B; |
flash_buf |
是 |
差分还原时所需的flash缓存空间,最小4KB,单位KB; 大于扇区大小,且为扇区大小整数倍; |
flash_sector |
是 |
flash扇区大小,单位byte; |
diff_mode |
是 |
差分模式,二进制字符串,默认使用10模式即可; value verify auto_config 00 disable disable 01 disable enable 10 enable disable 11 enable enable |
double_control |
否 |
是否使用2个flash_sector作为差分控制区域; 此字段不填或者0:1个sector,1:2个sector; 如果在Flash空间上没有特别的紧张,建议使用2个sector作为差分控制区域; |
2.3 flash字段说明
字段 |
是否必选 |
说明 |
base_address |
是 |
flash的起始绝对地址 |
run_base_address |
否 |
镜像的运行地址,不填则为flash起始地址 |
sector |
是 |
flash每个sector的尺寸,单位byte |
size |
是 |
flash总的大小,单位byte |
2.4 partitions字段说明
字段 |
是否必选 |
说明 |
name |
是 |
分区名字,最长8个字节 |
address |
是 |
分区起始地址 |
load_addr |
否 |
分区加载地址,如果没有此字段,则默认使用address为加载地址 |
size |
是 |
分区大小,单位byte |
update |
否 |
分区升级类型[DIFF, FULL, NONE],不填则默认为NONE;针对boot分区的升级需要谨慎,因为本身升级的功能在boot里面。 |
verify |
否 |
是否要对分区进行签名 |
file |
否 |
指定分区对应的镜像文件名字,不填则表示文件名与分区名相同 |
2.5 常用分区说明
分区 |
说明 |
imtb |
分区表信息,包含所有分区位置及安全信息 |
tee |
安全执行镜像 |
boot |
bootloader |
prim |
应用镜像 |
kv |
用户数据区域 |
misc |
升级备份区 |
lpm |
低功耗信息保存区 |
2.6 注意事项
- bmtb分区名字固定,大小为1个sector大小,非必选分区。
- imtb分区名字固定,大小为2个sector大小,必选分区。最好放在比较靠前的地址区域,可以减少查表的时间。
- tee、prim、boot、kv分区名字固定,不建议修改,大小根据用户自己实际情况来配置,sector对齐。
- misc分区名字固定,全量和差分升级时所需要的备份分区,大小根据实际情况来配置,sector对齐。
- 其他分区大小也是sector对齐,名字用户可以自定义。
03 配置与接口介绍
介绍partition组件的一些参数配置和常用API接口。
3.1 参数配置
以下宏定义在PARTITION组件的yoc/partition.h文件中,用户可以在应用方案的package.yaml中的def_config字段中进行重新定义。
宏配置 |
说明 |
CONFIG_MAX_PARTITION_NUM |
分区个数配置。 定义最大的分区个数,如果用户没有自定义,那么默认为12个分区大小。如果ram资源比较紧张,而分区又没有达到12个,那么可以把这个宏改成实际分区个数。每减少一个分区,分别可以节省40个字节的data段size,和调用partition_init的任务最多40个字节的栈空间。 |
CONFIG_PARITION_NO_VERIFY |
分区校验配置。 是否开启分区校验功能,默认值为1,为不开启校验。 安全的方案需要配置成0。 |
CONFIG_NOT_SUPORRT_SASC |
安全区域设置配置。配置分区的访问权限。 是否支持设置安全区域,默认值为1,不支持设置安全区域。 如果芯片支持,可以在board组件中配置为0,开启此功能。 |
3.2 接口介绍
API接口定义在yoc/partition.h文件中。提供了包括分区初始化、打开、关闭、读写、Verify等操作。
整个系统中需要调用partition_init初始化一次,后面才能对分区进行一些操作。
接口 |
说明 |
partition_init |
分区初始化 |
partition_open |
打开分区 |
partition_close |
关闭分区 |
partition_info_get |
获取分区信息 |
partition_read |
读取分区数据 |
partition_write |
往分区写数据 |
partition_erase |
擦除分区数据 |
partition_verify |
校验分区 |
partition_all_verify |
校验所有分区 |
partition_get_digest |
获取分区数字摘要信息 |
partition_set_region_safe |
设置安全区域,调用此接口可以把分区配置成只在安全环境下可读写。 |
3.3 Flash操作接口适配
在yoc/partition_flash.h文件中,定义了一个partition_flash_ops_t结构体,有自定义Flash操作接口的用户可以实现这个结构体的操作接口,并通过partition_flash_register接口进行注册。
注意:系统默认带有一套基于设备驱动框架的Flash接口。如果是无操作系统的应用,则需要用户自己实现一套接口,并注册。
以下为在BOOT方案中实现Flash接口的一个例子:
#include <drv/spiflash.h> #include <yoc/partition_flash.h> static csi_spiflash_t spiflash_hd; static csi_spiflash_info_t spiflash_info; static int _boot_flash_info_get(void *handle, partition_flash_info_t *info) { if (info != NULL) { csi_error_t ret = csi_spiflash_get_flash_info(&spiflash_hd, &spiflash_info); if (ret != CSI_OK) { return -1; } info->start_addr = spiflash_info.xip_addr; info->sector_size = spiflash_info.sector_size; info->sector_count = spiflash_info.flash_size / spiflash_info.sector_size; return 0; } return -1; } static int _boot_flash_read(void *handle, uint32_t addr, void *data, size_t data_len) { int ret = csi_spiflash_read(&spiflash_hd, addr - spiflash_info.xip_addr, data, data_len); if (ret < 0) { return -1; } return 0; } static int _boot_flash_write(void *handle, uint32_t addr, void *data, size_t data_len) { int ret = csi_spiflash_program(&spiflash_hd, addr - spiflash_info.xip_addr, data, data_len); if ( ret < 0) { return -1; } return 0; } static int _boot_flash_erase(void *handle, uint32_t addr, size_t len) { csi_error_t ret; if (len % spiflash_info.sector_size) { len = (len / spiflash_info.sector_size + 1) * spiflash_info.sector_size; } ret = csi_spiflash_erase(&spiflash_hd, addr, len); if (ret) { return ret; } return 0; } static const partition_flash_ops_t g_flash_ops = { .open = NULL, .close = NULL, .info_get = _boot_flash_info_get, .read = _boot_flash_read, .write = _boot_flash_write, .erase = _boot_flash_erase }; int boot_flash_init(void) { csi_spiflash_qspi_init(&spiflash_hd, 0, NULL); partition_flash_register((void *)&g_flash_ops); return 0; }
04 配置示例
下面介绍几种方案的配置。主要是BOOT、TEE、APP三种类型的方案。其中BOOT、TEE是无操作系统的,APP是带操作系统的。
4.1 BOOT方案
BOOT方案只涉及到package.yaml的配置。
4.1.1 非安全方案
def_config: CONFIG_PARITION_NO_VERIFY: 1 CONFIG_NOT_SUPORRT_SASC: 1
4.1.2 安全方案
def_config: CONFIG_PARITION_NO_VERIFY: 0 CONFIG_NOT_SUPORRT_SASC: 0
4.2 TEE方案
TEE方案只涉及到package.yaml的配置。
def_config: CONFIG_PARITION_NO_VERIFY: 0 CONFIG_NOT_SUPORRT_SASC: 0
4.3 APP方案
APP方案涉及到package.yaml和config.yaml的配置。
4.3.1 非安全方案
非安全的方案不会对分区进行验签,没有TEE。
- config.yaml分区配置表中partitions字段的配置
partitions: - { name: bmtb, address: 0x8000000, size: 0x001000 } - { name: boot, address: 0x8001000, size: 0x020000 } - { name: imtb, address: 0x8031000, size: 0x002000 } - { name: prim, address: 0x8033000, load_addr: 0x18010000, size: 0x300000, update: FULL} - { name: kv, address: 0x8633000, size: 0x004000 } - { name: lpm, address: 0x8637000, size: 0x020000 } - { name: misc, address: 0x8657000, size: 0x400000 }
- 应用方案的package.yaml文件
def_config: CONFIG_PARITION_NO_VERIFY: 1 CONFIG_NOT_SUPORRT_SASC: 1
4.3.2 安全方案
安全方案需要对分区进行验签,需要有TEE的系统。当然还需要有OTP或者eFuse来保证验签公钥的安全可靠性。
- config.yaml分区配置表中partitions字段的配置
partitions: - { name: bmtb, address: 0x8000000, size: 0x001000 } - { name: boot, address: 0x8001000, size: 0x020000 } - { name: tee, address: 0x8021000, load_addr: 0x18000000, size: 0x010000, verify: true } - { name: imtb, address: 0x8031000, size: 0x002000 } - { name: prim, address: 0x8033000, load_addr: 0x18010000, size: 0x300000, verify: true, update: FULL} - { name: kv, address: 0x8633000, size: 0x004000 } - { name: lpm, address: 0x8637000, size: 0x020000 } - { name: misc, address: 0x8657000, size: 0x400000 }
跟非安全方案相比较,主要是多了TEE系统分区,然后对tee和prim分区进行验签配置。对需要验签的分区加上verify: true,打包工具会把这个字段保存到imtb表中,由bootloader去判断这个分区是否需要验签。
- 应用方案的package.yaml文件
def_config: CONFIG_PARITION_NO_VERIFY: 0 CONFIG_NOT_SUPORRT_SASC: 0
05 下期预告
PARTITION组件是一个轻量级的分区管理组件。用户可以根据宏进行灵活的配置,打开或者关闭某些功能。是一个适用于RTOS系统或者裸系统的功能组件。下期内容,我们将为大家介绍YoC的KV组件,欢迎大家持续关注RISC-V系列内容。