esp_system: support riscv panic

This commit is contained in:
Renz Bagaporo 2020-10-08 13:18:16 +08:00 committed by Angus Gratton
parent 420aef1ffe
commit 4cc6b5571b
32 changed files with 803 additions and 570 deletions

View File

@ -5,7 +5,7 @@ COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := private_include port/include
COMPONENT_ADD_LDFRAGMENTS += linker.lf
-include $(COMPONENT_PATH)/port/$(SOC_NAME)/component.mk
include $(COMPONENT_PATH)/port/soc/$(SOC_NAME)/component.mk
# disable stack protection in files which are involved in initialization of that feature
startup.o: CFLAGS := $(filter-out -fstack-protector%, $(CFLAGS))

View File

@ -16,14 +16,20 @@
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
extern bool g_panic_abort;
extern void *g_exc_frames[SOC_CPU_CORES_NUM];
// Function to print longer amounts of information such as the details
// and backtrace field of panic_info_t. These functions should limit themselves
// to printing to the console and should do other more involved processing,
@ -72,6 +78,20 @@ void panic_print_hex(int h);
void __attribute__((noreturn)) panic_abort(const char *details);
void panic_arch_fill_info(void *frame, panic_info_t *info);
void panic_soc_fill_info(void *frame, panic_info_t *info);
void panic_print_registers(const void *frame, int core);
void panic_print_backtrace(const void *frame, int core);
uint32_t panic_get_address(const void* frame);
void panic_set_address(void *frame, uint32_t addr);
uint32_t panic_get_cause(const void* frame);
#ifdef __cplusplus
}
#endif

View File

@ -3,6 +3,7 @@ archive: libesp_system.a
entries:
panic (noflash)
panic_handler (noflash)
panic_arch (noflash)
reset_reason (noflash)
system_api:esp_system_abort (noflash)
startup:do_core_init (default)

View File

@ -46,11 +46,26 @@
#include "sdkconfig.h"
#if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
#include "esp_private/gdbstub.h"
#endif
#if CONFIG_ESP32_ENABLE_COREDUMP
#include "esp_core_dump.h"
#endif
#if CONFIG_APPTRACE_ENABLE
#include "esp_app_trace.h"
#if CONFIG_SYSVIEW_ENABLE
#include "SEGGER_RTT.h"
#endif
#if CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1
#define APPTRACE_ONPANIC_HOST_FLUSH_TMO ESP_APPTRACE_TMO_INFINITE
#else
#define APPTRACE_ONPANIC_HOST_FLUSH_TMO (1000*CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO)
#endif
#endif // CONFIG_APPTRACE_ENABLE
#if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
#include "esp_private/gdbstub.h"

View File

@ -1,10 +1,9 @@
target_include_directories(${COMPONENT_LIB} PRIVATE include)
set(srcs "cpu_start.c")
set(srcs "cpu_start.c" "panic_handler.c")
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs})
target_sources(${COMPONENT_LIB} PRIVATE ${srcs})
idf_build_get_property(target IDF_TARGET)
add_subdirectory(${target})
add_subdirectory(soc/${target})

View File

@ -0,0 +1,127 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include "esp_private/panic_internal.h"
#include "riscv/rvruntime-frames.h"
extern void esp_panic_handler(panic_info_t *);
void panic_print_registers(const void *f, int core)
{
uint32_t *regs = (uint32_t *)f;
// only print ABI name
const char *desc[] = {
"MEPC ", "RA ", "SP ", "GP ", "TP ", "T0 ", "T1 ", "T2 ",
"S0/FP ", "S1 ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
"A6 ", "A7 ", "S2 ", "S3 ", "S4 ", "S5 ", "S6 ", "S7 ",
"S8 ", "S9 ", "S10 ", "S11 ", "T3 ", "T4 ", "T5 ", "T6 ",
"MSTATUS ", "MTVEC ", "MCAUSE ", "MTVAL ", "MHARTID "
};
panic_print_str("Core ");
panic_print_dec(((RvExcFrame *)f)->mhartid);
panic_print_str(" register dump:");
for (int x = 0; x < sizeof(desc) / sizeof(desc[0]); x += 4) {
panic_print_str("\r\n");
for (int y = 0; y < 4 && x + y < sizeof(desc) / sizeof(desc[0]); y++) {
if (desc[x + y][0] != 0) {
panic_print_str(desc[x + y]);
panic_print_str(": 0x");
panic_print_hex(regs[x + y]);
panic_print_str(" ");
}
}
}
}
void panic_soc_fill_info(void *f, panic_info_t *info)
{
// TODO ESP32-C3 IDF-2386 / support soc panic
return;
}
void panic_arch_fill_info(void *frame, panic_info_t *info)
{
RvExcFrame *regs = (RvExcFrame *) frame;
info->core = 0;
info->exception = PANIC_EXCEPTION_FAULT;
//Please keep in sync with PANIC_RSN_* defines
static const char *reason[] = {
"Instruction address misaligned",
"Instruction access fault",
"Illegal instruction",
"Breakpoint",
"Load address misaligned",
"Load access fault",
"Store address misaligned",
"Store access fault",
"Environment call from U-mode",
"Environment call from S-mode",
NULL,
"Environment call from M-mode",
"Instruction page fault",
"Load page fault",
NULL,
"Store page fault",
};
if (regs->mcause < (sizeof(reason) / sizeof(reason[0]))) {
if (reason[regs->mcause] != NULL) {
info->reason = (reason[regs->mcause]);
}
}
info->description = "Exception was unhandled.";
info->addr = (void *) regs->mepc;
info->frame = &regs;
}
void panic_print_backtrace(const void *frame, int core)
{
// Basic backtrace
panic_print_str("\r\nStack memory:\n");
uint32_t sp = (uint32_t)((RvExcFrame *)frame)->sp;
const int per_line = 8;
for (int x = 0; x < 1024; x += per_line * sizeof(uint32_t)) {
uint32_t *spp = (uint32_t *)(sp + x);
panic_print_hex(sp + x);
panic_print_str(": ");
for (int y = 0; y < per_line; y++) {
panic_print_str("0x");
panic_print_hex(spp[y]);
panic_print_char(y == per_line - 1 ? '\n' : ' ');
}
}
}
uint32_t panic_get_address(const void *f)
{
return ((RvExcFrame *)f)->mepc;
}
uint32_t panic_get_cause(const void *f)
{
return ((RvExcFrame *)f)->mcause;
}
void panic_set_address(void *f, uint32_t addr)
{
((RvExcFrame *)f)->mepc = addr;
}

View File

