首先是一些背景知识。当固件由于某种原因崩溃时(例如堆栈溢出、函数指针损坏......),它可能会跳转到某个地方并开始执行一些代码。这迟早会导致看门狗复位。 MCU 将重置,我们又回到正轨。除非...
当我们有写入闪存的代码(例如引导加载程序)时该怎么办?现在,我们可能会意外地直接跳到闪存写入代码 - 跳过所有检查。在看门狗吠叫之前,您将得到损坏的固件。这正是发生在我身上的事情。
现在有些人可能会说 - 修复导致我们甚至开始编写代码的根本错误。嗯,当你开发时,你会不断地改变代码。即使现在没有这样的错误,明天也可能会有。此外,没有代码是没有错误的——或者至少不是我的。
所以现在我正在做某种交叉检查。我有一个名为“wen”的变量,在常规检查之前将其设置为 0xa5(例如检查以确保目的地有效)。然后在进行实际删除或写入之前,我检查“wen”是否确实设置为 0xa5。否则,这意味着我们不知何故意外地开始编写代码。成功写入后“wen”被清除。我已经用 C 语言完成了这个工作,效果很好。但理论上仍然有轻微的机会发生损坏,因为从最终检查“wen”到写入 SPMCR 寄存器,几乎没有指令。
现在我想通过将此检查放入汇编中(在写入 SPMCR 和 spm 指令之间)来改进这一点。
__asm__ __volatile__
(
"lds __zero_reg__, %0\n\t"
"out %1, %2\n\t"
"ldi r25, %3\n\t"
"add __zero_reg__, r25\n\t"
"brne spm_fail\n\t"
"spm\n\t"
"rjmp spm_done\n\t"
"spm_fail: clr __zero_reg__\n\t"
"call __assert\n\t"
"spm_done:"
:
: "i" ((uint16_t)(&wen)),
"I" (_SFR_IO_ADDR(__SPM_REG)),
"r" ((uint8_t)(__BOOT_PAGE_ERASE)),
"M" ((uint8_t)(-ACK)),
"z" ((uint16_t)(adr))
: "r25"
);
还没有尝试过代码,明天会尝试。你看到什么问题了吗?您将如何解决这样的问题?
最佳答案
我见过的一种技术是确保闪存写入例程之前的字节将触发某种看门狗超时,或重置处理器。这样,就不可能执行导致闪存写入函数的随机数据并且只是“落入”该函数。
在重置之前,您可能需要执行一些 NOP,以确保正确解释说明。
假设您在完成写入后清除了 wen
变量,那么您验证函数是否从一开始就运行的技术看起来不错。
关于assembly - 避免固件意外覆盖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9320652/