mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/interrupted_thread_gdb_bt' into 'master'
riscv: Fixes GDB backtrace of interrupted threads See merge request espressif/esp-idf!16939
This commit is contained in:
commit
4a553510b7
@ -27,8 +27,6 @@ typedef struct {
|
||||
esp_apptrace_mem_block_t * mem_blocks;
|
||||
} esp_apptrace_riscv_ctrl_block_t;
|
||||
|
||||
#define RISCV_APPTRACE_SYSNR 0x64
|
||||
|
||||
#define ESP_APPTRACE_RISCV_BLOCK_LEN_MSK 0x7FFFUL
|
||||
#define ESP_APPTRACE_RISCV_BLOCK_LEN(_l_) ((_l_) & ESP_APPTRACE_RISCV_BLOCK_LEN_MSK)
|
||||
#define ESP_APPTRACE_RISCV_BLOCK_LEN_GET(_v_) ((_v_) & ESP_APPTRACE_RISCV_BLOCK_LEN_MSK)
|
||||
@ -104,7 +102,7 @@ __attribute__((weak)) int esp_apptrace_advertise_ctrl_block(void *ctrl_block_add
|
||||
if (!esp_cpu_in_ocd_debug_mode()) {
|
||||
return 0;
|
||||
}
|
||||
return (int) semihosting_call_noerrno(RISCV_APPTRACE_SYSNR, (long*)ctrl_block_addr);
|
||||
return (int) semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_APPTRACE_INIT, (long*)ctrl_block_addr);
|
||||
}
|
||||
|
||||
/* Returns up buffers config.
|
||||
|
@ -14,7 +14,6 @@
|
||||
|
||||
const static char *TAG = "esp_dbg_stubs";
|
||||
|
||||
#define RISCV_DBG_STUBS_SYSNR 0x65
|
||||
|
||||
/* Advertises apptrace control block address to host */
|
||||
static int esp_dbg_stubs_advertise_table(void *stub_table_addr)
|
||||
@ -22,7 +21,7 @@ static int esp_dbg_stubs_advertise_table(void *stub_table_addr)
|
||||
if (!esp_cpu_in_ocd_debug_mode()) {
|
||||
return 0;
|
||||
}
|
||||
return (int) semihosting_call_noerrno(RISCV_DBG_STUBS_SYSNR, (long*)stub_table_addr);
|
||||
return (int) semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_DBG_STUBS_INIT, (long*)stub_table_addr);
|
||||
}
|
||||
|
||||
void esp_dbg_stubs_ll_init(void *stub_table_addr)
|
||||
|
@ -115,7 +115,7 @@ void vPortEndScheduler(void)
|
||||
|
||||
// ------------------------ Stack --------------------------
|
||||
|
||||
static void prvTaskExitError(void)
|
||||
__attribute__((noreturn)) static void _prvTaskExitError(void)
|
||||
{
|
||||
/* A function that implements a task must not exit or attempt to return to
|
||||
its caller as there is nothing to return to. If a task wants to exit it
|
||||
@ -128,6 +128,18 @@ static void prvTaskExitError(void)
|
||||
abort();
|
||||
}
|
||||
|
||||
__attribute__((naked)) static void prvTaskExitError(void)
|
||||
{
|
||||
asm volatile(".option push\n" \
|
||||
".option norvc\n" \
|
||||
"nop\n" \
|
||||
".option pop");
|
||||
/* Task entry's RA will point here. Shifting RA into prvTaskExitError is necessary
|
||||
to make GDB backtrace ending inside that function.
|
||||
Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */
|
||||
_prvTaskExitError();
|
||||
}
|
||||
|
||||
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
|
||||
{
|
||||
extern uint32_t __global_pointer$;
|
||||
@ -190,7 +202,9 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
|
||||
sp -= RV_STK_FRMSZ;
|
||||
RvExcFrame *frame = (RvExcFrame *)sp;
|
||||
memset(frame, 0, sizeof(*frame));
|
||||
frame->ra = (UBaseType_t)prvTaskExitError;
|
||||
/* Shifting RA into prvTaskExitError is necessary to make GDB backtrace ending inside that function.
|
||||
Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */
|
||||
frame->ra = (UBaseType_t)prvTaskExitError + 4/*size of the nop insruction at the beginning of prvTaskExitError*/;
|
||||
frame->mepc = (UBaseType_t)pxCode;
|
||||
frame->a0 = (UBaseType_t)pvParameters;
|
||||
frame->gp = (UBaseType_t)&__global_pointer$;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "riscv/csr.h"
|
||||
#include "riscv/semihosting.h"
|
||||
|
||||
/*performance counter*/
|
||||
#define CSR_PCER_MACHINE 0x7e0
|
||||
@ -71,8 +72,29 @@ static inline void cpu_ll_init_hwloop(void)
|
||||
// Nothing needed here for ESP32-C3
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* If we want to set breakpoint which when hit transfers control to debugger
|
||||
* we need to set `action` in `mcontrol` to 1 (Enter Debug Mode).
|
||||
* That `action` value is supported only when `dmode` of `tdata1` is set.
|
||||
* But `dmode` can be modified by debugger only (from Debug Mode).
|
||||
*
|
||||
* So when debugger is connected we use special syscall to ask it to set breakpoint for us.
|
||||
*/
|
||||
long args[] = {true, id, (long)pc};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
||||
if (ret == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* The code bellow sets breakpoint which will trigger `Breakpoint` exception
|
||||
* instead transfering control to debugger. */
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_SET_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
||||
@ -82,6 +104,14 @@ static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
|
||||
static inline void cpu_ll_clear_breakpoint(int id)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {false, id};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
||||
if (ret == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
||||
@ -105,6 +135,17 @@ static inline void cpu_ll_set_watchpoint(int id,
|
||||
bool on_write)
|
||||
{
|
||||
uint32_t addr_napot;
|
||||
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {true, id, (long)addr, (long)size,
|
||||
(long)((on_read ? ESP_SEMIHOSTING_WP_FLG_RD : 0) | (on_write ? ESP_SEMIHOSTING_WP_FLG_WR : 0))};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
||||
if (ret == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
|
||||
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
||||
@ -123,6 +164,14 @@ static inline void cpu_ll_set_watchpoint(int id,
|
||||
|
||||
static inline void cpu_ll_clear_watchpoint(int id)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {false, id};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
||||
if (ret == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
||||
@ -132,11 +181,6 @@ static inline void cpu_ll_clear_watchpoint(int id)
|
||||
return;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_break(void)
|
||||
{
|
||||
asm volatile("ebreak\n");
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "riscv/csr.h"
|
||||
#include "riscv/semihosting.h"
|
||||
|
||||
/*performance counter*/
|
||||
#define CSR_PCER_MACHINE 0x7e0
|
||||
@ -71,8 +72,29 @@ static inline void cpu_ll_init_hwloop(void)
|
||||
// Nothing needed here for ESP32-C3
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* If we want to set breakpoint which when hit transfers control to debugger
|
||||
* we need to set `action` in `mcontrol` to 1 (Enter Debug Mode).
|
||||
* That `action` value is supported only when `dmode` of `tdata1` is set.
|
||||
* But `dmode` can be modified by debugger only (from Debug Mode).
|
||||
*
|
||||
* So when debugger is connected we use special syscall to ask it to set breakpoint for us.
|
||||
*/
|
||||
long args[] = {true, id, (long)pc};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
||||
if (ret == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* The code bellow sets breakpoint which will trigger `Breakpoint` exception
|
||||
* instead transfering control to debugger. */
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_SET_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
||||
@ -82,6 +104,14 @@ static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
|
||||
static inline void cpu_ll_clear_breakpoint(int id)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {false, id};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
||||
if (ret == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
||||
@ -105,6 +135,17 @@ static inline void cpu_ll_set_watchpoint(int id,
|
||||
bool on_write)
|
||||
{
|
||||
uint32_t addr_napot;
|
||||
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {true, id, (long)addr, (long)size,
|
||||
(long)((on_read ? ESP_SEMIHOSTING_WP_FLG_RD : 0) | (on_write ? ESP_SEMIHOSTING_WP_FLG_WR : 0))};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
||||
if (ret == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
|
||||
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
||||
@ -123,6 +164,14 @@ static inline void cpu_ll_set_watchpoint(int id,
|
||||
|
||||
static inline void cpu_ll_clear_watchpoint(int id)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {false, id};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
||||
if (ret == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
||||
@ -132,11 +181,6 @@ static inline void cpu_ll_clear_watchpoint(int id)
|
||||
return;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_break(void)
|
||||
{
|
||||
asm volatile("ebreak\n");
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "soc/assist_debug_reg.h"
|
||||
#include "esp_attr.h"
|
||||
#include "riscv/csr.h"
|
||||
#include "riscv/semihosting.h"
|
||||
|
||||
/*performance counter*/
|
||||
#define CSR_PCER_MACHINE 0x7e0
|
||||
@ -69,8 +70,29 @@ static inline void cpu_ll_init_hwloop(void)
|
||||
// Nothing needed here for ESP32-H2
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* If we want to set breakpoint which when hit transfers control to debugger
|
||||
* we need to set `action` in `mcontrol` to 1 (Enter Debug Mode).
|
||||
* That `action` value is supported only when `dmode` of `tdata1` is set.
|
||||
* But `dmode` can be modified by debugger only (from Debug Mode).
|
||||
*
|
||||
* So when debugger is connected we use special syscall to ask it to set breakpoint for us.
|
||||
*/
|
||||
long args[] = {true, id, (long)pc};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
||||
if (ret == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* The code bellow sets breakpoint which will trigger `Breakpoint` exception
|
||||
* instead transfering control to debugger. */
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_SET_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
||||
@ -80,6 +102,14 @@ static inline void cpu_ll_set_breakpoint(int id, uint32_t pc)
|
||||
|
||||
static inline void cpu_ll_clear_breakpoint(int id)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {false, id};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_BREAKPOINT_SET, args);
|
||||
if (ret == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE|TDATA1_EXECUTE);
|
||||
@ -103,6 +133,17 @@ static inline void cpu_ll_set_watchpoint(int id,
|
||||
bool on_write)
|
||||
{
|
||||
uint32_t addr_napot;
|
||||
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {true, id, (long)addr, (long)size,
|
||||
(long)((on_read ? ESP_SEMIHOSTING_WP_FLG_RD : 0) | (on_write ? ESP_SEMIHOSTING_WP_FLG_WR : 0))};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
||||
if (ret == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_SET_CSR(CSR_TCONTROL, TCONTROL_MPTE | TCONTROL_MTE);
|
||||
RV_SET_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
||||
@ -121,6 +162,14 @@ static inline void cpu_ll_set_watchpoint(int id,
|
||||
|
||||
static inline void cpu_ll_clear_watchpoint(int id)
|
||||
{
|
||||
if (cpu_ll_is_debugger_attached()) {
|
||||
/* see description in cpu_ll_set_breakpoint() */
|
||||
long args[] = {false, id};
|
||||
int ret = semihosting_call_noerrno(ESP_SEMIHOSTING_SYS_WATCHPOINT_SET, args);
|
||||
if (ret == 0){
|
||||
return;
|
||||
}
|
||||
}
|
||||
RV_WRITE_CSR(tselect,id);
|
||||
RV_CLEAR_CSR(CSR_TCONTROL,TCONTROL_MTE);
|
||||
RV_CLEAR_CSR(CSR_TDATA1, TDATA1_USER|TDATA1_MACHINE);
|
||||
@ -130,11 +179,6 @@ static inline void cpu_ll_clear_watchpoint(int id)
|
||||
return;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR bool cpu_ll_is_debugger_attached(void)
|
||||
{
|
||||
return REG_GET_BIT(ASSIST_DEBUG_CORE_0_DEBUG_MODE_REG, ASSIST_DEBUG_CORE_0_DEBUG_MODULE_ACTIVE);
|
||||
}
|
||||
|
||||
static inline void cpu_ll_break(void)
|
||||
{
|
||||
asm volatile("ebreak\n");
|
||||
|
@ -10,6 +10,53 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* ESP custom semihosting calls numbers */
|
||||
|
||||
/**
|
||||
* @brief Initialize apptrace data at host side
|
||||
*
|
||||
* @param addr address of apptrace control data block
|
||||
* @return return 0 on sucess or non-zero error code
|
||||
*/
|
||||
#define ESP_SEMIHOSTING_SYS_APPTRACE_INIT 0x64
|
||||
|
||||
/**
|
||||
* @brief Initialize debug stubs table at host side
|
||||
*
|
||||
* @param addr address of debug stubs table
|
||||
* @return return 0 on sucess or non-zero error code
|
||||
*/
|
||||
#define ESP_SEMIHOSTING_SYS_DBG_STUBS_INIT 0x65
|
||||
|
||||
/**
|
||||
* @brief Set/clear breakpoint
|
||||
*
|
||||
* @param set if true set breakpoint, otherwise clear it
|
||||
* @param id breakpoint ID
|
||||
* @param addr address to set breakpoint at. Ignored if `set` is false.
|
||||
* @return return 0 on sucess or non-zero error code
|
||||
*/
|
||||
#define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET 0x66
|
||||
|
||||
/**
|
||||
* @brief Set/clear watchpoint
|
||||
*
|
||||
* @param set if true set watchpoint, otherwise clear it
|
||||
* @param id watchpoint ID
|
||||
* @param addr address to set watchpoint at. Ignored if `set` is false.
|
||||
* @param size size of watchpoint. Ignored if `set` is false.
|
||||
* @param flags watchpoint flags, see description below. Ignored if `set` is false.
|
||||
* @return return 0 on sucess or non-zero error code
|
||||
*/
|
||||
#define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET 0x67
|
||||
|
||||
/* bit values for `flags` argument of ESP_SEMIHOSTING_SYS_WATCHPOINT_SET call. Can be ORed. */
|
||||
/* watch for 'reads' at `addr` */
|
||||
#define ESP_SEMIHOSTING_WP_FLG_RD (1UL << 0)
|
||||
/* watch for 'writes' at `addr` */
|
||||
#define ESP_SEMIHOSTING_WP_FLG_WR (1UL << 1)
|
||||
|
||||
/**
|
||||
* @brief Perform semihosting call
|
||||
*
|
||||
|
@ -176,16 +176,31 @@ _panic_handler:
|
||||
bgeu a1, t0, _call_panic_handler
|
||||
sw a1, RV_STK_MCAUSE(sp)
|
||||
/* exception_from_panic never returns */
|
||||
j panic_from_exception
|
||||
jal panic_from_exception
|
||||
/* We arrive here if the exception handler has returned. */
|
||||
j _return_from_exception
|
||||
|
||||
_call_panic_handler:
|
||||
/* Remove highest bit from mcause (a1) register and save it in the
|
||||
* structure */
|
||||
not t0, t0
|
||||
and a1, a1, t0
|
||||
sw a1, RV_STK_MCAUSE(sp)
|
||||
/* exception_from_isr never returns */
|
||||
j panic_from_isr
|
||||
.size panic_from_isr, .-panic_from_isr
|
||||
jal panic_from_isr
|
||||
|
||||
/* We arrive here if the exception handler has returned. This means that
|
||||
* the exception was handled, and the execution flow should resume.
|
||||
* Restore the registers and return from the exception.
|
||||
*/
|
||||
_return_from_exception:
|
||||
restore_mepc
|
||||
/* MTVEC and SP are assumed to be unmodified.
|
||||
* MSTATUS, MHARTID, MTVAL are read-only and not restored.
|
||||
*/
|
||||
lw gp, RV_STK_GP(sp)
|
||||
restore_general_regs RV_STK_FRMSZ
|
||||
mret
|
||||
.size _panic_handler, .-_panic_handler
|
||||
|
||||
/* This is the interrupt handler.
|
||||
* It saves the registers on the stack,
|
||||
@ -201,6 +216,17 @@ _interrupt_handler:
|
||||
save_general_regs
|
||||
save_mepc
|
||||
|
||||
/* Though it is not necessary we save GP and SP here.
|
||||
* SP is necessary to help GDB to properly unwind
|
||||
* the backtrace of threads preempted by interrupts (OS tick etc.).
|
||||
* GP is saved just to have its proper value in GDB. */
|
||||
/* As gp register is not saved by the macro, save it here */
|
||||
sw gp, RV_STK_GP(sp)
|
||||
/* Same goes for the SP value before trapping */
|
||||
addi t0, sp, CONTEXT_SIZE /* restore sp with the value when interrupt happened */
|
||||
/* Save SP */
|
||||
sw t0, RV_STK_SP(sp)
|
||||
|
||||
/* Before doing anythig preserve the stack pointer */
|
||||
/* It will be saved in current TCB, if needed */
|
||||
mv a0, sp
|
||||
|
Loading…
x
Reference in New Issue
Block a user