更新基于 Linux 的设备的固件
本教程概述了更新基于 Linux 的固件的一般描述,并用一些具体的实现进行了说明。首先,考虑内存系统的各个部分(图 1)以及在将软件传输到新版本时应更新的内存部分。
通常,基于 Linux 的系统具有以下易失性内存结构。第一部分填充了 Linux 内核加载器,该加载器可以分几个阶段执行。例如,将小型引导加载程序复制到 CPU 内部存储器,执行外部存储器的初始化,并将第二级加载程序复制到外部 RAM。第二级加载程序(例如,U-Boot)将 Linux 内核复制到 RAM 并将控制权移交给它。最后,系统启动存储在 Flash 内存最后一部分中的自定义应用程序。因此,显然,有必要更新包含用户应用程序和操作系统内核的内存部分。

图 1. 基于 Linux 的设备的 Flash 内存的各个部分
启动更新过程的事件包括
- 系统启动(在这种情况下,更新应用程序内置于引导加载程序或在操作系统初始化时运行)。
- 操作期间连接外部介质(USB 或 SD 卡)。
- 检测到更新服务器上有较新版本的软件。
- 用户操作。
您可以通过插入介质复制更新文件,或者通过网络接收它们(如果系统配备了以太网端口或 Wi-Fi 模块)。通常,此过程使用各种加载程序广泛支持的 TFTP 协议。如果您使用操作系统中的程序执行更新过程,则可以使用 wget 应用程序或 libcurl 库从服务器复制必要的文件。
更新过程的重要部分是检查接收文件的版本及其完整性。您可以使用 MD5、CRC32 等算法执行此操作。我还建议检查新固件与设备的兼容性(PCB 版本)。
选项 1: 如果您的 ROM 容量足以存储旧固件和新固件(图 2),则系统实现该选项,以便在升级过程失败时可以回退到软件的先前版本。使用 flash_eraseall(用于擦除内存)和 nandwrite(用于将映像写入 NAND 内存)覆盖内存,这些工具包含在 mtd-utils 包中。
当收到并检查更新文件后,您可以开始将它们写入系统 ROM 的过程。您可以根据 ROM 容量实现各种软件更新选项。

图 2. 具有恢复旧固件功能的设备的 Flash 内存的各个部分
下一步是设置 U-Boot 引导加载程序环境变量以加载新固件。可以使用 fw_printenv 和 fw_setenv 等命令从 Linux 读取和写入 U-Boot 环境变量(源代码包含在 U-Boot 发行版中)。除了运行操作系统所需的典型参数(ROM 中内核映像的位置、包含根文件系统的部分名称等)之外,环境变量还可以存储失败的启动计数,并在达到某个阈值后将系统恢复到先前的软件(图 3)。

图 3. 具有恢复到先前固件功能的软件更新算法
选项 2: 对于小 ROM 容量,应将 Linux 内核和应用程序以及必要的库复制到 RAM。之后,您可以擦除并重写 Flash 内存。显然,如果更新过程失败,此选项不允许系统恢复到先前的固件。
U-Boot 加载程序实现了一个内置功能,用于检查加载的 Linux 内核映像的完整性(由 verify 变量控制),这有助于在操作系统启动之前检查其完整性,并(使用 hush 脚本)识别启动软件的替代来源(旧固件或 TFTP,http://www.denx.de/wiki/DULG/CommandLineParsing)。
让我们考虑几个开源项目(例如 OpenWrt、Openmoko 和 OpenInkpot)中软件更新机制的各种实现。
OpenWrt在一个 为 OpenWrt 网络路由器创建免费软件的项目中,您可以从各种来源(Web 界面或 TFTP)更新固件。
最简单的方法是通过 Web 页面更新。您只需访问设备设置页面(软件更新部分),然后使用特殊的 HTML 表单复制新软件。
第二种方法是通过 TFTP 更新软件。此方法非常适合那些创建了自己的固件映像的人。如果出现问题,您将能够(通过 TFTP)回退到旧固件。步骤如下:设备开机后,启动引导加载程序,该加载程序执行系统初始化,以及检查和加载可执行代码。如果固件未能通过完整性检查,则加载程序将被视为损坏,它将自动进入加载程序模式,直到通过网络加载固件。然后,您可以从 PC 通过 TFTP 下载新固件。
如有必要,您可以手动从 TFTP 服务器加载软件。您需要通过串行端口连接到 CFE(通用固件环境)控制台,并中断标准设备初始化过程。之后,您需要配置网络,从 TFTP 服务器复制新固件,并将其写入设备的 Flash 内存。
Openmoko一个为 Openmoko 智能手机创建免费固件的项目 (http://wiki.openmoko.org/wiki/USB_DFU) 是通过 USB 更新设备软件的一个示例。更新机制符合 设备固件升级 的 USB 设备类规范。此规范的目的是为更新配备 USB 的设备的软件提供一种多用途机制——例如,一种独立于制造商和特定硬件平台的机制。这允许您在操作系统中使用单个程序在不同设备上安装软件,使用相应的固件映像。除了写入新固件外,USB 设备类规范还描述了在 PC 上读取当前固件的过程。
在 Openmoko 项目下,DFU 是 U-Boot 引导加载程序的修改版本的一部分。该项目还涉及 DFU-Util 实用程序的开发,该实用程序有助于将软件发送和写入设备的内部 NAND 内存,并将程序写入其随机存取存储器。您可以使用后一个功能来调试低级代码(例如内核代码),而无需重写 Flash 内存。此外,DFU-Util 允许读取 NAND 内存内容,以帮助创建固件备份。
OpenInkpotOpenInkpot 项目 使用 SD 存储卡来更新电子书的软件。您应将新软件作为 .oifw 文件下载到 SD 卡根目录中。供电后,修改后的 U-Boot 引导加载程序会检查卡上的固件,并使用 CRC32 验证其完整性。如果可以更新,则必须确认覆盖设备 Flash 内存的操作。然后,系统更新内核和根文件系统,或者完全重新安装软件,包括初始引导加载程序。
结论如您所见,有多种更新 Linux 软件的方法,即为您的设备配备对多种更新选项的支持,并选择最简单、最可靠的一种。