@ -11,185 +11,38 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include "freertos/xtensa_context.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_spi_flash.h"
#include "esp_private/panic_reason.h"
#include "esp_private/system_internal.h"
#include "esp_debug_helpers.h"
#include "soc/soc_memory_layout.h"
#include "soc/cpu.h"
#include "soc/soc_caps.h"
#include "soc/rtc.h"
#include "hal/soc_hal.h"
#include "hal/cpu_hal.h"
#include "hal/wdt_types.h"
#include "hal/wdt_hal.h"
#include "esp_private/panic_internal.h"
#include "esp_private/panic_reason.h"
#include "soc/soc.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/cache_err_int.h"
#include "esp32/dport_access.h"
#include "esp32/rom/uart.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/cache_err_int.h"
#include "esp32s2/rom/uart.h"
#include "esp32s2/memprot.h"
#else
#include "soc/extmem_reg.h"
#include "soc/cache_memory.h"
#include "soc/rtc_cntl_reg.h"
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/cache_err_int.h"
#include "esp32s2/memprot.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/cache_err_int.h"
#include "esp32s3/rom/uart.h"
#include "esp32s3/memprot.h"
#include "soc/extmem_reg.h"
#include "soc/cache_memory.h"
#include "soc/rtc_cntl_reg.h"
#endif
#endif // CONFIG_IDF_TARGET_ESP32
#include "esp_private/panic_internal.h"
extern int _invalid_pc_placeholder;
extern void esp_panic_handler(panic_info_t*);
static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
static XtExcFrame *xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
/*
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
task switching / interrupt code runs into an unrecoverable error. The default task stack
overflow handler and abort handler are also in here.
*/
/*
Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
*/
static void print_illegal_instruction_details(const void *f)
{
XtExcFrame *frame = (XtExcFrame *) f;
/* Print out memory around the instruction word */
uint32_t epc = frame->pc;
epc = (epc & ~0x3) - 4;
/* check that the address was sane */
if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
return;
}
volatile uint32_t *pepc = (uint32_t *)epc;
panic_print_str("Memory dump at 0x");
panic_print_hex(epc);
panic_print_str(": ");
panic_print_hex(*pepc);
panic_print_str(" ");
panic_print_hex(*(pepc + 1));
panic_print_str(" ");
panic_print_hex(*(pepc + 2));
}
static void print_debug_exception_details(const void *f)
{
int debug_rsn;
asm("rsr.debugcause %0":"=r"(debug_rsn));
panic_print_str("Debug exception reason: ");
if (debug_rsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
panic_print_str("SingleStep ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
panic_print_str("HwBreakpoint ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
//Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
//reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
//debugcause if the cause is watchpoint 1 and clearing it if it's watchpoint 0.
if (debug_rsn & (1 << 8)) {
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
int core = 0;
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
if (f == xt_exc_frames[1]) {
core = 1;
}
#endif
const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core));
panic_print_str("Stack canary watchpoint triggered (");
panic_print_str(name);
panic_print_str(") ");
#else
panic_print_str("Watchpoint 1 triggered ");
#endif
} else {
panic_print_str("Watchpoint 0 triggered ");
}
}
if (debug_rsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
panic_print_str("BREAK instr ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
panic_print_str("BREAKN instr ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
panic_print_str("DebugIntr ");
}
}
static void print_backtrace_entry(uint32_t pc, uint32_t sp)
{
panic_print_str("0x");
panic_print_hex(pc);
panic_print_str(":0x");
panic_print_hex(sp);
}
static void print_backtrace(const void *f, int core)
{
XtExcFrame *frame = (XtExcFrame *) f;
int depth = 100;
//Initialize stk_frame with first frame of stack
esp_backtrace_frame_t stk_frame = {.pc = frame->pc, .sp = frame->a1, .next_pc = frame->a0};
panic_print_str("\r\nBacktrace:");
print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
//Check if first frame is valid
bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) &&
(esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) ||
/* Ignore the first corrupted PC in case of InstrFetchProhibited */
frame->exccause == EXCCAUSE_INSTR_PROHIBITED));
uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed
while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame
corrupted = true;
}
panic_print_str(" ");
print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
}
//Print backtrace termination marker
if (corrupted) {
panic_print_str(" |<-CORRUPTED");
} else if (stk_frame.next_pc != 0) { //Backtrace continues
panic_print_str(" |<-CONTINUES");
}
}
static void print_registers(const void *f, int core)
void panic_print_registers(const void *f, int core)
{
XtExcFrame *frame = (XtExcFrame *) f;
int *regs = (int *)frame;
const char *sdesc[] = {
"PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
"A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
@ -248,37 +101,76 @@ static void print_registers(const void *f, int core)
}
}
static void print_state_for_core(const void *f, int core)
static void print_illegal_instruction_details(const void *f)
{
if (!g_panic_abort) {
print_registers(f, core);
panic_print_str("\r\n");
XtExcFrame *frame = (XtExcFrame *) f;
/* Print out memory around the instruction word */
uint32_t epc = frame->pc;
epc = (epc & ~0x3) - 4;
/* check that the address was sane */
if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
return;
}
print_backtrace(f, core);
volatile uint32_t *pepc = (uint32_t *)epc;
panic_print_str("Memory dump at 0x");
panic_print_hex(epc);
panic_print_str(": ");
panic_print_hex(*pepc);
panic_print_str(" ");
panic_print_hex(*(pepc + 1));
panic_print_str(" ");
panic_print_hex(*(pepc + 2));
}
static void print_state(const void *f)
static void print_debug_exception_details(const void *f)
{
int debug_rsn;
asm("rsr.debugcause %0":"=r"(debug_rsn));
panic_print_str("Debug exception reason: ");
if (debug_rsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
panic_print_str("SingleStep ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
panic_print_str("HwBreakpoint ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
//Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
//reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
//debugcause if the cause is watchpoint 1 and clearing it if it's watchpoint 0.
if (debug_rsn & (1 << 8)) {
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
int core = 0;
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
int err_core = f == xt_exc_frames[0] ? 0 : 1;
#else
int err_core = 0;
if (f == g_exc_frames[1]) {
core = 1;
}
#endif
print_state_for_core(f, err_core);
panic_print_str("\r\n");
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
// If there are other frame info, print them as well
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
// `f` is the frame for the offending core, see note above.
if (err_core != i && xt_exc_frames[i] != NULL) {
print_state_for_core(xt_exc_frames[i], i);
panic_print_str("\r\n");
const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core));
panic_print_str("Stack canary watchpoint triggered (");
panic_print_str(name);
panic_print_str(") ");
#else
panic_print_str("Watchpoint 1 triggered ");
#endif
} else {
panic_print_str("Watchpoint 0 triggered ");
}
}
#endif
if (debug_rsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
panic_print_str("BREAK instr ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
panic_print_str("BREAKN instr ");
}
if (debug_rsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
panic_print_str("DebugIntr ");
}
}
#if CONFIG_IDF_TARGET_ESP32S2
@ -460,194 +352,146 @@ static inline void print_memprot_err_details(const void *f)
}
#endif
static void frame_to_panic_info(XtExcFrame *frame, panic_info_t *info, bool pseudo_excause)
void panic_arch_fill_info(void *f, panic_info_t *info)
{
info->core = cpu_hal_get_core_id();
info->exception = PANIC_EXCEPTION_FAULT;
info->details = NULL;
XtExcFrame *frame = (XtExcFrame*) f;
static const char *reason[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
"Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
"Privileged", "LoadStoreAlignment", "res", "res",
"InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
"InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
"InstrFetchProhibited", "res", "res", "res",
"LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
"LoadProhibited", "StoreProhibited", "res", "res",
"Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
"Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
};
info->pseudo_excause = pseudo_excause;
if (pseudo_excause) {
if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
info->core = 0;
info->exception = PANIC_EXCEPTION_IWDT;
} else if (frame->exccause == PANIC_RSN_INTWDT_CPU1) {
info->core = 1;
info->exception = PANIC_EXCEPTION_IWDT;
} else if (frame->exccause == PANIC_RSN_CACHEERR) {
info->core = esp_cache_err_get_cpuid();
} else {}
//Please keep in sync with PANIC_RSN_* defines
static const char *pseudo_reason[] = {
"Unknown reason",
"Unhandled debug exception",
"Double exception",
"Unhandled kernel exception",
"Coprocessor exception",
"Interrupt wdt timeout on CPU0",
"Interrupt wdt timeout on CPU1",
#if CONFIG_IDF_TARGET_ESP32
"Cache disabled but cached memory region accessed",
#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
"Cache exception",
#endif
};
info->reason = pseudo_reason[0];
info->description = NULL;
if (frame->exccause <= PANIC_RSN_MAX) {
info->reason = pseudo_reason[frame->exccause];
}
if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
info->details = print_debug_exception_details;
info->exception = PANIC_EXCEPTION_DEBUG;
}
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
if (frame->exccause == PANIC_RSN_CACHEERR) {
if ( esp_memprot_get_active_intr_memtype() != MEMPROT_NONE ) {
info->details = print_memprot_err_details;
info->reason = "Memory protection fault";
} else {
info->details = print_cache_err_details;
}
}
#endif
if (frame->exccause < (sizeof(reason) / sizeof(char *))) {
info->reason = (reason[frame->exccause]);
} else {
static const char *reason[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
"Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
"Privileged", "LoadStoreAlignment", "res", "res",
"InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
"InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
"InstrFetchProhibited", "res", "res", "res",
"LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
"LoadProhibited", "StoreProhibited", "res", "res",
"Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
"Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
};
if (frame->exccause < (sizeof(reason) / sizeof(char *))) {
info->reason = (reason[frame->exccause]);
} else {
info->reason = "Unknown";
}
info->description = "Exception was unhandled.";
if (frame->exccause == EXCCAUSE_ILLEGAL) {
info->details = print_illegal_instruction_details;
}
info->reason = "Unknown";
}
info->description = "Exception was unhandled.";
if (frame->exccause == EXCCAUSE_ILLEGAL) {
info->details = print_illegal_instruction_details;
}
info->state = print_state;
info->addr = ((void *) ((XtExcFrame *) frame)->pc);
info->frame = frame;
}
static void panic_handler(XtExcFrame *frame, bool pseudo_excause)
void panic_soc_fill_info(void *f, panic_info_t *info)
{
/*
* Setup environment and perform necessary architecture/chip specific
* steps here prior to the system panic handler.
* */
int core_id = cpu_hal_get_core_id();
// If multiple cores arrive at panic handler, save frames for all of them
xt_exc_frames[core_id] = frame;
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
// These are cases where both CPUs both go into panic handler. The following code ensures
// only one core proceeds to the system panic handler.
if (pseudo_excause) {
#define BUSY_WAIT_IF_TRUE(b) { if (b) while(1); }
// For WDT expiry, pause the non-offending core - offending core handles panic
BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU0 && core_id == 1);
BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU1 && core_id == 0);
// For cache error, pause the non-offending core - offending core handles panic
if (frame->exccause == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid()) {
// Only print the backtrace for the offending core in case of the cache error
xt_exc_frames[core_id] = NULL;
while (1) {
;
}
}
}
esp_rom_delay_us(1);
SOC_HAL_STALL_OTHER_CORES();
#endif
// [refactor-todo] this should be in the common port panic_handler.c, once
// these special exceptions are supported in there.
XtExcFrame *frame = (XtExcFrame*) f;
if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
info->core = 0;
info->exception = PANIC_EXCEPTION_IWDT;
} else if (frame->exccause == PANIC_RSN_INTWDT_CPU1) {
info->core = 1;
info->exception = PANIC_EXCEPTION_IWDT;
} else if (frame->exccause == PANIC_RSN_CACHEERR) {
info->core = esp_cache_err_get_cpuid();
} else {}
//Please keep in sync with PANIC_RSN_* defines
static const char *pseudo_reason[] = {
"Unknown reason",
"Unhandled debug exception",
"Double exception",
"Unhandled kernel exception",
"Coprocessor exception",
"Interrupt wdt timeout on CPU0",
"Interrupt wdt timeout on CPU1",
#if CONFIG_IDF_TARGET_ESP32
esp_dport_access_int_abort();
"Cache disabled but cached memory region accessed",
#elif CONFIG_IDF_TARGET_ESP32S2
"Cache exception",
#endif
};
#if !CONFIG_ESP_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);
panic_print_str("Re-enable cpu cache.\r\n");
}
#endif
info->reason = pseudo_reason[0];
info->description = NULL;
if (esp_cpu_in_ocd_debug_mode()) {
if (!(esp_ptr_executable(cpu_ll_pc_to_ptr(frame->pc)) && (frame->pc & 0xC0000000U))) {
/* Xtensa ABI sets the 2 MSBs of the PC according to the windowed call size
* Incase the PC is invalid, GDB will fail to translate addresses to function names
* Hence replacing the PC to a placeholder address in case of invalid PC
*/
frame->pc = (uint32_t)&_invalid_pc_placeholder;
}
if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
frame->exccause == PANIC_RSN_INTWDT_CPU1) {
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_handle_intr(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
}
if (frame->exccause <= PANIC_RSN_MAX) {
info->reason = pseudo_reason[frame->exccause];
}
// Convert architecture exception frame into abstracted panic info
panic_info_t info;
frame_to_panic_info(frame, &info, pseudo_excause);
// Call the system panic handler
esp_panic_handler(&info);
}
void panicHandler(XtExcFrame *frame)
{
// This panic handler gets called for when the double exception vector,
// kernel exception vector gets used; as well as handling interrupt-based
// faults cache error, wdt expiry. EXCAUSE register gets written with
// one of PANIC_RSN_* values.
panic_handler(frame, true);
}
void xt_unhandled_exception(XtExcFrame *frame)
{
panic_handler(frame, false);
}
void __attribute__((noreturn)) panic_restart(void)
{
bool digital_reset_needed = false;
#ifdef CONFIG_IDF_TARGET_ESP32
// On the ESP32, cache error status can only be cleared by system reset
if (esp_cache_err_get_cpuid() != -1) {
digital_reset_needed = true;
if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
info->details = print_debug_exception_details;
info->exception = PANIC_EXCEPTION_DEBUG;
}
#endif
#if CONFIG_IDF_TARGET_ESP32S2
if (esp_memprot_is_intr_ena_any() || esp_memprot_is_locked_any()) {
digital_reset_needed = true;
if (frame->exccause == PANIC_RSN_CACHEERR) {
if ( esp_memprot_is_intr_ena_any() ) {
info->details = print_memprot_err_details;
info->reason = "Memory protection fault";
} else {
info->details = print_cache_err_details;
}
}
#endif
if (digital_reset_needed) {
esp_restart_noos_dig();
}
esp_restart_noos();
}
static void print_backtrace_entry(uint32_t pc, uint32_t sp)
{
panic_print_str("0x");
panic_print_hex(pc);
panic_print_str(":0x");
panic_print_hex(sp);
}
uint32_t panic_get_address(const void* f)
{
return ((XtExcFrame*)f)->pc;
}
uint32_t panic_get_cause(const void* f)
{
return ((XtExcFrame*)f)->exccause;
}
void panic_set_address(void *f, uint32_t addr)
{
((XtExcFrame*)f)->pc = addr;
}
void panic_print_backtrace(const void *f, int core)
{
// [refactor-todo] once debug helpers have support for both xtensa and riscv, move to
// common panic_handler.c
XtExcFrame *frame = (XtExcFrame *) f;
int depth = 100;
//Initialize stk_frame with first frame of stack
esp_backtrace_frame_t stk_frame = {.pc = frame->pc, .sp = frame->a1, .next_pc = frame->a0};
panic_print_str("\r\nBacktrace:");
print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
//Check if first frame is valid
bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) &&
(esp_ptr_executable((void *)esp_cpu_process_stack_pc(stk_frame.pc)) ||
/* Ignore the first corrupted PC in case of InstrFetchProhibited */
frame->exccause == EXCCAUSE_INSTR_PROHIBITED));
uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed
while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame
corrupted = true;
}
panic_print_str(" ");
print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
}
//Print backtrace termination marker
if (corrupted) {
panic_print_str(" |<-CORRUPTED");
} else if (stk_frame.next_pc != 0) { //Backtrace continues
panic_print_str(" |<-CONTINUES");
}
}

