FLASH 分区管理
概述
partition(分区管理)是基于imtb(image mtb)里的分区信息来统一管理flash分区的接口。它能够统一管理flash分区信息,并对分区进行统一的读写以及擦除的操作。
分区定义
分区说明
分区信息保存在每个board
组件的config
中, 例如boards/pangu/config/config.yaml
该文件为文本格式可打开查看分区情况。
分区示例
mtb_version: 4
chip: yunvoice
diff:
digest_type: SHA1
signature_type: RSA1024
fota_version: 0
ram_buf: 50 #DEC KB ( max ram need)
flash_buf: 8 #DEC KB ( buffer size)
flash_sector: 4096 #DEC byte ( flash sector)
diff_mode: 010 #BIN
double_control: 1
flash:
base_address: 0
run_base_address: 0x40000000 # base address of Storage
sector: 4096 # Bytes
size: 8388608 # $(sector count) * sector
partitions:
- { name: boot, address: 0x000000, load_addr: 0x20000, size: 0x01E000, verify: true }
- { name: imtb, address: 0x01E000, size: 0x001000 }
- { name: ai, address: 0x020000, size: 0x080000, load_addr: 0x40600000, update: DIFF, verify: true }
- { name: prim, address: 0x0A0000, size: 0x200000, load_addr: 0x40000000, update: DIFF, verify: true }
- { name: kv, address: 0x2A0000, size: 0x008000 }
- { name: spiffs, address: 0x2A8000, size: 0x200000 }
一级字段说明
字段 | 说明 |
---|---|
mtb_version | mtb格式版本号 |
chip | 芯片类型 |
diff | 用于差分相关的配置参数 |
flash | flash相关参数 |
partitions | 分区表相关参数 |
diff字段说明
diff | 是否必选 | 说明 |
---|---|---|
ram_buf | 是 | 差分还原时所需的ram空间,单位KB |
flash_buf | 是 | 差分还原时所需的flash空间,单位KB |
flash_sector | 是 | flash每个sector的尺寸,单位byte |
diff_mode | 是 | 差分模式,二进制字符串 |
double_control | 否 | 是否使用双flash,此字段不填或者0:单片flash,1:双片flash |
signature_type | 是 | 签名算法 |
digest_type | 是 | 摘要算法 |
diff_mode字段说明
mode_value | verify | auto_config |
---|---|---|
00 | disable | disable |
01 | disable | enable |
10 | enable | disable |
11 | enable | enable |
partitions字段说明
字段 | 是否必选 | 说明 |
---|---|---|
name | 是 | 分区名字,最长8个字节 |
address | 是 | 分区起始地址 |
load_addr | 否 | 分区加载地址,如果没有此字段,则默认使用address 为加载地址 |
size | 是 | 分区大小,单位byte |
update | 否 | 分区升级类型[DIFF ,FULL ],默认值为DIFF ;类似boot 这种分区是不能升级的,因此不能填写此字段 |
verify | 否 | 是否要对分区进行签名 |
file | 否 | 指定分区对应的镜像文件名字,不填则表示文件名与分区名相同 |
常用分区说明
分区 | 说明 |
---|---|
imtb | 分区表,包含所有分区位置及安全信息 |
tee | 安全执行镜像 |
boot | bootloader |
prim | 应用镜像 |
misc | 升级备份区 |
lpm | 低功耗信息保存区 |
otp | 只读分区,存放设备信息及安全密钥 |
imtb\tee\boot分区的调整会涉及tee镜像、boot镜像、otp安全数据的调整,不建议用户调整
prim\misc\kv 可以根据实际情况进行调整
安全引导流程
- 上电BootRom验签bootloader,并跳转到bootloader
- bootloader验签tee和prim分区,并跳转到tee
- tee进行安全的初始化后,跳到prim执行用户应用
接口定义
相关数据结构
typedef int partition_t;
typedef struct {
char description[MTB_IMAGE_NAME_SIZE]; // 分区名字
uint32_t base_addr; // Flash基地址
uint32_t start_addr; // 分区的偏移地址(不是绝对地址)
uint32_t length; // 分区大小
uint32_t sector_size; // Flash sector大小
uint8_t idx;
void *flash_dev;
uint32_t load_addr; // 加载地址,一般指在RAM中的运行地址
uint32_t image_size; // 镜像实际大小
scn_type_t type;
uint16_t rsv;
} partition_info_t;
初始化分区管理
int partition_init(void);
初始化分区信息,从当前 IMTB 中读取分区信息,参考 分区定义。
参数: 无
返回值:
- 成功:>0
- 失败:小于等于0
根据分区名字打开分区
partition_t partition_open(const char *name);
根据分区名字获取分区序列号
- 参数:
- name:分区名字
- 返回值:
- 分区管理的分区序列号:成功
- <0:失败
根据分区序号关闭分区
void partition_close(partition_t partition);
根据分区序列号清除该分区信息
- 参数:
- partition:分区管理的分区序列号
- 返回值: 无
获取分区详细信息
partition_info_t *partition_info_get(partition_t partition);
hal_flash_get_info(partition) partition_info_get(partition);
根据分区序列号获取该分区的详细信息。
- 参数:
- partition:分区管理的分区序列号
- 返回值:
- 0:成功
- 非0:失败
按照分区读 flash
int partition_read(partition_t partition, off_t off_set, void *data, size_t size);
根据分区序列号读flash
- 参数:
- partition:分区管理的分区序列号
- off_set:读取的分区起始地址
- data:读取分区的数据指针
- size:读取分区的数据量,单位byte
- 返回值:
- 0:成功
- <0:失败
按照分区写flash
int partition_write(partition_t partition, off_t off_set, void *data, size_t size);
根据分区序列号写flash
- 参数:
- partition:分区管理的分区序列号
- off_set:写入的分区起始地址
- data:写入分区的数据指针
- size:写入分区的数据量,单位byte
- 返回值:
- 0:成功
- <0:失败
按照分区擦除flash信息
int partition_erase(partition_t partition, off_t off_set, uint32_t block_count );
根据分区序列号擦除flash信息
- 参数:
- partition:分区管理的分区序列号
- off_set:擦除的分区起始地址
- block_count:擦除的分区block数量
- 返回值:
- 0:成功
- <0:失败
验证单个分区数据
int partition_verify(partition_t partition);
- 参数:
- partition:分区管理的分区序列号
- 返回值:
- 0:成功
- <0:失败
验证分区数据
int partition_all_verify(void);
- 参数:
- 无
- 返回值:
- 0:成功
- <0:失败
获取目标分区的SHA摘要和类型
int partition_get_digest(partition_t partition, uint8_t *out_hash, uint32_t *out_len);
- 参数:
- partition:分区管理的分区序列号
- out_hash:返回的SHA摘要
- out_len:返回的SHA数据长度
- 返回值:
- 0:成功
- <0:失败
设置安全分区
int partition_set_region_safe(partition_t partition);
- 参数:
- partition:分区管理的分区序列号
- 返回值:
- 0:成功
- <0:失败
获取flash id
int get_flashid_by_abs_addr(unsigned long address);
- 参数:
- address:分区地址
- 返回值:
- flash id:成功
- <0:失败
示例代码
分区信息接口
#ifndef YOC_PARTITION_H
#define YOC_PARTITION_H
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <devices/device.h>
#ifndef MTB_IMAGE_NAME_SIZE
#define MTB_IMAGE_NAME_SIZE 8
#endif
#define MAX_FLASH_NUM 10
typedef int partition_t;
typedef struct {
char description[MTB_IMAGE_NAME_SIZE];
uint32_t start_addr;
uint32_t length;
uint16_t sector_size;
uint8_t idx;
dev_t *g_eflash_dev;
} hal_logic_partition_t;
#endif
partition初始化
#include <yoc_init.h>
void board_base_init()
{
flash_csky_register(0);
partition_init();
}
partition接口对接kv api
#include <yoc_config.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <devices/flash.h>
#include <yoc/partition.h>
#include <aos/debug.h>
#ifndef CONFIG_KVFS_EBLOCK_FOR_GC
#define CONFIG_KVFS_EBLOCK_FOR_GC 1
#endif
static int32_t g_block_size;
static int32_t g_kv_blk_cnt;
static partition_t g_eflash_part = -1;
ssize_t kvp_flash_read(int32_t bytesize, void *buff, int32_t off, int32_t blk_num)
{
return partition_read(g_eflash_part, blk_num * g_block_size + off, buff, bytesize);
}
ssize_t kvp_flash_write(int32_t bytesize, void *buff, int32_t off, int32_t blk_num)
{
return partition_write(g_eflash_part, blk_num * g_block_size + off, buff, bytesize);
}
ssize_t kvp_flash_erase(int32_t blk_num)
{
return partition_erase(g_eflash_part, blk_num * g_block_size, 1);
}
extern int __kv_core_init(int eblock_num, int eblock_for_gc, int eblock_size);
int aos_kv_init(const char *partname)
{
aos_check_return_einval(partname);
g_eflash_part = partition_open(partname);
if (g_eflash_part >= 0) {
hal_logic_partition_t *lp = hal_flash_get_info(g_eflash_part);
aos_assert(lp);
g_block_size = lp->sector_size;
g_kv_blk_cnt = lp->length / lp->sector_size;
return __kv_core_init(g_kv_blk_cnt, CONFIG_KVFS_EBLOCK_FOR_GC, g_block_size);
}
return -1;
}