Skip to content

Commit b2816ef

Browse files
authored
Merge pull request vedderb#87 from paltatech/flash-memory-crc-integrity-check
Flash memory CRC integrity check
2 parents 5202ef4 + fbc7767 commit b2816ef

8 files changed

+200
-2
lines changed

conf_general.c

+5
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ void conf_general_init(void) {
6565
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
6666
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
6767
EE_Init();
68+
FLASH_Lock();
6869
}
6970

7071
/**
@@ -113,6 +114,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) {
113114
uint8_t *conf_addr = (uint8_t*)conf;
114115
uint16_t var;
115116

117+
FLASH_Unlock();
116118
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
117119
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
118120

@@ -125,6 +127,7 @@ bool conf_general_store_app_configuration(app_configuration *conf) {
125127
break;
126128
}
127129
}
130+
FLASH_Lock();
128131

129132
timeout_configure_IWDT();
130133

@@ -179,6 +182,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) {
179182
bool is_ok = true;
180183
uint8_t *conf_addr = (uint8_t*)conf;
181184

185+
FLASH_Unlock();
182186
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
183187
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
184188

@@ -191,6 +195,7 @@ bool conf_general_store_mc_configuration(mc_configuration *conf) {
191195
break;
192196
}
193197
}
198+
FLASH_Lock();
194199

195200
timeout_configure_IWDT();
196201

crc.c

+27
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919

2020
#include "crc.h"
21+
#include "stm32f4xx.h"
2122

2223
// CRC Table
2324
const unsigned short crc16_tab[] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084,
@@ -58,3 +59,29 @@ unsigned short crc16(unsigned char *buf, unsigned int len) {
5859
}
5960
return cksum;
6061
}
62+
63+
/**
64+
* @brief Computes the 32-bit CRC of a given buffer of data word(32-bit) using
65+
* Hardware Acceleration.
66+
* @param pBuffer: pointer to the buffer containing the data to be computed
67+
* @param BufferLength: length of the buffer to be computed
68+
* @retval 32-bit CRC
69+
*/
70+
uint32_t crc32(uint32_t *pBuffer, uint32_t BufferLength) {
71+
uint32_t index = 0;
72+
73+
for(index = 0; index < BufferLength; index++) {
74+
CRC->DR = pBuffer[index];
75+
}
76+
return (CRC->DR);
77+
}
78+
79+
/**
80+
* @brief Resets the CRC Data register (DR).
81+
* @param None
82+
* @retval None
83+
*/
84+
void crc32_reset(void) {
85+
/* Reset CRC generator */
86+
CRC->CR = CRC_CR_RESET;
87+
}

crc.h

+4
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@
2020
#ifndef CRC_H_
2121
#define CRC_H_
2222

23+
#include <stdint.h>
24+
2325
/*
2426
* Functions
2527
*/
2628
unsigned short crc16(unsigned char *buf, unsigned int len);
29+
uint32_t crc32(uint32_t *buf, uint32_t len);
30+
void crc32_reset(void);
2731

2832
#endif /* CRC_H_ */

datatypes.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ typedef enum {
9292
FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET,
9393
FAULT_CODE_ENCODER_SPI,
9494
FAULT_CODE_ENCODER_SINCOS_BELOW_MIN_AMPLITUDE,
95-
FAULT_CODE_ENCODER_SINCOS_ABOVE_MAX_AMPLITUDE
95+
FAULT_CODE_ENCODER_SINCOS_ABOVE_MAX_AMPLITUDE,
96+
FAULT_CODE_FLASH_CORRUPTION
9697
} mc_fault_code;
9798