View File

@ -1,2 +0,0 @@
COMPONENT_SRCDIRS += port port/esp32 port/arch/xtensa
COMPONENT_OBJEXCLUDE += port/async_memcpy_impl_gdma.o

View File

@ -0,0 +1,220 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include "esp_spi_flash.h"
#include "esp_private/system_internal.h"
#include "soc/soc_memory_layout.h"
#include "soc/cpu.h"
#include "soc/soc_caps.h"
#include "soc/rtc.h"
#include "hal/soc_hal.h"
#include "hal/cpu_hal.h"
#include "sdkconfig.h"
#include "esp_rom_sys.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/dport_access.h"
#include "esp32/cache_err_int.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/memprot.h"
#include "esp32s2/cache_err_int.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/memprot.h"
#include "esp32s3/cache_err_int.h"
#endif
#include "esp_private/panic_internal.h"
#include "esp_private/panic_reason.h"
#include "hal/wdt_types.h"
#include "hal/wdt_hal.h"
extern int _invalid_pc_placeholder;
extern void esp_panic_handler(panic_info_t*);
static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
void *g_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
/*
Panic handlers; these get called when an unhandled exception occurs or the assembly-level
task switching / interrupt code runs into an unrecoverable error. The default task stack
overflow handler and abort handler are also in here.
*/
/*
Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
*/
static void print_state_for_core(const void *f, int core)
{
if (!g_panic_abort) {
panic_print_registers(f, core);
panic_print_str("\r\n");
}
panic_print_backtrace(f, core);
}
static void print_state(const void *f)
{
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
int err_core = f == g_exc_frames[0] ? 0 : 1;
#else
int err_core = 0;
#endif
print_state_for_core(f, err_core);
panic_print_str("\r\n");
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
// If there are other frame info, print them as well
for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
// `f` is the frame for the offending core, see note above.
if (err_core != i && g_exc_frames[i] != NULL) {
print_state_for_core(g_exc_frames[i], i);
panic_print_str("\r\n");
}
}
#endif
}
static void frame_to_panic_info(void *frame, panic_info_t *info, bool pseudo_excause)
{
info->core = cpu_hal_get_core_id();
info->exception = PANIC_EXCEPTION_FAULT;
info->details = NULL;
info->reason = "Unknown";
info->pseudo_excause = pseudo_excause;
if (pseudo_excause) {
panic_soc_fill_info(frame, info);
} else {
panic_arch_fill_info(frame, info);
}
info->state = print_state;
info->frame = frame;
}
static void panic_handler(void *frame, bool pseudo_excause)
{
/*
* Setup environment and perform necessary architecture/chip specific
* steps here prior to the system panic handler.
* */
int core_id = cpu_hal_get_core_id();
// If multiple cores arrive at panic handler, save frames for all of them
g_exc_frames[core_id] = frame;
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
// These are cases where both CPUs both go into panic handler. The following code ensures
// only one core proceeds to the system panic handler.
if (pseudo_excause) {
#define BUSY_WAIT_IF_TRUE(b) { if (b) while(1); }
// For WDT expiry, pause the non-offending core - offending core handles panic
BUSY_WAIT_IF_TRUE(panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU0 && core_id == 1);
BUSY_WAIT_IF_TRUE(panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1 && core_id == 0);
// For cache error, pause the non-offending core - offending core handles panic
if (panic_get_cause(frame) == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid()) {
// Only print the backtrace for the offending core in case of the cache error
g_exc_frames[core_id] = NULL;
while (1) {
;
}
}
}
esp_rom_delay_us(1);
SOC_HAL_STALL_OTHER_CORES();
#endif
#if CONFIG_IDF_TARGET_ESP32
esp_dport_access_int_abort();
#endif
#if !CONFIG_ESP_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);
panic_print_str("Re-enable cpu cache.\r\n");
}
#endif
if (esp_cpu_in_ocd_debug_mode()) {
#if __XTENSA__
if (!(esp_ptr_executable(cpu_ll_pc_to_ptr(panic_get_address(frame))) && (panic_get_address(frame) & 0xC0000000U))) {
/* Xtensa ABI sets the 2 MSBs of the PC according to the windowed call size
* Incase the PC is invalid, GDB will fail to translate addresses to function names
* Hence replacing the PC to a placeholder address in case of invalid PC
*/
panic_set_address(frame, (uint32_t)&_invalid_pc_placeholder);
}
#endif
if (panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU0 ||
panic_get_cause(frame) == PANIC_RSN_INTWDT_CPU1) {
wdt_hal_write_protect_disable(&wdt0_context);
wdt_hal_handle_intr(&wdt0_context);
wdt_hal_write_protect_enable(&wdt0_context);
}
}
// Convert architecture exception frame into abstracted panic info
panic_info_t info;
frame_to_panic_info(frame, &info, pseudo_excause);
// Call the system panic handler
esp_panic_handler(&info);
}
void panicHandler(void *frame)
{
// This panic handler gets called for when the double exception vector,
// kernel exception vector gets used; as well as handling interrupt-based
// faults cache error, wdt expiry. EXCAUSE register gets written with
// one of PANIC_RSN_* values.
panic_handler(frame, true);
}
void xt_unhandled_exception(void *frame)
{
panic_handler(frame, false);
}
void __attribute__((noreturn)) panic_restart(void)
{
bool digital_reset_needed = false;
#ifdef CONFIG_IDF_TARGET_ESP32
// On the ESP32, cache error status can only be cleared by system reset
if (esp_cache_err_get_cpuid() != -1) {
digital_reset_needed = true;
}
#endif
#if CONFIG_IDF_TARGET_ESP32S2
if (esp_memprot_is_intr_ena_any() || esp_memprot_is_locked_any()) {
digital_reset_needed = true;
}
#endif
if (digital_reset_needed) {
esp_restart_noos_dig();
}
esp_restart_noos();
}

