espcoredump: fix issue with spi_flash access

spi_flash has been updated and its functions work from flash by default instead of IRAM that cause issue
add Kconfig value into espcoredump to enable spi_flash legacy mode (CONFIG_SPI_FLASH_USE_LEGACY_IMPL) when core dump is selected
fix spi_flash issues to work correctly with legacy mode when CONFIG_SPI_FLASH_USE_LEGACY_IMPL is used
This commit is contained in:
Alex Lisitsyn 2019-09-06 15:37:55 +08:00 committed by Angus Gratton
parent fc62542e18
commit 7ff9538c48
12 changed files with 87 additions and 16 deletions

View file

@ -776,6 +776,20 @@ menu "ESP32-specific"
To prevent interrupting DPORT workarounds, To prevent interrupting DPORT workarounds,
need to disable interrupt with a maximum used level in the system. need to disable interrupt with a maximum used level in the system.
config ESP32_PANIC_HANDLER_IRAM
bool "Place panic handler code in IRAM"
default n
help
If this option is disabled (default), the panic handler code is placed in flash not IRAM.
This means that if ESP-IDF crashes while flash cache is disabled, the panic handler will
automatically re-enable flash cache before running GDB Stub or Core Dump. This adds some minor
risk, if the flash cache status is also corrupted during the crash.
If this option is enabled, the panic handler code is placed in IRAM. This allows the panic
handler to run without needing to re-enable cache first. This may be necessary to debug some
complex issues with crashes while flash cache is disabled (for example, when writing to
SPI flash.)
endmenu # ESP32-Specific endmenu # ESP32-Specific
menu "Power Management" menu "Power Management"

View file

@ -404,9 +404,11 @@ void start_cpu0_default(void)
/* init default OS-aware flash access critical section */ /* init default OS-aware flash access critical section */
spi_flash_guard_set(&g_flash_guard_default_ops); spi_flash_guard_set(&g_flash_guard_default_ops);
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
esp_flash_app_init(); esp_flash_app_init();
esp_err_t flash_ret = esp_flash_init_default_chip(); esp_err_t flash_ret = esp_flash_init_default_chip();
assert(flash_ret == ESP_OK); assert(flash_ret == ESP_OK);
#endif
uint8_t revision = esp_efuse_get_chip_ver(); uint8_t revision = esp_efuse_get_chip_ver();
ESP_LOGI(TAG, "Chip Revision: %d", revision); ESP_LOGI(TAG, "Chip Revision: %d", revision);

View file

@ -608,6 +608,14 @@ static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
reconfigureAllWdts(); reconfigureAllWdts();
#endif #endif
#if !CONFIG_ESP32_PANIC_HANDLER_IRAM
// Re-enable CPU cache for current CPU if it was disabled
if (!spi_flash_cache_enabled()) {
spi_flash_enable_cache(core_id);
panicPutStr("Re-enable cpu cache.\r\n");
}
#endif
#if CONFIG_ESP32_PANIC_GDBSTUB #if CONFIG_ESP32_PANIC_GDBSTUB
disableAllWdts(); disableAllWdts();
rtc_wdt_disable(); rtc_wdt_disable();

View file

@ -1,4 +1,7 @@
[mapping:esp_gdbstub] [mapping:esp_gdbstub]
archive: libesp_gdbstub.a archive: libesp_gdbstub.a
entries: entries:
* (noflash) if ESP32_PANIC_HANDLER_IRAM = y:
* (noflash_text)
else:
* (default)

View file

@ -13,6 +13,7 @@ menu "Core dump"
config ESP32_ENABLE_COREDUMP_TO_FLASH config ESP32_ENABLE_COREDUMP_TO_FLASH
bool "Flash" bool "Flash"
select ESP32_ENABLE_COREDUMP select ESP32_ENABLE_COREDUMP
select SPI_FLASH_USE_LEGACY_IMPL
config ESP32_ENABLE_COREDUMP_TO_UART config ESP32_ENABLE_COREDUMP_TO_UART
bool "UART" bool "UART"
select ESP32_ENABLE_COREDUMP select ESP32_ENABLE_COREDUMP

View file

@ -1,7 +1,10 @@
[mapping:espcoredump] [mapping:espcoredump]
archive: libespcoredump.a archive: libespcoredump.a
entries: entries:
core_dump_uart (noflash_text) if ESP32_PANIC_HANDLER_IRAM = y:
core_dump_flash (noflash_text) core_dump_uart (noflash_text)
core_dump_common (noflash_text) core_dump_flash (noflash_text)
core_dump_port (noflash_text) core_dump_common (noflash_text)
core_dump_port (noflash_text)
else:
* (default)

View file

