【问题标题】:Bootloader Strategy for Corrupt Applications损坏应用程序的引导加载程序策略
【发布时间】:2020-06-27 09:40:45
【问题描述】:

我已经为 Kinetis ARM Cortex-M4 微控制器实现了引导加载程序。

主应用程序(从 0x10000 开始)通过自定义 RS232 接口通过引导加载程序重新编程。我已经从引导加载程序和应用程序的角度实现了 jumpToApplicationjumpToBootloader 函数,到目前为止一切正常。

我很想了解的一个策略是在主应用程序损坏时该怎么办?

引导加载程序当前检查主应用程序的堆栈指针和程序计数器,然后再决定是否跳转。但是,如果主应用程序损坏,则会出现以下两个问题:

  1. 主应用程序将挂起,难以重新编程
  2. 微控制器将重新启动并卡在bootloader > application > bootloader (etc) 循环中

我有一个SharedData 结构,它允许我在引导加载程序和应用程序之间共享数据(通过固定的 RAM 位置)。我已经考虑在这个结构中添加一个rebootCounter,它会在主应用程序中触发HardFaultInterrupt 时递增。

可以在引导加载程序中测试该值,并根据计数器值决定是留在引导加载程序中还是尝试启动应用程序。

是否有更多“行业标准”的方法来处理这个问题?

更新

为了澄清,提出这个问题的最终原因是涵盖以下场景:

  1. 在生产阶段通过 JTAG 将引导加载程序编程到器件中
  2. 在测试阶段加载主应用程序(最新版本)
  3. 在测试阶段,出现断电或连接问题,设备仅部分编程
  4. 当再次上电时,引导加载程序将“假定”闪存的主要部分中存在有效程序并“跳转”到该应用程序
  5. 微控制器现在卡在无人区,无法再次通过引导加载程序重新加载闪存,而无需打开产品外壳并通过 JTAG 重新刷新芯片 - 当产品在字段。

在引导加载程序编程阶段,固件被逐字节编程和验证,以确保数据传输期间没有损坏。如果在此阶段发生损坏(例如,由于 USB 集线器问题导致的错误数据包),则引导加载程序将继续接受重新编程命令。

更新 #2

下面的帖子似乎也有类似的想法:

https://interrupt.memfault.com/blog/how-to-write-a-bootloader-from-scratch

【问题讨论】:

  • 引导加载程序的唯一任务应该是program主应用程序flash。为什么需要沟通?听起来好像您打算同时执行两者...为什么要检查“主应用程序 SP 和 PC”?如果引导加载程序发现主应用程序闪存已损坏,则尝试再次对其进行编程。就是这样。
  • “如何在不实际运行主应用程序的情况下确定主应用程序闪存是否损坏” 理想情况下,通过逐字节比较闪存。或者,如果这不可能,则使用 CRC32。我看不出您如何“从应用程序返回引导加载程序”,同时引导加载程序将应用程序存储在哪里?在另一段闪光?为什么那个闪光灯会更好?您实际上要防止什么 - 数据保留?
  • 闪存编程序列在将应用程序写入闪存(从地址 0x10000 开始)时已经执行了字节验证,但我想要说明的是,如果在编程期间断电,然后当板重新通电 - 我如何阻止应用程序执行,因为从所有意图和目的来看,它已损坏。不知何故,我需要留在引导加载程序中以允许进一步重新编程。我不是在掩盖不良代码——这不是我的问题。
  • 然后 - 传输通过应用程序字节计算的校验和。让您的引导加载程序根据编程数据计算校验和。比较它们。但无论如何,你应该在闪存中有一个字节来存储引导加载程序“状态”本身 - 即。编程或像往常一样。这样一旦它进入“编程”状态,就不会像你描述的那样在掉电后进入应用程序。
  • @KamilCuk 是的,我认为这是解决方案。我认为将校验和存储在闪存的最顶部也可能是值得的,这样我就可以通过重新启动和电源循环来验证这一点。如果此校验和在固件更新开始时被擦除,然后存储在最后(一旦 BL 比较并验证了校验和),那么只有经过验证的应用程序才能从引导加载程序执行。谢谢

标签: gcc embedded bootloader cortex-m


【解决方案1】:

首先,我建议在您的引导加载程序中添加一些延迟,以等待固件更新过程开始指示。我开发了类似的东西;桌面应用程序会定期发送启动字节,当您连接设备时,它会进入引导加载程序模式并再等待五秒钟以获取新的固件信息;所以闪存上是否有有效的主应用程序并不重要。 在固件更新过程擦除该扇区之前,检查主应用程序是否存在的另一种解决方案使用闪存的特定扇区获取固件信息。固件更新成功后,将特定数据写入该扇区。在引导加载程序中读取该扇区并验证闪存上是否存在有效的应用程序。

【讨论】:

    【解决方案2】:

    我会在应用程序的末尾添加一些“魔法”值(比如 0xDEAD00D),然后只跳转到魔法值的应用程序。您可以在0x10000 获得指向该位置的指针。

    为了让事情变得更加健壮,请在验证完成后对魔法值进行编程。

    【讨论】:

    • 谢谢 - 我实际上正在做一些非常相似的事情。我为主应用程序的 CRC、版本信息、“签名值”(如上)以及其他一些零碎保留了闪存的最后 0x1000 字节(1 个扇区)。只有引导加载程序可以写入该区域,并且只有在主应用程序被编程和验证后才会这样做。在重新编程操作开始时,这个结束扇区首先被擦除作为故障保护。似乎很健壮,可以满足我的需要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 2021-06-19
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 1970-01-01
    • 2018-08-31
    相关资源
    最近更新 更多