From 54569fb001ac19af3471c3bfb2f900ee8e73a7bd Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Thu, 27 Jan 2022 00:39:52 +0300 Subject: [PATCH 1/4] riscv: Fixes GDB backtrace of interrupted threads Save missed SP value on stack --- components/riscv/vectors.S | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index f7169a73d6..b046dfee1b 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -201,6 +201,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 From 088e940528027121b9807c71dd043ffaa1f41d8b Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Thu, 27 Jan 2022 12:06:30 +0300 Subject: [PATCH 2/4] riscv: Fixes GDB backtrace end function to point to prvTaskExitError --- .../FreeRTOS-Kernel/portable/riscv/port.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 8a3ca7f606..7efdbce52c 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -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,15 @@ static void prvTaskExitError(void) abort(); } +__attribute__((naked)) static void prvTaskExitError(void) +{ + asm volatile(".option push\n" \ + ".option norvc\n" \ + "nop\n" \ + ".option pop"); + _prvTaskExitError(); +} + StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) { extern uint32_t __global_pointer$; @@ -190,7 +199,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/*nop size*/; frame->mepc = (UBaseType_t)pxCode; frame->a0 = (UBaseType_t)pvParameters; frame->gp = (UBaseType_t)&__global_pointer$; From 72822dfc8fc093848a2564f68bbb2f1693872409 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 2 Feb 2022 22:25:13 +0300 Subject: [PATCH 3/4] riscv: Adds support for returning from exception handler --- components/riscv/vectors.S | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index b046dfee1b..9b868280db 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -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, From dea45a9d723f656e462b0694d22437b71aa18de3 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 2 Feb 2022 22:27:13 +0300 Subject: [PATCH 4/4] riscv: Use semihosting to set breakpoint and watchpoint when running under debugger --- components/app_trace/port/riscv/port.c | 4 +- .../esp_system/port/arch/riscv/debug_stubs.c | 3 +- .../FreeRTOS-Kernel/portable/riscv/port.c | 5 +- components/hal/esp32c2/include/hal/cpu_ll.h | 54 +++++++++++++++++-- components/hal/esp32c3/include/hal/cpu_ll.h | 54 +++++++++++++++++-- components/hal/esp32h2/include/hal/cpu_ll.h | 54 +++++++++++++++++-- components/riscv/include/riscv/semihosting.h | 47 ++++++++++++++++ 7 files changed, 200 insertions(+), 21 deletions(-) diff --git a/components/app_trace/port/riscv/port.c b/components/app_trace/port/riscv/port.c index 78887124f2..f35fbeed0a 100644 --- a/components/app_trace/port/riscv/port.c +++ b/components/app_trace/port/riscv/port.c @@ -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. diff --git a/components/esp_system/port/arch/riscv/debug_stubs.c b/components/esp_system/port/arch/riscv/debug_stubs.c index e4ba4f66c0..63a46173ae 100644 --- a/components/esp_system/port/arch/riscv/debug_stubs.c +++ b/components/esp_system/port/arch/riscv/debug_stubs.c @@ -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) diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 7efdbce52c..30c13faab1 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -134,6 +134,9 @@ __attribute__((naked)) static void prvTaskExitError(void) ".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(); } @@ -201,7 +204,7 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC memset(frame, 0, sizeof(*frame)); /* 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/*nop size*/; + 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$; diff --git a/components/hal/esp32c2/include/hal/cpu_ll.h b/components/hal/esp32c2/include/hal/cpu_ll.h index 3c5dfcb3ce..bb3332b0f3 100644 --- a/components/hal/esp32c2/include/hal/cpu_ll.h +++ b/components/hal/esp32c2/include/hal/cpu_ll.h @@ -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"); diff --git a/components/hal/esp32c3/include/hal/cpu_ll.h b/components/hal/esp32c3/include/hal/cpu_ll.h index 3c5dfcb3ce..bb3332b0f3 100644 --- a/components/hal/esp32c3/include/hal/cpu_ll.h +++ b/components/hal/esp32c3/include/hal/cpu_ll.h @@ -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"); diff --git a/components/hal/esp32h2/include/hal/cpu_ll.h b/components/hal/esp32h2/include/hal/cpu_ll.h index 56c29f9dd2..41c59ea47c 100644 --- a/components/hal/esp32h2/include/hal/cpu_ll.h +++ b/components/hal/esp32h2/include/hal/cpu_ll.h @@ -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"); diff --git a/components/riscv/include/riscv/semihosting.h b/components/riscv/include/riscv/semihosting.h index 3539a3cd68..d5402964b0 100644 --- a/components/riscv/include/riscv/semihosting.h +++ b/components/riscv/include/riscv/semihosting.h @@ -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 *