View File

@ -1,8 +1,8 @@
set(srcs "dport_panic_highint_hdl.S"
"clk.c"
"reset_reason.c"
"../arch/xtensa/panic_handler.c"
"../arch/xtensa/panic_handler_asm.S"
"../../arch/xtensa/panic_arch.c"
"../../arch/xtensa/panic_handler_asm.S"
)
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs})

View File

@ -177,7 +177,8 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk)
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
#endif
rtc_cpu_freq_config_t old_config, new_config;
rtc_cpu_freq_config_t old_config;
rtc_cpu_freq_config_t new_config;
rtc_clk_cpu_freq_get_config(&old_config);
const uint32_t old_freq_mhz = old_config.freq_mhz;
const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
@ -205,7 +206,9 @@ static void select_rtc_slow_clk(slow_clk_sel_t slow_clk)
*/
__attribute__((weak)) void esp_perip_clk_init(void)
{
uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0;
uint32_t common_perip_clk;
uint32_t hwcrypto_perip_clk;
uint32_t wifi_bt_sdio_clk;
#if CONFIG_FREERTOS_UNICORE
RESET_REASON rst_reas[1];

View File

@ -0,0 +1,2 @@
COMPONENT_SRCDIRS += port port/soc/esp32 port/arch/xtensa
COMPONENT_OBJEXCLUDE += port/async_memcpy_impl_gdma.o

View File

@ -2,8 +2,8 @@ set(srcs "async_memcpy_impl_cp_dma.c"
"dport_panic_highint_hdl.S"
"clk.c"
"reset_reason.c"
"../arch/xtensa/panic_handler.c"
"../arch/xtensa/panic_handler_asm.S"
"../../arch/xtensa/panic_arch.c"
"../../arch/xtensa/panic_handler_asm.S"
)
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs})

