5

首先是一些背景。当固件由于某种原因崩溃(例如堆栈溢出、损坏的函数指针......)时,它可能会跳转到某个地方并开始执行一些代码。这迟早会导致看门狗复位。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"
);

代码还没试过,明天试试。你看有什么问题吗?你如何/将如何解决这样的问题?

4

2 回答 2

3

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

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

您验证函数是否从一开始就运行的技术看起来不错,假设您wen在完成写入后清除了变量。

于 2012-02-17T00:12:05.047 回答
2

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

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

如果你的IP真的可以任意跳转,那可能就无法防止误写了。您可以期望的最好的结果是,您确保到达那里的唯一途径还设置了成功写入所需的所有其他内容。

于 2012-02-17T15:06:43.303 回答