Merge branch 'refactor/cache_err_panic' into 'master'

refactor(panic): refactor and unify cache panic errors

See merge request espressif/esp-idf!34382
This commit is contained in:
Marius Vikhammer
2024-11-13 10:19:38 +08:00
19 changed files with 354 additions and 216 deletions

View File

@@ -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");
}

View File

@@ -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)

View File

@@ -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 <stdbool.h>
#include <stdint.h>
#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

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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: