From a55cc99f507491ab8b6b6d79d8dbab11f897aa6f Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 13 Sep 2017 21:30:48 +0300 Subject: [PATCH] esp32: Replaces magic numbers with CRC for core dump in flash --- components/esp32/Kconfig | 7 -- components/esp32/core_dump.c | 86 +++++++++++-------- components/esp32/include/esp_core_dump.h | 34 ++++---- components/espcoredump/espcoredump.py | 39 ++++----- components/espcoredump/test/expected_output | 2 +- .../espcoredump/test/expected_output_new_CT | 2 +- .../include/freertos/FreeRTOSConfig.h | 7 +- docs/en/api-guides/core_dump.rst | 4 +- 8 files changed, 90 insertions(+), 91 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index b53a68409..32f699d7b 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -306,13 +306,6 @@ config ESP32_CORE_DUMP_UART_DELAY Config delay (in ms) before printing core dump to UART. Delay can be interrupted by pressing Enter key. -config ESP32_CORE_DUMP_LOG_LEVEL - int "Core dump module logging level" - depends on ESP32_ENABLE_COREDUMP - default 1 - help - Config core dump module logging level (0-5). - choice NUMBER_OF_UNIVERSAL_MAC_ADDRESS bool "Number of universally administered (by IEEE) MAC address" default FOUR_UNIVERSAL_MAC_ADDRESS diff --git a/components/esp32/core_dump.c b/components/esp32/core_dump.c index 078afe93b..6150893fa 100644 --- a/components/esp32/core_dump.c +++ b/components/esp32/core_dump.c @@ -25,11 +25,12 @@ #include "esp_partition.h" #include "esp_clk.h" -#if CONFIG_ESP32_ENABLE_COREDUMP -#define LOG_LOCAL_LEVEL CONFIG_ESP32_CORE_DUMP_LOG_LEVEL #include "esp_log.h" -const static DRAM_ATTR char TAG[] = "esp_core_dump"; +const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump"; +typedef uint32_t core_dump_crc_t; + +#if CONFIG_ESP32_ENABLE_COREDUMP #define ESP_COREDUMP_LOG( level, format, ... ) if (LOG_LOCAL_LEVEL >= level) { ets_printf(DRAM_STR(format), esp_log_early_timestamp(), (const char *)TAG, ##__VA_ARGS__); } #define ESP_COREDUMP_LOGE( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_ERROR, LOG_FORMAT(E, format), ##__VA_ARGS__) #define ESP_COREDUMP_LOGW( format, ... ) ESP_COREDUMP_LOG(ESP_LOG_WARN, LOG_FORMAT(W, format), ##__VA_ARGS__) @@ -47,6 +48,7 @@ const static DRAM_ATTR char TAG[] = "esp_core_dump"; #define COREDUMP_MAX_TASKS_NUM 32 #define COREDUMP_MAX_TASK_STACK_SIZE (64*1024) + typedef esp_err_t (*esp_core_dump_write_prepare_t)(void *priv, uint32_t *data_len); typedef esp_err_t (*esp_core_dump_write_start_t)(void *priv); typedef esp_err_t (*esp_core_dump_write_end_t)(void *priv); @@ -143,9 +145,9 @@ static void esp_core_dump_write(XtExcFrame *frame, core_dump_write_config_t *wri else { #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH XtExcFrame *task_frame2 = (XtExcFrame *)tasks[i].pxTopOfStack; -#endif ESP_COREDUMP_LOG_PROCESS("Task EXIT/PC/PS/A0/SP %x %x %x %x %x", task_frame2->exit, task_frame2->pc, task_frame2->ps, task_frame2->a0, task_frame2->a1); +#endif } } len = (uint32_t)tasks[i].pxEndOfStack - (uint32_t)tasks[i].pxTopOfStack; @@ -248,13 +250,10 @@ static void esp_core_dump_write(XtExcFrame *frame, core_dump_write_config_t *wri #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH -// magic numbers to control core dump data consistency -#define COREDUMP_FLASH_MAGIC_START 0xE32C04EDUL -#define COREDUMP_FLASH_MAGIC_END 0xE32C04EDUL - typedef struct _core_dump_write_flash_data_t { - uint32_t off; + uint32_t off; // current offset in partition + core_dump_crc_t crc; // CRC of dumped data } core_dump_write_flash_data_t; typedef struct _core_dump_partition_t @@ -267,15 +266,20 @@ typedef struct _core_dump_partition_t typedef struct _core_dump_flash_config_t { - // core dump partition start + // core dump partition config core_dump_partition_t partition; - // core dump partition size - uint32_t crc; + // CRC of core dump partition config + core_dump_crc_t partition_config_crc; } core_dump_flash_config_t; // core dump flash data static core_dump_flash_config_t s_core_flash_config; +static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void) +{ + return crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition)); +} + static uint32_t esp_core_dump_write_flash_padded(size_t off, uint8_t *data, uint32_t data_size) { esp_err_t err; @@ -302,8 +306,9 @@ static uint32_t esp_core_dump_write_flash_padded(size_t off, uint8_t *data, uint if (len) { // write last bytes with padding, actual TCB len can be retrieved by esptool from core dump header rom_data.data32 = 0; - for (k = 0; k < len; k++) + for (k = 0; k < len; k++) { rom_data.data8[k] = *(data + data_len + k); + } err = spi_flash_write(off + data_len, &rom_data, sizeof(uint32_t)); if (err != ESP_OK) { ESP_COREDUMP_LOGE("Failed to finish write data to flash (%d)!", err); @@ -322,18 +327,19 @@ static esp_err_t esp_core_dump_flash_write_prepare(void *priv, uint32_t *data_le core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv; // check for available space in partition - // add space for 2 magics. TODO: change to CRC - if ((*data_len + 2*sizeof(uint32_t)) > s_core_flash_config.partition.size) { + if ((*data_len + sizeof(uint32_t)) > s_core_flash_config.partition.size) { ESP_COREDUMP_LOGE("Not enough space to save core dump!"); return ESP_ERR_NO_MEM; } - *data_len += 2*sizeof(uint32_t); + // add space for CRC + *data_len += sizeof(core_dump_crc_t); - wr_data->off = 0; + memset(wr_data, 0, sizeof(*wr_data)); sec_num = *data_len / SPI_FLASH_SEC_SIZE; - if (*data_len % SPI_FLASH_SEC_SIZE) + if (*data_len % SPI_FLASH_SEC_SIZE) { sec_num++; + } assert(sec_num * SPI_FLASH_SEC_SIZE <= s_core_flash_config.partition.size); err = spi_flash_erase_range(s_core_flash_config.partition.start + 0, sec_num * SPI_FLASH_SEC_SIZE); if (err != ESP_OK) { @@ -362,9 +368,7 @@ static esp_err_t esp_core_dump_flash_write_word(core_dump_write_flash_data_t *wr static esp_err_t esp_core_dump_flash_write_start(void *priv) { - core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv; - // save magic 1 - return esp_core_dump_flash_write_word(wr_data, COREDUMP_FLASH_MAGIC_START); + return ESP_OK; } static esp_err_t esp_core_dump_flash_write_end(void *priv) @@ -381,17 +385,16 @@ static esp_err_t esp_core_dump_flash_write_end(void *priv) if (err != ESP_OK) { ESP_COREDUMP_LOGE("Failed to read flash (%d)!", err); return err; - } - else { + } else { ESP_COREDUMP_LOG_PROCESS("Data from flash:"); for (uint32_t i = 0; i < sizeof(rom_data)/sizeof(rom_data.data32[0]); i++) { ESP_COREDUMP_LOG_PROCESS("%x", rom_data.data32[i]); } } #endif - - // save magic 2 - return esp_core_dump_flash_write_word(wr_data, COREDUMP_FLASH_MAGIC_END); + // write core dump CRC + ESP_COREDUMP_LOG_PROCESS("Dump data CRC = 0x%x", wr_data->crc); + return esp_core_dump_flash_write_word(wr_data, wr_data->crc); } static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_t data_len) @@ -400,10 +403,12 @@ static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_ core_dump_write_flash_data_t *wr_data = (core_dump_write_flash_data_t *)priv; uint32_t len = esp_core_dump_write_flash_padded(s_core_flash_config.partition.start + wr_data->off, data, data_len); - if (len != data_len) + if (len != data_len) { return ESP_FAIL; + } wr_data->off += len; + wr_data->crc = crc32_le(wr_data->crc, data, data_len); return err; } @@ -413,10 +418,14 @@ void esp_core_dump_to_flash(XtExcFrame *frame) core_dump_write_config_t wr_cfg; core_dump_write_flash_data_t wr_data; - uint32_t crc = crc32_le(UINT32_MAX, (uint8_t const *)&s_core_flash_config.partition, - sizeof(s_core_flash_config.partition)); - if (s_core_flash_config.crc != crc) { - ESP_COREDUMP_LOGE("Core dump flash config is corrupted! CRC=0x%x instead of 0x%x", crc, s_core_flash_config.crc); + core_dump_crc_t crc = esp_core_dump_calc_flash_config_crc(); + if (s_core_flash_config.partition_config_crc != crc) { + ESP_COREDUMP_LOGE("Core dump flash config is corrupted! CRC=0x%x instead of 0x%x", crc, s_core_flash_config.partition_config_crc); + return; + } + // check that partition can hold at least core dump data length + if (s_core_flash_config.partition.start == 0 || s_core_flash_config.partition.size < sizeof(uint32_t)) { + ESP_COREDUMP_LOGE("Invalid flash partition config!"); return; } @@ -500,10 +509,11 @@ static esp_err_t esp_core_dump_uart_write_data(void *priv, void * data, uint32_t static int esp_core_dump_uart_get_char() { int i; uint32_t reg = (READ_PERI_REG(UART_STATUS_REG(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; - if (reg) + if (reg) { i = READ_PERI_REG(UART_FIFO_REG(0)); - else + } else { i = -1; + } return i; } @@ -532,8 +542,9 @@ void esp_core_dump_to_uart(XtExcFrame *frame) ch = esp_core_dump_uart_get_char(); while (!(ch == '\n' || ch == '\r')) { tm_cur = xthal_get_ccount() / cpu_ticks_per_ms; - if (tm_cur >= tm_end) + if (tm_cur >= tm_end){ break; + } ch = esp_core_dump_uart_get_char(); } ESP_COREDUMP_LOGI("Print core dump to uart..."); @@ -554,10 +565,9 @@ void esp_core_dump_init() return; } ESP_COREDUMP_LOGI("Found partition '%s' @ %x %d bytes", core_part->label, core_part->address, core_part->size); - s_core_flash_config.partition.start = core_part->address; - s_core_flash_config.partition.size = core_part->size; - s_core_flash_config.crc = crc32_le(UINT32_MAX, (uint8_t const *)&s_core_flash_config.partition, - sizeof(s_core_flash_config.partition)); + s_core_flash_config.partition.start = core_part->address; + s_core_flash_config.partition.size = core_part->size; + s_core_flash_config.partition_config_crc = esp_core_dump_calc_flash_config_crc(); #endif #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART ESP_COREDUMP_LOGI("Init core dump to UART"); diff --git a/components/esp32/include/esp_core_dump.h b/components/esp32/include/esp_core_dump.h index c6634364c..89a1c2779 100644 --- a/components/esp32/include/esp_core_dump.h +++ b/components/esp32/include/esp_core_dump.h @@ -25,29 +25,29 @@ void esp_core_dump_init(); * @brief Saves core dump to flash. * * The structure of data stored in flash is as follows: - * | MAGIC1 | + * * | TOTAL_LEN | TASKS_NUM | TCB_SIZE | * | TCB_ADDR_1 | STACK_TOP_1 | STACK_END_1 | TCB_1 | STACK_1 | * . . . . * . . . . * | TCB_ADDR_N | STACK_TOP_N | STACK_END_N | TCB_N | STACK_N | - * | MAGIC2 | + * | CRC32 | + * * Core dump in flash consists of header and data for every task in the system at the moment of crash. - * For flash data integrity control two magic numbers are used at the beginning and the end of core dump. + * For flash data integrity control CRC is used at the end of core the dump data. * The structure of core dump data is described below in details. - * 1) MAGIC1 and MAGIC2 are special numbers stored at the beginning and the end of core dump. - * They are used to control core dump data integrity. Size of every number is 4 bytes. - * 2) Core dump starts with header: - * 2.1) TOTAL_LEN is total length of core dump data in flash including magic numbers. Size is 4 bytes. - * 2.2) TASKS_NUM is the number of tasks for which data are stored. Size is 4 bytes. - * 2.3) TCB_SIZE is the size of task's TCB structure. Size is 4 bytes. - * 3) Core dump header is followed by the data for every task in the system. + * 1) Core dump starts with header: + * 1.1) TOTAL_LEN is total length of core dump data in flash including CRC. Size is 4 bytes. + * 1.2) TASKS_NUM is the number of tasks for which data are stored. Size is 4 bytes. + * 1.3) TCB_SIZE is the size of task's TCB structure. Size is 4 bytes. + * 2) Core dump header is followed by the data for every task in the system. * Task data are started with task header: - * 3.1) TCB_ADDR is the address of TCB in memory. Size is 4 bytes. - * 3.2) STACK_TOP is the top of task's stack (address of the topmost stack item). Size is 4 bytes. - * 3.2) STACK_END is the end of task's stack (address from which task's stack starts). Size is 4 bytes. - * 4) Task header is followed by TCB data. Size is TCB_SIZE bytes. - * 5) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes. + * 2.1) TCB_ADDR is the address of TCB in memory. Size is 4 bytes. + * 2.2) STACK_TOP is the top of task's stack (address of the topmost stack item). Size is 4 bytes. + * 2.2) STACK_END is the end of task's stack (address from which task's stack starts). Size is 4 bytes. + * 3) Task header is followed by TCB data. Size is TCB_SIZE bytes. + * 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes. + * 5) CRC is placed at the end of the data. */ void esp_core_dump_to_flash(); @@ -55,8 +55,8 @@ void esp_core_dump_to_flash(); * @brief Print base64-encoded core dump to UART. * * The structure of core dump data is the same as for data stored in flash (@see esp_core_dump_to_flash) with some notes: - * 1) Magic numbers are not present in core dump printed to UART. - * 2) Since magic numbers are omitted TOTAL_LEN does not include their size. + * 1) CRC is not present in core dump printed to UART. + * 2) Since CRC is omitted TOTAL_LEN does not include its size. * 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data. */ void esp_core_dump_to_uart(); diff --git a/components/espcoredump/espcoredump.py b/components/espcoredump/espcoredump.py index 7f024eb5f..bb45dfb24 100755 --- a/components/espcoredump/espcoredump.py +++ b/components/espcoredump/espcoredump.py @@ -24,6 +24,7 @@ import struct import array import errno import base64 +import binascii idf_path = os.getenv('IDF_PATH') if idf_path: @@ -35,7 +36,7 @@ except ImportError: print("Esptool is not found! Set proper $IDF_PATH in environment.") sys.exit(2) -__version__ = "0.2-dev" +__version__ = "0.3-dev" if os.name == 'nt': CLOSE_FDS = False @@ -690,12 +691,10 @@ class ESPCoreDumpFileLoader(ESPCoreDumpLoader): class ESPCoreDumpFlashLoader(ESPCoreDumpLoader): """Core dump flash loader class """ - ESP32_COREDUMP_FLASH_MAGIC_START = 0xE32C04ED - ESP32_COREDUMP_FLASH_MAGIC_END = 0xE32C04ED - ESP32_COREDUMP_FLASH_MAGIC_FMT = ' ESP32-specific config -> Core dump module logging level`). Value is a number from 0 (no output) to 5 (most verbose). - -3. Delay before core dump will be printed to UART (`Components -> ESP32-specific config -> Core dump print to UART delay`). Value is in ms. +2. Delay before core dump will be printed to UART (`Components -> ESP32-specific config -> Core dump print to UART delay`). Value is in ms. Save core dump to flash