Merge pull request #87 from paltatech/flash-memory-crc-integrity-check

Flash memory CRC integrity check
This commit is contained in:
Benjamin Vedder 2019-04-18 20:02:56 +02:00 committed by GitHub
commit b2816ef596
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 200 additions and 2 deletions

View File

@ -65,6 +65,7 @@ void conf_general_init(void) {
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
EE_Init();
FLASH_Lock();
}
/**
@ -113,6 +114,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) {
uint8_t *conf_addr = (uint8_t*)conf;
uint16_t var;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
@ -125,6 +127,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) {
break;
}
}
FLASH_Lock();
timeout_configure_IWDT();
@ -179,6 +182,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) {
bool is_ok = true;
uint8_t *conf_addr = (uint8_t*)conf;
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
@ -191,6 +195,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) {
break;
}
}
FLASH_Lock();
timeout_configure_IWDT();

27
crc.c
View File

@ -18,6 +18,7 @@
*/
#include "crc.h"
#include "stm32f4xx.h"
// CRC Table
const unsigned short crc16_tab[] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084,
@ -58,3 +59,29 @@ unsigned short crc16(unsigned char *buf, unsigned int len) {
}
return cksum;
}
/**
* @brief Computes the 32-bit CRC of a given buffer of data word(32-bit) using
* Hardware Acceleration.
* @param pBuffer: pointer to the buffer containing the data to be computed
* @param BufferLength: length of the buffer to be computed
* @retval 32-bit CRC
*/
uint32_t crc32(uint32_t *pBuffer, uint32_t BufferLength) {
uint32_t index = 0;
for(index = 0; index < BufferLength; index++) {
CRC->DR = pBuffer[index];
}
return (CRC->DR);
}
/**
* @brief Resets the CRC Data register (DR).
* @param None
* @retval None
*/
void crc32_reset(void) {
/* Reset CRC generator */
CRC->CR = CRC_CR_RESET;
}

4
crc.h
View File

@ -20,9 +20,13 @@
#ifndef CRC_H_
#define CRC_H_
#include <stdint.h>
/*
* Functions
*/
unsigned short crc16(unsigned char *buf, unsigned int len);
uint32_t crc32(uint32_t *buf, uint32_t len);
void crc32_reset(void);
#endif /* CRC_H_ */

View File

