具有构建具有单板更新的Linux组件的经验,并提供支持

图片

引言


目前,市场以合理的价格为每种口味提供了范围广泛的单一付款人。

通常,制造商会设计各种组件来评估平台,它们是新项目的起点,因此它们并不总是适合于特定任务。 在要求高可靠性的任务中,开发人员面临的问题是如何最终确定分发工具包,然后不为映像和更新系统的完整修订版付费。

在Internet上,几乎没有关于发行版本应该是什么以及如何实现其更新的信息,因此开发人员被迫提出“自行车”或使用自己的开发,而这些开发并不一定经过100%的测试。

由于我参与了各种Linux设备的软件开发(我的投资组合可以用develinux这个词在google上找到),并且还是11个部分的项目的作者,因此我经常不仅要负责构建程序集,还必须负责通过WEB或USB闪存开发更新机制。

在本文中,我想分享我在相关领域的经验和知识。

组装要求


在为各种设备开发组件和更新的过程中,我为自己确定了几个要求:

  • 突然关闭电源时,组件不应损坏;
  • 组件应快速加载;
  • 引导加载程序应正常运行;
  • 程序集必须支持更新。

我将在下面尝试更详细地解释这些要求,然后,我将描述将图像分为几个部分及其更新的3种方法。

突然关闭电源时,不得损坏组件。


谁需要设备在第十次重启后停止工作? 为了没有人! 如果您使用现成的发行版(并且用于嵌入式的发行版很少),那么在包装盒中如果没有文件,它们在这方面都是非常不可靠的。 我非常清楚地记得我在imx6下使用ubuntu的项目,卡上的文件系统已损坏,有时是从第十次重新启动开始,有时是从第四十次开始,这取决于天空中的星星。 该项目保存了FS aufs。 事实是ubuntu并非设计为只读的,它应该始终写一些东西。 我记得另一个项目中的类似情况,其中yocto用于SD卡。 因此,请注意,通常,SD卡是崩溃最快的驱动器类型,比emmc和nand更可靠。 如果您使用SD卡,建议在操作过程中尽可能少地写入SD卡,扇区的背景传输算法非常难以预测,我使用了世界品牌的数十种不同SD卡,但没有找到我推荐的单卡。
但是SD卡具有几个优点,它们价格实惠,价格便宜并且在调试软件中方便。

我为什么...而且,这就是问题-根FS应该是只读的,在运行过程中不应有任何条目。 您可能会想:怎么回事? 数百万的Android设备始终会编写某些东西,并且不会失败。 没错,但这全是因为大多数Android设备首先有电池,其次,根FS框架为虚拟磁盘,系统分区为只读。

如果系统应该可靠,则在根FS中安装软件包的各种事情都会破坏很多。 我建议将squashfs作为文件系统。 它工作迅速,无法编写任何内容,由于压缩而节省了空间...

但是如何保存配置,下载文件等等。 你问?
但是为此,您需要创建单独的RW分区。 如果您打算用NAND编写,那么我建议您使用一种经过验证的选项-UBIFS。 如果为NOR,则为jffs2。 如果我写另一个驱动器,我建议使用ext4,btrfs,ReiserFS,因为这些驱动器中我无法指出最好的FS, 每个人都有各种各样的问题。

在这种情况下,始终在安装rw分区之前,请务必使用类似fsck的实用程序检查分区中是否有错误。

组件应快速加载


设备下载速度会影响整体可用性。 在某些任务中,加载时间不超过30秒,在某些情况下,允许5分钟。 对我自己来说,我的锻炼时间最多为1分钟,越少越好。 等待下载一分钟以上的时间过长,似乎设备已挂起,因此,如果可以减少时间,则最好使用它。

引导加载程序应运行平稳


加载程序是装配将无法启动的地方。 最近,我经常观察单板制造商如何通过上载SD卡演示来促进开发,该演示中描述了如何使用简单地用dd命令填充的引导加载程序注册引导加载程序或完成的映像。 但是,如果SD卡死机了怎么办? 相同的情况并不少见。 就我个人而言,在我的实践中,卡经常掉下来。 这样,您要花几个小时才能工作,编写软件,使用bam,仅此而已...内核中的错误开始大量涌入,卡掉了。 但是,如果这是一种无需重启就可以在现场工作的设备怎么办? 顺便说一句,包括看门狗在内的重启并不总是能够使挂起的卡恢复正常,卡也没有复位信号,这不是emmc,当然这对于板的电路系统来说是一个更大的问题,如果板具有卡的电源复位功能,这将节省下来,但这并不是无处不在。 在某些板上,只有使电源或卡失真才有帮助。 根据我的经验,如果在运行期间在驱动器上进行记录,则不建议将引导加载程序与主组件一起存储在驱动器中。 如果系统没有使用引导加载程序将任何内容写入驱动器,并且这种情况很少发生,请。 以我的经验,在只读模式下,文件系统仅由于硬件错误而不是软件错误而变形。

