diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index 52fb63dd37..1f4dd57b54 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -39,9 +39,11 @@ */ static inline void print_cache_err_details(const void *frame) { - const char* cache_err_msg = esp_cache_err_panic_string(); - if (cache_err_msg) { - panic_print_str(cache_err_msg); + esp_cache_err_info_t err_info = {}; + esp_cache_err_get_panic_info(&err_info); + + if (err_info.err_str) { + panic_print_str(err_info.err_str); } else { panic_print_str("Cache error active, but failed to find a corresponding error message"); } diff --git a/components/esp_system/port/arch/xtensa/panic_arch.c b/components/esp_system/port/arch/xtensa/panic_arch.c index 484774ecb1..610a4a0468 100644 --- a/components/esp_system/port/arch/xtensa/panic_arch.c +++ b/components/esp_system/port/arch/xtensa/panic_arch.c @@ -19,8 +19,6 @@ #include "sdkconfig.h" #if !CONFIG_IDF_TARGET_ESP32 -#include "soc/extmem_reg.h" -#include "soc/ext_mem_defs.h" #include "soc/rtc_cntl_reg.h" #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #ifdef CONFIG_IDF_TARGET_ESP32S2 @@ -167,95 +165,7 @@ static void print_debug_exception_details(const void *f) } } -#if CONFIG_IDF_TARGET_ESP32S2 -static inline void print_cache_err_details(const void *f) -{ - uint32_t vaddr = 0, size = 0; - uint32_t status[2]; - status[0] = REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG); - status[1] = REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG); - for (int i = 0; i < 32; i++) { - switch (status[0] & BIT(i)) { - case EXTMEM_IC_SYNC_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC0_REG); - size = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC1_REG); - panic_print_str("Icache sync parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_IC_PRELOAD_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG); - size = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG); - panic_print_str("Icache preload parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_ICACHE_REJECT_ST: - vaddr = REG_READ(EXTMEM_PRO_ICACHE_REJECT_VADDR_REG); - panic_print_str("Icache reject error occurred while accessing the address 0x"); - panic_print_hex(vaddr); - - if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) { - panic_print_str(" (invalid mmu entry)"); - } - panic_print_str("\r\n"); - break; - default: - break; - } - switch (status[1] & BIT(i)) { - case EXTMEM_DC_SYNC_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC0_REG); - size = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC1_REG); - panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_DC_PRELOAD_SIZE_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG); - size = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG); - panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_DCACHE_WRITE_FLASH_ST: - panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n"); - break; - case EXTMEM_DCACHE_REJECT_ST: - vaddr = REG_READ(EXTMEM_PRO_DCACHE_REJECT_VADDR_REG); - panic_print_str("Dcache reject error occurred while accessing the address 0x"); - panic_print_hex(vaddr); - - if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) { - panic_print_str(" (invalid mmu entry)"); - } - panic_print_str("\r\n"); - break; - case EXTMEM_MMU_ENTRY_FAULT_ST: - vaddr = REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_VADDR_REG); - panic_print_str("MMU entry fault error occurred while accessing the address 0x"); - panic_print_hex(vaddr); - - if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) { - panic_print_str(" (invalid mmu entry)"); - } - panic_print_str("\r\n"); - break; - default: - break; - } - } -} - -#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE +#if CONFIG_IDF_TARGET_ESP32S2 && CONFIG_ESP_SYSTEM_MEMPROT_FEATURE #define MEMPROT_OP_INVALID 0xFFFFFFFF static inline void print_memprot_err_details(const void *f) { @@ -290,75 +200,27 @@ static inline void print_memprot_err_details(const void *f) } #endif -#elif CONFIG_IDF_TARGET_ESP32S3 static inline void print_cache_err_details(const void *f) { - uint32_t vaddr = 0, size = 0; - uint32_t status; - status = REG_READ(EXTMEM_CACHE_ILG_INT_ST_REG); - for (int i = 0; i < 32; i++) { - switch (status & BIT(i)) { - case EXTMEM_ICACHE_SYNC_OP_FAULT_ST: - //TODO, which size should fetch - //vaddr = REG_READ(EXTMEM_ICACHE_MEM_SYNC0_REG); - //size = REG_READ(EXTMEM_ICACHE_MEM_SYNC1_REG); - panic_print_str("Icache sync parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_ICACHE_PRELOAD_OP_FAULT_ST: - //TODO, which size should fetch - vaddr = REG_READ(EXTMEM_ICACHE_PRELOAD_ADDR_REG); - size = REG_READ(EXTMEM_ICACHE_PRELOAD_SIZE_REG); - panic_print_str("Icache preload parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_DCACHE_SYNC_OP_FAULT_ST: - //TODO, which size should fetch - //vaddr = REG_READ(EXTMEM_DCACHE_MEM_SYNC0_REG); - //size = REG_READ(EXTMEM_DCACHE_MEM_SYNC1_REG); - panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_DCACHE_PRELOAD_OP_FAULT_ST: - //TODO, which size should fetch - vaddr = REG_READ(EXTMEM_DCACHE_PRELOAD_ADDR_REG); - size = REG_READ(EXTMEM_DCACHE_PRELOAD_SIZE_REG); - panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x"); - panic_print_hex(vaddr); - panic_print_str("(0x"); - panic_print_hex(size); - panic_print_str(")\r\n"); - break; - case EXTMEM_DCACHE_WRITE_FLASH_ST: - panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n"); - panic_print_str("The following backtrace may not indicate the code that caused Cache invalid access\r\n"); - break; - case EXTMEM_MMU_ENTRY_FAULT_ST: - vaddr = REG_READ(EXTMEM_CACHE_MMU_FAULT_VADDR_REG); - panic_print_str("MMU entry fault error occurred while accessing the address 0x"); - panic_print_hex(vaddr); + esp_cache_err_info_t err = {}; + esp_cache_err_get_panic_info(&err); - if (REG_READ(EXTMEM_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) { - panic_print_str(" (invalid mmu entry)"); - } - panic_print_str("\r\n"); - break; - default: - break; + if (err.err_str) { + panic_print_str(err.err_str); + if (err.vaddr) { + panic_print_str(", error address: 0x"); + panic_print_hex(err.vaddr); } + if (err.size) { + panic_print_str(", error size: 0x"); + panic_print_hex(err.vaddr); + } + } else { + // Default to cache disabled message if no specific error is found + panic_print_str("Cache disabled but cached memory region accessed"); } panic_print_str("\r\n"); } -#endif void panic_arch_fill_info(void *f, panic_info_t *info) { @@ -383,7 +245,6 @@ void panic_arch_fill_info(void *f, panic_info_t *info) } info->description = "Exception was unhandled."; - if (frame->exccause == EXCCAUSE_ILLEGAL) { info->details = print_illegal_instruction_details; } @@ -426,7 +287,7 @@ void panic_soc_fill_info(void *f, panic_info_t *info) "Coprocessor exception", "Interrupt wdt timeout on CPU0", "Interrupt wdt timeout on CPU1", - "Cache disabled but cached memory region accessed", + "Cache error", }; info->reason = pseudo_reason[0]; @@ -442,8 +303,6 @@ void panic_soc_fill_info(void *f, panic_info_t *info) } //MV note: ESP32S3 PMS handling? - -#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 if (frame->exccause == PANIC_RSN_CACHEERR) { #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE && CONFIG_IDF_TARGET_ESP32S2 if (esp_memprot_is_intr_ena_any()) { @@ -455,7 +314,6 @@ void panic_soc_fill_info(void *f, panic_info_t *info) info->details = print_cache_err_details; } } -#endif } uint32_t panic_get_address(const void *f) diff --git a/components/esp_system/port/include/private/esp_private/cache_err_int.h b/components/esp_system/port/include/private/esp_private/cache_err_int.h index 3d911bca5c..369257358c 100644 --- a/components/esp_system/port/include/private/esp_private/cache_err_int.h +++ b/components/esp_system/port/include/private/esp_private/cache_err_int.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,11 +7,21 @@ #pragma once #include +#include #ifdef __cplusplus extern "C" { #endif +/** + * @brief Cache error information + */ +typedef struct { + const char* err_str; /*!< Error message for the current panic */ + uint32_t vaddr; /*!< Virtual address that caused the error */ + uint32_t size; /*!< Size of the access which caused the error */ +} esp_cache_err_info_t; + /** * @brief initialize cache invalid access interrupt * @@ -34,11 +44,11 @@ void esp_cache_err_int_init(void); int esp_cache_err_get_cpuid(void); /** - * @brief Returns a pointer to the cache error message + * @brief Get error info for the current cache exception * - * @return const char* Pointer to the error message + * @err_info struct containing the information of the current error */ -const char *esp_cache_err_panic_string(void); +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info); /** * @brief Checks if any cache errors are active diff --git a/components/esp_system/port/soc/esp32/cache_err_int.c b/components/esp_system/port/soc/esp32/cache_err_int.c index 491d122b9a..61d0e9d36e 100644 --- a/components/esp_system/port/soc/esp32/cache_err_int.c +++ b/components/esp_system/port/soc/esp32/cache_err_int.c @@ -26,6 +26,15 @@ #include "esp_rom_sys.h" #include "sdkconfig.h" +#include "esp_private/cache_err_int.h" + +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) +{ + if (err_info == NULL) { + return; + } + (void)err_info; +} void esp_cache_err_int_init(void) { diff --git a/components/esp_system/port/soc/esp32c2/cache_err_int.c b/components/esp_system/port/soc/esp32c2/cache_err_int.c index ff2a431269..3807aa12eb 100644 --- a/components/esp_system/port/soc/esp32c2/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c2/cache_err_int.c @@ -17,6 +17,7 @@ #include "soc/periph_defs.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; @@ -106,25 +107,26 @@ static inline const char* test_and_print_register_bits(const uint32_t status, return NULL; } -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } /* Read the status register EXTMEM_CORE0_ACS_CACHE_INT_ST_REG. This status - * register is not equal to 0 when a cache access error occured. */ + * register is not equal to 0 when a cache access error occurred. */ const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* If the panic is due to a cache access error, one of the bit of the * register is set. Thus, this function will return an error string. */ - const char* err_str = test_and_print_register_bits(access_err_status, core0_acs_bits, DIM(core0_acs_bits)); + err_info->err_str = test_and_print_register_bits(access_err_status, core0_acs_bits, DIM(core0_acs_bits)); /* If the panic was due to a cache illegal error, the previous call returned NULL and this * EXTMEM_CACHE_ILG_INT_ST_REG register should not be equal to 0. * Check each bit of it and print the message associated if found. */ - if (err_str == NULL) { + if (err_info->err_str == NULL) { const uint32_t cache_ilg_status = cache_ll_l1_get_illegal_error_intr_status(0, CACHE_LL_L1_ILG_EVENT_MASK); - err_str = test_and_print_register_bits(cache_ilg_status, cache_ilg_bits, DIM(cache_ilg_bits)); + err_info->err_str = test_and_print_register_bits(cache_ilg_status, cache_ilg_bits, DIM(cache_ilg_bits)); } - - return err_str; } bool esp_cache_err_has_active_err(void) @@ -169,7 +171,7 @@ void esp_cache_err_int_init(void) esprv_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); - /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + /* On the hardware side, start by clearing all the bits responsible for cache access error */ cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Then enable cache access error interrupts. */ cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); diff --git a/components/esp_system/port/soc/esp32c3/cache_err_int.c b/components/esp_system/port/soc/esp32c3/cache_err_int.c index dce1427e4f..8f9d2765da 100644 --- a/components/esp_system/port/soc/esp32c3/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c3/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,6 +17,7 @@ #include "soc/periph_defs.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; @@ -106,25 +107,26 @@ static inline const char* test_and_print_register_bits(const uint32_t status, return NULL; } -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } /* Read the status register EXTMEM_CORE0_ACS_CACHE_INT_ST_REG. This status - * register is not equal to 0 when a cache access error occured. */ + * register is not equal to 0 when a cache access error occurred. */ const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* If the panic is due to a cache access error, one of the bit of the * register is set. Thus, this function will return an error string. */ - const char* err_str = test_and_print_register_bits(access_err_status, core0_acs_bits, DIM(core0_acs_bits)); + err_info->err_str = test_and_print_register_bits(access_err_status, core0_acs_bits, DIM(core0_acs_bits)); /* If the panic was due to a cache illegal error, the previous call returned NULL and this * EXTMEM_CACHE_ILG_INT_ST_REG register should not be equal to 0. * Check each bit of it and return the message associated if found. */ - if (err_str == NULL) { + if (err_info->err_str == NULL) { const uint32_t cache_ilg_status = cache_ll_l1_get_illegal_error_intr_status(0, CACHE_LL_L1_ILG_EVENT_MASK); - err_str = test_and_print_register_bits(cache_ilg_status, cache_ilg_bits, DIM(cache_ilg_bits)); + err_info->err_str = test_and_print_register_bits(cache_ilg_status, cache_ilg_bits, DIM(cache_ilg_bits)); } - - return err_str; } bool esp_cache_err_has_active_err(void) @@ -169,7 +171,7 @@ void esp_cache_err_int_init(void) esprv_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); - /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + /* On the hardware side, start by clearing all the bits responsible for cache access error */ cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Then enable cache access error interrupts. */ cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); diff --git a/components/esp_system/port/soc/esp32c5/cache_err_int.c b/components/esp_system/port/soc/esp32c5/cache_err_int.c index 0a86015545..d4c1cae619 100644 --- a/components/esp_system/port/soc/esp32c5/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c5/cache_err_int.c @@ -18,19 +18,21 @@ #include "soc/soc.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; const char cache_error_msg[] = "Cache access error"; -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Return the error string if a cache error is active */ - const char* err_str = access_err_status ? cache_error_msg : NULL; - - return err_str; + err_info->err_str = access_err_status ? cache_error_msg : NULL; } bool esp_cache_err_has_active_err(void) diff --git a/components/esp_system/port/soc/esp32c6/cache_err_int.c b/components/esp_system/port/soc/esp32c6/cache_err_int.c index c272b217f9..9034f72ed9 100644 --- a/components/esp_system/port/soc/esp32c6/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c6/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,19 +17,21 @@ #include "soc/periph_defs.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; const char cache_error_msg[] = "Cache access error"; -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Return the error string if a cache error is active */ - const char* err_str = access_err_status ? cache_error_msg : NULL; - - return err_str; + err_info->err_str = access_err_status ? cache_error_msg : NULL; } bool esp_cache_err_has_active_err(void) @@ -60,7 +62,7 @@ void esp_cache_err_int_init(void) esprv_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); - /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + /* On the hardware side, start by clearing all the bits responsible for cache access error */ cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Then enable cache access error interrupts. */ cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); diff --git a/components/esp_system/port/soc/esp32c61/cache_err_int.c b/components/esp_system/port/soc/esp32c61/cache_err_int.c index e17c32f49d..141b52382d 100644 --- a/components/esp_system/port/soc/esp32c61/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c61/cache_err_int.c @@ -17,19 +17,21 @@ #include "soc/periph_defs.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; const char cache_error_msg[] = "Cache access error"; -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Return the error string if a cache error is active */ - const char* err_str = access_err_status ? cache_error_msg : NULL; - - return err_str; + err_info->err_str = access_err_status ? cache_error_msg : NULL; } bool esp_cache_err_has_active_err(void) diff --git a/components/esp_system/port/soc/esp32h2/cache_err_int.c b/components/esp_system/port/soc/esp32h2/cache_err_int.c index 770b411948..bad10facb9 100644 --- a/components/esp_system/port/soc/esp32h2/cache_err_int.c +++ b/components/esp_system/port/soc/esp32h2/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -17,19 +17,21 @@ #include "soc/periph_defs.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; const char cache_error_msg[] = "Cache access error"; -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } const uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Return the error string if a cache error is active */ - const char* err_str = access_err_status ? cache_error_msg : NULL; - - return err_str; + err_info->err_str = access_err_status ? cache_error_msg : NULL; } bool esp_cache_err_has_active_err(void) @@ -60,7 +62,7 @@ void esp_cache_err_int_init(void) esprv_int_set_priority(ETS_CACHEERR_INUM, SOC_INTERRUPT_LEVEL_MEDIUM); ESP_DRAM_LOGV(TAG, "access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); - /* On the hardware side, start by clearing all the bits reponsible for cache access error */ + /* On the hardware side, start by clearing all the bits responsible for cache access error */ cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); /* Then enable cache access error interrupts. */ cache_ll_l1_enable_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); diff --git a/components/esp_system/port/soc/esp32p4/cache_err_int.c b/components/esp_system/port/soc/esp32p4/cache_err_int.c index 24904c2d5a..86e5b8da07 100644 --- a/components/esp_system/port/soc/esp32p4/cache_err_int.c +++ b/components/esp_system/port/soc/esp32p4/cache_err_int.c @@ -17,19 +17,22 @@ #include "soc/periph_defs.h" #include "riscv/interrupt.h" #include "hal/cache_ll.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; const char cache_error_msg[] = "Cache access error"; -const char *esp_cache_err_panic_string(void) +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) { + if (err_info == NULL) { + return; + } uint32_t access_err_status = cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK) | cache_ll_l2_get_access_error_intr_status(0, CACHE_LL_L2_ACCESS_EVENT_MASK); /* Return the error string if a cache error is active */ - const char* err_str = access_err_status ? cache_error_msg : NULL; + err_info->err_str = access_err_status ? cache_error_msg : NULL; - return err_str; } bool esp_cache_err_has_active_err(void) diff --git a/components/esp_system/port/soc/esp32s2/cache_err_int.c b/components/esp_system/port/soc/esp32s2/cache_err_int.c index 0c969d79bc..424fb49130 100644 --- a/components/esp_system/port/soc/esp32s2/cache_err_int.c +++ b/components/esp_system/port/soc/esp32s2/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,10 +25,133 @@ #include "soc/extmem_reg.h" #include "soc/dport_reg.h" #include "soc/periph_defs.h" +#include "hal/cache_ll.h" #include "esp_rom_sys.h" #include "sdkconfig.h" +#include "esp_private/cache_err_int.h" + +#define DIM(array) (sizeof(array)/sizeof(*array)) + +/** + * Structure used to define a flag/bit to test in case of cache error. + * The message describes the cause of the error when the bit is set in + * a given status register. + */ +typedef struct { + const uint32_t bit; + const char *msg; + const uint32_t fault_addr_reg; + const uint32_t fault_size_reg; +} register_bit_t; + +/* Define the array that contains the status (bits) to test on the register + * EXTMEM_CACHE_DBG_STATUS0_REG. each bit is accompanied by a small + * message. + * The messages have been pulled from the header file where the status bit + * are defined. +*/ +const register_bit_t dbg_status0_bits[] = { + { + .bit = EXTMEM_IC_SYNC_SIZE_FAULT_ST, + .msg = "Icache sync parameter configuration error", + .fault_addr_reg = EXTMEM_PRO_ICACHE_MEM_SYNC0_REG, + .fault_size_reg = EXTMEM_PRO_ICACHE_MEM_SYNC1_REG, + }, + { + .bit = EXTMEM_IC_PRELOAD_SIZE_FAULT_ST, + .msg = "Icache preload parameter configuration error", + .fault_addr_reg = EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG, + .fault_size_reg = EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG, + }, + { + .bit = EXTMEM_ICACHE_REJECT_ST, + .msg = "Icache reject error", + .fault_addr_reg = EXTMEM_PRO_ICACHE_REJECT_VADDR_REG, + .fault_size_reg = 0, + }, +}; + +/* Define the array that contains the status (bits) to test on the register + * EXTMEM_CACHE_DBG_STATUS1_REG. each bit is accompanied by a small + * message. + * The messages have been pulled from the header file where the status bit + * are defined. */ +const register_bit_t dbg_status1_bits[] = { + { + .bit = EXTMEM_DC_SYNC_SIZE_FAULT_ST, + .msg = "Dcache sync parameter configuration error", + .fault_addr_reg = EXTMEM_PRO_DCACHE_MEM_SYNC0_REG, + .fault_size_reg = EXTMEM_PRO_DCACHE_MEM_SYNC1_REG, + }, + { + .bit = EXTMEM_DC_PRELOAD_SIZE_FAULT_ST, + .msg = "Dcache preload parameter configuration error", + .fault_addr_reg = EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG, + .fault_size_reg = EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG, + }, + { + .bit = EXTMEM_DCACHE_REJECT_ST, + .msg = "Dcache reject error", + .fault_addr_reg = EXTMEM_PRO_DCACHE_REJECT_VADDR_REG, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_DCACHE_WRITE_FLASH_ST, + .msg = "Write back error occurred while dcache tries to write back to flash", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_MMU_ENTRY_FAULT_ST, + .msg = "MMU entry fault error", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, +}; +/** + * Function to check each bits defined in the array reg_bits in the given + * status register. The first bit from the array to be set in the status + * register will have its associated message printed. This function returns + * true. If not bit was set in the register, it returns false. + * The order of the bits in the array is important as only the first bit to + * be set in the register will have its associated message printed. + */ +static inline void get_cache_error(const uint32_t status, const register_bit_t *reg_bits, + const uint32_t size, esp_cache_err_info_t *err_info) +{ + /* Browse the flag/bit array and test each one with the given status + * register. */ + for (int i = 0; i < size; i++) { + const uint32_t bit = reg_bits[i].bit; + if ((status & bit) == bit) { + /* Reason of the panic found, print the reason. */ + err_info->err_str = reg_bits[i].msg; + err_info->vaddr = reg_bits[i].fault_addr_reg ? REG_READ(reg_bits[i].fault_addr_reg) : 0; + err_info->size = reg_bits[i].fault_size_reg ? REG_READ(reg_bits[i].fault_size_reg) : 0; + + return; + } + } +} + +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) +{ + if (err_info == NULL) { + return; + } + /* Read the status register EXTMEM_CACHE_ILG_INT_ST_REG. This status + * register is not equal to 0 when a cache access error occurred. */ + const uint32_t dbg_status0 = cache_ll_get_dbg_status0(); + const uint32_t dbg_status1 = cache_ll_get_dbg_status1(); + + get_cache_error(dbg_status0, dbg_status0_bits, DIM(dbg_status0_bits), err_info); + + if (err_info->err_str == NULL) { + get_cache_error(dbg_status1, dbg_status1_bits, DIM(dbg_status1_bits), err_info); + } +} void esp_cache_err_int_init(void) { diff --git a/components/esp_system/port/soc/esp32s3/cache_err_int.c b/components/esp_system/port/soc/esp32s3/cache_err_int.c index d87d1ea367..9e6499b86a 100644 --- a/components/esp_system/port/soc/esp32s3/cache_err_int.c +++ b/components/esp_system/port/soc/esp32s3/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,9 +23,109 @@ #include "soc/periph_defs.h" #include "esp_rom_sys.h" #include "hal/cache_ll.h" +#include "soc/syscon_struct.h" +#include "esp_private/cache_err_int.h" static const char *TAG = "CACHE_ERR"; +#define DIM(array) (sizeof(array)/sizeof(*array)) + +/** + * Structure used to define a flag/bit to test in case of cache error. + * The message describes the cause of the error when the bit is set in + * a given status register. + */ +typedef struct { + const uint32_t bit; + const char *msg; + const uint32_t fault_addr_reg; + const uint32_t fault_size_reg; +} register_bit_t; + +/* Define the array that contains the status (bits) to test on the register + * EXTMEM_CACHE_ILG_INT_ST_REG. each bit is accompanied by a small + * message. + * The messages have been pulled from the header file where the status bit + * are defined. +*/ +const register_bit_t ilg_int_st_bits[] = { + { + .bit = EXTMEM_ICACHE_SYNC_OP_FAULT_ST, + .msg = "Icache sync parameter configuration error", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_ICACHE_PRELOAD_OP_FAULT_ST, + .msg = "Icache preload parameter configuration error", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_DCACHE_SYNC_OP_FAULT_ST, + .msg = "Dcache sync parameter configuration error", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_DCACHE_PRELOAD_OP_FAULT_ST, + .msg = "Dcache preload parameter configuration error", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_DCACHE_WRITE_FLASH_ST, + .msg = "Write back error occurred while dcache tries to write back to flash\r\nThe following backtrace may not indicate the code that caused Cache invalid access", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, + { + .bit = EXTMEM_MMU_ENTRY_FAULT_ST, + .msg = "MMU entry fault error", + .fault_addr_reg = 0, + .fault_size_reg = 0, + }, +}; + +/** + * Function to check each bits defined in the array reg_bits in the given + * status register. The first bit from the array to be set in the status + * register will have its associated message printed. This function returns + * true. If not bit was set in the register, it returns false. + * The order of the bits in the array is important as only the first bit to + * be set in the register will have its associated message printed. + */ +static inline void get_cache_error(const uint32_t status, const register_bit_t *reg_bits, + const uint32_t size, esp_cache_err_info_t *err_info) +{ + /* Browse the flag/bit array and test each one with the given status + * register. */ + for (int i = 0; i < size; i++) { + const uint32_t bit = reg_bits[i].bit; + if ((status & bit) == bit) { + /* Reason of the panic found, print the reason. */ + err_info->err_str = reg_bits[i].msg; + err_info->vaddr = reg_bits[i].fault_addr_reg ? REG_READ(reg_bits[i].fault_addr_reg) : 0; + err_info->size = reg_bits[i].fault_size_reg ? REG_READ(reg_bits[i].fault_size_reg) : 0; + + return; + } + } +} + +void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info) +{ + if (err_info == NULL) { + return; + } + /* Read the status register EXTMEM_CACHE_ILG_INT_ST_REG. This status + * register is not equal to 0 when a cache access error occurred. */ + const uint32_t illegal_intr_status = cache_ll_l1_get_illegal_error_intr_status(0, CACHE_LL_L1_ILG_EVENT_MASK); + + get_cache_error(illegal_intr_status, ilg_int_st_bits, DIM(ilg_int_st_bits), err_info); + +} + void esp_cache_err_int_init(void) { uint32_t core_id = esp_cpu_get_core_id(); @@ -52,7 +152,7 @@ void esp_cache_err_int_init(void) if (core_id == PRO_CPU_NUM) { esp_rom_route_intr_matrix(core_id, ETS_CACHE_CORE0_ACS_INTR_SOURCE, ETS_CACHEERR_INUM); - /* On the hardware side, stat by clearing all the bits reponsible for + /* On the hardware side, stat by clearing all the bits responsible for * enabling cache access error interrupts. */ ESP_DRAM_LOGV(TAG, "core 0 access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); @@ -60,7 +160,7 @@ void esp_cache_err_int_init(void) } else { esp_rom_route_intr_matrix(core_id, ETS_CACHE_CORE1_ACS_INTR_SOURCE, ETS_CACHEERR_INUM); - /* On the hardware side, stat by clearing all the bits reponsible for + /* On the hardware side, stat by clearing all the bits responsible for * enabling cache access error interrupts. */ ESP_DRAM_LOGV(TAG, "core 1 access error intr clr & ena mask is: 0x%x", CACHE_LL_L1_ACCESS_EVENT_MASK); cache_ll_l1_clear_access_error_intr(1, CACHE_LL_L1_ACCESS_EVENT_MASK); diff --git a/components/esp_system/test_apps/cache_panic/main/test_cache_disabled.c b/components/esp_system/test_apps/cache_panic/main/test_cache_disabled.c index 6dfc11af78..a95ae8369a 100644 --- a/components/esp_system/test_apps/cache_panic/main/test_cache_disabled.c +++ b/components/esp_system/test_apps/cache_panic/main/test_cache_disabled.c @@ -96,7 +96,7 @@ static void IRAM_ATTR cache_access_test_func(void* arg) #endif // These tests works properly if they resets the chip with the -// "Cache disabled but cached memory region accessed" reason and the correct CPU is logged. +// "Cache Error" reason and the correct CPU is logged. static void invalid_access_to_cache_pro_cpu(void) { xTaskCreatePinnedToCore(&cache_access_test_func, "ia", 2048, NULL, 5, NULL, 0); diff --git a/components/hal/esp32s2/include/hal/cache_ll.h b/components/hal/esp32s2/include/hal/cache_ll.h index 0a2ecbde7a..16f7a7fe90 100644 --- a/components/hal/esp32s2/include/hal/cache_ll.h +++ b/components/hal/esp32s2/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -551,6 +551,26 @@ static inline bool cache_ll_vaddr_to_cache_level_id(uint32_t vaddr_start, uint32 return valid; } +/** + * @brief Get cache debug status 0 + * + */ +__attribute__((always_inline)) +static inline uint32_t cache_ll_get_dbg_status0(void) +{ + return REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG); +} + +/** + * @brief Get cache debug status 1 + * + */ +__attribute__((always_inline)) +static inline uint32_t cache_ll_get_dbg_status1(void) +{ + return REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/cache_ll.h b/components/hal/esp32s3/include/hal/cache_ll.h index 215473731e..9ab5b7f5ff 100644 --- a/components/hal/esp32s3/include/hal/cache_ll.h +++ b/components/hal/esp32s3/include/hal/cache_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ diff --git a/docs/en/api-guides/fatal-errors.rst b/docs/en/api-guides/fatal-errors.rst index e138ca432a..49228163a8 100644 --- a/docs/en/api-guides/fatal-errors.rst +++ b/docs/en/api-guides/fatal-errors.rst @@ -532,7 +532,7 @@ The backtrace should point to the function where stack smashing has occurred. Ch .. |CPU_EXCEPTIONS_LIST| replace:: Illegal Instruction, Load/Store Alignment Error, Load/Store Prohibited error, Double Exception. .. |ILLEGAL_INSTR_MSG| replace:: IllegalInstruction - .. |CACHE_ERR_MSG| replace:: Cache disabled but cached memory region accessed + .. |CACHE_ERR_MSG| replace:: Cache error .. |STACK_OVERFLOW| replace:: Stack overflow .. only:: CONFIG_IDF_TARGET_ARCH_RISCV diff --git a/docs/zh_CN/api-guides/fatal-errors.rst b/docs/zh_CN/api-guides/fatal-errors.rst index 91491e5b3f..7cab6e65df 100644 --- a/docs/zh_CN/api-guides/fatal-errors.rst +++ b/docs/zh_CN/api-guides/fatal-errors.rst @@ -532,7 +532,7 @@ FreeRTOS 堆栈检查 .. |CPU_EXCEPTIONS_LIST| replace:: 非法指令,加载/存储时的内存对齐错误,加载/存储时的访问权限错误,双重异常。 .. |ILLEGAL_INSTR_MSG| replace:: IllegalInstruction - .. |CACHE_ERR_MSG| replace:: Cache disabled but cached memory region accessed + .. |CACHE_ERR_MSG| replace:: Cache error .. |STACK_OVERFLOW| replace:: 堆栈溢出 .. only:: CONFIG_IDF_TARGET_ARCH_RISCV diff --git a/tools/test_apps/system/panic/pytest_panic.py b/tools/test_apps/system/panic/pytest_panic.py index d0c093e357..4f522488e0 100644 --- a/tools/test_apps/system/panic/pytest_panic.py +++ b/tools/test_apps/system/panic/pytest_panic.py @@ -309,7 +309,8 @@ def test_cache_error(dut: PanicTestDut, config: str, test_func_name: str) -> Non # Cache error interrupt is not enabled, IDF-1558 dut.expect_gme('IllegalInstruction') elif dut.target in ['esp32', 'esp32s3']: - dut.expect_gme('Cache disabled but cached memory region accessed') + dut.expect_gme('Cache error') + dut.expect_exact('Cache disabled but cached memory region accessed') else: dut.expect_gme('Cache error') dut.expect_exact('Cache access error') @@ -572,7 +573,7 @@ def test_assert_cache_disabled( def cache_error_log_check(dut: PanicTestDut) -> None: if dut.is_xtensa: if dut.target == 'esp32s3': - dut.expect_exact("Guru Meditation Error: Core / panic'ed (Cache disabled but cached memory region accessed)") + dut.expect_exact("Guru Meditation Error: Core / panic'ed (Cache error)") dut.expect_exact('Write back error occurred while dcache tries to write back to flash') dut.expect_exact('The following backtrace may not indicate the code that caused Cache invalid access') else: