Edit online

设计说明

5 Dec 2024
Read time: 7 minute(s)

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 系统分区信息


part

1. A/B 系统方案分区信息

A/B 系统方案分区信息 所示,各分区详细描述如下:

  • ENV 分区:用来保存 env 环境变量,其中增加了一个备用 ENV 分区,确保在一份数据破坏后,另外一份数据还能继续使用。

  • OS, RODATA 和 DATA 分区各有一个主分区和一个备份分区,统称为 A/ B 系统。

  • 用户可根据实际 OTA 需求剪裁分区,例如只需升级 OS,则可以删除 RODATA 与 DATA 的备份分区。

OTA 分区说明

1. NAND 分区说明
设备名称 定义 注释说明
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 系统烧录只读文件系统
2. NOR 分区说明
设备名称 定义 注释说明
os 系统主分区 MTD 设备 用于 A 系统烧录 OS
os_r 系统备份分区 MTD 设备 用于 B 系统烧录 OS
blk_rodata 只读文件系统主分区块设备 用于 A 系统挂载只读文件系统
blk_rodata_r 只读文件系统备份分区块设备 用于 B 系统挂载只读文件系统
rodata 只读文件系统主分区 MTD 设备 用于 A 系统烧录只读文件系统
rodata_r 只读文件系统备份分区 MTD 设备 用于 B 系统烧录只读文件系统
3. eMMC 分区说明
设备名称 定义 注释说明
mmc0p3 系统主分区块设备 用于 A 系统烧录 OS
mmc0p4 系统备份分区块设备 用于 B 系统烧录 OS
mmc0p5 只读文件系统主分区块设备 用于 A 系统挂载与烧录只读文件系统
mmc0p6 只读文件系统备份分区块设备 用于 B 系统挂载与烧录只读文件系统
mmc0p7 读写文件系统主分区块设备 用于 A 系统挂载与烧录读写文件系统
mmc0p8 读写文件系统备份分区块设备 用于 B 系统挂载与烧录读写文件系统

A/B 系统升级过程


ab

2. A/B 系统升级过程
  1. 升级前,A 系统为启动系统,B 系统为备用系统。

  2. 启动 OTA 升级,给 B 系统升级程序。

  3. 升级完成后重启,从 B 系统启动,A 系统为备用系统。

ENV 环境变量

OTA 升级涉及的 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
4. 环境变量使用说明
环境变量名称 定义 注释说明
osAB_now 当前启动分区 osAB_now 取值说明:
  • “A”:OS 本次从 A 启动
  • “B”:OS 本次从 B 启动,无需手动修改
osAB_next 下次启动分区 osAB_next 取值说明:
  • “A”:OS 下次从 A 启动
  • “B”:OS 下次从 B 启动,可以手动修改
rodataAB_now 当前挂载的只读分区 rodataAB_now 取值说明:
  • “A”:rodata 本次从 A 挂载
  • “B”:rodata 本次从 B 挂载,无需手动修改
rodataAB_next 下次挂载的只读分区 rodataAB_next 取值说明:
  • “A”:rodata 下次从 A 挂载
  • “B”:rodata 下次从 B 挂载,可以手动修改
dataAB_now 当前挂载的读写分区 dataAB_now 取值说明:
  • “A”:data 本次从 A 挂载
  • “B”:data 本次从 B 挂载,无需手动修改
dataAB_next 下次挂载的读写分区 dataAB_next 取值说明:
  • “A”:data 下次从 A 挂载
  • “B”:data 下次从 B 挂载,可以手动修改
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 实际挂载的设备名称

如果系统设备名称改变,此处应该同步修改


env

3. 环境变量在 OTA 升级过程中的作用
注:

rodata 和 data 分区的升级原理与 OS 相同。

OTA 升级包制作原理

OTA 升级包配置文件ota-subimgs.cfg
[image]
size = "";
version = "1.0.0";

[file]
ota_info.bin:file;
d21x_os.itb:os;
rodata.fatfs:rodata;
data.fatfs:blk_data;
5. ota-subimgs.cfg 配置文件详细说明
环境变量名称 定义 注释说明
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 为即将升级到的设备。
注:
  1. FLASH 为 NAND 时,只读文件系统与读写文件系统升级的设备不同,读写文件系统依赖 NFTL 支持,烧写 FLASH 需使用块设备接口,而只读文件系统烧写 FLASH 使用 MTD 设备接口即可。

  2. FLASH 为 NOR 时,由于空间限制,目前读写文件系统不使用 OTA 进行升级。

  3. 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 包数据组成格式


cpio

4. 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 系统分区优势

  1. 避免出现升级过程中意外断电导致系统更新失败且重启后不能继续升级的问题。

  2. 自带回滚机制,可以恢复到原来的程序。

  3. 对比 Recovery 系统方案,配置简单,维护方便。

  4. 消耗的存储资源相对较少,现有平台存储资源完全能满足要求。

  5. 在 RTOS 系统上获取、校验和升级固件,不涉及 Boot,不需要额外存储空间保存 OTA 升级文件。

  6. 市面上的应用广泛。

网络 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);