设计说明
OTA 文件结构
- OTA 源码位于 Luban-Lite 根目录中的packages/artinchip/ota/ 文件夹
,文件结构如下:
├── absystem.c # 文件系统挂载源文件 ├── absystem.h ├── burn.c # FLASH 固化接口源文件 ├── burn.h ├── ota.c # OTA 接口源文件 ├── ota.h └── test_ota.c # 测试 TF 卡 OTA 源文件
- OTA 升级过程中使用到的相关文件位于各个 target/xx-chip/xx-board/pack
板级目录中,文件结构如下:
├── bootloader.bin # 引导加载程序,用于启动系统。 ├── ddr_init.json # DDR 初始化配置文件,用于配置内存参数。 ├── env.txt # 环境变量文件,用于环境变量存放。 ├── image_cfg.json # 系统分区配置文件,用作定义系统分区信息。 └── ota-subimgs.cfg # OTA 升级包配置文件,用于指定需要更新的子镜像及其顺序
A/B 系统分区信息
如A/B 系统方案分区信息 所示,各分区详细描述如下:
OTA 分区说明
设备名称 | 定义 | 注释说明 |
---|---|---|
os | 系统主分区 MTD 设备 | 用于 A 系统烧录 OS |
os_r | 系统备份分区 MTD 设备 | 用于 B 系统烧录 OS |
blk_rodata | 只读文件系统主分区块设备 | 用于 A 系统挂载只读文件系统 |
blk_rodata_r | 只读文件系统备份分区块设备 | 用于 B 系统挂载只读文件系统 |
blk_data | 读写文件系统主分区块设备 | 用于 A 系统挂载与烧录读写文件系统 |
blk_data_r | 读写文件系统备份分区块设备 | 用于 B 系统挂载与烧录读写文件系统 |
rodata | 只读文件系统主分区 MTD 设备 | 用于 A 系统烧录只读文件系统 |
rodata_r | 只读文件系统备份分区 MTD 设备 | 用于 B 系统烧录只读文件系统 |
设备名称 | 定义 | 注释说明 |
---|---|---|
os | 系统主分区 MTD 设备 | 用于 A 系统烧录 OS |
os_r | 系统备份分区 MTD 设备 | 用于 B 系统烧录 OS |
blk_rodata | 只读文件系统主分区块设备 | 用于 A 系统挂载只读文件系统 |
blk_rodata_r | 只读文件系统备份分区块设备 | 用于 B 系统挂载只读文件系统 |
rodata | 只读文件系统主分区 MTD 设备 | 用于 A 系统烧录只读文件系统 |
rodata_r | 只读文件系统备份分区 MTD 设备 | 用于 B 系统烧录只读文件系统 |
设备名称 | 定义 | 注释说明 |
---|---|---|
mmc0p3 | 系统主分区块设备 | 用于 A 系统烧录 OS |
mmc0p4 | 系统备份分区块设备 | 用于 B 系统烧录 OS |
mmc0p5 | 只读文件系统主分区块设备 | 用于 A 系统挂载与烧录只读文件系统 |
mmc0p6 | 只读文件系统备份分区块设备 | 用于 B 系统挂载与烧录只读文件系统 |
mmc0p7 | 读写文件系统主分区块设备 | 用于 A 系统挂载与烧录读写文件系统 |
mmc0p8 | 读写文件系统备份分区块设备 | 用于 B 系统挂载与烧录读写文件系统 |
A/B 系统升级过程
-
升级前,A 系统为启动系统,B 系统为备用系统。
-
启动 OTA 升级,给 B 系统升级程序。
-
升级完成后重启,从 B 系统启动,A 系统为备用系统。
ENV 环境变量
- 环境变量文件路径:target/xx-chip/xx-board/pack/env.txt
- 环境变量文件详细内容:
osAB_next=A osAB_now=A rodataAB_next=A rodataAB_now=A dataAB_next=A dataAB_now=A upgrade_available=0 bootlimit=5 bootcount=0 rodata_partname=blk_rodata rodata_partname_r=blk_rodata_r data_partname=blk_data data_partname_r=blk_data_r
环境变量名称 | 定义 | 注释说明 |
---|---|---|
osAB_now | 当前启动分区 | osAB_now 取值说明:
|
osAB_next | 下次启动分区 | osAB_next 取值说明:
|
rodataAB_now | 当前挂载的只读分区 | rodataAB_now 取值说明:
|
rodataAB_next | 下次挂载的只读分区 | rodataAB_next 取值说明:
|
dataAB_now | 当前挂载的读写分区 | dataAB_now 取值说明:
|
dataAB_next | 下次挂载的读写分区 | dataAB_next 取值说明:
|
upgrade_available | OTA 升级完成 | OTA 升级完成,指导 boot 程序更新启动分区和版本回退 |
bootcount | 失败启动次数 | 启动分区启动 os 程序失败的次数 |
bootlimit | 失败启动次数限制 | 启动分区启动失败次数超过 bootlimit 会触发版本回退 |
rodata_partname | rodata 挂载设备名称 | rodata 实际挂载的设备名称 如果系统设备名称改变,此处应该同步修改 |
rodata_partname_r | 备份 rodata 挂载设备名称 | rodata_r 实际挂载的设备名称 如果系统设备名称改变,此处应该同步修改 |
data_partname | data 挂载设备名称 | rodata 实际挂载的设备名称 如果系统设备名称改变,此处应该同步修改 |
data_partname_r | 备份 data 挂载设备名称 | rodata_r 实际挂载的设备名称 如果系统设备名称改变,此处应该同步修改 |
rodata 和 data 分区的升级原理与 OS 相同。
OTA 升级包制作原理
[image]
size = "";
version = "1.0.0";
[file]
ota_info.bin:file;
d21x_os.itb:os;
rodata.fatfs:rodata;
data.fatfs:blk_data;
环境变量名称 | 定义 | 注释说明 |
---|---|---|
size | 整个 ota.cpio 文件的大小 | size 为 py 脚本自动计算,在 C 文件中有解析此字段,供用户用做下载进度等使用。 |
version | 新更新的系统版本号 | version 为 py 脚本自动填充,从 image_cfg.json 中解析,用户应修改 image_cfg.json 中的版本号。 |
ota_info.bin | ota-subimgs.cfg 的二进制文件 | py 脚本会将本文件编译为二进制流文件,供 C 文件中解析使用。file 属性可以忽略。 |
d21x_os.itb | OS 的实际比特流文件 | 此文件编译会自动生成,此处存在代表将会被打包进 cpio 包。 os 为即将升级到的设备。 |
rodata.fatfs | 只读分区的实际比特流文件 | 此文件编译会自动生成,此处存在代表将会被打包进 cpio 包。 rodata 为即将升级到的设备。 |
data.fatfs | 读写分区的实际比特流文件 | 此文件编译会自动生成,此处存在代表将会被打包进 cpio 包。 blk_data 为即将升级到的设备。 |
-
FLASH 为 NAND 时,只读文件系统与读写文件系统升级的设备不同,读写文件系统依赖 NFTL 支持,烧写 FLASH 需使用块设备接口,而只读文件系统烧写 FLASH 使用 MTD 设备接口即可。
-
FLASH 为 NOR 时,由于空间限制,目前读写文件系统不使用 OTA 进行升级。
-
FLASH 为 eMMC 时,主分区应为 mmc0p* , 备份分区在 image_cfg.json 分配时应该在主分区下面,在 OTA 代码中,默认将 mmc0p*+1 作为备份分区。
OTA 升级包生成工具为 mkcpio.py,文件路径为 tools/scripts/mkcpio.py
执行编译命令,会自动执行 mkcpio.py 命令生成 ota.cpio。mkcpio.py 具体调用了 cpio, cpio.exe 命令进行打包。
OTA 包数据组成格式
struct filehdr {
unsigned int format;
unsigned int size;
unsigned int size_align;
unsigned int begin_offset;
unsigned int cpio_header_len;
unsigned int namesize;
unsigned int filename_size;
unsigned int filename_align;
unsigned int burn_len;
unsigned int chksum;
unsigned int sum;
char filename[MAX_IMAGE_FNAME];
};
A/B 系统分区优势
-
避免出现升级过程中意外断电导致系统更新失败且重启后不能继续升级的问题。
-
自带回滚机制,可以恢复到原来的程序。
-
对比 Recovery 系统方案,配置简单,维护方便。
-
消耗的存储资源相对较少,现有平台存储资源完全能满足要求。
-
在 RTOS 系统上获取、校验和升级固件,不涉及 Boot,不需要额外存储空间保存 OTA 升级文件。
-
市面上的应用广泛。
网络 OTA 流程
-
OS 阶段 app OTA 执行流程
http_ota //packages/third-party/ota_downloader/src/http_ota.c |-> http_ota_fw_download(argv[1]); |-> webclient_session_create(GET_HEADER_BUFSZ); |-> webclient_shard_head_function(session, uri, &file_size); |-> webclient_register_shard_position_function(session, http_ota_shard_download_swu_handle); |-> webclient_shard_position_function(session, uri, file_offset, file_size, HTTP_OTA_BUFF_LEN); |-> http_ota_shard_download_swu_handle //采用分片方式下载数据 |-> ota_buf_push(&shdr, buffer, length); //将下载的数据放到缓存区,供解析 cpio 头部信息 |-> find_cpio_data(&fhdr, shdr.buf, shdr.buflen); //解析 cpio 头部信息 |-> parse_cpio_file_info(&bhdr, &fhdr, &finfo); //解析 cpio 文件大小和版本号,供用户自定义使用,并且存储烧录的分区设备名字 |-> swu_buf_pop(&bhdr, &shdr, &fhdr); //将 cpio 头部信息后面的数据放到另外的缓存区,供升级使用 |-> ota_buf_push(&bhdr, buffer, length); //将下载的数据放到缓存区,供升级使用 |-> find_device(partname) //获取分区信息 |-> aic_ota_erase_part(dl_part, 0, dl_part->len) //擦除分区 |-> download_buf_pop(&bhdr, &fhdr) //将缓存区里面的数据取出来,升级到 FLASH 上 |-> aic_ota_part_write //写入数据到 FLASH 上 |-> cpio_file_checksum((unsigned char *)bhdr->buf, burn_len); //升级完成以后,校验和信息 |-> aic_upgrade_end(); //升级结束,更新环境变量信息 |-> rt_hw_cpu_reset(); //重新启动
-
Boot 阶段新系统程序加载启动流程
do_nor_boot //application/baremetal/bootloader/cmd/nor_boot.c |-> aic_ota_check(); //application/baremetal/bootloader/lib/absystem/absystem.c |-> aic_ota_version_fallback(); // OTA 升级失败,版本回退到之前的版本 |-> aic_get_os_to_startup(target); //获取新系统信息 |-> find_boot_part(target); // 获取新系统 OS 分区结构体 |-> spl_load_simple_fit(&info, &entry_point); // 加载 os 分区程序到缓存上
-
OS 阶段 app 挂载新文件系统
absystem.c //packages/artinchip/ota/absystem.c |-> INIT_ENV_EXPORT(aic_absystem_mount_fs_prio0); |-> INIT_LATE_APP_EXPORT(aic_absystem_mount_fs_prio1);