Merge branch 'feature/parametrize_core_dump_check_v4.3' into 'release/v4.3'

coredump: core dump data check can now be parametrized (v4.3)

See merge request espressif/esp-idf!13773
This commit is contained in:
Angus Gratton
2021-06-28 07:03:50 +00:00
3 changed files with 169 additions and 52 deletions

View File

@@ -48,6 +48,14 @@ menu "Core dump"
depends on ESP_COREDUMP_DATA_FORMAT_ELF && IDF_TARGET_ESP32
endchoice
config ESP_COREDUMP_CHECK_BOOT
bool "Check core dump data integrity on boot"
default y
depends on ESP_COREDUMP_ENABLE_TO_FLASH
help
When enabled, if any data are found on the flash core dump partition,
they will be checked by calculating their checksum.
config ESP_COREDUMP_ENABLE
bool
default F

View File

@@ -78,6 +78,19 @@ void esp_core_dump_to_uart(panic_info_t *info);
/*********************************** USER MODE API ************************************/
/**************************************************************************************/
/**
* @brief Check integrity of coredump data in flash.
* This function reads the coredump data while calculating their checksum. If it
* doesn't match the checksum written on flash, it means data are corrupted,
* an error will be returned. Else, ESP_OK is returned.
*
* @return `ESP_OK` if core dump is present and valid, `ESP_ERR_NOT_FOUND` if no core dump
* is stored in the partition, `ESP_ERR_INVALID_SIZE` or `ESP_ERR_INVALID_CRC`
* if the core dump is corrupted, other errors when unable to access flash, in that
* case please refer to \see esp_err_t
*/
esp_err_t esp_core_dump_image_check(void);
/**
* @brief Retrieves address and size of coredump data in flash.
* This function is always available, even when core dump is disabled in menuconfig.
@@ -89,6 +102,15 @@ void esp_core_dump_to_uart(panic_info_t *info);
*/
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
/**
* @brief Erases coredump data in flash. esp_core_dump_image_get() will then return
* ESP_ERR_NOT_FOUND. Can be used after a coredump has been transmitted successfully.
* This function is always available, even when core dump is disabled in menuconfig.
*
* @return ESP_OK on success, otherwise \see esp_err_t
*/
esp_err_t esp_core_dump_image_erase(void);
#ifdef __cplusplus
}
#endif

View File

