概览
在线下载(OTA)编程提供了一种从各种来源(例如,通过 USB 磁盘或 TCP/IP 网络)更新设备 firmware 的方法。目前,我们提供了一种通过 USB 磁盘实现 OTA firmware 升级的解决方案。用户可以参考 USB 升级解决方案,轻松实现自己的 OTA 解决方案。
架构
OTA firmware 升级通过以下系统模块实现:
主系统
主系统是运行用户应用程序的普通 Linux 系统。通常,它负责检测来自远程服务器或 USB 磁盘的新 OTA 包,并将 OTA 包下载到本地存储。在检测到并验证 OTA 包之后,主系统会在 BCB(bootloader 消息控制块)中设置升级信息,并重新启动系统,以通知 bootloader 将系统启动到恢复系统。
恢复系统
恢复系统是一个最小化的 Linux 系统。它负责根据主系统指定的特定 OTA 包来升级 firmware,将 OTA 包升级到设备。升级完成后,恢复系统会清除 BCB(bootloader 消息控制块)中的信息,并重新启动系统,以通知 bootloader 启动到新的主系统。
引导加载程序(bootloader)和 BCB
BCB 是 bootloader 消息控制块,是主系统和恢复系统共享的结构,也是主系统和恢复系统之间的桥梁。它可以存储是否进入主系统的信息,并在根据特定路径进行 OTA 升级时,将 OTA 包的路径也设置在 BCB 中。系统启动时,bootloader 会读取 BCB 的内容,进而决定进入主系统还是恢复系统。
三个模块之间的关系如下图所示。
分区布局
分区布局如下图所列。
除 rootfs 和 userdata 固件外,所有固件都有 A/B 分区。
Linux dtb image B
是用于恢复设备树固件的分区。Linux kernel image B
是用于恢复内核固件的分区。Linux vbmeta image B
是用于安全恢复 vbmeta 固件的分区。
下面的固件可以通过 OTA 更新。目前只有 km4_boot_all、km0_km4_app 和 boot 支持 A/B 槽位更新。
固件名 |
描述 |
支持 A/B 更新? |
---|---|---|
km4_boot_all |
启动 firmware |
√ |
km0_km4_app |
Wi-Fi/蓝牙 firmware |
√ |
boot |
Linux 启动固件 |
√ |
vbmeta |
Linux vbmeta 固件 |
x |
dtb |
Linux 设备树固件 |
x |
kernel |
Linux 内核固件 |
x |
rootfs |
Linux 根文件系统固件 |
x |
userdata |
Linux 用户数据固件 |
x |
启用 B 槽位启动
如果用户需要启用从槽位 B 启动,则需要将 bootloader 槽位 B 地址写入 OTP,将槽位 B 地址设置为 0x08300000。板子启动时,执行以下命令到 OTP。
# efuse wraw 36C 2 0083
当槽位 A 和槽位 B 都被刷写时,系统会检测以确定从哪个槽位启动。一般原则是比较两个槽位的版本号,以检查哪个槽位的版本更高。
BCB 与 Bootloader
BCB 的主要结构是结构体 bootloader_message。
//Bootloader Message (2KB)
struct bootloader_message {
char cmd[32];
char status[32];
char recovery[768];
char stage[32];
char reserved[1184];
};
其中只有 cmd 与 recovery 成员被使用到。
成员 cmd 指示板子是进入恢复系统还是主系统。如果设置为 boot-recovery ,则板子启动时将进入恢复系统。否则,板子将进入主系统。退出恢复系统时,该成员将被重置。
成员 recovery 用于存储 OTA 路径,当有新的 OTA 包可用时,该成员将在主系统中被设置。
成员 status 用于存储后续的恢复状态,而 reserved 计划用于存储恢复日志。
通过 USB 进行 OTA 更新的方案中,仅使用 BCB 的 cmd 来指示 bootloader 进入主系统或恢复系统。BCB 的其他成员未被使用。
主系统
主系统的流程如下面的图所示。提供了一种从 U 盘进行 OTA 更新的解决方案作为参考,该方案实现了从检测到 U 盘开始到图形用户界面的 OTA 更新。当 U 盘中有新的 OTA 版本时,GUI 可以接收到 OTA 版本的回调,GUI 可以决定是否更新此 OTA 版本。如果没有图形用户界面存在,当检测到 U 盘中有新的 OTA 版本时,主系统将设置 BCB 并重启以自动进入恢复系统。
主系统的 OTA 流程如下面的图所示。主系统中的 OTA 参考实现包含一个恢复守护进程:
恢复守护进程:它将检测是否有 U 盘连接到板子。如果是,它将尝试从 U 盘读取 OTA 包,如果 OTA 包存在,它将设置 BCB 并重启板子,以通知 bootloader 进入恢复系统。
USB OTA 解决方案的流程如下面的图所示。存储服务将检测 USB 热插拔,并通知 OTA 服务。OTA 服务会检查特定目录中是否有可用的 OTA 包。如果有可用的 OTA 包,OTA 服务会通知 OTA GUI(如果 OTA GUI 存在),然后通过恢复服务 API 设置 BCB(如果不存在 OTA GUI,OTA 服务将直接调用恢复服务 API)。当 BCB 设置成功后,恢复服务将重启板子以进入恢复系统。
恢复系统
恢复流程如下面的图所示。在 USB OTA 解决方案中,恢复过程将从内核获取 USB 热插拔回调,并在 USB 盘的特定目录中检测 OTA 包,目前 OTA 目录是 USB 根目录下的 ota
文件夹(将在后续部分介绍)。如果 ota
文件夹存在且其中检测到 OTA 包,恢复过程将优先更新此 OTA 包。如果没有 USB 连接到板子上,恢复过程将从 BCB 获取 OTA 包路径,然后从该路径进行升级。升级完成后,恢复过程将清除 BCB,并重启进入主系统。
恢复安装包流程
在 USB OTA 解决方案中,当主系统检测到 USB 插入时,它将设置 BCB 并重启进入恢复系统。恢复系统将加载分区表,从内核获取 USB 路径,解析配置文件(flash_image.cfg
,配置文件将在后续部分介绍),并根据 USB 上的配置文件进行升级。恢复的升级流程如下面的图所示。
恢复出厂设置
恢复系统还提供了出厂重置功能,出厂重置仅用于重置用户数据分区。
当主系统调用相应的 API 进行出厂重置时,板子将进入恢复系统,出厂重置的流程可以参考下面的图示。
在 NAND 闪存中,rootfs 和 userdata 采用 UBI 文件系统,而在 NOR 闪存中,rootfs 使用 squashfs,userdata 使用 jffs2,因此清除 userdata 在 NAND 和 NOR 闪存中有所不同。
恢复系统 A/B 更新
为了防止系统崩溃,A/B 槽位更新用于引导 firmware 固件、Wi-Fi/蓝牙固件和 Linux 引导固件。
A/B 分区的信息在上层内存布局中有所描述。
当板子进入恢复系统时,如果上述三个固件需要升级,恢复系统会从 Linux 驱动获取当前槽位信息,然后将 OTA 包更新到另一个槽位。
编译恢复系统
恢复系统内核配置在 <sdk>/sources/yocto/meta-realtek/meta-realtek-bsp/recipes-kernel/linux
目录中定义,kernel-5.4 对应的是 linux-ameba_5.4.bb
,而 kernel-6.6 对应的是 linux-ameba_6.6.bb
。
KBUILD_DEFCONFIG:rtl8730elh-recovery?= "rtl8730elh_recovery_defconfig"
恢复系统具有自己的设备树和内核固件。可以通过以下命令独立生成恢复固件:
source envsetup.sh -m rtl8730elh-recovery -d poky -b <recovery out>
mrecovery
包括设备树和内核固件的恢复固件将在 <recovery out>/tmp/deploy/images/rtl8730elh-recovery
文件夹下生成。
固件名 |
描述 |
---|---|
|
恢复设备树 blob 固件 |
|
恢复 linux 内核与根文件系统固件 |
烧录恢复固件
本节介绍如何单独将恢复固件烧录到开发板上。
开发板需要进入正常的烧录模式,然后打开 ImageTool,并在
tools/image_tool
下加载包含恢复信息的布局,如下图所示。对 NAND 闪存,载入
XXXX_Linux_NAND_128MB.rdev
或者XXXX_Linux_NAND_256MB.rdev
,对 NOR 闪存,载入XXXX_Linux_NOR_32MB.rdev
。
烧录恢复固件的步骤如下图所示。

