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
To prevent interrupting DPORT workarounds,
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
menu "Power Management"
/* init default OS-aware flash access critical section */
spi_flash_guard_set(&g_flash_guard_default_ops);
+#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
esp_flash_app_init();
esp_err_t flash_ret = esp_flash_init_default_chip();
assert(flash_ret == ESP_OK);
+#endif
uint8_t revision = esp_efuse_get_chip_ver();
ESP_LOGI(TAG, "Chip Revision: %d", revision);
reconfigureAllWdts();
#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
disableAllWdts();
rtc_wdt_disable();
[mapping:esp_gdbstub]
archive: libesp_gdbstub.a
-entries:
- * (noflash)
+entries:
+ if ESP32_PANIC_HANDLER_IRAM = y:
+ * (noflash_text)
+ else:
+ * (default)
\ No newline at end of file
config ESP32_ENABLE_COREDUMP_TO_FLASH
bool "Flash"
select ESP32_ENABLE_COREDUMP
+ select SPI_FLASH_USE_LEGACY_IMPL
config ESP32_ENABLE_COREDUMP_TO_UART
bool "UART"
select ESP32_ENABLE_COREDUMP
[mapping:espcoredump]
archive: libespcoredump.a
entries:
- core_dump_uart (noflash_text)
- core_dump_flash (noflash_text)
- core_dump_common (noflash_text)
- core_dump_port (noflash_text)
\ No newline at end of file
+ if ESP32_PANIC_HANDLER_IRAM = y:
+ core_dump_uart (noflash_text)
+ core_dump_flash (noflash_text)
+ core_dump_common (noflash_text)
+ core_dump_port (noflash_text)
+ else:
+ * (default)
void esp_core_dump_to_flash(XtExcFrame *frame)
{
- core_dump_write_config_t wr_cfg;
- core_dump_write_flash_data_t wr_data;
+ static core_dump_write_config_t wr_cfg;
+ static core_dump_write_flash_data_t wr_data;
core_dump_crc_t crc = esp_core_dump_calc_flash_config_crc();
if (s_core_flash_config.partition_config_crc != crc) {
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);
+#endif
memset(&wr_cfg, 0, sizeof(wr_cfg));
wr_cfg.prepare = esp_core_dump_flash_write_prepare;
ESP_COREDUMP_LOG_PROCESS("Stack len = %lu (%x %x)", len,
task_snaphort->stack_start, task_snaphort->stack_end);
// 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;
}
return task_is_valid;
#include "esp_spi_flash.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_restore_cache(uint32_t cpuid, uint32_t saved_state);
* 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)
{
uint32_t ret = 0;
+ const uint32_t cache_mask = DPORT_CACHE_GET_MASK(cpuid);
if (cpuid == 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) {
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) {
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);
}
}
-
IRAM_ATTR bool spi_flash_cache_enabled(void)
{
bool result = (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE) != 0);
#endif
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);
+}
*/
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.
*
err = ESP_ERR_NO_MEM;
break;
}
+#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
item->info.flash_chip = esp_flash_default_chip;
+#endif
item->info.address = it->pos.offset;
item->info.size = it->pos.size;
item->info.type = it->type;
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
} else {
#if CONFIG_SECURE_FLASH_ENC_ENABLED
+#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
if (partition->flash_chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
-
+#endif
/* Encrypted partitions need to be read via a cache mapping */
const void *buf;
spi_flash_mmap_handle_t handle;
#endif // CONFIG_SPI_FLASH_USE_LEGACY_IMPL
} else {
#if CONFIG_SECURE_FLASH_ENC_ENABLED
+#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
if (partition->flash_chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
+#endif
return spi_flash_write_encrypted(dst_offset, src, size);
#else
return ESP_ERR_NOT_SUPPORTED;
if (offset + size > partition->size) {
return ESP_ERR_INVALID_SIZE;
}
+#ifndef CONFIG_SPI_FLASH_USE_LEGACY_IMPL
if (partition->flash_chip != esp_flash_default_chip) {
return ESP_ERR_NOT_SUPPORTED;
}
+#endif
size_t phys_addr = partition->address + offset;
// offset within 64kB block
size_t region_offset = phys_addr & 0xffff;
- 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:
.. blockdiag::