From d9621108233eba2b7cb7351d5054f884477978cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Wed, 7 Apr 2021 23:14:45 +0200 Subject: [PATCH] Updater: Use -O0 and write flash writer and fix hex parser --- stm-firmware/updater/ram-code/CMakeLists.txt | 2 +- stm-firmware/updater/ram-code/flash-writer.c | 108 ++++++++ stm-firmware/updater/ram-code/flash-writer.h | 16 ++ stm-firmware/updater/ram-code/hex-parser.c | 270 +++++++++++++++---- stm-firmware/updater/ram-code/hex-parser.h | 6 +- stm-firmware/updater/ram-code/main.c | 51 +++- 6 files changed, 398 insertions(+), 55 deletions(-) create mode 100644 stm-firmware/updater/ram-code/flash-writer.c create mode 100644 stm-firmware/updater/ram-code/flash-writer.h diff --git a/stm-firmware/updater/ram-code/CMakeLists.txt b/stm-firmware/updater/ram-code/CMakeLists.txt index a958396..5cd4cf3 100644 --- a/stm-firmware/updater/ram-code/CMakeLists.txt +++ b/stm-firmware/updater/ram-code/CMakeLists.txt @@ -20,7 +20,7 @@ add_executable(${ELFFILE} ${SRCS} ${FATFS_SRCS} ${SDIO_SRCS} ${STM_PERIPH_SRCS} target_include_directories(${ELFFILE} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ../../include) target_compile_options(${ELFFILE} PRIVATE -Wall -Wextra -Wold-style-declaration -Wuninitialized -Wmaybe-uninitialized -Wunused-parameter) -target_compile_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare -Os -g3) +target_compile_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 -nostartfiles -Wimplicit-fallthrough=3 -Wsign-compare -O0 -g3) target_compile_definitions(${ELFFILE} PRIVATE -DGIT_VER=${GIT_DESCRIBE} -DHSE_VALUE=8000000UL -DSTM32F407xx -DSTM32F4XX -DARM_MATH_CM4 -DSAFETY_MEMORY_STRIPOUT_DUMP) target_link_options(${ELFFILE} PRIVATE -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork -mfloat-abi=hard -mfpu=fpv4-sp-d16 --disable-newlib-supplied-syscalls -nostartfiles -T${LINKER_SCRIPT} -Wl,--print-memory-usage) set(GEN_HEADER_PATH "${CMAKE_CURRENT_BINARY_DIR}/include/generated") diff --git a/stm-firmware/updater/ram-code/flash-writer.c b/stm-firmware/updater/ram-code/flash-writer.c new file mode 100644 index 0000000..dfcabe9 --- /dev/null +++ b/stm-firmware/updater/ram-code/flash-writer.c @@ -0,0 +1,108 @@ +#include "flash-writer.h" +#include +#include + +static bool flash_op_busy(void) +{ + return !!(FLASH->SR & FLASH_SR_BSY); +} + +static void lock_flash_cr(void) +{ + FLASH->CR |= FLASH_CR_LOCK; +} + +void flash_writer_enable_access(void) +{ + const uint32_t key1 = 0x45670123UL; + const uint32_t key2 = 0xCDEF89ABUL; + + FLASH->KEYR = key1; + FLASH->KEYR = key2; +} + +void flash_writer_perform_mass_erase(void) +{ + flash_writer_enable_access(); + while (flash_op_busy()); + + FLASH->CR = DMA_SxCR_PSIZE_1; + FLASH->CR |= FLASH_CR_MER; + FLASH->CR |= FLASH_CR_STRT; + + while(flash_op_busy()); + lock_flash_cr(); +} + +uint32_t flash_writer_get_flash_size(void) +{ + uint32_t flash_size; + const uint32_t *flash_size_ptr = (const uint32_t *)0x1FFF7A22UL; + + flash_size = *flash_size_ptr; + flash_size *= 1024; + + return flash_size; +} + +int flash_writer_write_to_memory(void *dest, void *src, uint32_t size) +{ + uint32_t full_word_cnt; + uint32_t byte_cnt; + uint32_t idx; + uint32_t *word_src_ptr; + uint32_t *word_dest_ptr; + char *char_src_ptr; + char *char_dest_ptr; + + flash_writer_enable_access(); + while (flash_op_busy()); + + /* Do the full words */ + full_word_cnt = size / 4u; + byte_cnt = size % 4; + + word_dest_ptr = dest; + word_src_ptr = src; + + if (full_word_cnt) { + FLASH->CR = FLASH_CR_PSIZE_1; + FLASH->CR |= FLASH_CR_PG; + + for (idx = 0; idx < full_word_cnt; idx++) { + *word_dest_ptr = *word_src_ptr; + word_dest_ptr++; + word_src_ptr++; + } + + while (flash_op_busy()); + FLASH->CR = 0; + } + + /* write remaining bytes */ + if (byte_cnt) { + char_src_ptr = (char *)word_src_ptr; + char_dest_ptr = (char *)word_dest_ptr; + + FLASH->CR = 0; + FLASH->CR |= FLASH_CR_PG; + + for (idx = 0; idx < byte_cnt; idx++) { + *char_dest_ptr = *char_src_ptr; + char_dest_ptr++; + char_src_ptr++; + } + + while (flash_op_busy()); + FLASH->CR = 0; + } + + lock_flash_cr(); + + return 0; +} + +uint32_t flash_writer_get_base_address(void) +{ + return FLASH_BASE; +} diff --git a/stm-firmware/updater/ram-code/flash-writer.h b/stm-firmware/updater/ram-code/flash-writer.h new file mode 100644 index 0000000..69c9ba4 --- /dev/null +++ b/stm-firmware/updater/ram-code/flash-writer.h @@ -0,0 +1,16 @@ +#ifndef _FLASH_WRITER_H_ +#define _FLASH_WRITER_H_ + +#include + +void flash_writer_enable_access(void); + +void flash_writer_perform_mass_erase(void); + +uint32_t flash_writer_get_flash_size(void); + +uint32_t flash_writer_get_base_address(void); + +int flash_writer_write_to_memory(void *dest, void *src, uint32_t size); + +#endif /* _FLASH_WRITER_H_ */ diff --git a/stm-firmware/updater/ram-code/hex-parser.c b/stm-firmware/updater/ram-code/hex-parser.c index de7d7c8..8c2c338 100644 --- a/stm-firmware/updater/ram-code/hex-parser.c +++ b/stm-firmware/updater/ram-code/hex-parser.c @@ -1,72 +1,74 @@ #include "hex-parser.h" #include +#include static int convert_hex_char_to_value(char c, uint32_t *out) { - int ret = 0; - uint32_t value = 0; + int ret = 0; + uint32_t value = 0; - if (!out) - return -1002; + if (!out) + return -1002; - switch (c) { - case '0' ... '9': - value = (uint32_t)c - (uint32_t)'0'; - break; - case 'a' ... 'f': - /* Convert to upper */ - c -= 0x20; - /* FALLTHRU */ - case 'A' ... 'F': - value = (uint32_t)c - (uint32_t)'A' + 10UL; - break; - default: - ret = -1; - } + switch (c) { + case '0' ... '9': + value = (uint32_t)c - (uint32_t)'0'; + break; + case 'a' ... 'f': + /* Convert to upper */ + c -= 0x20; + /* FALLTHRU */ + case 'A' ... 'F': + value = (uint32_t)c - (uint32_t)'A' + 10UL; + break; + default: + ret = -1; + } - if (ret == 0) - *out = value; + if (ret == 0) + *out = value; - return ret; + return ret; } static int convert_big_endian_hex_string_to_val(const char *string, size_t len, uint32_t *out) { - int ret_val = -1; - uint32_t converted_value = 0UL; - uint32_t digit; - int res; - unsigned int i; + int ret_val = -1; + uint32_t converted_value = 0UL; + uint32_t digit; + int res; + unsigned int i; - /* Return error in case of an input error */ - if (!string || !len) - goto exit; + /* Return error in case of an input error */ + if (!string || !len) + goto exit; - if (!out) - return -1003; + if (!out) + return -1003; - /* we don't support strings larger than 8 chars */ - if (len > 8) - goto exit; + /* we don't support strings larger than 8 chars */ + if (len > 8) + goto exit; - for (i = 0; i < len && string[i] != '\0'; i++) { - /* Convert current character to number */ - res = convert_hex_char_to_value(string[i], &digit); - if (res) { - /* Not a hex number */ - ret_val = -2; - goto exit; - } + for (i = 0; i < len && string[i] != '\0'; i++) { + /* Convert current character to number */ + res = convert_hex_char_to_value(string[i], &digit); + if (res) { + /* Not a hex number */ + ret_val = -2; + goto exit; + } - converted_value *= 0x10; - converted_value += digit; - } + converted_value *= 0x10; + converted_value += digit; + } - *out = converted_value; + *out = converted_value; + ret_val = 0; exit: - return ret_val; + return ret_val; } enum hex_parser_ret hex_parser_open(struct hex_parser *parser, const char *file_name) @@ -85,7 +87,179 @@ enum hex_parser_ret hex_parser_open(struct hex_parser *parser, const char *file_ return HEX_PARSER_OK; } -enum hex_parser_ret hex_parser_parse(struct hex_parser *parser, uint32_t *address, char *data, size_t data_len); +static int read_line_from_file(FIL *file, char *data, int size) +{ + char *ret_ptr; + int length; + + ret_ptr = f_gets(data, size, file); + if (!ret_ptr) + return -1; + + /* To be sure */ + data[size - 1] = 0; + length = strlen(ret_ptr); + + return length; +} + +static int hex_record_check_checksum(const char *buff, int hex_byte_count) +{ + int i; + int res; + uint32_t checksum = 0; + uint32_t tmp; + + if (!buff || !hex_byte_count) + return -1000; + + for (i = 0; i < hex_byte_count; i++) { + res = convert_big_endian_hex_string_to_val(&buff[2 * i], 2, &tmp); + if (res) + return -1; + checksum += tmp; + } + + if (checksum & 0xFF) { + return 1; + } + + return 0; +} + +enum hex_parser_ret hex_parser_parse(struct hex_parser *parser, uint32_t *address, char *data, size_t data_len, + size_t *lenout) +{ + static char workbuff[512]; + int count; + int i; + enum hex_parser_ret retval = HEX_PARSER_DATA_OK; + uint32_t hex_addr; + uint32_t byte_count; + uint32_t record_type; + uint32_t tmp; + + if (!parser || !lenout || !data_len || !data || !address) + return HEX_PARSER_ERROR; + + /* Read a line from the file */ + count = read_line_from_file(&parser->file, workbuff, sizeof(workbuff)); + if (!count) { + /* Check for error in case nothing is read */ + if (f_error(&parser->file)) { + retval = HEX_PARSER_ERROR; + goto exit; + } else if (f_eof(&parser->file)) { + retval = HEX_PARSER_FILE_END; + goto exit; + } + } + + /* Strip out invalid characters at the end */ + for (i = count - 1; i >= 0; i--) { + if (workbuff[i] == '\r' || workbuff[i] == '\n' || + workbuff[i] == '\t' || workbuff[i] == ' ') + { + workbuff[i] = 0; + count--; + } + } + + /* We read a valid line, check for valid marker */ + if (workbuff[0] != ':') { + retval = HEX_PARSER_ERROR; + goto exit; + } + + /* Line has to be longer than 11 chars in total */ + if (count < 11) { + retval = HEX_PARSER_ERROR; + goto exit; + } + + /* Read in the data count */ + if (convert_big_endian_hex_string_to_val(&workbuff[1], 2, &byte_count)) { + retval = HEX_PARSER_ERROR; + goto exit; + } + + /* Read in the address */ + if (convert_big_endian_hex_string_to_val(&workbuff[3], 4, &hex_addr)) { + retval = HEX_PARSER_ERROR; + goto exit; + } + + /* Read in the record type */ + if (convert_big_endian_hex_string_to_val(&workbuff[7], 2, &record_type)) { + retval = HEX_PARSER_ERROR; + goto exit; + } + + if (byte_count * 2 + 9 + 2 != (unsigned int)count) { + /* Line not the expected length */ + retval = HEX_PARSER_ERROR; + goto exit; + } + + /* Check the checksum. We have bytecount + 5 bytes in a record */ + if (hex_record_check_checksum(&workbuff[1], byte_count + 5)) { + retval = HEX_PARSER_ERROR; + goto exit; + } + + /* Check record type */ + switch (record_type) { + case 0x00: /* Data */ + if (byte_count > data_len) { + retval = HEX_PARSER_ERROR; + break; + } + + *lenout = 0; + *address = hex_addr + parser->current_address_offset; + + for (i = 0; i < (int)byte_count; i++) { + if (convert_big_endian_hex_string_to_val(&workbuff[9 + 2*i], 2, &tmp)) { + retval = HEX_PARSER_ERROR; + break; + } + + *data = (char)(tmp & 0xFF); + data++; + (*lenout)++; + } + retval = HEX_PARSER_DATA_OK; + break; + case 0x01: /* End of file */ + retval = HEX_PARSER_EOF_RECORD; + break; + case 0x04: /* extended linear address */ + if (byte_count != 2) { + retval = HEX_PARSER_ERROR; + break; + } + + /* Parse the upper 16 bit of the address */ + if (convert_big_endian_hex_string_to_val(&workbuff[9], 4, &tmp)) { + retval = HEX_PARSER_ERROR; + break; + } + + parser->current_address_offset = tmp << 16; + retval = HEX_PARSER_OK; + break; + case 0x05: + retval = HEX_PARSER_OK; + break; + default: + retval = HEX_PARSER_ERROR; + break; + + } + +exit: + return retval; +} enum hex_parser_ret hex_parser_close(struct hex_parser *parser) { if (!parser) diff --git a/stm-firmware/updater/ram-code/hex-parser.h b/stm-firmware/updater/ram-code/hex-parser.h index d8ea13f..6048fbb 100644 --- a/stm-firmware/updater/ram-code/hex-parser.h +++ b/stm-firmware/updater/ram-code/hex-parser.h @@ -6,10 +6,11 @@ #include enum hex_parser_ret { - HEX_PARSER_OK, + HEX_PARSER_OK = 0, HEX_PARSER_DATA_OK, HEX_PARSER_ERROR, HEX_PARSER_FILE_END, + HEX_PARSER_EOF_RECORD, }; struct hex_parser { @@ -19,7 +20,8 @@ struct hex_parser { enum hex_parser_ret hex_parser_open(struct hex_parser *parser, const char *file_name); -enum hex_parser_ret hex_parser_parse(struct hex_parser *parser, uint32_t *address, char *data, size_t data_len); +enum hex_parser_ret hex_parser_parse(struct hex_parser *parser, uint32_t *address, char *data, size_t data_len, + size_t *len_out); enum hex_parser_ret hex_parser_close(struct hex_parser *parser); diff --git a/stm-firmware/updater/ram-code/main.c b/stm-firmware/updater/ram-code/main.c index e8b7499..3a48eba 100644 --- a/stm-firmware/updater/ram-code/main.c +++ b/stm-firmware/updater/ram-code/main.c @@ -10,6 +10,7 @@ #include #include +#include "flash-writer.h" #include @@ -49,13 +50,52 @@ static void __attribute__((noreturn)) ram_code_exit(bool updated) while(1); } +static int check_hex_file(const char *fname) +{ + enum hex_parser_ret hex_ret; + struct hex_parser parser; + uint32_t addr; + char data[128]; + size_t dlen; + int retval = -1; + uint32_t flash_base; + uint32_t flash_top; + + flash_base = flash_writer_get_base_address(); + flash_top = flash_base + flash_writer_get_flash_size(); + + hex_ret = hex_parser_open(&parser, fname); + if (hex_ret != HEX_PARSER_OK) { + retval = -1; + goto exit; + } + + do { + hex_ret = hex_parser_parse(&parser, &addr, data, sizeof(data), &dlen); + if (hex_ret == HEX_PARSER_DATA_OK) { + if (addr < flash_base || addr+dlen >= flash_top) { + retval = -2; + goto ret_close_parser; + } + } + } while (hex_ret == HEX_PARSER_DATA_OK || hex_ret == HEX_PARSER_OK); + + if (hex_ret == HEX_PARSER_EOF_RECORD) { + retval = 0; + } + +ret_close_parser: + hex_parser_close(&parser); +exit: + return retval; +} + int ram_code_main(void) { FRESULT fres; int res; enum safety_memory_state safety_mem_state; - enum hex_parser_ret hex_ret; - struct hex_parser parser; + static char filename[256]; SysTick_Config(168000UL); external_watchdog_disable(); @@ -71,8 +111,11 @@ int ram_code_main(void) ram_code_exit(false); } - hex_ret = hex_parser_open(&parser, "update.hex"); - if (hex_ret != HEX_PARSER_OK) { + res = safety_memory_get_update_filename(filename, NULL); + if (res) + ram_code_exit(false); + + if (check_hex_file(filename)) { ram_code_exit(false); }