备注
恢复固件需要更新,除非已经更新过恢复固件,否则只需烧录一次即可。
在 USB 上设置 OTA 环境
对于 USB OTA 升级,当前的 SDK OTA 支持 USB 中的固件文件和压缩的 gz 文件。无论是固件文件还是 gz 文件,都应该放在 USB 根目录下的 ota
文件夹中。
备注
在 Yocto 项目中,设备树固件(例如:rtl8730elh-va8-generic.dtb`
/ rtl8730elh-va8-full.dtb
)应重命名为 dtb.img
以用于 OTA。
对于 gz 压缩包,其名称必须为 updater.tar.gz
,并且需要在所有固件编译成功后生成,例如:tar -czvf updater.tar.gz boot.img dtb.img kernel.img rootfs.img userdata.img flash_image.cfg。文件 flash_image.cfg
是配置文件,是进行 OTA 更新所必需的,具体内容将在后面的章节中描述。
在 Windows 上设置 USB OTA 环境:
在 USB 根目录中创建一个名为 ota 的文件夹。
将需要刷写的固件文件和配置文件(
flash_image.cfg
)放入 OTA 目录。例如,如果用户想要更新 Linux 引导固件、Linux 内核固件、Linux dtb 固件和 Linux 根文件系统固件,则将boot.img
、dtb.img
、kernel.img
、rootfs.img
和flash_image.cfg
放在 USB 的ota
文件夹中。修改
flash_image.cfg
文件以刷写所需的固件。开发者只需修改flash_type
部分来启用或禁用对应固件的刷写。如果flash_type
设置为 1,则刷写该固件;如果设置为 0,则不刷写。在下图中,boot.img
、dtb.img
、kernel.img
、rootfs.img
将会被刷写到板子上,其他的则不会被刷写。
下面所列为一个示例:
{
"skip_md5_check" : "1",
"images" : [{
"name" : "KM4 boot",
"path" : "km4_boot_all.bin",
"flash_type" : 0
}, {
"name" : "KM4 image2",
"path" : "km0_km4_app.bin",
"flash_type" : 0
}, {
"name" : "AP boot image",
"path" : "boot.img",
"flash_type" : 1
}, {
"name" : "AP vbmeta",
"path" : "vbmeta.img",
"flash_type" : 0
}, {
"name" : "Device tree blob",
"path" : "dtb.img",
"flash_type" : 1
}, {
"name" : "Kernel image",
"path" : "kernel.img",
"flash_type" : 1
}, {
"name" : "Squashfs filesystem",
"path" : "rootfs.img",
"flash_type" : 1
}, {
"name" : "ubi/jffs2 filesystem",
"path" : "userdata.img",
"flash_type" : 0
}
]
}