基于Linux的固件,如何实现更新的好方法?

时间:2011-03-02 12:08:10

标签: linux firmware buildroot

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

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

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

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

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

每种解决方案都有自己的优势:   - 文件系统映像将让我删除任何未使用的文件,但需要很多时间,它会快速杀死紧凑型闪存;   - 存档较小,需要较少的更新时间,但我会在短时间内对根文件系统产生错误。

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

您怎么看?

3 个答案:

答案 0 :(得分:17)

我使用了以下方法。它有点基于“建立墨菲兼容的嵌入式Linux系统”一文,可用here。我使用了那篇文章中描述的versions.conf东西,而不是cfgsh的东西。

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

答案 1 :(得分:2)

您可以拥有一个单独的分区进行更新(Say Side1 / Side2)。 现有的内核,rootfs在Side1中,然后将更新放在Side2中并切换。 通过这种方式,您可以减少磨损均衡并延长使用寿命,但设备成本更高。

答案 2 :(得分:0)

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