9899
typedef enum {

flash_helper.c

+120
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "mc_interface.h"
2626
#include "timeout.h"
2727
#include "hw.h"
28+
#include "crc.h"
2829
#include <string.h>
2930

3031
/*
@@ -35,6 +36,8 @@
3536
#define APP_BASE 0
3637
#define NEW_APP_BASE 8
3738
#define NEW_APP_SECTORS 3
39+
#define APP_MAX_SIZE (3 * (1 << 17))
40+
#define EEPROM_EMULATION_SIZE 0x8000
3841

3942
// Base address of the Flash sectors
4043
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) // Base @ of Sector 0, 16 Kbytes
@@ -50,6 +53,23 @@
5053
#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) // Base @ of Sector 10, 128 Kbytes
5154
#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) // Base @ of Sector 11, 128 Kbytes
5255

56+
#define APP_CRC_WAS_CALCULATED_FLAG ((uint32_t)0xAAAAAAAA)
57+
#define APP_CRC_WAS_CALCULATED_FLAG_ADDRESS (uint32_t*)(APP_MAX_SIZE - 8)
58+
59+
#define VECTOR_TABLE_ADDRESS ((uint32_t *)ADDR_FLASH_SECTOR_0)
60+
#define VECTOR_TABLE_SIZE ((uint32_t)(ADDR_FLASH_SECTOR_1 - ADDR_FLASH_SECTOR_0))
61+
62+
#define APP_START_ADDRESS ((uint32_t *)(ADDR_FLASH_SECTOR_1 + EEPROM_EMULATION_SIZE))
63+
#define APP_SIZE ((uint32_t)(APP_MAX_SIZE - VECTOR_TABLE_SIZE - EEPROM_EMULATION_SIZE))
64+
65+
typedef struct {
66+
uint32_t crc_flag;
67+
uint32_t crc;
68+
}crc_info_t;
69+
70+
//Make sure the app image has the CRC bits set to '1' to later write the flag and CRC.
71+
const crc_info_t __attribute__((section (".crcinfo"))) crc_info = {0xFFFFFFFF, 0xFFFFFFFF};
72+
5373
// Private constants
5474
static const uint32_t flash_addr[FLASH_SECTORS] = {
5575
ADDR_FLASH_SECTOR_0,
@@ -96,12 +116,14 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) {
96116
if (new_app_size > flash_addr[NEW_APP_BASE + i]) {
97117
uint16_t res = FLASH_EraseSector(flash_sector[NEW_APP_BASE + i], VoltageRange_3);
98118
if (res != FLASH_COMPLETE) {
119+
FLASH_Lock();
99120
return res;
100121
}
101122
} else {
102123
break;
103124
}
104125
}
126+
FLASH_Lock();
105127

106128
timeout_configure_IWDT();
107129
utils_sys_unlock_cnt();
@@ -110,6 +132,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size) {
110132
}
111133

112134
uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_t len) {
135+
FLASH_Unlock();
113136
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
114137
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
115138

@@ -121,9 +144,11 @@ uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_
121144
for (uint32_t i = 0;i < len;i++) {
122145
uint16_t res = FLASH_ProgramByte(flash_addr[NEW_APP_BASE] + offset + i, data[i]);
123146
if (res != FLASH_COMPLETE) {
147+
FLASH_Lock();
124148
return res;
125149
}
126150
}
151+
FLASH_Lock();
127152

128153
timeout_configure_IWDT();
129154

@@ -191,3 +216,98 @@ uint8_t* flash_helper_get_sector_address(uint32_t fsector) {
191216

192217
return res;
193218
}
219+
220+
/**
221+
* @brief Compute the CRC of the application code to verify its integrity
222+
* @retval FAULT_CODE_NONE or FAULT_CODE_FLASH_CORRUPTION
223+
*/
224+
uint32_t flash_helper_verify_flash_memory(void) {
225+
uint32_t crc;
226+
// Look for a flag indicating that the CRC was previously computed.
227+
// If it is blank (0xFFFFFFFF), calculate and store the CRC.
228+
if( (APP_CRC_WAS_CALCULATED_FLAG_ADDRESS)[0] == APP_CRC_WAS_CALCULATED_FLAG )
229+
{
230+
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
231+
crc32_reset();
232+
233+
// compute vector table (sector 0)
234+
crc32((VECTOR_TABLE_ADDRESS), (VECTOR_TABLE_SIZE)/4);
235+
236+
// skip emulated EEPROM (sector 1 and 2)
237+
238+
// compute application code
239+
crc = crc32(APP_START_ADDRESS, (APP_SIZE)/4);
240+
241+
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, DISABLE);
242+
243+
// A CRC over the full image should return zero.
244+
return (crc == 0)? FAULT_CODE_NONE : FAULT_CODE_FLASH_CORRUPTION;
245+
}
246+
else {
247+
FLASH_Unlock();
248+
FLASH_ClearFlag(FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR |
249+
FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);
250+
251+
//Write the flag to indicate CRC has been computed.
252+
uint16_t res = FLASH_ProgramWord((uint32_t)APP_CRC_WAS_CALCULATED_FLAG_ADDRESS, APP_CRC_WAS_CALCULATED_FLAG);
253+
if (res != FLASH_COMPLETE) {
254+
FLASH_Lock();
255+
return FAULT_CODE_FLASH_CORRUPTION;
256+
}
257+
258+
// Compute flash crc including the new flag
259+
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
260+
crc32_reset();
261+
262+
// compute vector table (sector 0)
263+
crc32(VECTOR_TABLE_ADDRESS, (VECTOR_TABLE_SIZE)/4);
264+
265+
// skip emulated EEPROM (sector 1 and 2)
266+
267+
// compute application code
268+
crc = crc32(APP_START_ADDRESS, (APP_SIZE - 4)/4);
269+
270+
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, DISABLE);
271+
272+
//Store CRC
273+
res = FLASH_ProgramWord(APP_MAX_SIZE - 4, crc);
274+
if (res != FLASH_COMPLETE) {
275+
FLASH_Lock();
276+
return FAULT_CODE_FLASH_CORRUPTION;
277+
}
278+
FLASH_Lock();
279+
280+
// reboot
281+
NVIC_SystemReset();
282+
return FAULT_CODE_NONE;
283+
}
284+
}
285+
286+
uint32_t flash_helper_verify_flash_memory_chunk(void) {
287+
static uint32_t index = 0;
288+
const uint32_t chunk_size = 8192;
289+
uint32_t res = FAULT_CODE_NONE;
290+
uint32_t crc = 0;
291+
292+
// Make sure RCC_AHB1Periph_CRC is enabled
293+
if (index == 0) {
294+
crc32_reset();
295+
}
296+
297+
if (index < VECTOR_TABLE_SIZE) {
298+
crc32((VECTOR_TABLE_ADDRESS + index), chunk_size/4);
299+
}
300+
else {
301+
crc = crc32((uint32_t*)((uint32_t)APP_START_ADDRESS + index - VECTOR_TABLE_SIZE), chunk_size/4);
302+
}
303+
304+
index += chunk_size;
305+
if (index >= (VECTOR_TABLE_SIZE + APP_SIZE)) {
306+
index = 0;
307+
if (crc != 0) {
308+
res = FAULT_CODE_FLASH_CORRUPTION;
309+
}
310+
}
311+
return res;
312+
}
313+

