【发布时间】:2020-06-27 09:40:45
【问题描述】:
我已经为 Kinetis ARM Cortex-M4 微控制器实现了引导加载程序。
主应用程序(从 0x10000 开始)通过自定义 RS232 接口通过引导加载程序重新编程。我已经从引导加载程序和应用程序的角度实现了 jumpToApplication 和 jumpToBootloader 函数,到目前为止一切正常。
我很想了解的一个策略是在主应用程序损坏时该怎么办?
引导加载程序当前检查主应用程序的堆栈指针和程序计数器,然后再决定是否跳转。但是,如果主应用程序损坏,则会出现以下两个问题:
- 主应用程序将挂起,难以重新编程
- 微控制器将重新启动并卡在
bootloader>application>bootloader(etc) 循环中
我有一个SharedData 结构,它允许我在引导加载程序和应用程序之间共享数据(通过固定的 RAM 位置)。我已经考虑在这个结构中添加一个rebootCounter,它会在主应用程序中触发HardFaultInterrupt 时递增。
可以在引导加载程序中测试该值,并根据计数器值决定是留在引导加载程序中还是尝试启动应用程序。
是否有更多“行业标准”的方法来处理这个问题?
更新
为了澄清,提出这个问题的最终原因是涵盖以下场景:
- 在生产阶段通过 JTAG 将引导加载程序编程到器件中
- 在测试阶段加载主应用程序(最新版本)
- 在测试阶段,出现断电或连接问题,设备仅部分编程
- 当再次上电时,引导加载程序将“假定”闪存的主要部分中存在有效程序并“跳转”到该应用程序
- 微控制器现在卡在无人区,无法再次通过引导加载程序重新加载闪存,而无需打开产品外壳并通过 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