@ -92,7 +92,8 @@ typedef enum {
FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET,
FAULT_CODE_ENCODER_SPI,
FAULT_CODE_ENCODER_SINCOS_BELOW_MIN_AMPLITUDE,
FAULT_CODE_ENCODER_SINCOS_ABOVE_MAX_AMPLITUDE
FAULT_CODE_ENCODER_SINCOS_ABOVE_MAX_AMPLITUDE,
FAULT_CODE_FLASH_CORRUPTION
} mc_fault_code;
typedef enum {

View File

@ -25,6 +25,7 @@
#include "mc_interface.h"
#include "timeout.h"
#include "hw.h"
#include "crc.h"
#include <string.h>
/*
@ -35,6 +36,8 @@
#define APP_BASE 0
#define NEW_APP_BASE 8
#define NEW_APP_SECTORS 3
#define APP_MAX_SIZE (3 * (1 << 17))
#define EEPROM_EMULATION_SIZE 0x8000
// Base address of the Flash sectors
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) // Base @ of Sector 0, 16 Kbytes
@ -50,6 +53,23 @@
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) // Base @ of Sector 10, 128 Kbytes
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) // Base @ of Sector 11, 128 Kbytes
#define APP_CRC_WAS_CALCULATED_FLAG ((uint32_t)0xAAAAAAAA)
#define APP_CRC_WAS_CALCULATED_FLAG_ADDRESS (uint32_t*)(APP_MAX_SIZE - 8)
#define VECTOR_TABLE_ADDRESS ((uint32_t *)ADDR_FLASH_SECTOR_0)
#define VECTOR_TABLE_SIZE ((uint32_t)(ADDR_FLASH_SECTOR_1 - ADDR_FLASH_SECTOR_0))
#define APP_START_ADDRESS ((uint32_t *)(ADDR_FLASH_SECTOR_1 + EEPROM_EMULATION_SIZE))
#define APP_SIZE ((uint32_t)(APP_MAX_SIZE - VECTOR_TABLE_SIZE - EEPROM_EMULATION_SIZE))
typedef struct {
uint32_t crc_flag;
uint32_t crc;
}crc_info_t;
//Make sure the app image has the CRC bits set to '1' to later write the flag and CRC.
const crc_info_t __attribute__((section (".crcinfo"))) crc_info = {0xFFFFFFFF, 0xFFFFFFFF};
// Private constants
static const uint32_t flash_addr[FLASH_SECTORS] = {
ADDR_FLASH_SECTOR_0,
@ -96,12 +116,14 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) {
if (new_app_size > flash_addr[NEW_APP_BASE + i]) {
uint16_t res = FLASH_EraseSector(flash_sector[NEW_APP_BASE + i], VoltageRange_3);
if (res != FLASH_COMPLETE) {
FLASH_Lock();
return res;
}
} else {
break;
}
}
FLASH_Lock();
timeout_configure_IWDT();
utils_sys_unlock_cnt();
@ -110,6 +132,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) {
}
uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_t len) {
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
@ -121,9 +144,11 @@ uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_
for (uint32_t i = 0;i < len;i++) {
uint16_t res = FLASH_ProgramByte(flash_addr[NEW_APP_BASE] + offset + i, data[i]);
if (res != FLASH_COMPLETE) {
FLASH_Lock();
return res;
}
}
FLASH_Lock();
timeout_configure_IWDT();
@ -191,3 +216,98 @@ uint8_t* flash_helper_get_sector_address(uint32_t fsector) {
return res;
}
/**
* @brief Compute the CRC of the application code to verify its integrity
* @retval FAULT_CODE_NONE or FAULT_CODE_FLASH_CORRUPTION
*/
uint32_t flash_helper_verify_flash_memory(void) {
uint32_t crc;
// Look for a flag indicating that the CRC was previously computed.
// If it is blank (0xFFFFFFFF), calculate and store the CRC.
if( (APP_CRC_WAS_CALCULATED_FLAG_ADDRESS)[0] == APP_CRC_WAS_CALCULATED_FLAG )
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
crc32_reset();
// compute vector table (sector 0)
crc32((VECTOR_TABLE_ADDRESS), (VECTOR_TABLE_SIZE)/4);
// skip emulated EEPROM (sector 1 and 2)
// compute application code
crc = crc32(APP_START_ADDRESS, (APP_SIZE)/4);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, DISABLE);
// A CRC over the full image should return zero.
return (crc == 0)? FAULT_CODE_NONE : FAULT_CODE_FLASH_CORRUPTION;
}
else {
FLASH_Unlock();
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
//Write the flag to indicate CRC has been computed.
uint16_t res = FLASH_ProgramWord((uint32_t)APP_CRC_WAS_CALCULATED_FLAG_ADDRESS, APP_CRC_WAS_CALCULATED_FLAG);
if (res != FLASH_COMPLETE) {
FLASH_Lock();
return FAULT_CODE_FLASH_CORRUPTION;
}
// Compute flash crc including the new flag
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
crc32_reset();
// compute vector table (sector 0)
crc32(VECTOR_TABLE_ADDRESS, (VECTOR_TABLE_SIZE)/4);
// skip emulated EEPROM (sector 1 and 2)
// compute application code
crc = crc32(APP_START_ADDRESS, (APP_SIZE - 4)/4);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, DISABLE);
//Store CRC
res = FLASH_ProgramWord(APP_MAX_SIZE - 4, crc);
if (res != FLASH_COMPLETE) {
FLASH_Lock();
return FAULT_CODE_FLASH_CORRUPTION;
}
FLASH_Lock();
// reboot
NVIC_SystemReset();
return FAULT_CODE_NONE;
}
}
uint32_t flash_helper_verify_flash_memory_chunk(void) {
static uint32_t index = 0;
const uint32_t chunk_size = 8192;
uint32_t res = FAULT_CODE_NONE;
uint32_t crc = 0;
// Make sure RCC_AHB1Periph_CRC is enabled
if (index == 0) {
crc32_reset();
}
if (index < VECTOR_TABLE_SIZE) {
crc32((VECTOR_TABLE_ADDRESS + index), chunk_size/4);
}
else {
crc = crc32((uint32_t*)((uint32_t)APP_START_ADDRESS + index - VECTOR_TABLE_SIZE), chunk_size/4);
}
index += chunk_size;
if (index >= (VECTOR_TABLE_SIZE + APP_SIZE)) {
index = 0;
if (crc != 0) {
res = FAULT_CODE_FLASH_CORRUPTION;
}
}
return res;
}

