Tina_Linux_OTA_开发指南
Posted 韦东山
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tina_Linux_OTA_开发指南相关的知识,希望对你有一定的参考价值。
Tina Linux OTA开发指南
1 概述
OTA 是Over The Air 的简称,顾名思义就是通过无线网络从服务器上下载更新文件对本地系统或文件进行升级,便于客户为其用户及时更新系统和应用以提供更
好的产品服务,这对于客户和消费者都极其重要。
1.1 编写目的
本文主要服务于使用Tina 软件平台的广大客户,以冀帮助客户使用Tina 平台的OTA 升级系统并做二次开发。
1.2 适用范围
Allwinner 软件平台Tina。
1.3 相关人员
适用Tina 平台的广大客户和关心OTA 的相关人员。
1.4 OTA 方案
1.4.1 recovery 系统方案
recovery 系统方案,是在主系统之外,增加一个recovery 系统。升级时,主系统负责升级recovery系统,recovery 系统负责升级主系统。
这样如果升级中途发生掉电,也不会影响当前正在使用的这个系统。重启后仍可正常进入系统,继续完成升级。
一般recovery 系统会使用intiramfs 功能,并大量裁剪不必要的应用,只保留OTA 必需的功能,把size 尽量减小。
recovery 系统方案优点:
- recovery 系统可以做得比较小,省flash 空间。
recovery 系统方案缺点:
- recovery 系统一般不包含主应用,所以OTA 期间,处于recovery 系统中时,无法为用户正常提供服务。
- 需要重启两次。
- 需要维护两份系统配置,即主系统和recovery 系统。
1.4.2 AB 系统方案
AB 系统方案,是将原有的系统,增加一份。即flash 上总共有AB 两套系统。两套系统互相升级。OTA 时,若当前运行的是A 系统,则升级B 系统,升级完成后,
设置标志,重启切换到B系统。OTA 时,若当前运行的是B 系统,则升级A 系统,升级完成后,设置标志,重启切换到A 系统。
AB 系统方案优点:
- 更新过程是在完整系统中进行的,更新期间可正常提供服务,用户无感知。最终做一次重启即可。
- 逻辑简单,只重启一次。
- 只维护一套系统配置。
AB 系统方案缺点:
- flash 占用较大。
2 ota-burnboot 介绍
2.1 文档说明
此文档主要介绍如何在OTA 时升级boot0/uboot。
升级工具包含两个方面内容:
OTA 命令升级boot0 和uboot。
OTA 升级boot0 和uboot 的C/C++ APIs。
2.2 概念说明
概念 | 说明 |
---|---|
boot0 | 较为简单, 主要作用是初始化dram 并加载运行uboot。一般不需修改。 |
uboot | 功能较丰富, 支持烧写, 启动内核, 烧key 及其他一些定制化的功能。 |
sys_config | 全志特有的配置文件, 对于使用linxu3.4/uboot2011 的平台, 在打包之 后sys_config 会跟uboot 拼接到一起。对于使用 linux3.10/uboot2014 及更高版本的平台,sys_config 会在打包阶段, 跟设备树的配置合并, 生成最终的dtb。linux5.4 开始不再合并到 dtb。 |
dtb | 设备树, 由dts 配置和sys_config 配置综合得到。 |
u-boot.fex | 使用linxu3.4/uboot2011 的平台最终用到的uboot, 其实是 uboot+sys_config。 |
boot_package.fex | 使用linux3.10/uboot2014 及更高版本的平台最终用到的uboot, 其 实包含的文件由配置文件boot_package.cfg 决定, 一般至少包含了 uboot 和dtb, 安全方案会包含一些安全所需文件文件, 可能还有 bootlogo 等文件。 |
toc0.fex | 安全方案使用的boot0。 |
toc1.fex | 安全方案使用的uboot, 类似boot_package.fex 说明, 其中实际也包 含了dts 等多个文件。 |
即, 本文介绍的升级uboot, 其实是升级uboot+dtb 这样的一个整体文件。后文不再区分更新uboot, 更新sys_config, 更新dtb。这几个打包完毕是合成一个文件的,
暂不支持单独更新其中一个, 需整体更新。
2.3 用于更新的bin 文件
获取用于OTA 的boot0 与uboot 的bin 文件, 用于加入OTA 包中。
2.3.1 编译boot0 uboot
如果原本的固件生成流程已经包含编译uboot, 则正常编译固件即可。
否则可按照如下步骤编译生成uboot
$ source build/envsetup.sh
=> 设置环境变量。
$ lunch
=> 选择方案。
$ muboot
=> 编译uboot。
$ mboot0
=> 编译boot0 (注意,此命令在大多数平台无效,因为boot0不开源,SDK中提供了编译好的bin文件)。
编译后会自行拷贝bin 文件到该平台的目录下, 即:
对于tina3.5.0 及之前版本,路径为:
target/allwinner/xxx-common/bin
对于tina3.5.1 及之后版本,路径为:
device/config/chips/$CHIP/bin
编译出的boot0/uboot 还不能直接用于OTA, 请继续编译和打包固件, 如执行:
$ make -j <N>
=> 编译命令,若只修改boot0/uboot/sys_config 无需重新编译,可跳过。
=> 若修改了dts 则需要执行,重新编译。
$ pack [-d]。
=> 非安全方案的打包命令。
$ pack -s [-d]
=> 安全方案的打包命令。
2.3.2 关于更新boot0
大多数平台,代码环境中并不包含boot0 相关代码, 因此无法编译boot0。
一般情况下并不需要修改boot0, 而是直接使用提供的boot0 的bin 文件即可。少部分平台提供了可编译的boot0 代码,可使用mboot0 编译。
2.3.3 Bin 文件路径
2.3.3.1 使用uboot2011 的非安全方案
以R16 的astar-parrot 方案为例。
根据对应存储介质选择bin。
boot0:
out/astar-parrot/image/boot0_nand.fex :nand 方案使用的boot0。
out/astar-parrot/image/boot0_sdcard.fex :mmc 方案使用的boot0。
out/astar-parrot/image/boot0_spinor.fex :nor 方案使用的boot0。
uboot:
out/astar-parrot/image/u-boot.fex :nand/mmc 方案使用的uboot。
out/astar-parrot/image/u-boot-spinor.fex :nor 方案使用的uboot。
2.3.3.2 使用uboot2014 及更高版本的非安全方案
以R6 的sitar-evb 方案为例。
根据对应存储介质选择bin。
boot0:
out/sitar-evb/image/boot0_nand.fex :nand 方案使用的boot0。
out/sitar-evb/image/boot0_sdcard.fex :mmc 方案使用的boot0。
out/sitar-evb/image/boot0_spinor.fex :nor 方案使用的boot0。
uboot:
out/sitar-evb/image/boot_package.fex :nand/mmc 方案使用的uboot。
out/sitar-evb/image/boot_package_nor.fex :nor 方案使用的uboot。
2.3.3.3 安全方案
以R18 的tulip-noma 方案为例。
boot0:
out/tulip-noma/image/toc0.fex :安全方案使用的boot0。
uboot:
out/tulip-noma/image/toc1.fex :安全方案使用的uboot。
2.4 OTA 升级命令
2.4.1 支持OTA 升级命令
升级boot0 与uboot 分别使用ota-burnboot0 与ota-burnuboot 命令。
两个命令都是OTA 升级boot0 和uboot 的C/C++ APIs 的封装。
要支持本功能, 需要选中ota-burnboot 的包, 即:
Make menuconfig --> Allwinner ---> <*>ota-burnboot
2.4.2 ota-burnboot0
2.4.2.1 命令说明
$ Usage: ota-burnboot0 <boot0-image>
升级boot0, 其中boot0-image 是镜像的路径。
请注意, 安全和非安全方案所使用的boot0-image 是不同的, 具体见“用于更新的bin 文件” 章节。
2.4.2.2 使用示例
root@TinaLinux:/# ota-burnboot0 /tmp/boot0_nand.fex
Burn Boot0 Success
2.4.3 ota-burnuboot
2.4.3.1 命令说明
$ Usage: ota-burnuboot <uboot-image>
升级uboot, 其中uboot-image 是镜像的路径。请注意, 安全和非安全方案, 不同的uboot 版本,所使用的uboot-image 是不同的,具体见第二章。
2.4.3.2 使用示例
root@TinaLinux:/# ota-burnuboot /tmp/u-boot.fex
Burn Uboot Success
2.5 OTA 升级C/C++ APIs
包含头文件OTA_BurnBoot.h,使用库libota-burnboot.so
2.5.1 int OTA_burnboot0(const char *img_path)
函数原型 | int OTA_burnboot0(const char *img_path); |
---|---|
参数说明 | img_path:boot0 镜像路径 |
返回说明 | 0:成功; 非零:失败 |
功能描述 | 烧写boot0 |
2.5.2 int OTA_burnuboot(const char *img_path)
函数原型 | int OTA_burnuboot(const char *img_path); |
---|---|
参数说明 | img_path:uboot 镜像路径 |
返回说明 | 0:成功; 非零:失败 |
功能描述 | 烧写uboot |
2.6 底层实现
2.6.1 如何保证安全更新boot0/uboot
前提条件是,flash 中存有不止一份boot0/uboot。在这个基础上, 启动流程需支持校验并选择完整的boot0/uboot 进行启动, 更新流程需保证任意时刻掉电,flash 上
总存在至少一份可用的boot0/uboot。
2.6.2 Nand Flash NFTL 方案实现
在nand nftl 方案中,boot0 和uboot 是由nand 驱动管理, 保存在物理地址中, 逻辑分区不可见。
Nand 驱动会保存多份boot0 和uboot, 启动时, 从第一份开始依次尝试, 直到找到一份完整的boot0/uboot 进行使用。
更新boot0/uboot 时, 上层调用nand 驱动提供的接口, 驱动中会从第一份开始依次更新, 多份全部更新完毕后返回。因此可保证在OTA 过程中任意时刻掉电,flash
中均有至少一份完整的boot0/uboot 可用。再次启动后, 只需重新调用更新接口进行更新, 直到调用成功返回即可。
目前nand 中的多份boot0/uboot 是由nand 驱动管理的, 只能整体更新, 暂不支持单独更新其中的一份。
2.6.3 Nand Flash UBI 方案实现
在nand ubi 方案中, boot0 一般存放于mtd0 中,uboot 存放于mtd1 中。
与nftl 方案一样,底层实际是保存多份boot0 和uboot。启动时, 从第一份开始依次尝试, 直到找到一份完整的boot0/uboot 进行使用。对上提供多份统一的更新接
口,软件包会通过对mtd的iotcl 接口发起更新。
注:用户空间直接读写/dev/mtdx 节点,需要内核使能CONFIG_MTD_CHAR=y。
2.6.4 MMC Flash 实现
在mmc 方案中, boot0 和uboot 各有两份, 存在mmc 上的指定偏移处, 逻辑分区不可见。需要读写可直接操作/dev/mmcblk0 节点的指定偏移。
具体位置:
1 sector = 512 bytes = 0.5k。
boot0/toc0 保存了两份,offset1: 16 sector, offset2: 256 sector。
uboot/toc1 保存了两份,offset1: 32800 sector, offset2: 24576 sector。
启动时会先读取offset1,如果完整性校验失败,则读取offset2。
更新时, 默认只更新offset1, 而offset2 是保持在出厂状态的。只要offset1 正常更新了, 则启动时会优先使用。如果在更新offset1 的过程中掉电导致数据损坏, 则自
动使用offset2 进行启动。
如需定制策略,例如改成每次offset1 和offset2 均更新,可自行修改ota-burnboot 代码。
2.6.5 NOR Flash 实现
nor 方案中, 只保存一份boot0 和uboot, 更新过程中掉电可能导致无法启动, 只能进行刷机。故目前未实现ota 更新, 需后续扩展。
3 Tina SWUpdate OTA 介绍
3.1 swupdate 介绍
3.1.1 简介
SWUpdate 是一个开源的OTA 框架,提供了一种灵活可靠的方式来更新嵌入式系统上的软件。
官方源码:
https://github.com/sbabic/swupdate
官方文档:
http://sbabic.github.io/swupdate/
非官方翻译的中文文档:
https://zqb-all.github.io/swupdate/
源码自带文档:
解压tina/dl/swupdate-xxx.tar.xz ,解压后的doc 目录下即为此版本源码附带的文档。
社区论坛:
https://groups.google.com/forum/#!forum/swupdate
3.1.2 移植到tina 的改动
移植到tina 主要做了以下修改:
• 位置在package/allwinner/swupdate。
• 仿照busybox,添加了配置项,可通过make menuconfig 直接配置。
• 添加patch,支持了更新boot0,uboot。
• 添加了自启动脚本。
• 默认启动progress 在后台,输出到串口。这样升级时会打印进度条。实际方案不需要的话,可去除。客户应用可参考progress 源码,自行获取进度信息。
• 默认启动一个脚本swupdate_cmd.sh,负责完善参数,最终调用swupdate。脚本介绍详见后续章节。
3.2 配置
3.2.1 recovery 系统介绍
若选用主系统+recovery 系统的方式,则需要一个recovery 系统。
recovery 系统是一个带initramfs 的kernel。对应的配置文件是target/allwinner/xxx/defconfig_ota。
如果没有此文件,可以拷贝defconfig 为defconfig_ota,再做配置裁剪。
3.2.2 系统配置命令
对于主系统,使用:
make menuconfig
配置结果保存在:
target/allwinner/xxx/defconfig
对于recovery 系统,使用:
make ota_menuconfig
配置结果保存在:
target/allwinner/xxx/defconfig_ota
3.2.3 主系统和recovery 都需要的swupdate 包
选上swupdate 包。
Allwinner --> [*]swupdate
swupdate 中还有很多细分选项,一般用默认配置即可。需要的话可以做一些调整,比如裁剪掉网络部分。
swupdate 会依赖选中uboot-envtools 包,以提供用户空间读写env 分区的功能。
3.2.4 主系统和recovery 都需要的wifimanager daemon
如果想从网络升级,则需要启动系统自动联网。
一种实现方式是,使用wifimanager daemon 。当然,如果用户自己在脚本或应用中去做联网,则不需要此选项。
Allwinner
---> <*> wifimanager
---> [*] Enable wifimanager daemon support
---> <*> wifimanager-daemon-demo..................... Tina wifimanager
daemon demo
3.2.5 配置主系统
就以上提到的几个包,暂时没有只针对主系统的需要选的包。
3.2.6 编译主系统
正常make 即生成主系统。
make
3.2.7 配置recovery 系统
对于recovey 系统,需要选上ramdisk,同时建议使用xz 压缩方式以节省flash 空间。
make ota_menuconfig
---> Target Images
---> [*] ramdisk
---> Compression (xz)
选上recovery 后缀,避免编译recovery 系统时,影响到主系统。
make ota_menuconfig
---> Target Images
---> [*] customize image name
---> Boot Image(kernel) name suffix (boot_recovery.img/boot_initramfs_recovery.img)
---> Rootfs Image name suffix (rootfs_recovery.img)
3.2.8 编译recovery 系统
要编译生成recovery 系统,可使用:
swupdate_make_recovery_img
或手工调用:
make -j16 TARGET_CONFIG=./target/allwinner/xxx/defconfig_ota
编译得到:
out/xxx/boot_initramfs_recovery.img
3.2.9 配置env
本方案推荐使用env 来保存信息,不使用misc 分区。
uboot 会从env 分区读取启动命令,并根据启动命令来启动系统。只要我们能在用户空间改动到env,即可控制下次启动的系统。
3.2.9.1 boot_partition 变量
增加一个boot_partition 变量,用于指定要启动的内核所在分区。
配置env 主要是修改boot_normal 命令,将要启动的分区独立成boot_partition 变量。
即从:
boot_normal=fatload sunxi_flash boot 40007fc0 uImage;bootm 40007fc0
改成:
boot_partition=boot
boot_normal=fatload sunxi_flash $boot_partition 40007fc0 uImage;bootm 40007fc0
这样可以通过控制boot_partition 来直接选择下次要启动的系统,无需uboot 介入。uboot 只需按照boot_normal 启动即可。
对于recovery 方案,可设置boot_partition 为boot 或recovery。OTA 切换系统时,只需要改变此变量即可达到切换主系统和recovery 系统的目的。
对于AB 系统方案,可设置为boot_partition 为bootA 或bootB。OTA 切换系统时,只需要改变此变量即可达到切换kernel 的目的。
3.2.9.2 root_partition 变量
增加一个root_partition 变量,用于指定要启动的rootfs 所在分区。
uboot 会解析分区表,找出此变量指定的分区并在cmdline 中指定root 参数。
例如,在env 中设置:
root_partition=rootfs
则启动时uboot 会遍历分区表,找到名字为rootfs 的分区,假设找到的分区为/dev/nand0p4,则在cmdline 中增加root=/dev/nand0p4。
kernel 需要挂载rootfs 时,取出root 参数,则得知需要挂载/dev/nand0p4 分区。
对于recovery 方案,就一直设置root_partition 为rootfs 即可。主系统需要从rootfs 分区读取数据,而recovery 系统使用initramfs,无需从rootfs 分区读取数据
即可正常运行OTA 应用等。当然,recovery 系统中要更新rootfs 的话,还是会访问(写入)rootfs 分区的,但这个动作就跟env 的root_partition 无关了。
对于AB 系统方案,可设置root_partition 为rootfsA 或rootfsB,以匹配不同的系统。OTA切换系统时,只需要改变此变量即可达到切换rootfs 的目的。
3.2.10 配置备份env
由于写入env 时断电,可能导致env 的数据被破坏,因此需要支持备份env。
3.2.10.1 方式一:env 分区扩展为存放两份env
此方式是在uboot 中进行定制实现,非社区原生方案。
可在uboot源码中搜索CONFIG_SUNXI_ENV_NOT_BACKUP, 若存在则说明支持此功能。
支持此功能后,只要uboot不配置CONFIG_SUNXI_ENV_NOT_BACKUP,则此功能默认开启。uboot会将env数据在同一分区中进行备份。
启用方法:
- 修改分区表,将env 分区扩大到128k*2=256k。
工作方式:
uboot 检测到env 分区足够大,则激活env 备份功能,认为0-128k 存放第一份env 数据,128k-256k 存放第二份env 数据。由于env 数据本身带有CRC 校验,所
以可判断一份env 是否完整。启动时,uboot 会对两份env 进行同步,若某一份损坏则取另一份进行覆盖,若两份均完整,则以第一份为准。
对于用户空间的fw_printenv,默认只会更新第一份env,即执行fw_setenv 之后两份env 就有差异了,要到下次启动才由uboot 进行同步。若更新env 的过程中发
生掉电,则第一份env不完整,重新启动时,uboot 会识别到并用第二份env 覆盖第一份。
确认是否生效:
1.直接观察。
用户空间控制台执行:
hexdump -C /dev/by-name/env
确认是否存在两份。
2.尝试破坏env。
dd if=/dev/zero of=/dev/by-name/env bs=1k count=1
损坏第一份env,重启看能否正常启动,并尝试
fw_printenv
hexdump -C /dev/by-name/env
确认env 分区数据是否正常。
3.2.10.2 方式二:增加env-redund 分区
此方式是uboot 原生功能。虽然也需要修改sunxi 的env 读取代码进行适配,但总体读写逻辑是社区原生的。
启用方法:
1.增加env-redund 分区。
将env 分区复制一份,分区名改为env-redund。
注意只是分区名修改为env-redund,其downloadfile 仍然指定为env.fex
2.支持在打包时制作冗余env。
make menuconfig --> Global build settings --> [*] sunxi make redundant env data
注意事项:
启用上述选项之后,打包时会调用mkenvimage 工具来制作env,对env 的格式有一定要求。
如注释和有效配置不能合并在一行。
若env-x.x.cfg 中存在类似如下配置
bootcmd=run setargs_nand boot_normal#default nand boot
则需要改成:
#default nand boot
bootcmd=run setargs_nand boot_normal
3.配置uboot 并重新编译uboot bin。
以r328 spinand 方案为例。
在
lichee/brandy-2.0/u-boot-2018/configs/sun8iw18p1_defconfig
中增加配置:
CONFIG_SUNXI_REDUNDAND_ENVIRONMENT=y
重新编译uboot。
4.修改fw_env.config
拷贝
package/utils/uboot-envtools/files/fw_env.config
到
target/allwinner/<board>/base-files/etc/ (若使用procd-init)
target/allwinner/<board>/busybox-init-base-files/etc/ (若使用busybox-init)
修改拷贝后的fw_env.config,增加备份env 的配置。
例如原本最后一行为:
/dev/by-name/env 0x0000 0x20000
则增加一行:
/dev/by-name/env-redund 0x0000 0x20000
这样用户空间的fw_printenv 和fw_setenv 即可正确处理两份env。
3.2.11 配置启动脚本
procd-init 是默认配置好的。
busybox-init 需要手工配置下。
参考《Tina System init 使用说明文档》, 拷贝
<tina>/package/busybox-init-base-files/files/etc/init.d/load_script.conf
到
<tina>/target/allwinner/<platform>/busybox-init-base-files/etc/init.d/
并在其中添加一行:
swupdate_autorun
3.3 OTA 包
OTA 包中,需要包含sw-description 文件,以及本次升级会用到的各个文件,例如kernel,rootfs。
整个OTA 包是cpio 格式,且要求sw-description 文件在第一个。
3.3.1 OTA 策略描述文件:sw-description
sw-description 文件是swupdate 官方规定的,OTA 策略的描述文件,具体语法可参考swupdate官方文档。
tina 提供了几个示例:
target/allwinner/generic/swupdate/sw-description-ab
target/allwinner/generic/swupdate/sw-description
也可以自行为具体的方案编写描述文件:
target/allwinner/<board>/swupdate/sw-description
本文件在SDK 中的存放路径和名字没有限定,只要最终打包进OTA 包中,重命名为swdescription并放在第一个文件即可。
3.3.2 OTA 包配置文件:sw-subimgs.cfg
sw-subimgs.cfg 是tina 提供的,用于指示如何生成OTA 包。
基本格式为
swota_file_list=(
#表示把文件xxx拷贝到swupdate目录下,重命名为yyy,并把yyy打包到最终的OTA包中
xxx:yyy
)
swota_copy_file_list=(
#表示把文件xxx拷贝到swupdate目录下,重命名为yyy,但不把yyy打包到最终的OTA包中
xxx:yyy
)
swota_copy_file_list 存在的原因是,有一些文件我们只需要其sha256 值,而不需要文件本身。例如使用差分包配合readback handler 时,readback handler 需
要原始镜像的sha256值用于校验。
例子:
swota_file_list=(
#将target/allwinner/generic/swupdate/sw-description-ab-sign拷贝成sw-description,后续同理。
target/allwinner/generic/swupdate/sw-description-ab-sign:sw-description
out/$TARGET_BOARD/uboot.img:uboot
out/$TARGET_BOARD/boot0.img:boot0
out/$TARGET_BOARD/image/boot.fex.gz:kernel.gz
out/$TARGET_BOARD/image/rootfs.fex.gz:rootfs.gz
out/$TARGET_BOARD/image/rootfs.fex.zst:rootfs.zst
)
tina 提供了几个示例:
target/allwinner/generic/swupdate/sw-subimgs.cfg # 普通系统,recovery系统,整包升级。这是其余demo的基础版本。
target/allwinner/generic/swupdate/sw-subimgs-ab.cfg # 改为AB系统。
target/allwinner/generic/swupdate/sw-subimgs-secure.cfg # 改为安全系统。
target/allwinner/generic/swupdate/sw-subimgs-ab-rdiff.cfg # 改为AB方案,差分方案。
target/allwinner/generic/swupdate/sw-subimgs-readback.cfg # 增加回读校验。
target/allwinner/generic/swupdate/sw-subimgs-sign.cfg # 增加签名校验。
target/allwinner/generic/swupdate/sw-subimgs-ubi.cfg # 改为ubi方案。
也可以自行为具体的方案编写描述文件。
target/allwinner/<board>/swupdate/sw-subimgs.cfg
本文件在SDK 中的路径需位于target/allwinner//swupdate 目录下,或target/allwinner/generic/swupdate 目录下。
名字需要命名为sw-subimg.cfg 或sw-subimgsxxx.cfg,其中xxx 可自定义。
这个限定主要是为了方便打包函数处理。在打包时,命令行传入参数xxx,则会使用swsubimgsxxx.cfg 进行打包。
3.3.3 OTA 包生成:swupdate_pack_swu
在build/envsetup.sh 中提供了一个swupdate_pack_swu 函数。
可以参考该函数,自行实现一套打包swupdate 升级包的脚本。也可以直接使用,使用方式如下。
- 准备好sw-descrition 文件,具体作用和语法请参考swupdate 说明文档。
- 准备好sw-subimgs.cfg 文件,里面需要每一行列出一个打包需要的子镜像文件,即内核,rootfs 等。可以使用冒号分隔,前面为SDK 中的文件,后面为打包进OTA 包的文件名。若没有冒号则使用原文件名字。使用相对于tina 根目录的相对路径进行描述。其中第一个必须为swdescription。
- 编译好所需的子镜像,例如主系统的内核和rootfs,recovery 系统等。
- 执行swupdate_pack_swu 生成swupdate 升级包。不带参数执行,则会在特定路径下寻找sw-subimgs.cfg,解析配置生成OTA 包。带参数-xx 执行,则会在特定路径下寻找swsubimgs-xx.cfg,解析配置生成OTA 包。例如执行swupdate_pack_swu -sign,则会寻找sw-subimgs-sign.cfg,如此方便配置多个不同用途的sw-subimgs-xx.cfg。
注:不同介质使用的boot0/uboot 镜像不同,swupate_pack_swu 需要sys_config.fex 中的storage_type 配置明确指出介质类型,才能取得正确的boot0.img 和
uboot.img 具体可直接查看build/envsetup.sh 中swupdate_pack_swu 的实现。
3.4 recovery 系统方案举例
3.4.1 配置分区和env
在分区表中,增加一个recovery 分区,用于保存recovery 系统。
size 根据实际recovery 系统的大小,再加点裕量。
download_file 可以留空,因为OTA 第一步就是写入一个recovery 系统。
当然也可以配置上download_file,并在打包固件之前先编译好recovery 系统,一并打包到固件中,这样出厂就带recovery 系统,后续的OTA 执行过程,可以考
虑不写入recovert 系统,用现成的,直接重启并升级主系统。
在env 中指定:
boot_partition=boot
root_partition=rootfs
并配置boot_normal 命令,从$boot_partition 变量指定的分区加载系统。
3.4.2 配置主系统
lunch 选择方案后, make menuconfig, 选上swupdate。
3.4.3 配置recovery 系统
假设没有现成的recovery 系统配置,则我们从主系统配置修改得到。lunch 选择方案后, 拷贝配置文件。
cdevice
cp defconfig defconfig_ota
根据上文介绍,make ota_menuconfig 选上swupdate, ramdisk, recovery 后缀等必要的配置。
recovery 系统整个运行在ram 中,如果系统过大会无法启动,所以需要进行裁剪。make ota_menuconfig, 将不必要的包尽量从recovery 系统中去掉。
3.4.4 准备sw-description
这里我们直接使用:
target/allwinner/generic/swupdate/sw-description
内容如下,中文部分是注释,原文件中没有。
/* 固定格式,最外层为software = */
software =
/* 版本号和描述*/
version = "0.1.0";
description = "Firmware update for Tina Project";
/*
* 外层tag,stable,
* 没有特殊含义,就理解为一个字符串标志即可。
* 可以修改,调用的时候传入匹配的字符串即可
*/
stable =
/*
* 内层tag,upgrade_recovery,
* 当调用swupdate xxx -e stable,upgrade_recovery时,就会匹配到这部分,执行{}内的动作,
* 可以修改,调用的时候传入匹配的字符串即可
*/
/* upgrade recovery,uboot,boot0 ==> change swu_mode,boot_partition ==> reboot */
upgrade_recovery =
/* 这部分是为了在主系统中,升级recovery系统,升级uboot和boot0 */
/* upgrade recovery */
images: ( /* 处理各个image */
filename = "recovery"; /* 源文件是OTA包中的recovery文件*/
device = "/dev/by-name/recovery"; /* 要写到/dev/by-name/recovery节点中, 这
个节点在tina上就对应recovery分区*/
installed-directly = true; /* 流式升级,即从网络升级时边下载边写入, 而不是先完
整下载到本地再写入,避免占用额外的RAM或ROM */
,
filename = "uboot"; /* 源文件是OTA包中的uboot文件*/
type = "awuboot"; /* type为awuboot,则swupdate会调用对应的handler做处理*/
,
filename = "boot0"; /* 源文件是OTA包中的boot0文件*/
type = "awboot0"; /* type为awuboot,则swupdate会调用对应的handler做处理*/
);
/* image处理完之后,需要设置一些标志,切换状态*/
/* change swu_mode to upgrade_kernel,boot_partition to recovery & reboot*/
bootenv: ( /* 处理bootenv,会修改uboot的env分区*/
/* 设置env:swu_mode=upgrade_kernel, 这是为了记录OTA进度*/
name = "swu_mode";
value = "upgrade_kernel";
,
/* 设置env:boot_partition=recovery, 这是为了切换系统,下次uboot就会启动
recovery系统(kernel位于recovery分区) */
name = "boot_partition";
value = "recovery";
,
/* 设置env:swu_next=reboot, 这是为了跟外部脚本配合,指示外部脚本做reboot动作*/
name = "swu_next";
value = "reboot";
/* 实际有什么其他需求,都可以灵活增删标志来解决, 外部脚本和应用可通过fw_setenv/
fw_printenv操作env */
/* 注意,以上几个env,是一起在ram中修改好再写入的, 不会出现部分写入部分未写入的情况*/
);
;
/*
* 内层tag,upgrade_kernel,
* 当调用swupdate xxx -e stable,upgrade_kernel时,就会匹配到这部分,执行{}内的动作,
* 可以修改,调用的时候传入匹配的字符串即可。
*/
/* upgrade kernel,rootfs ==> change sw_mode */
upgrade_kernel =
/* upgrade kernel,rootfs */
/* image部分,不赘述*/
images: (
filename = "kernel";
device = "/dev/by-name/boot";
installed-directly = true;
,
filename = "rootfs";
device = "/dev/by-name/rootfs";
installed-directly = true;
);
/* change sw_mode to upgrade_usr,change boot_partition to boot */
bootenv: (
/* 设置env:swu_mode=upgrade_usr, 这是为了记录OTA进度*/
name = "swu_mode";
value = "upgrade_usr";
,
/* 设置env:boot_partition=boot, 这是为了切换系统,下次uboot就会启动主系统(
kernel位于boot分区) */
name = "boot_partition";
value = "boot";
);
;
/* 内层tag,upgrade_usr,
当调用swupdate xxx -e stable,upgrade_usr时,就会匹配到这部分,执行{}内的动作,
可以修改,调用的时候传入匹配的字符串即可*/
/* upgrade usr ==> clean ==> reboot */
upgrade_usr =
/*
* misc-upgrade的小容量方案,将usr拆成独立分区了。
* 这里我们不需要,如果保留的话,不做任何image操作即可。
* 也可以彻底删除这一部分,并将上面的upgrade_usr改掉。
*/
/* upgrade usr */
/* OTA结束,清空各种标志*/
/* clean swu_param,swu_software,swu_mode & reboot */
bootenv: (
name = "swu_param";
value = "";
,
name = "swu_software";
value = "";
,
name = "swu_mode";
value = "";
,
name = "swu_next";
value = "reboot";
);
;
;
/* 当没有匹配上面的tag,进入对应的处理流程时,则运行到此处。我们默认清除掉一些状态*/
/* when not call with -e xxx,xxx just clean */
bootenv: (
name = "swu_param";
value = "";
,
name = "swu_software";
value = "";
,
name = "swu_mode";
value = "";
,
name = "swu_version";
value = "";
);
说明:
升级过程会进行两次重启。具体的:
(1)升级recovery 分区(recovery),uboot(uboot),boot0(boot0) 。设置boot_partition为recovery。
(2)重启,进入recovery 系统。
(3)升级内核(kernel) 和rootfs(rootfs) 。设置boot_partition 为boot。
(4)重启,进入主系统,升级完成。
3.4.5 准备sw-subimgs.cfg
我们直接看下tina 默认的:
target/allwinner/generic/swupdate/sw-subimgs.cfg
内容如下,中文部分是注释,原文件中没有。
swota_file_list=(
#取得sw-description,放到OTA包中。
#注意第一行必须为sw-description。如果源文件不叫sw-description,可在此处加:sw-description做一次重命名
target/allwinner/generic/swupdate/sw-description
#取得boot_initramfs_recovery.img,重命名为recovery,放到OTA包中。以下雷同
out/$TARGET_BOARD/boot_initramfs_recovery.img:recovery
#uboot.img和boot0.img是执行swupdate_pack_swu时自动拷贝得到的,需配置sys_config.fex中的
storage_type
out/$TARGET_BOARD/uboot.img:uboot
#注:boot0没有修改的话,以下这行可去除,其他雷同,可按需升级
out/$TARGET_BOARD/boot0.img:boot0
out/$TARGET_BOARD/boot.img:kernel
out/$TARGET_BOARD/rootfs.img:rootfs
#下面这行是给小容量方案预留的,目前注释掉
#out/$TARGET_BOARD/usr.img:usr
)
说明:
指明打包swupdate 升级包所需的各个文件的位置。这些文件会被拷贝到out 目录下,再生成swupdate OTA 包。
3.4.6 编译OTA 包所需的子镜像
编译kernel 和rootfs。
make
编译recovery 系统。
swupdate_make_recovery_img
编译uboot。
muboot
打包,若需要升级boot0/uboot,则是必要步骤,打包会将boot0 和uboot 拷贝到out 目录下,并对头部参数等进行修改。生成的固件也可用于测试。注:如果希
望生成的固件的recovery分区是有系统的,则需要先编译recovery 系统,再打包。
pack / pack -s
生成OTA 包。因为我们使用的就是sw-subimgs.cfg,所以不同带参数。
注意,如果方案目录下存在sw-subimgs.cfg,则优先用方案目录下的。没有方案特定配置才用generic 下的。如果需要升级boot0/uboot,需要配置好
sys_config.fex 中的storage_type参数,swupdate_pack_swu 才能正确拷贝对应的boot0/uboot。
swupdate_pack_swu
3.4.7 执行OTA
3.4.7.1 准备OTA 包
对于测试来说,直接推入。
adb push out/<board>/swupdate/<board>.swu /mnt/UDISK
实际应用时, 可从先从网络下载到本地, 再调用swupdate, 也可以直接传入url 给swupdate。
3.4.7.2 调用swupdate
若使用原生的swupdate,则调用:
swupdate -i /mnt/UDISK/<board>.swu -e stable,upgrade_recovery
但这样不会在自启动的时候帮我们准备好swupdate 所需的-e 参数。
我们可以使用辅助脚本:
swupdate_cmd.sh -i /mnt/UDISK/<board>.swu -e stable,upgrade_recovery
3.5 AB 系统方案举例
3.5.1 配置分区和env
在分区表中,将原有的boot 分区和rootfs 分区,分区名改为bootA 和rootfsA。
将这两个分区配置拷贝一份,即新增两个分区,并把名字改为bootB 和rootfsB。
这样flash 中就存在A 系统(bootA+rootfsA) 和B 系统(bootB+rootfsB)。
一般是一个系统烧录两份。即分区表中的bootA 和bootB 都指定的boot.fex,rootfsA 和rootfsB 都指定的rootfs.fex。
在env 中,指定:
boot_partition=bootA
root_partition=rootfsA
并配置boot_normal 命令,从$boot_partition 变量指定的分区加载系统。
3.5.2 配置主系统
lunch 选择方案后, make menuconfig, 选上swupdate。
3.5.3 配置recovery 系统
AB 系统方案没有使用recovery 系统,无需配置和生成。
3.5.4 准备sw-description
这里我们直接使用:
target/allwinner/generic/swupdate/sw-description-ab
内容如下,中文部分是注释,原文件中没有。
/* 固定格式,最外层为software = */
software =
/* 版本号和描述*/
version = "0.1.0";
description = "Firmware update for Tina Project";
/*
* 外层tag,stable,
* 没有特殊含义,就理解为一个字符串标志即可。
* 可以修改,调用的时候传入匹配的字符串即可。
*/
stable =
/*
* 内层tag,now_A_next_B,
* 当调用swupdate xxx -e stable,now_A_next_B时,就会匹配到这部分,执行{}内的动作,
* 可以修改,调用的时候传入匹配的字符串即可。
*/
/* now in systemA, we need to upgrade systemB(bootB, rootfsB) */
now_A_next_B =
/* 这部分是描述,当前处于A系统,需要更新B系统,该执行的动作。执行完后下次启动为B系统*/
images: ( /* 处理各个image */
filename = "kernel"; /* 源文件是OTA包中的kernel文件*/
device = "/dev/by-name/bootB"; /* 要写到/dev/by-name/bootB节点中, 这个节点
在tina上就对应bootB分区*/
installed-directly = true; /* 流式升级,即从网络升级时边下载边写入, 而不是先完
整下载到本地再写入,避免占用额外的RAM或ROM */
,
filename = "rootfs"; /* 同上,但处理rootfs,不赘述*/
device = "/dev/by-name/rootfsB";
installed-directly = true;
,
filename = "uboot"; /* 源文件是OTA包中的uboot文件*/
type = "awuboot"; /* type为awuboot,则swupdate会调用对应的handler做处理*/
,
filename = "boot0"; /* 源文件是OTA包中的boot0文件*/
type = "awboot0"; /* type为awuboot,则swupdate会调用对应的handler做处理*/
);
/* image处理完之后,需要设置一些标志,切换状态*/
bootenv: ( /* 处理bootenv,会修改uboot的env分区*/
/* 设置env:swu_mode=upgrade_kernel, 这是为了记录OTA进度, 对于AB系统来说,此时
已经升级完成,置空*/
name = "swu_mode";
value = "";
,
/* 设置env:boot_partition=bootB, 这是为了切换系统,下次uboot就会启动B系统(
kernel位于bootB分区) */
name = "boot_partition";
value = "bootB";
,
/* 设置env:root_partition=rootfsB, 这是为了切换系统,下次uboot就会通过cmdline
指示挂载B系统的rootfs */
name = "root_partition";
value = "rootfsB";
,
/* 兼容另外的切换方式,可以先不管*/
name = "systemAB_next";
value = "B";
,
/* 设置env:swu_next=reboot, 这是为了跟外部脚本配合,指示外部脚本做reboot动作*/
name = "swu_next";
value = "reboot";
);
;
/*
* 内层tag,now_B_next_A,
* 当调用swupdate xxx -e stable,now_B_next_A时,就会匹配到这部分,执行{}内的动作,
* 可以修改,调用的时候传入匹配的字符串即可
*/
/* now in systemB, we need to upgrade systemA(bootA, rootfsA) */
now_B_next_A =
/* 这里面就不赘述了, 跟上面基本一致,只是AB互换了*/
images: (
filename = "kernel";
device = "/dev/by-name/bootA";
installed-directly = true;
,
filename = "rootfs";
device = "/dev/by-name/rootfsA";
installed-directly = true;
,
filename = "uboot";
type = "awuboot";
,
filename = "boot0";
type = "awboot0";
);
bootenv: (
name = "swu_mode";
value = "";
,
name = "boot_partition";
value = "bootA";
,
name = "root_partition";
value = "rootfsA";
,
name = "systemAB_next";
value = "A";
,
name = "swu_next";
value = "reboot";
);
;
;
/* 当没有匹配上面的tag,进入对应的处理流程时,则运行到此处。我们默认清除掉一些状态*/
/* when not call with -e xxx,xxx just clean */
bootenv: (
name = "swu_param";
value = "";
,
name = "swu_software";
value = "";
,
name = "swu_mode";
value = "";
,
name = "swu_version";
value = "";
);
说明:
升级过程会进行一次重启。具体的:
(1)升级kernel 和rootfs 到另一个系统所在分区,升级uboot(uboot),boot0(boot0) 。设置boot_partition 为切换系统。
(2)重启,进入新系统。
3.5.5 准备sw-subimgs.cfg
我们直接看下tina 默认的:
target/allwinner/generic/swupdate/sw-subimgs-ab.cfg
内容如下,中文部分是注释,原文件中没有。
swota_file_list=(
#取得sw-description-ab, 重命名成sw-description, 放到OTA包中。
#注意第一行必须为sw-description
target/allwinner/generic/swupdate/sw-description-ab:sw-description
#取得uboot.img,重命名为uboot,放到OTA包中。以下雷同
#uboot.img和boot0.img是执行swupdate_pack_swu时自动拷贝得到的,需配置sys_config.fex中的
storage_type
out/$TARGET_BOARD/uboot.img:uboot
#注:boot0没有修改的话,以下这行可去除,其他雷同,可按需升级
out/$TARGET_BOARD/boot0.img:boot0
out/$TARGET_BOARD/boot.img:kernel
out/$TARGET_BOARD/rootfs.img:rootfs
)
说明:
指明打包swupdate 升级包所需的各个文件的位置。这些文件会被拷贝到out 目录下,再生成
swupdate OTA 包。
3.5.6 编译OTA 包所需的子镜像
编译kernel 和rootfs。
make
编译uboot。
muboot
打包,若需要升级boot0/uboot,则是必要步骤,打包会将boot0 和uboot 拷贝到out 目录下,并对头部参数等进行修改。生成的固件也可用于测试。
pack / pack -s
生成OTA 包。因为我们使用的是sw-subimgs-ab.cfg,所以调用时带参数-ab。
注意,如果方案目录下存在sw-subimgs-ab.cfg,则优先用方案目录下的。没有方案特定配置才用generic 下的。
swupdate_pack_swu -ab
3.5.7 执行OTA
3.5.7.1 准备OTA 包
对于测试来说,直接推入。
adb push out/<board>/swupdate/<board>.swu /mnt/UDISK
实际应用时, 可从先从网络下载到本地, 再调用swupdate, 也可以直接传入url 给swupdate。
3.5.7.2 判断AB 系统
对于AB 系统方案来说,必须判断当前所处系统,才能知道需要升级哪个分区的数据。
判断当前是处于A 系统还是B 系统。
方式一:直接使用fw_printenv 读取判断当前的boot_partition 和root_partition 的值。
3.5.7.3 调用swupdate
若使用原生的swupdate,则调用:
当前处于A系统:
swupdate -i /mnt/UDISK/<board>.swu -e stable,now_A_next_B
当前处于B系统:
swupdate -i /mnt/UDISK/<board>.swu -e stable,now_B_next_A
但这样不会在自启动的时候帮我们准备好swupdate 所需的-e 参数。
我们可以使用辅助脚本:
当前处于A系统:
swupdate_cmd.sh -i /mnt/UDISK/<board>.swu -e stable,now_A_next_B
当前处于B系统:
swupdate_cmd.sh -i /mnt/UDISK/<board>.swu -e stable,now_B_next_A
3.6 辅助脚本swupdate_cmd.sh
为什么需要辅助脚本?
因为我们需要启动时能自动调用swupdate,自动传递合适的-e 参数给swupdate, 需要在合适的时候调用重启。
具体可直接看下脚本内容。
其基本思路是,当带参数调用时,脚本从传入的参数中,取出”-e xxx,yyy” 部分,将其余参数原样保存为env 的swu_param 变量。
取出的”-e xxx,yyy” 中的xxx 保存到env 的swu_software 变量, yyy 保存为env 的swu_mode变量。
然后就取出变量,循环调用。
swupdate $swu_param -e "$swu_software,$swu_mode"
sw-description 中可以通过改变env 的swu_software 和swu_mode 变量,来影响下次的调用参数。
实际应用时,可不使用此脚本,直接在主应用中,调用swupdate 即可。但要自行做好-e 参数的处理。
3.7 版本号
3.7.1 使用方式
在sw-descriptionwen 文件中,会配置一个版本号字符串,如:
software =
version = "1.0.0";
...
如果需要在升级时检查版本号,则可使用-N 参数,传入的参数代表小机端当前的版本号。如果不需要,则不传递-N 参数,忽略版本号即可。
swupdate 会进行比较,如果OTA 包中sw-descriptionwen 文件配置的版本号小于当前版本号,则不允许升级。
如何在小机端保存,获取,更新版本号,需要自定义, swupdate 没有规定具体的方式。
3.7.2 实现例子
应用可以按自己的逻辑维护版本号,不依赖系统env 等,只需按照swupate 要求传递参数即可。
此处提供一种依赖系统env 的实现方式供参考。
1.初始化设备端版本号。
首先需要定义设备端的版本号存放在哪,如何获取。
本方法定义设备端的版本号保存于env 之中,用swu_version 记录。则在SDK 中,需在env-x.x.cfg 中添加一行:
swu_version=1.0.0
表示此时版本为1.0.0,烧录固件后可执行fw_printenv 查看。
此步骤如果不做,则第一次烧录固件后env 中不存在swu_version,调用swupdate 时也无法传入获得并版本号,则第一次升级时不会检查版本。
注:这是tina 自定义的,可修改。只要读写这个版本号的地方均配套修改即可。实际应用时版本号可以存在任意分区中,或者存放在文件系统的文件中,或者硬编
码在系统和应用的二进制中,swupdate 未做限制。
2.在sw-description 中,设置OTA 包版本号。
升级时如果检查到OTA 包的sw-description 中的version,小于通过-N 参数传入的版本号,则不允许升级。
software =
version = "2.0.0";
...
例如当设备端的env 中设置了swu_version=2.0.0, 则调用swupdate_cmd.sh 时,会自动获取此参数并在调用swupdate 时传入-N 2.0.0。
此时若OTA 包中定义了version = “1.0.0” , 则此时升级会降低版本号,拒绝升级。
此时若OTA 包中定义了version = “2.0.0” , 则此次升级不会降低版本号,可以升级。
此时若OTA 包中定义了version = “3.0.0” , 则此次升级不会降低版本号,可以升级。
注:这是swupdate 原生的OTA 包版本号规则,不是tina 自定义的。
3.更新设备端版本号。
本方式版本号定义在env 中,则升级kernel 和rootfs 分区不会自动更新版本号,需要主动修改env。
若版本号是记录于rootfs 的某个文件,则不必在sw_description 中添加这种操作,因为更新rootfs 时版本号就自然更新了。但缺点是版本号跟rootfs 绑定了,每
次OTA 必须升级rootfs 才能更新版本号。
添加一个设置version 代表swu_version 的env 操作, 在OTA 时自动更新版本号。
software =
#表示这个OTA包的版本号,给swupdate读取检查的。原生规定的。
version = "2.0.0";
...
bootenv: (
...
#表示这个OTA包的版本号,OTA时会写入env分区,用于在下次OTA时读出作为-N参数的值。
Tina自定义的。
name = "swu_version";
value = "2.0.0";
...
);
...
注意,这么做的话,更新版本时需要修改env 中的版本号,以使得新的固件包拥有新的版本号,以及更新sw-description 的两个位置,一处是最上面的version =
xxx 的版本号,一处是bootenv 操作中的版本号,以使得OTA 包拥有新的版本号,以及能在OTA 时写入新版本号。
- 读取设备端版本号传给swupdate。
假如小机端是用脚本调用,则可用如下方式读取并传给swupdate:
swu_version=$(fw_printenv -n swu_version)
swupdate ... -N $swu_version
更好的方式是判断非空才传入,如此可支持不在env 中提前配置好swu_version。
check_version_para=""
[ x"$swu_version" != x"" ] &&
echo "now version is $swu_version"
check_version_para="-N $swu_version"
swupdate ... $check_version_para
注:
如果不使用版本号,则不在env 中设置swu_version,也不在bootenv 中写swu_version 即可。
如果sw_description 中的版本号一直保持v1.0.0,也总是能升级。
3.8 签名校验
3.8.1 检验原理
OTA 包中包含了sw-decsription 文件和各个具体的镜像,如kernel,rootfs。
如果对整个OTA 包进行完整校验,则会对流式升级造成影响,要求必须把整个OTA 包下载下来,才能判断出校验是否通过。
为了避免上述问题,swupdate 的校验是分镜像的,首先从OTA 包最前面取出两个文件,即swdescription和sw-description.sig,使用传入的公钥校验sw-
description,校验通过则认为sw-description 可信,则说明其中描述的image 和sha256 也是可信的。
后续无需再使用公钥,直接校验每个镜像的sha256 即可。因此可以逐个镜像处理,无需全部下载完毕再处理。
3.8.2 配置
swupdate 支持使用签名校验功能,需要在编译时选中对应功能。
出于安全考虑,一旦使能了校验,则swupdate 不再支持不使用签名的更新调用。
make menuconfig --->
Allwinner --->
<*> swupdate --->
[*] Enable verification of signed images
Signature verification algorithm (RSA PKCS#1.5) --->(选择校验算法,此处以RSA为例)
注意,recovery 系统也需要对应进行配置,即:
make ota_menuconfig ---> ...(重复以上配置)
3.8.3 使用方法
在PC 端使用私钥签名OTA 包。
在小机端调用swupdate 时,使用-k 参数传入公钥。
3.8.4 初始化key
Tina 封装了一条命令,生成默认的密钥对。执行:
swupdate_init_key
执行后会使用默认密码生成密钥对并拷贝到指定目录:
密码/私钥/公钥:
password:tina/target/allwinner/方案名/swupdate/swupdate_priv.password
private key:tina/target/allwinner/方案名/swupdate/swupdate_priv.pem
public key:tina/target/allwinner/方案名/swupdate/swupdate_public.pem
公钥拷贝到base-files中,供使用procd-init的方案使用
public key:tina/target/allwinner/方案名/base-files/swupdate_public.pem
公钥拷贝到busybox-init-base-files中,供使用busybox-init的方案使用
public key:tina/target/allwinner/方案名/busybox-init-base-files/swupdate_public.pem
此步骤仅为方便调试使用,只需要做一次。
用户也可使用自己的密码自行生成密钥,生成密钥的具体命令可参考build/envsetup.sh 中swupdate_init_key 的实现:
local password="swupdate";
echo "$password" > swupdate_priv.password;
echo "-------------------- init priv key --------------------";
openssl genrsa -aes256 -passout file:swupdate_priv.password -out swupdate_priv.pem;
echo "-------------------- init public key --------------------";
openssl rsa -in swupdate_priv.pem -passin file:swupdate_priv.password -out
swupdate_public.pem -outform PEM -pubout;
生成的密钥如swupdate_init_key 一般放到tina/target/allwinner/方案名/swupdate/ 中,即可在打包OTA 包时自动使用。
主要就是调用openssl 生成,私钥拷贝到SDK 指定目录,供生成OTA 包时使用。公钥放到设备端,供设备端执行OTA 时使用。
密钥的作用是校验OTA 包,意味着拿到密钥的人即可生成可通过校验的OTA 包,因此正式产品中一般密钥只掌握在少数人手中,并采取适当措施避免泄漏或丢失。
一种可参考的实践方式是,正式密钥做好备份,并仅部署在有权限管控的服务器上,只能代码入库后通过自动构建生成OTA 包,普通工程师无法拿到密钥自行本地
生成用于正式产品的OTA包。
3.8.5 修改sw-description
如上文所述,每个image 在使用时会校验sha256,因此需要在为每个更新文件在swdesctiption中添加sha256 属性,指定sha256 的值供更新过程校验。
有独立镜像的文件才需要sha256 属性,例如images 中配置的文件。而bootenv 等直接写在sw-description 中的,则无需sha256 属性。
目前脚本支持自动在生成OTA 包时,更新sha256 的值。但需要在sw-description 中,手工添加:
sha256 = @文件名
如:
$ git diff sw-description
diff --git a/allwinner/cowbell-perf1/configs/sw-description b/allwinner/cowbell-perf1/
configs/sw-description
index ed04b64..467ac3b 100644
--- a/allwinner/cowbell-perf1/configs/sw-description
+++ b/allwinner/cowbell-perf1/configs/sw-description
@@ -9,14 +9,17 @@ software =
filename = "boot_initramfs_recovery.img"
device = "/dev/by-name/recovery";
+ sha256 = "@boot以上是关于Tina_Linux_OTA_开发指南的主要内容,如果未能解决你的问题,请参考以下文章