@@ -20,6 +20,8 @@
#include "esp_flash_encrypt.h"
#include "esp_rom_crc.h"
#define BLANK_COREDUMP_SIZE 0xFFFFFFFF
const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_flash";
#if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
@@ -57,6 +59,9 @@ static core_dump_flash_config_t s_core_flash_config;
#define ESP_COREDUMP_FLASH_ERASE(_off_, _len_) esp_flash_erase_region(esp_flash_default_chip, _off_, _len_)
#endif
esp_err_t esp_core_dump_image_check(void);
static esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size);
static esp_err_t esp_core_dump_flash_custom_write(uint32_t address, const void *buffer, uint32_t length)
{
esp_err_t err = ESP_OK;
@@ -70,8 +75,6 @@ static esp_err_t esp_core_dump_flash_custom_write(uint32_t address, const void *
return err;
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
static inline core_dump_crc_t esp_core_dump_calc_flash_config_crc(void)
{
return esp_rom_crc32_le(0, (uint8_t const *)&s_core_flash_config.partition, sizeof(s_core_flash_config.partition));
@@ -302,6 +305,7 @@ static esp_err_t esp_core_dump_flash_write_end(core_dump_write_data_t* priv)
}
wr_data->off += cs_len;
ESP_COREDUMP_LOGI("Write end offset 0x%x, check sum length %d", wr_data->off, cs_len);
return err;
}
@@ -341,19 +345,26 @@ void esp_core_dump_to_flash(panic_info_t *info)
void esp_core_dump_init(void)
{
size_t core_data_sz = 0;
size_t core_data_addr = 0;
esp_core_dump_flash_init();
if (esp_core_dump_image_get(&core_data_addr, &core_data_sz) == ESP_OK && core_data_sz > 0) {
ESP_COREDUMP_LOGI("Found core dump %d bytes in flash @ 0x%x", core_data_sz, core_data_addr);
#if CONFIG_ESP_COREDUMP_CHECK_BOOT
const esp_partition_t *partition = 0;
uint32_t size = 0;
if (esp_core_dump_image_check() == ESP_OK
&& esp_core_dump_partition_and_size_get(&partition, &size) == ESP_OK) {
ESP_COREDUMP_LOGI("Found core dump %d bytes in flash @ 0x%x", size, partition->address);
}
#endif
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
esp_err_t esp_core_dump_image_check(void)
{
esp_err_t err = ESP_OK;
const esp_partition_t *core_part = NULL;
core_dump_write_data_t wr_data = { 0 };
uint32_t size = 0;
uint32_t total_size = 0;
uint32_t offset = 0;
const uint32_t checksum_size = esp_core_dump_checksum_size();
core_dump_checksum_bytes checksum_calc = NULL;
@@ -364,51 +375,15 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
/* Assert that we won't have any problems with our checksum size. */
ESP_COREDUMP_DEBUG_ASSERT(checksum_size <= COREDUMP_CHECKSUM_MAX_LEN);
/* Check the validity of the parameters. */
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Find the partition that could potentially contain a (previous) core dump. */
const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (!core_part) {
ESP_LOGE(TAG, "No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_LOGE(TAG, "Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
/* The partition has been found, get its first uint32_t value, which
* describes the core dump file size. */
err = esp_partition_read(core_part, 0, &size, sizeof(uint32_t));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read core dump data size (%d)!", err);
return err;
}
/* Verify that the size read from the flash is not corrupted. */
if (size == 0xFFFFFFFF) {
ESP_LOGD(TAG, "Blank core dump partition!");
err = ESP_ERR_INVALID_SIZE;
} else if ((size < sizeof(uint32_t)) || (size > core_part->size)) {
ESP_LOGE(TAG, "Incorrect size of core dump image: %d", size);
err = ESP_ERR_INVALID_SIZE;
}
/* Retrieve the partition and size. */
err = esp_core_dump_partition_and_size_get(&core_part, &total_size);
if (err != ESP_OK) {
return err;
}
/* Save the size read. */
*out_size = size;
/* The final checksum, from the image, doesn't take part into the checksum
* calculation, so subtract it from the bytes we are going to read. */
size -= checksum_size ;
size = total_size - checksum_size ;
/* Initiate the checksum calculation for the coredump in the flash. */
esp_core_dump_checksum_init(&wr_data.checksum_ctx);
@@ -421,7 +396,7 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
/* Read the content of the flash. */
err = esp_partition_read(core_part, offset, wr_data.cached_data, toread);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read data from core dump (%d)!", err);
ESP_COREDUMP_LOGE("Failed to read data from core dump (%d)!", err);
return err;
}
@@ -438,24 +413,136 @@ esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
/* Read the checksum from the flash and compare to the one just
* calculated. */
err = esp_partition_read(core_part, *out_size - checksum_size, checksum_read, checksum_size);
err = esp_partition_read(core_part, total_size - checksum_size, checksum_read, checksum_size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to read checksum from core dump (%d)!", err);
ESP_COREDUMP_LOGE("Failed to read checksum from core dump (%d)!", err);
return err;
}
/* Compare the checksum read from the flash and the one just calculated. */
if (memcmp(checksum_calc, checksum_read, checksum_size) != 0) {
ESP_LOGE(TAG, "Core dump data check failed:");
ESP_COREDUMP_LOGE("Core dump data check failed:");
esp_core_dump_print_checksum("Calculated checksum", checksum_calc);
esp_core_dump_print_checksum("Image checksum", checksum_read);
return ESP_ERR_INVALID_CRC;
} else {
ESP_LOGI(TAG, "Core dump data checksum is correct");
ESP_COREDUMP_LOGI("Core dump data checksum is correct");
}
*out_addr = core_part->address;
return ESP_OK;
}
#endif
esp_err_t esp_core_dump_image_erase(void)
{
/* Find the partition that could potentially contain a (previous) core dump. */
const esp_partition_t *core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (!core_part) {
ESP_LOGE(TAG, "No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_LOGE(TAG, "Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
esp_err_t err = ESP_OK;
err = esp_partition_erase_range(core_part, 0, core_part->size);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase core dump partition (%d)!", err);
return err;
}
// Mark core dump as deleted by setting field size
const uint32_t blank_size = BLANK_COREDUMP_SIZE;
err = esp_partition_write(core_part, 0, &blank_size, sizeof(blank_size));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to write core dump partition size (%d)!", err);
}
return err;
}
static esp_err_t esp_core_dump_partition_and_size_get(const esp_partition_t **partition, uint32_t* size)
{
uint32_t core_size = 0;
const esp_partition_t *core_part = NULL;
/* Check the arguments, at least one should be provided. */
if (partition == NULL && size == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Find the partition that could potentially contain a (previous) core dump. */
core_part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_COREDUMP,
NULL);
if (core_part == NULL) {
ESP_COREDUMP_LOGE("No core dump partition found!");
return ESP_ERR_NOT_FOUND;
}
if (core_part->size < sizeof(uint32_t)) {
ESP_COREDUMP_LOGE("Too small core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
/* The partition has been found, get its first uint32_t value, which
* describes the core dump file size. */
esp_err_t err = esp_partition_read(core_part, 0, &core_size, sizeof(uint32_t));
if (err != ESP_OK) {
ESP_COREDUMP_LOGE("Failed to read core dump data size (%d)!", err);
return err;
}
/* Verify that the size read from the flash is not corrupted. */
if (core_size == 0xFFFFFFFF) {
ESP_COREDUMP_LOGD("Blank core dump partition!");
return ESP_ERR_INVALID_SIZE;
}
if ((core_size < sizeof(uint32_t)) || (core_size > core_part->size)) {
ESP_COREDUMP_LOGE("Incorrect size of core dump image: %d", core_size);
return ESP_ERR_INVALID_SIZE;
}
/* Return the values if needed. */
if (partition != NULL) {
*partition = core_part;
}
if (size != NULL) {
*size = core_size;
}
return ESP_OK;
}
esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size)
{
esp_err_t err = ESP_OK;
uint32_t size = 0;
const esp_partition_t *core_part = NULL;
/* Check the validity of the parameters. */
if (out_addr == NULL || out_size == NULL) {
return ESP_ERR_INVALID_ARG;
}
/* Retrieve the partition and size. */
err = esp_core_dump_partition_and_size_get(&core_part, &size);
if (err != ESP_OK) {
return err;
}
/* Save the address. */
*out_addr = core_part->address;
/* Save the size read. */
*out_size = size;
return ESP_OK;
}