Linux应用之OTA升级

本文介绍了Linux设备中的在线固件更新(OTA)技术,特别是使用swupdate工具进行AB系统升级的过程,包括分区保护、升级步骤、sw-description配置和sw-subimgs.cfg文件的准备。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Linux应用之OTA升级

OTA简单理解就是在线升级固件,将固件下载之后,相应的写入对应的分区,只是在这个过程,需要注意分区保护,避免升级过程出现断电导致设备变砖,所以需要做好断电保护。

OTA升级在Linux中,可以使用swupdate进行升级,升级可以分AB系统和recovery系统,下面主要介绍AB系统的升级。

AB系统升级

AB系统的意思就是设备的存储空间存在两份系统,两份系统是一样的,所以AB系统的操作如下:

  1. 先确认当前的分区表中是否有两份系统的分区表并增加downfile,两份系统应该包括内核以及rootfs;
  2. 了解清楚当前系统的是如何判断使用哪份内核和rootfs进行加载的,因为这个到切换AB系统的时候需要使用到;
  3. 完成上述准备之后,可以使用swupdate进行AB系统升级;

swupdate AB系统配置

准备 sw-description

内容如下,中文部分是注释,实际使用去掉。

/* 固定格式,最外层为software = { } */
software =
{
	/* 版本号和描述 */
	version = "0.1.0";
	description = "Firmware update for Linux 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文件 */
				volume = "bootB"; /* 要写到/dev/by-name/bootB节点中, 这个节点对应bootB分区 */
				installed-directly = true; /* 流式升级,即从网络升级时边下载边写入, 而不是先完整下载到本地再写入,避免占用额外的RAM或ROM */
			},
			{
				filename = "rootfs"; /* 同上,但处理rootfs,不赘述 */
				volume = "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";
                    volume = "bootA";
                    installed-directly = true;
                },
                {
                    filename = "rootfs";
                    volume = "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. 重启,进入新系统。
准备 sw-subimgs.cfg

内容如下,中文部分是注释。

swota_file_list=(
	#取得sw-description-ab, 重命名成sw-description, 放到OTA包中。
	#注意第一行必须为sw-description
	target/allwinner/d1-nezha/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 包。

执行OTA

调用 swupdate,

当前处于A系统:
swupdate -i /mnt/UDISK/tina-d1-nezha-ab.swu -e stable,now_A_next_B
当前处于B系统:
swupdate -i /mnt/UDISK/tina-d1-nezha-ab.swu -e stable,now_B_next_A
<think>好的,用户想了解Linux环境下OTA升级的具体操作步骤。首先,我需要回顾之前提供的参考资料,引用[1]和引用[2]中提到OTA升级的基本原理和流程,特别是针对嵌入式设备和Linux系统的情况。 用户的问题集中在详细步骤和教程,所以需要分步骤说明。首先应该概述OTA升级的总体流程,然后分解为各个阶段。根据引用[2],Linux OTA分为两个主要步骤:下载更新包和安装更新。但可能需要更详细的子步骤,比如准备阶段、下载、验证、安装、回滚等。 接下来,需要考虑具体操作。例如,如何生成更新包,使用什么工具(比如swupdate或Mender),如何设置服务器,客户端的脚本如何编写。需要确保每个步骤都有对应的命令或代码示例,这样用户更容易操作。 同时,要注意安全性,比如校验和签名验证,这在引用[1]中提到的设计缺陷可能涉及安全措施。需要强调在下载后验证文件的完整性,防止损坏或恶意软件。 可能还需要提到不同的文件系统方案,如A/B分区,这在嵌入式系统中常见,确保升级失败可以回滚。这部分在引用[1]中提到的OTA升级方案可能相关。 用户可能需要实际操作的例子,比如使用swupdate工具的具体命令,或者如何配置HTTP服务器。此外,测试和日志记录也是重要步骤,需要包含在内,帮助用户排查问题。 最后,生成相关问题,可能涉及优化方法、安全性或工具比较,这样用户可以进一步探索。要确保引用正确,比如在提到回滚机制时引用[1],在步骤分解时引用[2]。 检查是否需要更多的细节,比如差分更新和全量更新的区别,或者如何设置看门狗防止升级卡死,这些可能对用户有帮助。确保回答结构清晰,分步骤讲解,并给出代码示例,如shell脚本片段,符合用户要求的格式。</think>### Linux环境OTA升级详细操作步骤 #### 一、准备工作 1. **构建更新包** 使用$swupdate$工具生成包含内核、根文件系统、配置文件的`.swu`镜像包: ```bash swupdate -H "hwrev:1.0" -f sw-description -o update.swu ``` 其中`sw-description`文件需定义更新内容的分区映射[^2]。 2. **搭建传输服务** 配置HTTP服务器存放更新包(以Nginx为例): ```bash sudo apt install nginx sudo cp update.swu /var/www/html/ota/ ``` #### 二、客户端升级流程 1. **触发更新检测** 编写守护进程定期检查更新(示例Python脚本): ```python import requests def check_update(): response = requests.get("http://ota-server/version") return response.json()["latest_version"] > local_version ``` 2. **安全下载更新包** 通过HTTPS下载并验证签名: ```bash wget https://ota-server/update.swu --ca-certificate=ca.pem openssl dgst -sha256 -verify public.pem -signature update.sig update.swu ``` 3. **双分区切换更新** 采用A/B分区方案保证回滚能力(典型嵌入式方案): ```bash # 查看当前活动分区 fw_printenv upgrade_available # 写入新分区 dd if=update.swu of=/dev/mmcblk0p3 bs=1M # 切换标志位 fw_setenv upgrade_available 1 ``` 4. **调用swupdate安装** 通过hook脚本实现原子操作: ```bash swupdate -i update.swu -e "stable,copy1" \ -k public.pem \ -r "echo 0 > /proc/sysrq-trigger" # 防止系统崩溃 ``` 5. **验证与回滚机制** 添加启动时校验脚本`/etc/rc.local`: ```bash if [ -f /boot/bootcount ]; then if [ $(cat /boot/bootcount) -gt 3 ]; then fw_setenv upgrade_available 0 reboot fi fi ``` #### 三、关键安全措施 1. **加密传输** 使用TLS 1.3协议传输更新包,部署OCSP装订技术 2. **完整性校验** 必须包含SHA-256校验和EdDSA数字签名验证 3. **看门狗防护** 硬件看门狗在升级过程中持续喂狗: ```c int fd = open("/dev/watchdog", O_WRONLY); ioctl(fd, WDIOC_SETTIMEOUT, &timeout); while(updating){ write(fd, "\0", 1); sleep(10); } ``` #### 四、日志与调试 1. 记录升级过程到持久化存储: ```bash swupdate -v -d -l 3 -f /etc/swupdate.conf 2>&1 | tee /persist/ota.log ``` 2. 通过syslog上传远程服务器: ```bash logger -t OTA -n logserver.example.com -P 514 < ota.log ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chengwei_peng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值