Improve code and add a Flash CRC check
This commit is contained in:
parent
864c3fa0f2
commit
1e870972e3
@ -45,6 +45,7 @@ endif (GIT_FOUND)
|
||||
|
||||
set(ELFFILE ${PROJECT_NAME}.elf)
|
||||
set(HEXFILE ${PROJECT_NAME}.hex)
|
||||
set(MAPFILE ${PROJECT_NAME}.map)
|
||||
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/stm32f407vet6_flash.ld)
|
||||
|
||||
add_compile_options(-Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter)
|
||||
@ -62,6 +63,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_definitions(-DDEBUGBUILD)
|
||||
add_compile_options(-O0 -g)
|
||||
add_link_options(-Wl,-Map=${MAPFILE})
|
||||
ELSE()
|
||||
add_compile_options(-O3 -g)
|
||||
add_link_options(-Wl,--gc-sections)
|
||||
|
113
stm-firmware/crc-patch-elf.py
Executable file
113
stm-firmware/crc-patch-elf.py
Executable file
@ -0,0 +1,113 @@
|
||||
#!/bin/python
|
||||
|
||||
"""
|
||||
This script patches the CRC checksums into an existing ELF file.
|
||||
|
||||
For this, it searches the follwoing sections:
|
||||
1) .text
|
||||
2) .data
|
||||
3) .ccmdata
|
||||
4) .vectors
|
||||
|
||||
All sections MUST be a multiple of 4 bytes long because the CRC calculation relies on whole 32 bit words.
|
||||
The sections are excrated and the CRC is calculated for each section.
|
||||
|
||||
In the section .flashcrc, the script expects a single struct with the prototype:
|
||||
struct flash_crcs {
|
||||
uint32_t start_magic;
|
||||
uint32_t crc_section_text;
|
||||
uint32_t crc_section_data;
|
||||
uint32_t crc_section_ccm_data;
|
||||
uint32_t crc_section_vectors;
|
||||
uint32_t end_magic;
|
||||
};
|
||||
|
||||
It checks, if the start magic and end magic are set to the appropriate values and then patches in the CRC values of the sections.
|
||||
The magic values checked for are: 0xA8BE53F9 and 0xFFA582FF
|
||||
"""
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from elftools.elf.segments import Segment
|
||||
import elftools.elf.constants as elf_const
|
||||
import sys
|
||||
import crcmod
|
||||
import crcmod.predefined
|
||||
import struct
|
||||
|
||||
crc_calc = crcmod.predefined.mkCrcFun('crc-32-mpeg')
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:", sys.argv[0], ' <elf file>')
|
||||
sys.exit(-1)
|
||||
|
||||
filename=sys.argv[1]
|
||||
|
||||
def section_calculate_crc(section):
|
||||
data = bytearray(section.data())
|
||||
be_data = bytearray([0 for k in range(0, len(data))])
|
||||
# Rearrange data, because the STM controller sees it as 32 bit little endian words
|
||||
for i in range(0, int(len(data)/4)):
|
||||
be_data[i*4+0] = data[i*4+3]
|
||||
be_data[i*4+1] = data[i*4+2]
|
||||
be_data[i*4+2] = data[i*4+1]
|
||||
be_data[i*4+3] = data[i*4+0]
|
||||
|
||||
return crc_calc(be_data)
|
||||
|
||||
with open(filename, 'r+b') as f:
|
||||
elf = ELFFile(f)
|
||||
sections = {}
|
||||
sections['.text'] = elf.get_section_by_name('.text')
|
||||
sections['.data'] = elf.get_section_by_name('.data')
|
||||
sections['.ccmdata'] = elf.get_section_by_name('.ccmdata')
|
||||
sections['.vectors'] = elf.get_section_by_name('.vectors')
|
||||
|
||||
for key, sec in sections.items():
|
||||
if sec is None:
|
||||
print("Error! Section", key, "not found in ELF file!")
|
||||
sys.exit(-1)
|
||||
print('Found section', key, 'Size:',
|
||||
sec.data_size, 'Type:', sec['sh_type'])
|
||||
if sec['sh_type'] != 'SHT_PROGBITS':
|
||||
print('Error! Section must be of type SHT_PROGBITS')
|
||||
sys.exit(-1)
|
||||
if (sec.data_size % 4 != 0):
|
||||
print("Section", key, "has wrong size. Must be a multiple of 4 bytes!")
|
||||
sys.exit(-1)
|
||||
|
||||
text_crc = section_calculate_crc(sections['.text'])
|
||||
print('CRC of .text section:', hex(text_crc))
|
||||
data_crc = section_calculate_crc(sections['.data'])
|
||||
print('CRC of .data section:', hex(data_crc))
|
||||
ccmdata_crc = section_calculate_crc(sections['.ccmdata'])
|
||||
print('CRC of .ccmdata section:', hex(ccmdata_crc))
|
||||
vextors_crc = section_calculate_crc(sections['.vectors'])
|
||||
print('CRC of .vectors section:', hex(vextors_crc))
|
||||
|
||||
# Check the flashcrc section
|
||||
flashcrc_sec = elf.get_section_by_name('.flashcrc')
|
||||
if flashcrc_sec is None:
|
||||
print('Section for flash CRC missing!')
|
||||
sys.exit(-1)
|
||||
if flashcrc_sec.data_size != 6*4:
|
||||
print("Warning!!! .flashcrc section has wrong size:",flashcrc_sec.data_size)
|
||||
|
||||
crc_sec_data = bytearray(flashcrc_sec.data())
|
||||
magic1 = struct.unpack('<I'*1, bytes(crc_sec_data[0:4]))[0]
|
||||
magic2 = struct.unpack('<I'*1, bytes(crc_sec_data[-4:]))[0]
|
||||
print("CRC section magic values:", hex(magic1), hex(magic2))
|
||||
if magic1 != 0xA8BE53F9 or magic2 != 0xFFA582FF:
|
||||
print("Wrong magics in CRC section. Data misalignment?")
|
||||
sys.exit(-2)
|
||||
|
||||
crc_sec_offset = flashcrc_sec['sh_offset']
|
||||
print('CRC section ELF file offset:', hex(crc_sec_offset))
|
||||
|
||||
crc_sec_data[4:8] = struct.pack('<I',text_crc)
|
||||
crc_sec_data[8:12] = struct.pack('<I',data_crc)
|
||||
crc_sec_data[12:16] = struct.pack('<I',ccmdata_crc)
|
||||
crc_sec_data[16:20] = struct.pack('<I',vextors_crc)
|
||||
f.seek(crc_sec_offset)
|
||||
f.write(crc_sec_data)
|
||||
print('CRCs patched successfully')
|
||||
|
||||
|
@ -56,6 +56,8 @@ enum safety_flag {
|
||||
ERR_FLAG_SAFETY_TAB_CORRUPT = (1<<16),
|
||||
ERR_FLAG_AMON_SUPPLY_VOLT = (1<<17),
|
||||
ERR_FLAG_OVERTEMP = (1<<18),
|
||||
ERR_FLAG_FLASH_CRC_CODE = (1<<19),
|
||||
ERR_FLAG_FLASH_CRC_DATA = (1<<20),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -166,6 +168,8 @@ enum analog_value_monitor {
|
||||
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, true), \
|
||||
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, false), \
|
||||
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_OVERTEMP, false), \
|
||||
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_CODE, true), \
|
||||
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true)
|
||||
/**
|
||||
* @brief Default config weights of safety flags. These values are loaded into the safety tables on startup
|
||||
*/
|
||||
@ -188,5 +192,7 @@ enum analog_value_monitor {
|
||||
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_PANIC), \
|
||||
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
|
||||
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \
|
||||
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
|
||||
ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \
|
||||
|
||||
#endif /* __SAFETY_CONFIG_H__ */
|
||||
|
@ -267,6 +267,13 @@ int safety_controller_set_overtemp_limit(float over_temperature);
|
||||
*/
|
||||
float safety_controller_get_overtemp_limit(void);
|
||||
|
||||
/**
|
||||
* @brief Perform a CRC check of the flash memory and set appropriate flags
|
||||
* @return negative if internal error occured. Otherwise (independent from CRC check result) 0.
|
||||
* @note This function requires the safety controller to be set up before!
|
||||
*/
|
||||
int safety_controller_trigger_flash_crc_check(void);
|
||||
|
||||
#endif /* __SAFETY_CONTROLLER_H__ */
|
||||
|
||||
/** @} */
|
||||
|
@ -35,9 +35,14 @@
|
||||
#define SAFETY_MEMORY_MAGIC 0x12AA5CB7
|
||||
|
||||
/**
|
||||
* @brief Error memory NOP entry
|
||||
* @brief Error memory NOP entry word written to the memory
|
||||
*/
|
||||
#define SAFETY_MEMORY_NOP_ENTRY 0xC1AA1222
|
||||
#define SAFETY_MEMORY_NOP_ENTRY_WORD 0xC1AA1222UL
|
||||
|
||||
/**
|
||||
* @brief Low Byte (byte 0) of error memory entry
|
||||
*/
|
||||
#define SAFETY_MEMORY_ERROR_ENTRY_MARKER 0x51U
|
||||
|
||||
/**
|
||||
* @brief Offset address for the safety_memory_header.
|
||||
|
@ -36,6 +36,6 @@ int temp_converter_convert_resistance_to_temp(float resistance, float *temp_out)
|
||||
* @return 0 if ok, -1 if tmeperature is below the lookup table, 1 if value is above the lookup table, -1000 in case of a pointer error,
|
||||
* -100 if an internal error occured. This should never happen, if the lookup table is correct
|
||||
*/
|
||||
int temp_convertet_convert_temp_to_resistance(float temp, float *resistance_out);
|
||||
int temp_converter_convert_temp_to_resistance(float temp, float *resistance_out);
|
||||
|
||||
#endif /* __TEMP_CONVERTER_H__ */
|
||||
|
@ -153,6 +153,15 @@ struct overtemp_config {
|
||||
uint32_t crc;
|
||||
};
|
||||
|
||||
struct flash_crcs {
|
||||
uint32_t start_magic;
|
||||
uint32_t crc_section_text;
|
||||
uint32_t crc_section_data;
|
||||
uint32_t crc_section_ccm_data;
|
||||
uint32_t crc_section_vectors;
|
||||
uint32_t end_magic;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief All safety error flags.
|
||||
*/
|
||||
@ -176,6 +185,8 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = {
|
||||
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_TAB_CORRUPT),
|
||||
ERR_FLAG_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT),
|
||||
ERR_FLAG_ENTRY(ERR_FLAG_OVERTEMP),
|
||||
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_CODE),
|
||||
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -257,7 +268,7 @@ static void set_overtemp_config(float over_temperature)
|
||||
int result;
|
||||
float resistance;
|
||||
|
||||
result = temp_convertet_convert_temp_to_resistance(over_temperature, &resistance);
|
||||
result = temp_converter_convert_temp_to_resistance(over_temperature, &resistance);
|
||||
/* An error in this function is really bad... */
|
||||
if (result < -1)
|
||||
panic_mode();
|
||||
@ -764,6 +775,7 @@ void safety_controller_init()
|
||||
/* This is usually done by the safety memory already. But, since this module also uses the CRC... */
|
||||
crc_unit_init();
|
||||
|
||||
safety_controller_trigger_flash_crc_check();
|
||||
stack_check_init_corruption_detect_area();
|
||||
|
||||
hw_rev = get_pcb_hardware_version();
|
||||
@ -1296,4 +1308,102 @@ float safety_controller_get_overtemp_limit(void)
|
||||
return safety_controller_overtemp_config.overtemp_deg_celsius;
|
||||
}
|
||||
|
||||
extern const uint32_t __ld_vectors_start;
|
||||
extern const uint32_t __ld_vectors_end;
|
||||
extern const uint32_t __ld_text_start;
|
||||
extern const uint32_t __ld_text_end;
|
||||
|
||||
extern const uint32_t __ld_sdata_ccm;
|
||||
extern const uint32_t __ld_edata_ccm;
|
||||
extern const uint32_t __ld_load_ccm_data;
|
||||
|
||||
extern const uint32_t __ld_sdata;
|
||||
extern const uint32_t __ld_edata;
|
||||
extern const uint32_t __ld_load_data;
|
||||
|
||||
int safety_controller_trigger_flash_crc_check()
|
||||
{
|
||||
/* This structs needs to be volatile!!
|
||||
* This prevents the compiler form optimizing out the reads to the crcs which will be patched in later by
|
||||
* a separate python script!
|
||||
*/
|
||||
static volatile const struct flash_crcs IN_SECTION(.flashcrc) crcs_in_flash =
|
||||
{
|
||||
.start_magic = 0xA8BE53F9UL,
|
||||
.crc_section_ccm_data = 0UL,
|
||||
.crc_section_text = 0UL,
|
||||
.crc_section_data = 0UL,
|
||||
.crc_section_vectors = 0UL,
|
||||
.end_magic = 0xFFA582FFUL,
|
||||
};
|
||||
|
||||
int ret = -1;
|
||||
uint32_t len;
|
||||
uint32_t crc;
|
||||
|
||||
/* Perform CRC check over vector table */
|
||||
len = (uint32_t)((void *)&__ld_vectors_end - (void *)&__ld_vectors_start);
|
||||
if (len % 4) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
|
||||
} else {
|
||||
len /= 4;
|
||||
crc_unit_reset();
|
||||
crc_unit_input_array(&__ld_vectors_start, len);
|
||||
crc = crc_unit_get_crc();
|
||||
if (crc != crcs_in_flash.crc_section_vectors) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform CRC check over text section */
|
||||
len = (uint32_t)((void *)&__ld_text_end - (void *)&__ld_text_start);
|
||||
if (len % 4) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
|
||||
} else {
|
||||
len /= 4;
|
||||
crc_unit_reset();
|
||||
crc_unit_input_array(&__ld_text_start, len);
|
||||
crc = crc_unit_get_crc();
|
||||
if (crc != crcs_in_flash.crc_section_text) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform CRC check over data section */
|
||||
len = (uint32_t)((void *)&__ld_edata - (void *)&__ld_sdata);
|
||||
if (len % 4) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
|
||||
} else {
|
||||
len /= 4;
|
||||
crc_unit_reset();
|
||||
crc_unit_input_array(&__ld_load_data, len);
|
||||
crc = crc_unit_get_crc();
|
||||
if (crc != crcs_in_flash.crc_section_data) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform CRC check over ccm data section */
|
||||
len = (uint32_t)((void *)&__ld_edata_ccm - (void *)&__ld_sdata_ccm);
|
||||
if (len % 4) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
|
||||
} else {
|
||||
len /= 4;
|
||||
crc_unit_reset();
|
||||
crc_unit_input_array(&__ld_load_ccm_data, len);
|
||||
crc = crc_unit_get_crc();
|
||||
if (crc != crcs_in_flash.crc_section_ccm_data) {
|
||||
safety_controller_report_error(ERR_FLAG_FLASH_CRC_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
crc_unit_reset();
|
||||
crc_unit_input(0x04030201);
|
||||
crc_unit_input(0xA0B0C0D0);
|
||||
crc = crc_unit_get_crc();
|
||||
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -35,11 +35,11 @@ static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_e
|
||||
if (!out)
|
||||
return -1002;
|
||||
|
||||
if (entry_data == SAFETY_MEMORY_NOP_ENTRY) {
|
||||
if (entry_data == SAFETY_MEMORY_NOP_ENTRY_WORD) {
|
||||
out->flag_num = 0U;
|
||||
out->type = SAFETY_MEMORY_ERR_ENTRY_NOP;
|
||||
out->counter = 0U;
|
||||
} else if ((entry_data & 0xFFU) == 0x51U) {
|
||||
} else if ((entry_data & 0xFFU) == SAFETY_MEMORY_ERROR_ENTRY_MARKER) {
|
||||
out->flag_num = (uint8_t)((entry_data >> 8U) & 0xFFU);
|
||||
out->type = SAFETY_MEMORY_ERR_ENTRY_FLAG;
|
||||
out->counter = (uint16_t)((entry_data >> 16U) & 0xFFFF);
|
||||
@ -57,10 +57,10 @@ static uint32_t error_memory_entry_to_word(const struct error_memory_entry *entr
|
||||
|
||||
switch (entry->type) {
|
||||
case SAFETY_MEMORY_ERR_ENTRY_NOP:
|
||||
word = SAFETY_MEMORY_NOP_ENTRY;
|
||||
word = SAFETY_MEMORY_NOP_ENTRY_WORD;
|
||||
break;
|
||||
case SAFETY_MEMORY_ERR_ENTRY_FLAG:
|
||||
word = 0x51UL | ((uint32_t)entry->flag_num << 8U) |
|
||||
word = (uint32_t)SAFETY_MEMORY_ERROR_ENTRY_MARKER | ((uint32_t)entry->flag_num << 8U) |
|
||||
((uint32_t)entry->counter << 16U);
|
||||
break;
|
||||
}
|
||||
@ -322,9 +322,9 @@ static int safety_memory_check_error_entries()
|
||||
return -100;
|
||||
|
||||
/* Valid flag entry */
|
||||
if ((data & 0xFF) == 0x51)
|
||||
if ((data & 0xFF) == SAFETY_MEMORY_ERROR_ENTRY_MARKER)
|
||||
continue;
|
||||
if (data == SAFETY_MEMORY_NOP_ENTRY)
|
||||
if (data == SAFETY_MEMORY_NOP_ENTRY_WORD)
|
||||
continue;
|
||||
|
||||
ret--;
|
||||
|
@ -44,12 +44,15 @@ SECTIONS
|
||||
{
|
||||
.vectors : ALIGN(4)
|
||||
{
|
||||
__ld_vectors_start = .;
|
||||
KEEP(*(.vectors))
|
||||
. = ALIGN(4);
|
||||
__ld_vectors_end = .;
|
||||
} >FLASH =0xFF
|
||||
|
||||
.text : ALIGN(4)
|
||||
{
|
||||
__ld_text_start = .;
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
@ -59,6 +62,8 @@ SECTIONS
|
||||
*(.eh_frame)
|
||||
KEEP(*(.init)) /* Constructors */
|
||||
KEEP(*(.fini)) /* Destructors */
|
||||
. = ALIGN(4);
|
||||
__ld_text_end = .;
|
||||
} >FLASH =0xFF
|
||||
|
||||
.ARM.extab : ALIGN(4)
|
||||
@ -99,6 +104,13 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
} >FLASH =0xFF
|
||||
|
||||
.flashcrc : ALIGN(4)
|
||||
{
|
||||
KEEP(*(.flashcrc))
|
||||
KEEP(*(.flashcrc.*))
|
||||
. = ALIGN(4);
|
||||
} >FLASH =0xFF
|
||||
|
||||
/* Initialized CCM data */
|
||||
__ld_load_ccm_data = LOADADDR(.ccmdata);
|
||||
.ccmdata : ALIGN(4)
|
||||
|
@ -75,7 +75,7 @@ return_ret_val:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int temp_convertet_convert_temp_to_resistance(float temp, float *resistance_out)
|
||||
int temp_converter_convert_temp_to_resistance(float temp, float *resistance_out)
|
||||
{
|
||||
int retcode = 0;
|
||||
unsigned int i;
|
||||
|
Loading…
Reference in New Issue
Block a user