引导加载程序应存储在安全可靠的驱动器上,例如单独的NOR或EEPROM芯片中。 以下是基于imx6ull芯片的模块示例,带有SPI NOR来存储引导加载程序。

图片

构建必须支持升级


没有更新,无处...我参与了许多项目,却从未获得完美的软件来完成工作。 总是会检测到错误或需要改进功能。 您需要了解,当人们编写软件时,他们会犯错误,而当人们使用该设备时,他们会想要更多。 在90%的情况下,缺少经过深思熟虑的更新系统会导致制造商头疼,并导致整个项目崩溃。 例如,已经开发出了用于运输的视频监控系统,该系统已在整个俄罗斯安装,结果发现营销人员低估了市场,没有提供流媒体,此外,在固件中发现了一些错误,此外,消费者也开始盯着竞争对手的方向,因为他们拥有所购买的设备中没有某些东西……是的,是的,在一个陌生的花园中,草莓更鲜美,天气也更好(心理)。
在这种情况下该怎么办? 如果支持此更新,则有很多解决方案,可以纠正错误,可以改善流广播,并且可以为用户定制功能,为用户固件提供说明,仅此而已。 但是,如果不提供支持,那么制造商将经历巨大的冒险,服务工程师出差到更换设备。

应该仔细考虑设备中的更新系统,并进行100%的测试。 这部分中的一个错误将使铁变成砖,因此不应有任何公差和例外。

更新过程必须能抵抗关闭电源,并且在任何情况下都不应损坏设备。

未来更新的分区方法概述


在许多方法中,我可以推荐我亲自实现的3种类型。 这些还不是全部方法;它们的范围超出了本文的范围。 所有这三种类型都有缺陷,远非理想,但是,在我看来,这接近常识的中庸之道。

方法一


图片

最简单,最实惠的方式:
将映像放在驱动器(例如SD卡)上,该驱动器将从u-boot闪存到设备的内置驱动器(例如NAND闪存)中。
在u-boot中,您需要为此准备脚本。
优点-这是最简单的更新类型,其开发最多需要1天的时间。
这种方法的缺点是缺乏过程的可视化,并且引导加载程序的功能非常有限,即 使用标准工具没有复杂的逻辑,除非您当然提出了自己的u-boot命令(但这是另一种更新,C是强大的力量)。 此方法不适用于通过WEB进行更新-控制固件映像的完整性是有问题的;在某些情况下,程序集的大小不应超过RAM的大小。
另外,在某些任务中,需要在升级过程中保存设置,而使用这种方法很难实现。

方法二


图片


被认为是最可靠和受保护的方法,但是最困难。 我建议将此方法用于特别负责任的开发中,因为 由于电路使用了额外的电路,因此它既可以保护图像免受损坏,又可以防止对主驱动器造成物理损坏。

该方法使用最小的构建(ramdisk大小为8-16MB)和主要构建。 Ramdisk是一个压缩的存档,因此16MB的版本实际上要小几倍。
最小装配的目的是评估主装配并加载它。
Ramdisk由FIT映像中的内核和u-boot脚本托管。

为什么选择FIT图片,它能提供什么? FIT映像是u-boot支持的格式。 它确保所有组件(内核,dts,ramdisk,脚本)的完整性。 FIT映像的解压缩是在u-boot中执行的,如果校验和未收敛,则u-boot将拒绝加载它。 这很方便,即 无需自己进行完整性控制,无需分别编写多个文件或创建自己的映像,所有操作均由FIT映像完成。 FIT映像通常占用7-20MB,应将其写入单独的高度可靠的驱动器中,例如,在qspi或Flash中。 主机组件可以存储在更便宜且不可靠的内存中,例如NAND闪存。 由于主要工作将在主机中进行,因此恰恰是它首先会受到损坏。 在这种情况下,具有最少rootfs的单独驱动器将可以解决。

引导过程。