View File

@ -1,9 +1,9 @@
set(srcs "dport_panic_highint_hdl.S"
"clk.c"
"reset_reason.c"
"../async_memcpy_impl_gdma.c"
"../arch/xtensa/panic_handler.c"
"../arch/xtensa/panic_handler_asm.S"
"../../async_memcpy_impl_gdma.c"
"../../arch/xtensa/panic_arch.c"
"../../arch/xtensa/panic_handler_asm.S"
)
add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs})

View File

@ -0,0 +1,20 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#define PANIC_RSN_NONE 0
#define PANIC_RSN_INTWDT_CPU0 1
#define PANIC_RSN_INTWDT_CPU1 2
#define PANIC_RSN_CACHEERR 3
#define PANIC_RSN_MAX 3

View File

@ -1,8 +1,22 @@
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __RVRUNTIME_FRAMES_H__
#define __RVRUNTIME_FRAMES_H__
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
#define ALIGNUP(n, val) (((val) + (n)-1) & -(n))
#define ALIGNUP(n, val) (((val) + (n) - 1) & -(n))
#ifdef STRUCT_BEGIN
#undef STRUCT_BEGIN
@ -12,19 +26,15 @@
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#define STRUCT_BEGIN .pushsection .text; .struct 0
#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size
#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
#define STRUCT_END(sname) sname##Size:; .popsection
#else
#define STRUCT_BEGIN typedef struct {
#define STRUCT_FIELD(ctype,size,asname,name) ctype name;
#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
#define STRUCT_END(sname) } sname;
#endif
/*
@ -33,63 +43,54 @@
-------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, RV_STK_MEPC, mepc) /* Machine Exception Program Counter */
STRUCT_FIELD (long, 4, RV_STK_RA, ra) /* Return address */
STRUCT_FIELD (long, 4, RV_STK_SP, sp) /* Stack pointer */
STRUCT_FIELD (long, 4, RV_STK_GP, gp) /* Global pointer */
STRUCT_FIELD (long, 4, RV_STK_TP, tp) /* Thread pointer */
STRUCT_FIELD (long, 4, RV_STK_T0, t0) /* Temporary/alternate link register */
STRUCT_FIELD (long, 4, RV_STK_T1, t1) /* t1-2: Temporaries */
STRUCT_FIELD (long, 4, RV_STK_T2, t2)
STRUCT_FIELD (long, 4, RV_STK_S0, s0) /* Saved register/frame pointer */
STRUCT_FIELD (long, 4, RV_STK_S1, s1) /* Saved register */
STRUCT_FIELD (long, 4, RV_STK_A0, a0) /* a0-1: Function arguments/return address */
STRUCT_FIELD (long, 4, RV_STK_A1, a1)
STRUCT_FIELD (long, 4, RV_STK_A2, a2) /* a2-7: Function arguments */
STRUCT_FIELD (long, 4, RV_STK_A3, a3)
STRUCT_FIELD (long, 4, RV_STK_A4, a4)
STRUCT_FIELD (long, 4, RV_STK_A5, a5)
STRUCT_FIELD (long, 4, RV_STK_A6, a6)
STRUCT_FIELD (long, 4, RV_STK_A7, a7)
STRUCT_FIELD (long, 4, RV_STK_S2, s2) /* s2-11: Saved registers */
STRUCT_FIELD (long, 4, RV_STK_S3, s3)
STRUCT_FIELD (long, 4, RV_STK_S4, s4)
STRUCT_FIELD (long, 4, RV_STK_S5, s5)
STRUCT_FIELD (long, 4, RV_STK_S6, s6)
STRUCT_FIELD (long, 4, RV_STK_S7, s7)
STRUCT_FIELD (long, 4, RV_STK_S8, s8)
STRUCT_FIELD (long, 4, RV_STK_S9, s9)
STRUCT_FIELD (long, 4, RV_STK_S10, s10)
STRUCT_FIELD (long, 4, RV_STK_S11, s11)
STRUCT_FIELD (long, 4, RV_STK_T3, t3) /* t3-6: Temporaries */
STRUCT_FIELD (long, 4, RV_STK_T4, t4)
STRUCT_FIELD (long, 4, RV_STK_T5, t5)
STRUCT_FIELD (long, 4, RV_STK_T6, t6)
STRUCT_FIELD (long, 4, RV_STK_MSTATUS, mstatus) /* Machine Status */
STRUCT_FIELD (long, 4, RV_STK_MTVEC, mtvec) /* Machine Trap-Vector Base Address */
STRUCT_FIELD (long, 4, RV_STK_MCAUSE, mcause) /* Machine Trap Cause */
STRUCT_FIELD (long, 4, RV_STK_PCCRS, pccrs) /* Performance Counter Counter Registers */
STRUCT_FIELD (long, 4, RV_STK_PCER, pcer) /* Performance Counter Enable */
STRUCT_FIELD (long, 4, RV_STK_PCMR, pcmr) /* Performance Counter Mode */
STRUCT_FIELD (long, 4, RV_STK_HWLP, hwlp) /* Hardware Loop Registers */
STRUCT_FIELD (long, 4, RV_STK_PRIVLV, privlv) /* Privilege Level */
STRUCT_FIELD (long, 4, RV_STK_UHARTID, uhartid) /* Hardware Thread ID */
STRUCT_FIELD (long, 4, RV_STK_MHARTID, mhartid) /* Hardware Thread ID */
STRUCT_FIELD (long, 4, RV_STK_DCSR, dcsr) /* Debug Control and Status */
STRUCT_FIELD (long, 4, RV_STK_DPC, dpc) /* Debug PC */
STRUCT_FIELD (long, 4, RV_STK_INTC_THRESH, intc_thresh)
STRUCT_FIELD (long, 4, RV_STK_RESERVED0, reserved0)
STRUCT_FIELD (long, 4, RV_STK_MEPC, mepc) /* Machine Exception Program Counter */
STRUCT_FIELD (long, 4, RV_STK_RA, ra) /* Return address */
STRUCT_FIELD (long, 4, RV_STK_SP, sp) /* Stack pointer */
STRUCT_FIELD (long, 4, RV_STK_GP, gp) /* Global pointer */
STRUCT_FIELD (long, 4, RV_STK_TP, tp) /* Thread pointer */
STRUCT_FIELD (long, 4, RV_STK_T0, t0) /* Temporary/alternate link register */
STRUCT_FIELD (long, 4, RV_STK_T1, t1) /* t1-2: Temporaries */
STRUCT_FIELD (long, 4, RV_STK_T2, t2)
STRUCT_FIELD (long, 4, RV_STK_S0, s0) /* Saved register/frame pointer */
STRUCT_FIELD (long, 4, RV_STK_S1, s1) /* Saved register */
STRUCT_FIELD (long, 4, RV_STK_A0, a0) /* a0-1: Function arguments/return address */
STRUCT_FIELD (long, 4, RV_STK_A1, a1)
STRUCT_FIELD (long, 4, RV_STK_A2, a2) /* a2-7: Function arguments */
STRUCT_FIELD (long, 4, RV_STK_A3, a3)
STRUCT_FIELD (long, 4, RV_STK_A4, a4)
STRUCT_FIELD (long, 4, RV_STK_A5, a5)
STRUCT_FIELD (long, 4, RV_STK_A6, a6)
STRUCT_FIELD (long, 4, RV_STK_A7, a7)
STRUCT_FIELD (long, 4, RV_STK_S2, s2) /* s2-11: Saved registers */
STRUCT_FIELD (long, 4, RV_STK_S3, s3)
STRUCT_FIELD (long, 4, RV_STK_S4, s4)
STRUCT_FIELD (long, 4, RV_STK_S5, s5)
STRUCT_FIELD (long, 4, RV_STK_S6, s6)
STRUCT_FIELD (long, 4, RV_STK_S7, s7)
STRUCT_FIELD (long, 4, RV_STK_S8, s8)
STRUCT_FIELD (long, 4, RV_STK_S9, s9)
STRUCT_FIELD (long, 4, RV_STK_S10, s10)
STRUCT_FIELD (long, 4, RV_STK_S11, s11)
STRUCT_FIELD (long, 4, RV_STK_T3, t3) /* t3-6: Temporaries */
STRUCT_FIELD (long, 4, RV_STK_T4, t4)
STRUCT_FIELD (long, 4, RV_STK_T5, t5)
STRUCT_FIELD (long, 4, RV_STK_T6, t6)
STRUCT_FIELD (long, 4, RV_STK_MSTATUS, mstatus) /* Machine Status */
STRUCT_FIELD (long, 4, RV_STK_MTVEC, mtvec) /* Machine Trap-Vector Base Address */
STRUCT_FIELD (long, 4, RV_STK_MCAUSE, mcause) /* Machine Trap Cause */
STRUCT_FIELD (long, 4, RV_STK_MTVAL, mtval) /* Machine Trap Value */
STRUCT_FIELD (long, 4, RV_STK_MHARTID, mhartid) /* Hardware Thread ID in machine mode */
STRUCT_END(RvExcFrame)
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
# define RV_STK_SZ1 RvExcFrameSize
#define RV_STK_SZ1 RvExcFrameSize
#else
# define RV_STK_SZ1 sizeof(RvExcFrame)
#define RV_STK_SZ1 sizeof(RvExcFrame)
#endif
/*
* This is the frame size.
* Exception stack frame size, after align up to 16 bytes boundary
*/
#define RV_STK_FRMSZ (ALIGNUP(0x10, RV_STK_SZ1))
#define RV_STK_FRMSZ (ALIGNUP(0x10, RV_STK_SZ1))
#endif /* #ifndef __RVRUNTIME_FRAMES_H__ */

