首先是一些背景。当固件由于某种原因崩溃(例如堆栈溢出、损坏的函数指针......)时,它可能会跳转到某个地方并开始执行一些代码。这迟早会导致看门狗复位。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"
);
代码还没试过,明天试试。你看有什么问题吗?你如何/将如何解决这样的问题?