避免意外固件覆盖

时间:2012-02-16 23:20:59

标签: assembly embedded avr avr-gcc

首先是一些背景。当固件因任何原因崩溃(例如堆栈溢出,损坏的函数指针......)时,它可能会发生,它会跳转到某处并开始执行某些代码。这迟早会导致看门狗复位。 MCU将重置,我们将重新回到正轨。除非...

当我们有代码写入flash(例如bootloader)时怎么办?现在我们可能会意外地直接跳转到flash写代码 - 跳过所有检查。在看门狗吠叫之前,你最终会遇到损坏的固件。这正是发生在我身上的事情。

现在有人可能会说 - 修复导致我们甚至跳进编写代码的根错误。好吧,当你开发时,你不断改变代码。即使此刻没有这样的错误,明天也许会有。此外,没有代码没有错误 - 或者至少不是我的。

所以现在我正在进行某种交叉检查。我有一个名为'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"
);

尚未尝试过代码,明天会这样做。你看到有什么问题吗?你怎么解决这个问题?

2 个答案:

答案 0 :(得分:3)

我见过的一种技术是确保闪存写入例程之前的字节会触发某种看门狗超时,或重置处理器。这样,就不可能执行导致闪存写入功能的随机数据,只是“陷入”该功能。

在重置之前,您可能需要一些NOP才能确保正确解释说明。

验证函数从头开始运行的技巧看起来很好,假设您在完成写入后清除了wen变量。

答案 1 :(得分:2)

我不确定你为什么需要能够在你的bootloader中写入flash。我们的引导程序可以,因为它可以通过串口更新应用程序。因此,我们通过确保加载器不包含任何写入闪存的代码来消除无意写入的可能性。下载的代码是包含要写入的图像的同一包中的标题。板载映像具有存储的编程算法的校验和,并在运行之前对其进行验证。

如果您正在编写内部生成的内容,那么我会查看与硬件相关的互锁。如果先前已将特定离散输出引脚设置为ON,则仅允许写入。要回答“如果IP跳过检查会怎么样”的问题?你可以分为两部分。首先为算法设置一些关键变量。 (例如写入的地址 - 保持初始化为无效的存储器,并且只在写入之前的单独调用中正确设置它。然后让写入功能检查你的HW互锁。执行中断中的一个启用步骤,或响应计时器,如果您有流氓IP,则不太可能以正确的顺序命中。

如果您的IP可以真正跳到任何地方,则可能无法防止无意写入。您可以期待的最好的方法是确保到达那里的唯一途径还可以设置成功写入所需的一切。