View File

@ -13,101 +13,85 @@
// limitations under the License.
#include "soc/soc.h"
#include "soc/interrupt_reg.h"
#include "riscv/rvruntime-frames.h"
.equ SAVE_REGS, 32
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
.equ PANIC_REGS, 38
.equ PANIC_REGS_SIZE, (PANIC_REGS * 4)
.altmacro
.macro lwsp a, b
lw \a, ((\b)*4)(sp)
.endm
.macro swsp a, b
sw \a, ((\b)*4)(sp)
.endm
.macro save_regs
addi sp, sp, -CONTEXT_SIZE
swsp ra, 1
swsp a0, 2
swsp a1, 3
swsp a2, 4
swsp a3, 5
swsp a4, 6
swsp a5, 7
swsp a6, 8
swsp a7, 9
swsp t0, 10
swsp t1, 11
swsp t2, 12
swsp t3, 13
swsp t4, 14
swsp t5, 15
swsp t6, 16
//swsp sp, 17
//swsp gp, 18
swsp tp, 19
swsp s0, 20
swsp s1, 21
swsp s2, 22
swsp s3, 23
swsp s4, 24
swsp s5, 25
swsp s6, 26
swsp s7, 27
swsp s8, 28
swsp s9, 29
swsp s10, 30
swsp s11, 31
addi sp, sp, -CONTEXT_SIZE
sw ra, RV_STK_RA(sp)
sw tp, RV_STK_TP(sp)
sw t0, RV_STK_T0(sp)
sw t1, RV_STK_T1(sp)
sw t2, RV_STK_T2(sp)
sw s0, RV_STK_S0(sp)
sw s1, RV_STK_S1(sp)
sw a0, RV_STK_A0(sp)
sw a1, RV_STK_A1(sp)
sw a2, RV_STK_A2(sp)
sw a3, RV_STK_A3(sp)
sw a4, RV_STK_A4(sp)
sw a5, RV_STK_A5(sp)
sw a6, RV_STK_A6(sp)
sw a7, RV_STK_A7(sp)
sw s2, RV_STK_S2(sp)
sw s3, RV_STK_S3(sp)
sw s4, RV_STK_S4(sp)
sw s5, RV_STK_S5(sp)
sw s6, RV_STK_S6(sp)
sw s7, RV_STK_S7(sp)
sw s8, RV_STK_S8(sp)
sw s9, RV_STK_S9(sp)
sw s10, RV_STK_S10(sp)
sw s11, RV_STK_S11(sp)
sw t3, RV_STK_T3(sp)
sw t4, RV_STK_T4(sp)
sw t5, RV_STK_T5(sp)
sw t6, RV_STK_T6(sp)
.endm
.macro save_mepc
csrr t0, mepc
swsp t0, 0
csrr t0, mepc
sw t0, RV_STK_MEPC(sp)
.endm
.macro restore_regs
lwsp ra, 1
lwsp a0, 2
lwsp a1, 3
lwsp a2, 4
lwsp a3, 5
lwsp a4, 6
lwsp a5, 7
lwsp a6, 8
lwsp a7, 9
lwsp t0, 10
lwsp t1, 11
lwsp t2, 12
lwsp t3, 13
lwsp t4, 14
lwsp t5, 15
lwsp t6, 16
//lwsp sp, 17
//lwsp gp, 18
lwsp tp, 19
lwsp s0, 20
lwsp s1, 21
lwsp s2, 22
lwsp s3, 23
lwsp s4, 24
lwsp s5, 25
lwsp s6, 26
lwsp s7, 27
lwsp s8, 28
lwsp s9, 29
lwsp s10, 30
lwsp s11, 31
lw ra, RV_STK_RA(sp)
lw tp, RV_STK_TP(sp)
lw t0, RV_STK_T0(sp)
lw t1, RV_STK_T1(sp)
lw t2, RV_STK_T2(sp)
lw s0, RV_STK_S0(sp)
lw s1, RV_STK_S1(sp)
lw a0, RV_STK_A0(sp)
lw a1, RV_STK_A1(sp)
lw a2, RV_STK_A2(sp)
lw a3, RV_STK_A3(sp)
lw a4, RV_STK_A4(sp)
lw a5, RV_STK_A5(sp)
lw a6, RV_STK_A6(sp)
lw a7, RV_STK_A7(sp)
lw s2, RV_STK_S2(sp)
lw s3, RV_STK_S3(sp)
lw s4, RV_STK_S4(sp)
lw s5, RV_STK_S5(sp)
lw s6, RV_STK_S6(sp)
lw s7, RV_STK_S7(sp)
lw s8, RV_STK_S8(sp)
lw s9, RV_STK_S9(sp)
lw s10, RV_STK_S10(sp)
lw s11, RV_STK_S11(sp)
lw t3, RV_STK_T3(sp)
lw t4, RV_STK_T4(sp)
lw t5, RV_STK_T5(sp)
lw t6, RV_STK_T6(sp)
addi sp, sp, CONTEXT_SIZE
.endm
.macro restore_mepc
lwsp t0, 0
lw t0, RV_STK_MEPC(sp)
csrw mepc, t0
.endm
@ -143,61 +127,61 @@ _vector_table:
.size _vector_table, .-_vector_table
/* Exception handler.*/
.global panicHandler
.global xt_unhandled_exception
.type _panic_handler, @function
_panic_handler:
addi sp, sp, -PANIC_REGS_SIZE
swsp x0, 0
swsp x1, 1
/* x2 is sp - it will be placed on stack later (after we can use the other registers for computation) */
swsp x3, 3
swsp x4, 4
swsp x5, 5
swsp x6, 6
swsp x7, 7
swsp x8, 8
swsp x9, 9
swsp x10, 10
swsp x11, 11
swsp x12, 12
swsp x13, 13
swsp x14, 14
swsp x15, 15
swsp x16, 16
swsp x17, 17
swsp x18, 18
swsp x19, 19
swsp x20, 20
swsp x21, 21
swsp x22, 22
swsp x23, 23
swsp x24, 24
swsp x25, 25
swsp x26, 26
swsp x27, 27
swsp x28, 28
swsp x29, 29
swsp x30, 30
swsp x31, 31
/* "Undo" the modification already done to the sp (x2) by the panic handler */
addi a1, x2, PANIC_REGS_SIZE
swsp a1, 2
csrr a1, mcause
swsp a1, 32
csrr a1, mepc
swsp a1, 33
csrr a1, mhartid
swsp a1, 34
csrr a1, mstatus
swsp a1, 35
csrr a1, mtval
swsp a1, 36
csrr a1, mtvec
swsp a1, 37
addi sp, sp, -RV_STK_FRMSZ /* allocate space on stack to store necessary registers */
/* save general registers */
sw ra, RV_STK_RA(sp)
sw gp, RV_STK_GP(sp)
sw tp, RV_STK_TP(sp)
sw t0, RV_STK_T0(sp)
sw t1, RV_STK_T1(sp)
sw t2, RV_STK_T2(sp)
sw s0, RV_STK_S0(sp)
sw s1, RV_STK_S1(sp)
sw a0, RV_STK_A0(sp)
sw a1, RV_STK_A1(sp)
sw a2, RV_STK_A2(sp)
sw a3, RV_STK_A3(sp)
sw a4, RV_STK_A4(sp)
sw a5, RV_STK_A5(sp)
sw a6, RV_STK_A6(sp)
sw a7, RV_STK_A7(sp)
sw s2, RV_STK_S2(sp)
sw s3, RV_STK_S3(sp)
sw s4, RV_STK_S4(sp)
sw s5, RV_STK_S5(sp)
sw s6, RV_STK_S6(sp)
sw s7, RV_STK_S7(sp)
sw s8, RV_STK_S8(sp)
sw s9, RV_STK_S9(sp)
sw s10, RV_STK_S10(sp)
sw s11, RV_STK_S11(sp)
sw t3, RV_STK_T3(sp)
sw t4, RV_STK_T4(sp)
sw t5, RV_STK_T5(sp)
sw t6, RV_STK_T6(sp)
addi t0, sp, RV_STK_FRMSZ /* restore sp with the value when trap happened */
sw t0, RV_STK_SP(sp)
csrr t0, mepc
sw t0, RV_STK_MEPC(sp)
csrr t0, mstatus
sw t0, RV_STK_MSTATUS(sp)
csrr t0, mtvec
sw t0, RV_STK_MTVEC(sp)
csrr t0, mcause
sw t0, RV_STK_MCAUSE(sp)
csrr t0, mtval
sw t0, RV_STK_MTVAL(sp)
csrr t0, mhartid
sw t0, RV_STK_MHARTID(sp)
/* call xt_unhandled_exception(sp,cause) */
mv a0, sp
csrr a1, mcause
jal zero, panicHandler
/* panicHandler never returns */
jal zero, xt_unhandled_exception
/* panicHandler never returns */
.size _panic_handler, .-_panic_handler
/* This is the interrupt handler.
@ -215,16 +199,15 @@ _interrupt_handler:
/* scheduler not enabled, jump directly to ISR handler */
lw t0, uxSchedulerRunning
beq t0,zero,already_on_handler
beq t0, zero, already_on_handler
/* increments the ISR nesting count */
/* This will work properly when we have nested interrupts */
la t0, uxInterruptNesting
lw t1, 0x0(t0)
addi t2,t1,1
sw t2, 0x0(t0)
/* If reached here from another low-prio ISR, skip stack pushing to TCB */
/* If reached here from another low priority ISR, skip stack pushing to TCB */
bne t1,zero, already_on_handler
/* Otherwise, save current sp, and use the isr stack from here */
@ -242,7 +225,7 @@ already_on_handler:
lw s3, 0(t0)
/* Increase interrupt threshold level */
la t2, 0x7fffffff
li t2, 0x7fffffff
and t1, s1, t2 /* t1 = mcause & mask */
slli t1, t1, 2 /* t1 = mcause * 4 */
la t2, INTC_INT_PRIO_REG(0)
@ -252,14 +235,14 @@ already_on_handler:
sw t2, 0(t0) /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */
fence
la t0, 0x8
li t0, 0x8
csrrs t0, mstatus, t0
/* call the C dispatcher */
mv a0, sp /* argument 1, stack pointer */
csrr a1, mcause /* argument 2, interrupt number */
/* mask off the interrupt flag of mcause */
la t0, 0x7fffffff
li t0, 0x7fffffff
and a1, a1, t0
jal _global_interrupt_handler
@ -281,7 +264,7 @@ already_on_handler:
la t0, uxInterruptNesting
lw t1, 0x0(t0)
/* Already zero, protect againts underflow */
/* Already zero, protect against underflow */
beq t1, zero, isr_skip_decrement
addi t1,t1, -1
sw t1, 0x0(t0)
@ -290,7 +273,7 @@ isr_skip_decrement:
/* may still have interrupts pending, skip section below and exit */
bne t1,zero,isr_exit
/* handlered all the ISRs and scheduled the next task, take its stack */
/* handled all the ISRs and scheduled the next task, take its stack */
/* load on sp, then exit. */
lw sp, pxCurrentTCB
lw sp, 0x0(sp)

