【问题标题】:Linux-Based Firmware, how to implement a good way to update?Linux-Based Firmware,如何实现更新的好方法?
【发布时间】:2011-07-07 05:41:00
【问题描述】:

我正在使用 alix 2d13 开发基于 linux 的设备。

我开发了一个脚本,负责创建映像文件、创建分区、安装引导加载程序 (syslinux)、内核和 initrd,并负责将根文件系统文件放入正确的分区。

配置文件位于 tmpfs 文件系统上,并在系统启动时由软件创建,该软件读取驻留在自己分区上的 XML 文件。

我正在寻找一种更新文件系统的方法,我考虑了两种解决方案:

  • 固件更新是一个压缩文件,可能包含内核、initrd 和/或 rootfs 分区,这样,在重新启动时,initrd 会注意将 rootfs 映像添加到正确的分区;
  • 固件更新是一个压缩文件,其中可能包含两个 tar 归档文件,一个用于引导文件系统,一个用于根文件系统。

每种解决方案都有自己的优势: - 文件系统映像可以让我删除任何未使用的文件,但需要很多时间,并且会快速杀死紧凑型闪存; - 存档更小,更新所需的时间更少,但我很快就会在根文件系统上获得 caos。

另一种解决方案是放置一个文件列表并将更新前/后更新脚本放入 tar 存档中,这样任何不在文件列表中的文件都将被删除。

你怎么看?

【问题讨论】:

    标签: linux firmware buildroot


    【解决方案1】:

    我使用了以下方法。它有点基于here 提供的论文“构建与墨菲兼容的嵌入式 Linux 系统”。我使用了该论文中描述的versions.conf,而不是cfgsh。

    • 使用引导内核,其任务是环回挂载“主”根文件系统。如果您需要较新的内核,则在环回挂载后立即将 kexec 插入该较新的内核。我选择将引导内核的完整 init 以及busybox 和 kexec(都是静态链接的)放在 initramfs 中,而我的 init 是我编写的一个简单的 shell 脚本。
    • 一个或多个“主操作系统”根文件系统作为磁盘映像文件存在于“操作系统映像”文件系统上。引导内核根据versions.conf 文件选择其中之一。我只维护两个主要的操作系统映像文件,当前文件和备用文件。如果当前的失败(稍后将详细介绍失败检测),则引导内核引导回退。如果两者都失败或没有回退,则引导内核提供一个 shell。
    • 系统配置位于单独的分区上。这通常不会升级,但没有理由不能升级。
    • 共有四个分区:启动、操作系统映像、配置和数据。数据分区用于用于频繁写入的用户应用程序内容。引导永远不会以读/写方式安装。操作系统映像仅在升级期间(重新)安装读/写。 config 仅在需要更改配置内容时才以读/写方式安装(希望永远不会)。数据始终以读/写方式挂载。
    • 每个磁盘映像文件都包含一个完整的 Linux 系统,包括内核、初始化脚本、用户程序(例如,busybox、产品应用程序)以及在首次启动时复制到配置分区的默认配置。这些文件的大小可以容纳其中的所有内容。只要我允许足够的增长空间,以便操作系统映像分区总是足够大以容纳三个主要的操作系统映像文件(在升级期间,我不会删除旧的回退直到提取新的回退),我可以允许主操作系统映像根据需要增长。这些图像文件始终(环回)以只读方式安装。使用这些文件还消除了处理升级 rootfs 中单个文件失败的痛苦。
    • 通过将自解压 tarball 传输到 tmpfs 来完成升级。此脚本的开头重新安装操作系统映像读/写,然后将新的主操作系统映像提取到操作系统映像文件系统,然后更新versions.conf 文件(使用“墨菲”论文中描述的重命名方法)。完成此操作后,我触摸一个标记文件,指示已发生升级,然后重新启动。
    • 引导内核查找此标记文件。如果找到它,它会将其移动到另一个标记文件,然后启动新的主 OS 映像文件。主 OS 映像文件应在成功启动时删除标记文件。如果没有,看门狗将触发重新启动,然后启动内核将看到这一点并检测到故障。
    • 您会注意到在升级过程中有几个可能的故障点:在升级过程中同步versions.conf,以及触摸/删除戳文件(三个实例)。我找不到进一步减少这些并实现我想要的一切的方法。如果有人有更好的建议,我很想听听。写入操作系统映像时也可能发生文件系统错误或电源故障,但我希望 ext3 文件系统能够在这种情况下提供一些生存机会。

    【讨论】:

    • 我非常喜欢你的解决方案,最后我做了一些非常相似但没有启动故障检测的事情,但我认为我会实现类似的东西:-我将为启动故障检测保留一个扇区使用直接 io 和同步操作在其中写入 - 引导内核将启动一个 initrd,它将报告一个尝试引导,带有时间戳并安装操作系统映像 - 在引导过程中,新的 initrd 将逐步报告时间戳,识别问题的启动阶段 - 最终将在启动故障检测扇区中报告“全部完成”
    • 对于升级,我更喜欢下载数据分区中的压缩包,并且在重新启动时,如果第一个 initrd 检测到升级压缩包,它将处理压缩包(可能有用添加两个特殊文件到识别要删除的文件并执行升级脚本)。升级后,第一个 initrd 将 kexec 到新内核,将引导报告为升级(因此可以删除 tarball)。出于安全原因,tarball 需要使用私钥签名。要报告错误,它可以使用之前的磁盘扇区(启动失败检测),它只需要同步写入以避免问题
    • 我喜欢你的“地位部门”想法。至少它将一些故障点移动到单个磁盘位置,如果该扇区发生故障,您可以想象有备用扇区并且您可以尝试恢复,或者至少提供“恢复模式”。
    • 我在主操作系统中进行升级的一个原因是我允许升级脚本是任何东西(它可以只更新一个配置文件——它不必做主操作系统)。我想让引导内核保持简单,因此它一旦发布就不必更改(尽管在那里甚至可以进行一些有限的升级——因为 kexec 从头开始​​,它运行(可能)更新的引导内核)。在升级脚本中加入尽可能多的升级智能应该可以帮助我实现这一目标。
    • 但是这样一来,您不会冒着更换旧文件的风险吗?虽然加载到内存中的东西是好的,但它不是所有其他的东西:在任何时候,可执行文件都可以动态加载共享库,一切都可能变得疯狂。也许支持这两种方法是最好的: - 简单的更新,只是配置文件,系统规则或类似的东西; - 复杂的更新,在磁盘上可执行和类似的。您可以通过停止服务/可执行文件和所有相关应用程序来避免此类问题,但这可能会变得过于复杂
    【解决方案2】:

    您可以有一个单独的分区用于更新(例如 Side1/Side2)。 现有的内核,rootfs在Side1,然后把更新放到Side2并切换。 通过这种方式,您可以减少磨损均衡并延长使用寿命,但设备会变得更昂贵。

    【讨论】:

      【解决方案3】:

      您可以在解压 tar 文件之前快速格式化分区。或者使用图像解决方案,但使用尽可能小的图像,并在 dd 之后调整文件系统大小(尽管这对于只读存储不是必需的)

      【讨论】:

      • 嗯,如果我做 dd 我真的不需要调整大小,因为文件系统会知道它的大小......我真正需要的是调整 mbr 中的分区大小。无论如何,我可以避免调整更大的分区(实际上我需要少于 30mb 的分区,所以 64mb 的分区就可以了)。我可能会选择 tar+pre/post update scripts+file list 解决方案
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多