u-boot下载一个脚本,该脚本尝试使用FIT更新(FIT2),然后使用FIT工厂固件(FIT1)。

如果不存在FIT2或违反了FIT2的完整性,则适合性测试将失败,并且u-boot将加载第一个FIT(FIT1)。 如果有FIT更新(FIT2),并且没有损坏,则将加载其ramdisk,以检查rootfs更新(Rootfs2)。

如果Rootfs2损坏,则脚本将删除FIT更新(FIT2),然后在重新启动后,将下载包含FIT(FIT1)和Rootfs1的出厂映像。

更新过程。

更新映像包含FIT,rootfs和各种程序集信息,包括其所有组件的校验和。 升级过程中将使用程序集信息来监视完整性和兼容性。

分步更新进度:

  • 检查映像与硬件和软件的兼容性,
  • 检查更新文件中映像的完整性,
  • 将Rootfs2从更新文件复制到先前准备的部​​分,
  • 检查该部分中复制图像的完整性,
  • 将FIT2复制到适当的部分,
  • 重新启动。

如果该过程失败,则FIT2的缺失或损坏不会破坏系统,因为 u-boot只会拒绝使用它并加载出厂映像。 因此,在升级过程中,不会检查FIT2的完整性。

更新后,新组件将以FIT2和Rootfs2的形式放置在主驱动器上。

这种方法可以抵抗驱动器的机械损坏和FS错误。

万一发生严重故障,工厂映像将启动,恢复软件将在其中运行,例如,可以对NAND进行双重检查,使用SSH协议从网络下载固件,然后进行记录。

我仅给出了恢复的示例,有很多选择。 在这种方法中,恢复过程由成熟的Linux驱动,它可以完成所有工作……而不是第一个版本中的引导程序。

方法3


图片


由于这种更新效果很好,因此几乎在所有11个部分的项目中都使用这种更新。

此更新适用于任何组件大小,任何类型的驱动器。 与以前的类型不同,这里的SPI NOR仅用于u-boot,因此具有较小的尺寸和较低的成本,1 MB足够。

这种类型的更新不需要单独构建ramdisk,这意味着可以节省编程时间,以备将来开发和支持。

该示例使用SD卡驱动器,但也可以使用UBIFS为NAND,没有区别。 在这种方法中,加载之前无需检查Rootfs RO,如果组件损坏,系统将不会知道它已损坏,而是将其循环加载。 此处假定RO部分中的数据无法以任何方式更改,这种方法消除了驱动器的物理故障。 如果驱动器身体不健康,则必须将设备运送到服务中心,不提供自我修复功能。 这是提高开发速度,更便宜的支持和更便宜的元素基础所必须付出的代价,但这是合理的。 为什么要保证几乎从未发生过的事情。

下载和更新的逻辑与以前的方法相同。

在引导的情况下,u-boot首先加载FIT更新(FIT2),如果不存在或违反完整性,则u-boot加载第一个FIT(FIT1),工厂开始缝合的程序集将以此类推,直到系统更新为止。 系统更新后,将出现FIT2和Rootfs2。 在这种情况下,设备启动时,将首先启动FIT更新(FIT2)。 在每个FIT中存储的u-boot脚本中,必须写出要挂载的rootfs。

共享分区RW


在图表上,到处都有一个共享分区块,这是一组用于编写的部分。 仅在此处进行任何输入。 为了清楚起见,共享分区显示为一个分区。 实际上,其中有3种:对于配置在镜像中工作的配置,两个较小;对于其他所有配置,一个较大。 另外,我建议您在更新时保留一些配置,这很方便,例如,如果您配置网络并升级,则无需重新配置网络设置。

总结一下


本文讨论了三种支持更新的程序集,所有这些程序都由我亲自检查过,您可以在项目中安全地使用它们。

目前,我仅使用最后两个,因为它们最适合要求。 为了清楚起见,您可以看到使用这些类型的更新的设备的示例(11部分的详细信息):

  • 通过4G / WiFi / LAN的RS485中继器
  • 4K V-By-One工业显示控制器控制板,
  • 集成机库气候控制系统,
  • 2DisplayPort-LVDS工业显示视频控制器,
  • 线路控制系统
  • VPN网关。

如果我的文章有用且有趣,我准备在此站点上进一步分享我在嵌入式Linux领域的经验和行之有效的技术解决方案。

谢谢大家
戈尔恰科夫·伊利亚
电报: develinux

Source: https://habr.com/ru/post/zh-CN470519/


All Articles