@ -200,8 +200,8 @@ static esp_err_t esp_core_dump_flash_write_data(void *priv, void * data, uint32_
void esp_core_dump_to_flash(XtExcFrame *frame) void esp_core_dump_to_flash(XtExcFrame *frame)
{ {
core_dump_write_config_t wr_cfg; static core_dump_write_config_t wr_cfg;
core_dump_write_flash_data_t wr_data; static core_dump_write_flash_data_t wr_data;
core_dump_crc_t crc = esp_core_dump_calc_flash_config_crc(); core_dump_crc_t crc = esp_core_dump_calc_flash_config_crc();
if (s_core_flash_config.partition_config_crc != crc) { if (s_core_flash_config.partition_config_crc != crc) {
@ -214,8 +214,10 @@ void esp_core_dump_to_flash(XtExcFrame *frame)
return; return;
} }
/* init non-OS flash access critical section */ #if CONFIG_SPI_FLASH_USE_LEGACY_IMPL
// init non-OS flash access critical section
spi_flash_guard_set(&g_flash_guard_no_os_ops); spi_flash_guard_set(&g_flash_guard_no_os_ops);
#endif
memset(&wr_cfg, 0, sizeof(wr_cfg)); memset(&wr_cfg, 0, sizeof(wr_cfg));
wr_cfg.prepare = esp_core_dump_flash_write_prepare; wr_cfg.prepare = esp_core_dump_flash_write_prepare;

View file

@ -94,7 +94,9 @@ bool esp_core_dump_process_stack(core_dump_task_header_t* task_snaphort, uint32_
ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", len, ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", len,
task_snaphort->stack_start, task_snaphort->stack_end); task_snaphort->stack_start, task_snaphort->stack_end);
// Take stack padding into account // Take stack padding into account
*length = (len + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1); if (length) {
*length = (len + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
}
task_is_valid = true; task_is_valid = true;
} }
return task_is_valid; return task_is_valid;

View file

@ -31,6 +31,18 @@
#include "esp_spi_flash.h" #include "esp_spi_flash.h"
#include "esp_log.h" #include "esp_log.h"
#define DPORT_CACHE_BIT(cpuid, regid) DPORT_ ## cpuid ## regid
#define DPORT_CACHE_MASK(cpuid) (DPORT_CACHE_BIT(cpuid, _CACHE_MASK_OPSDRAM) | DPORT_CACHE_BIT(cpuid, _CACHE_MASK_DROM0) | \
DPORT_CACHE_BIT(cpuid, _CACHE_MASK_DRAM1) | DPORT_CACHE_BIT(cpuid, _CACHE_MASK_IROM0) | \
DPORT_CACHE_BIT(cpuid, _CACHE_MASK_IRAM1) | DPORT_CACHE_BIT(cpuid, _CACHE_MASK_IRAM0) )
#define DPORT_CACHE_VAL(cpuid) (~(DPORT_CACHE_BIT(cpuid, _CACHE_MASK_DROM0) | \
DPORT_CACHE_BIT(cpuid, _CACHE_MASK_DRAM1) | \
DPORT_CACHE_BIT(cpuid, _CACHE_MASK_IRAM0)))
#define DPORT_CACHE_GET_VAL(cpuid) (cpuid == 0) ? DPORT_CACHE_VAL(PRO) : DPORT_CACHE_VAL(APP)
#define DPORT_CACHE_GET_MASK(cpuid) (cpuid == 0) ? DPORT_CACHE_MASK(PRO) : DPORT_CACHE_MASK(APP)
static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state); static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state);
static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state); static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state);
@ -256,13 +268,10 @@ void IRAM_ATTR spi_flash_enable_interrupts_caches_no_os(void)
* Cache_Flush before Cache_Read_Enable, even if cached data was not modified. * Cache_Flush before Cache_Read_Enable, even if cached data was not modified.
*/ */
static const uint32_t cache_mask = DPORT_APP_CACHE_MASK_OPSDRAM | DPORT_APP_CACHE_MASK_DROM0 |
DPORT_APP_CACHE_MASK_DRAM1 | DPORT_APP_CACHE_MASK_IROM0 |
DPORT_APP_CACHE_MASK_IRAM1 | DPORT_APP_CACHE_MASK_IRAM0;
static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state) static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_state)
{ {
uint32_t ret = 0; uint32_t ret = 0;
const uint32_t cache_mask = DPORT_CACHE_GET_MASK(cpuid);
if (cpuid == 0) { if (cpuid == 0) {
ret |= DPORT_GET_PERI_REG_BITS2(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, 0); ret |= DPORT_GET_PERI_REG_BITS2(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, 0);
while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) { while (DPORT_GET_PERI_REG_BITS2(DPORT_PRO_DCACHE_DBUG0_REG, DPORT_PRO_CACHE_STATE, DPORT_PRO_CACHE_STATE_S) != 1) {
@ -281,6 +290,7 @@ static void IRAM_ATTR spi_flash_disable_cache(uint32_t cpuid, uint32_t* saved_st
static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state) static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_state)
{ {
const uint32_t cache_mask = DPORT_CACHE_GET_MASK(cpuid);
if (cpuid == 0) { if (cpuid == 0) {
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S); DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL_REG, 1, 1, DPORT_PRO_CACHE_ENABLE_S);
DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, saved_state, 0); DPORT_SET_PERI_REG_BITS(DPORT_PRO_CACHE_CTRL1_REG, cache_mask, saved_state, 0);
@ -290,7 +300,6 @@ static void IRAM_ATTR spi_flash_restore_cache(uint32_t cpuid, uint32_t saved_sta
} }
} }
IRAM_ATTR bool spi_flash_cache_enabled(void) IRAM_ATTR bool spi_flash_cache_enabled(void)
{ {
bool result = (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) != 0); bool result = (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) != 0);
@ -299,3 +308,12 @@ IRAM_ATTR bool spi_flash_cache_enabled(void)
#endif #endif
return result; return result;
} }
void IRAM_ATTR spi_flash_enable_cache(uint32_t cpuid)
{
uint32_t cache_value = DPORT_CACHE_GET_VAL(cpuid);
cache_value &= DPORT_CACHE_GET_MASK(cpuid);
// Re-enable cache on this CPU
spi_flash_restore_cache(cpuid, cache_value);
}

