Предотвращение случайной перезаписи прошивки

Сначала немного предыстории. Когда прошивка по какой-либо причине выходит из строя (например, переполнение стека, поврежденный указатель функции ...), может случиться так, что она куда-то прыгнет и начнет выполнять какой-то код. Это рано или поздно приведет к сбросу сторожевого таймера. MCU будет сброшен, и мы вернемся в нужное русло. Если только ...

А что насчет того, когда у нас есть код, который записывает во флеш-память (например, загрузчик)? Теперь может случиться так, что мы случайно перескочим прямо в код записи 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"
);

Код еще не пробовал, завтра сделаю. Вы видите какие-нибудь проблемы? Как бы вы решили такую ​​проблему?

5
задан Stefan 17 February 2012 в 06:59
поделиться