View File

@ -27,5 +27,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size);
uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_t len);
void flash_helper_jump_to_bootloader(void);
uint8_t* flash_helper_get_sector_address(uint32_t fsector);
uint32_t flash_helper_verify_flash_memory(void);
uint32_t flash_helper_verify_flash_memory_chunk(void);
#endif /* FLASH_HELPER_H_ */

View File

@ -20,11 +20,14 @@
/*
* STM32F407xG memory setup.
* Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
* Note: flash2 length decreased by 8 bytes to use it as hardcoded CRC
* flags.
*/
MEMORY
{
flash : org = 0x08000000, len = 16k
flash2 : org = 0x0800C000, len = 480k
flash2 : org = 0x0800C000, len = 393216 - 8 /* NEW_APP_MAX_SIZE - CRC_INFO */
crcinfo : org = 0x0805FFF8, len = 8 /* CRC info*/
ram0 : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
ram1 : org = 0x20000000, len = 112k /* SRAM1 */
ram2 : org = 0x2001C000, len = 16k /* SRAM2 */
@ -142,6 +145,13 @@ SECTIONS
. = ALIGN(4);
_etext = .;
_textdata = _etext;
_crcinfo_start_address = 0x0805FFF8;
.crcinfo _crcinfo_start_address :
{
KEEP(*(.crcinfo))
} > crcinfo
.mstack :
{

29
main.c
View File

@ -49,6 +49,7 @@
#include "spi_sw.h"
#include "timer.h"
#include "imu.h"
#include "flash_helper.h"
#if HAS_BLACKMAGIC
#include "bm_if.h"
#endif
@ -74,6 +75,22 @@
// Private variables
static THD_WORKING_AREA(periodic_thread_wa, 1024);
static THD_WORKING_AREA(timer_thread_wa, 128);
static THD_WORKING_AREA(flash_integrity_check_thread_wa, 1024);
static THD_FUNCTION(flash_integrity_check_thread, arg) {
(void)arg;
chRegSetThreadName("Flash integrity check");
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
for(;;) {
if (flash_helper_verify_flash_memory_chunk() == FAULT_CODE_FLASH_CORRUPTION) {
NVIC_SystemReset();
}
chThdSleepMilliseconds(50);
}
}
static THD_FUNCTION(periodic_thread, arg) {
(void)arg;
@ -183,6 +200,17 @@ int main(void) {
timer_init();
conf_general_init();
if( flash_helper_verify_flash_memory() == FAULT_CODE_FLASH_CORRUPTION ) {
// Loop here, it is not safe to run any code
while (1) {
chThdSleepMilliseconds(100);
LED_RED_ON();
chThdSleepMilliseconds(75);
LED_RED_OFF();
}
}
ledpwm_init();
mc_configuration mcconf;
@ -233,6 +261,7 @@ int main(void) {
// Threads
chThdCreateStatic(periodic_thread_wa, sizeof(periodic_thread_wa), NORMALPRIO, periodic_thread, NULL);
chThdCreateStatic(timer_thread_wa, sizeof(timer_thread_wa), NORMALPRIO, timer_thread, NULL);
chThdCreateStatic(flash_integrity_check_thread_wa, sizeof(flash_integrity_check_thread_wa), LOWPRIO, flash_integrity_check_thread, NULL);
#if WS2811_TEST
unsigned int color_ind = 0;