View file

@ -295,6 +295,13 @@ const void *spi_flash_phys2cache(size_t phys_offs, spi_flash_mmap_memory_t memor
*/ */
bool spi_flash_cache_enabled(void); bool spi_flash_cache_enabled(void);
/**
* @brief Re-enable cache for the core defined as cpuid parameter.
*
* @param cpuid the core number to enable instruction cache for
*/
void spi_flash_enable_cache(uint32_t cpuid);
/** /**
* @brief SPI flash critical section enter function. * @brief SPI flash critical section enter function.
* *

View file

@ -172,7 +172,9 @@ static esp_err_t load_partitions(void)
err = ESP_ERR_NO_MEM; err = ESP_ERR_NO_MEM;
break; break;
} }
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
item->info.flash_chip = esp_flash_default_chip; item->info.flash_chip = esp_flash_default_chip;
#endif
item->info.address = it->pos.offset; item->info.address = it->pos.offset;
item->info.size = it->pos.size; item->info.size = it->pos.size;
item->info.type = it->type; item->info.type = it->type;
@ -334,10 +336,11 @@ esp_err_t esp_partition_read(const esp_partition_t* partition,
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL #endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
} else { } else {
#if CONFIG_SECURE_FLASH_ENC_ENABLED #if CONFIG_SECURE_FLASH_ENC_ENABLED
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
if (partition->flash_chip != esp_flash_default_chip) { if (partition->flash_chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
#endif
/* Encrypted partitions need to be read via a cache mapping */ /* Encrypted partitions need to be read via a cache mapping */
const void *buf; const void *buf;
spi_flash_mmap_handle_t handle; spi_flash_mmap_handle_t handle;
@ -376,9 +379,11 @@ esp_err_t esp_partition_write(const esp_partition_t* partition,
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL #endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
} else { } else {
#if CONFIG_SECURE_FLASH_ENC_ENABLED #if CONFIG_SECURE_FLASH_ENC_ENABLED
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
if (partition->flash_chip != esp_flash_default_chip) { if (partition->flash_chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
#endif
return spi_flash_write_encrypted(dst_offset, src, size); return spi_flash_write_encrypted(dst_offset, src, size);
#else #else
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
@ -428,9 +433,11 @@ esp_err_t esp_partition_mmap(const esp_partition_t* partition, size_t offset, si
if (offset + size > partition->size) { if (offset + size > partition->size) {
return ESP_ERR_INVALID_SIZE; return ESP_ERR_INVALID_SIZE;
} }
#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
if (partition->flash_chip != esp_flash_default_chip) { if (partition->flash_chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED; return ESP_ERR_NOT_SUPPORTED;
} }
#endif
size_t phys_addr = partition->address + offset; size_t phys_addr = partition->address + offset;
// offset within 64kB block // offset within 64kB block
size_t region_offset = phys_addr & 0xffff; size_t region_offset = phys_addr & 0xffff;

View file

@ -62,6 +62,10 @@ Behavior of panic handler is affected by two other configuration options.
- If :doc:`Core Dump <core_dump>` feature is enabled (``CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH`` or ``CONFIG_ESP32_ENABLE_COREDUMP_TO_UART`` options), then system state (task stacks and registers) will be dumped either to Flash or UART, for later analysis. - If :doc:`Core Dump <core_dump>` feature is enabled (``CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH`` or ``CONFIG_ESP32_ENABLE_COREDUMP_TO_UART`` options), then system state (task stacks and registers) will be dumped either to Flash or UART, for later analysis.
- If :ref:`CONFIG_ESP32_PANIC_HANDLER_IRAM` is disabled (disabled by default), the panic handler code is placed in flash memory not IRAM. This means that if ESP-IDF crashes while flash cache is disabled, the panic handler will automatically re-enable flash cache before running GDB Stub or Core Dump. This adds some minor risk, if the flash cache status is also corrupted during the crash.
If this option is enabled, the panic handler code is placed in IRAM. This allows the panic handler to run without needing to re-enable cache first. This may be necessary to debug some complex issues with crashes while flash cache is disabled (for example, when writing to SPI flash).
The following diagram illustrates panic handler behavior: The following diagram illustrates panic handler behavior:
.. blockdiag:: .. blockdiag::