View File

@ -31,7 +31,7 @@ Using these symbols is done by creating an assembly file (suffix .S) and definin
rsr a0, EXCSAVE_5
rfi 5
For a real-life example, see the :component_file:`esp_system/port/{IDF_TARGET_PATH_NAME}/dport_panic_highint_hdl.S` file; the panic handler interrupt is implemented there.
For a real-life example, see the :component_file:`esp_system/port/soc/{IDF_TARGET_PATH_NAME}/dport_panic_highint_hdl.S` file; the panic handler interrupt is implemented there.
Notes

View File

@ -17299,7 +17299,7 @@ END GROUP
.literal.commonErrorHandler
0x0000000040080b80 0x4 /home/user/esp/esp-idf/tools/unit-test-app/build/esp32/libesp32.a(panic.o)
0x28 (size before relaxing)
.literal.panicHandler
.literal.panic_handle_pseudo_exception
0x0000000040080b84 0x38 /home/user/esp/esp-idf/tools/unit-test-app/build/esp32/libesp32.a(panic.o)
0xc0 (size before relaxing)
.literal.xt_unhandled_exception
@ -18250,10 +18250,10 @@ END GROUP
0x0000000040087c34 0x44 /home/user/esp/esp-idf/tools/unit-test-app/build/esp32/libesp32.a(panic.o)
0x56 (size before relaxing)
*fill* 0x0000000040087c78 0x0
.text.panicHandler
.text.panic_handle_pseudo_exception
0x0000000040087c78 0x1a0 /home/user/esp/esp-idf/tools/unit-test-app/build/esp32/libesp32.a(panic.o)
0x1cc (size before relaxing)
0x0000000040087c78 panicHandler
0x0000000040087c78 panic_handle_pseudo_exception
.text.xt_unhandled_exception
0x0000000040087e18 0x77 /home/user/esp/esp-idf/tools/unit-test-app/build/esp32/libesp32.a(panic.o)
0xa1 (size before relaxing)