flash_helper.h

+2
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,7 @@ uint16_t flash_helper_erase_new_app(uint32_t new_app_size);
2727
uint16_t flash_helper_write_new_app_data(uint32_t offset, uint8_t *data, uint32_t len);
2828
void flash_helper_jump_to_bootloader(void);
2929
uint8_t* flash_helper_get_sector_address(uint32_t fsector);
30+
uint32_t flash_helper_verify_flash_memory(void);
31+
uint32_t flash_helper_verify_flash_memory_chunk(void);
3032

3133
#endif /* FLASH_HELPER_H_ */

ld_eeprom_emu.ld

+11-1
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
/*
2121
* STM32F407xG memory setup.
2222
* Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
23+
* Note: flash2 length decreased by 8 bytes to use it as hardcoded CRC
24+
* flags.
2325
*/
2426
MEMORY
2527
{
2628
flash : org = 0x08000000, len = 16k
27-
flash2 : org = 0x0800C000, len = 480k
29+
flash2 : org = 0x0800C000, len = 393216 - 8 /* NEW_APP_MAX_SIZE - CRC_INFO */
30+
crcinfo : org = 0x0805FFF8, len = 8 /* CRC info*/
2831
ram0 : org = 0x20000000, len = 128k /* SRAM1 + SRAM2 */
2932
ram1 : org = 0x20000000, len = 112k /* SRAM1 */
3033
ram2 : org = 0x2001C000, len = 16k /* SRAM2 */
@@ -142,6 +145,13 @@ SECTIONS
142145
. = ALIGN(4);
143146
_etext = .;
144147
_textdata = _etext;
148+
149+
_crcinfo_start_address = 0x0805FFF8;
150+
151+
.crcinfo _crcinfo_start_address :
152+
{
153+
KEEP(*(.crcinfo))
154+
} > crcinfo
145155

146156
.mstack :
147157
{

main.c

+29
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "spi_sw.h"
5050
#include "timer.h"
5151
#include "imu.h"
52+
#include "flash_helper.h"
5253
#if HAS_BLACKMAGIC
5354
#include "bm_if.h"
5455
#endif
@@ -74,6 +75,22 @@
7475
// Private variables
7576
static THD_WORKING_AREA(periodic_thread_wa, 1024);
7677
static THD_WORKING_AREA(timer_thread_wa, 128);
78+
static THD_WORKING_AREA(flash_integrity_check_thread_wa, 1024);
79+
80+
static THD_FUNCTION(flash_integrity_check_thread, arg) {
81+
(void)arg;
82+
83+
chRegSetThreadName("Flash integrity check");
84+
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
85+
86+
for(;;) {
87+
if (flash_helper_verify_flash_memory_chunk() == FAULT_CODE_FLASH_CORRUPTION) {
88+
NVIC_SystemReset();
89+
}
90+
91+
chThdSleepMilliseconds(50);
92+
}
93+
}
7794

7895
static THD_FUNCTION(periodic_thread, arg) {
7996
(void)arg;
@@ -183,6 +200,17 @@ int main(void) {
183200

184201
timer_init();
185202
conf_general_init();
203+
204+
if( flash_helper_verify_flash_memory() == FAULT_CODE_FLASH_CORRUPTION ) {
205+
// Loop here, it is not safe to run any code
206+
while (1) {
207+
chThdSleepMilliseconds(100);
208+
LED_RED_ON();
209+
chThdSleepMilliseconds(75);
210+
LED_RED_OFF();
211+
}
212+
}
213+
186214
ledpwm_init();
187215

188216
mc_configuration mcconf;
@@ -233,6 +261,7 @@ int main(void) {
233261
// Threads
234262
chThdCreateStatic(periodic_thread_wa, sizeof(periodic_thread_wa), NORMALPRIO, periodic_thread, NULL);
235263
chThdCreateStatic(timer_thread_wa, sizeof(timer_thread_wa), NORMALPRIO, timer_thread, NULL);
264+
chThdCreateStatic(flash_integrity_check_thread_wa, sizeof(flash_integrity_check_thread_wa), LOWPRIO, flash_integrity_check_thread, NULL);
236265

237266
#if WS2811_TEST
238267
unsigned int color_ind = 0;

0 commit comments

Comments
 (0)