mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-09 20:41:14 +00:00
add detection of invalid cache access
- fix level 4 interrupt vectors to produce correct backtrace - initialize invalid cache access interrupt on startup - handle invalid cache access in panic handler
This commit is contained in:

committed by
Ivan Grokhotkov

parent
3c6c1e36ec
commit
0b79d07d34
@@ -16,6 +16,7 @@
|
||||
#include <xtensa/config/core.h>
|
||||
|
||||
#include "rom/rtc.h"
|
||||
#include "rom/uart.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -28,6 +29,7 @@
|
||||
#include "soc/timer_group_struct.h"
|
||||
#include "soc/timer_group_reg.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
|
||||
#include "esp_gdbstub.h"
|
||||
#include "esp_panic.h"
|
||||
@@ -35,6 +37,7 @@
|
||||
#include "esp_err.h"
|
||||
#include "esp_core_dump.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_cache_err_int.h"
|
||||
|
||||
/*
|
||||
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
|
||||
@@ -120,7 +123,7 @@ static __attribute__((noreturn)) inline void invoke_abort()
|
||||
void abort()
|
||||
{
|
||||
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
|
||||
ets_printf("abort() was called at PC 0x%08x on core %d\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID());
|
||||
#endif
|
||||
invoke_abort();
|
||||
}
|
||||
@@ -149,9 +152,23 @@ static void haltOtherCore()
|
||||
esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
|
||||
}
|
||||
|
||||
|
||||
static void setFirstBreakpoint(uint32_t pc)
|
||||
{
|
||||
asm(
|
||||
"wsr.ibreaka0 %0\n" \
|
||||
"rsr.ibreakenable a3\n" \
|
||||
"movi a4,1\n" \
|
||||
"or a4, a4, a3\n" \
|
||||
"wsr.ibreakenable a4\n" \
|
||||
::"r"(pc):"a3", "a4");
|
||||
}
|
||||
|
||||
|
||||
void panicHandler(XtExcFrame *frame)
|
||||
{
|
||||
int *regs = (int *)frame;
|
||||
int core_id = xPortGetCoreID();
|
||||
//Please keep in sync with PANIC_RSN_* defines
|
||||
const char *reasons[] = {
|
||||
"Unknown reason",
|
||||
@@ -161,15 +178,21 @@ void panicHandler(XtExcFrame *frame)
|
||||
"Coprocessor exception",
|
||||
"Interrupt wdt timeout on CPU0",
|
||||
"Interrupt wdt timeout on CPU1",
|
||||
"Cache disabled but cached memory region accessed",
|
||||
};
|
||||
const char *reason = reasons[0];
|
||||
//The panic reason is stored in the EXCCAUSE register.
|
||||
if (regs[20] <= PANIC_RSN_MAX) {
|
||||
reason = reasons[regs[20]];
|
||||
}
|
||||
if (frame->exccause == PANIC_RSN_CACHEERR && esp_cache_err_get_cpuid() != core_id) {
|
||||
// Cache error interrupt will be handled by the panic handler
|
||||
// on the other CPU.
|
||||
return;
|
||||
}
|
||||
haltOtherCore();
|
||||
panicPutStr("Guru Meditation Error: Core ");
|
||||
panicPutDec(xPortGetCoreID());
|
||||
panicPutDec(core_id);
|
||||
panicPutStr(" panic'ed (");
|
||||
if (!abort_called) {
|
||||
panicPutStr(reason);
|
||||
@@ -204,22 +227,12 @@ void panicHandler(XtExcFrame *frame)
|
||||
}
|
||||
|
||||
if (esp_cpu_in_ocd_debug_mode()) {
|
||||
asm("break.n 1");
|
||||
setFirstBreakpoint(regs[1]);
|
||||
return;
|
||||
}
|
||||
commonErrorHandler(frame);
|
||||
}
|
||||
|
||||
static void setFirstBreakpoint(uint32_t pc)
|
||||
{
|
||||
asm(
|
||||
"wsr.ibreaka0 %0\n" \
|
||||
"rsr.ibreakenable a3\n" \
|
||||
"movi a4,1\n" \
|
||||
"or a4, a4, a3\n" \
|
||||
"wsr.ibreakenable a4\n" \
|
||||
::"r"(pc):"a3", "a4");
|
||||
}
|
||||
|
||||
void xt_unhandled_exception(XtExcFrame *frame)
|
||||
{
|
||||
int *regs = (int *)frame;
|
||||
@@ -315,6 +328,22 @@ void esp_panic_wdt_stop()
|
||||
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
|
||||
}
|
||||
|
||||
static void esp_panic_dig_reset() __attribute__((noreturn));
|
||||
|
||||
static void esp_panic_dig_reset()
|
||||
{
|
||||
// make sure all the panic handler output is sent from UART FIFO
|
||||
uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
|
||||
// switch to XTAL (otherwise we will keep running from the PLL)
|
||||
rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
|
||||
// reset the digital part
|
||||
esp_cpu_unstall(PRO_CPU_NUM);
|
||||
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
|
||||
while (true) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool stackPointerIsSane(uint32_t sp)
|
||||
{
|
||||
return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
|
||||
@@ -416,7 +445,12 @@ static void commonErrorHandler(XtExcFrame *frame)
|
||||
esp_panic_wdt_stop();
|
||||
#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
panicPutStr("Rebooting...\r\n");
|
||||
esp_restart_noos();
|
||||
if (frame->exccause != PANIC_RSN_CACHEERR) {
|
||||
esp_restart_noos();
|
||||
} else {
|
||||
// The only way to clear invalid cache access interrupt is to reset the digital part
|
||||
esp_panic_dig_reset();
|
||||
}
|
||||
#else
|
||||
disableAllWdts();
|
||||
panicPutStr("CPU halted.\r\n");
|
||||
|
Reference in New Issue
Block a user