View File

@ -8909,7 +8909,7 @@ LOAD /home/xy/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-el
.literal.vApplicationStackOverflowHook
0x0000000040080bb8 0x8 esp-idf/esp32/libesp32.a(panic.c.obj)
0x18 (size before relaxing)
.literal.panicHandler
.literal.panic_handle_pseudo_exception
0x0000000040080bc0 0x34 esp-idf/esp32/libesp32.a(panic.c.obj)
0xa8 (size before relaxing)
.literal.xt_unhandled_exception
@ -10153,10 +10153,10 @@ LOAD /home/xy/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-el
0x23 (size before relaxing)
0x0000000040086bd0 vApplicationStackOverflowHook
*fill* 0x0000000040086be7 0x1
.text.panicHandler
.text.panic_handle_pseudo_exception
0x0000000040086be8 0x165 esp-idf/esp32/libesp32.a(panic.c.obj)
0x19c (size before relaxing)
0x0000000040086be8 panicHandler
0x0000000040086be8 panic_handle_pseudo_exception
*fill* 0x0000000040086d4d 0x3
.text.xt_unhandled_exception
0x0000000040086d50 0x88 esp-idf/esp32/libesp32.a(panic.c.obj)
@ -10939,7 +10939,7 @@ LOAD /home/xy/.espressif/tools/xtensa-esp32-elf/esp-2019r2-8.2.0/xtensa-esp32-el
.rodata.vApplicationStackOverflowHook.str1.4
0x000000003ffb1cbc 0x3e esp-idf/esp32/libesp32.a(panic.c.obj)
*fill* 0x000000003ffb1cfa 0x2
.rodata.panicHandler.str1.4
.rodata.panic_handle_pseudo_exception.str1.4
0x000000003ffb1cfc 0x1a9 esp-idf/esp32/libesp32.a(panic.c.obj)
*fill* 0x000000003ffb1ea5 0x3
.rodata.xt_unhandled_exception.str1.4
@ -17060,7 +17060,7 @@ newlib_include_locks_impl esp-idf/newlib/libnewlib.a(loc
newlib_include_pthread_impl esp-idf/newlib/libnewlib.a(pthread.c.obj)
newlib_include_syscalls_impl esp-idf/newlib/libnewlib.a(syscalls.c.obj)
opendir esp-idf/vfs/libvfs.a(vfs.c.obj)
panicHandler esp-idf/esp32/libesp32.a(panic.c.obj)
panic_handle_pseudo_exception esp-idf/esp32/libesp32.a(panic.c.obj)
esp-idf/freertos/libfreertos.a(xtensa_vectors.S.obj)
esp-idf/esp32/libesp32.a(dport_panic_highint_hdl.S.obj)
pcTaskGetTaskName esp-idf/freertos/libfreertos.a(tasks.c.obj)

View File

@ -7678,7 +7678,7 @@ LOAD /home/xy/.espressif/tools/xtensa-esp32s2-elf/esp-2019r2-8.2.0/xtensa-esp32s
.literal.vApplicationStackOverflowHook
0x0000000040024a4c 0x8 esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
0x18 (size before relaxing)
.literal.panicHandler
.literal.panic_handle_pseudo_exception
0x0000000040024a54 0x9c esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
0x1a8 (size before relaxing)
.literal.xt_unhandled_exception
@ -8819,10 +8819,10 @@ LOAD /home/xy/.espressif/tools/xtensa-esp32s2-elf/esp-2019r2-8.2.0/xtensa-esp32s
0x23 (size before relaxing)
0x0000000040029b88 vApplicationStackOverflowHook
*fill* 0x0000000040029b9f 0x1
.text.panicHandler
.text.panic_handle_pseudo_exception
0x0000000040029ba0 0x31d esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
0x3a0 (size before relaxing)
0x0000000040029ba0 panicHandler
0x0000000040029ba0 panic_handle_pseudo_exception
*fill* 0x0000000040029ebd 0x3
.text.xt_unhandled_exception
0x0000000040029ec0 0x7d esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
@ -9570,7 +9570,7 @@ LOAD /home/xy/.espressif/tools/xtensa-esp32s2-elf/esp-2019r2-8.2.0/xtensa-esp32s
.rodata.vApplicationStackOverflowHook.str1.4
0x000000003ffbd8f4 0x3e esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
*fill* 0x000000003ffbd932 0x2
.rodata.panicHandler.str1.4
.rodata.panic_handle_pseudo_exception.str1.4
0x000000003ffbd934 0x418 esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
.rodata.xt_unhandled_exception.str1.4
0x000000003ffbdd4c 0x4d esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
@ -15047,7 +15047,7 @@ newlib_include_locks_impl esp-idf/newlib/libnewlib.a(loc
newlib_include_pthread_impl esp-idf/newlib/libnewlib.a(pthread.c.obj)
newlib_include_syscalls_impl esp-idf/newlib/libnewlib.a(syscalls.c.obj)
opendir esp-idf/vfs/libvfs.a(vfs.c.obj)
panicHandler esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
panic_handle_pseudo_exception esp-idf/esp32s2/libesp32s2.a(panic.c.obj)
esp-idf/freertos/libfreertos.a(xtensa_vectors.S.obj)
esp-idf/esp32s2/libesp32s2.a(dport_panic_highint_hdl.S.obj)
pcTaskGetTaskName esp-idf/freertos/libfreertos.a(tasks.c.obj)