mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
Add handling of FPU for Xtensa CPU in gdbstub.
This commit is contained in:
parent
8d75f0d198
commit
6b56caba16
@ -62,11 +62,11 @@ void esp_gdbstub_panic_handler(void *in_frame)
|
||||
esp_gdbstub_send_end();
|
||||
} else if (s_scratch.state == GDBSTUB_NOT_STARTED) {
|
||||
s_scratch.state = GDBSTUB_STARTED;
|
||||
/* Save the paniced frame and get the list of tasks */
|
||||
/* Save the panicked frame and get the list of tasks */
|
||||
memcpy(&s_scratch.paniced_frame, frame, sizeof(*frame));
|
||||
init_task_info();
|
||||
find_paniced_task_index();
|
||||
/* Current task is the paniced task */
|
||||
/* Current task is the panicked task */
|
||||
if (s_scratch.paniced_task_index == GDBSTUB_CUR_TASK_INDEX_UNKNOWN) {
|
||||
set_active_task(0);
|
||||
} else {
|
||||
@ -144,7 +144,7 @@ static inline void disable_all_wdts(void)
|
||||
}
|
||||
|
||||
#if SOC_TIMER_GROUPS >= 2
|
||||
/* Interupt WDT is the Main Watchdog Timer of Timer Group 1 */
|
||||
/* Interrupt WDT is the Main Watchdog Timer of Timer Group 1 */
|
||||
if (true == wdt1_context_enabled) {
|
||||
wdt_hal_write_protect_disable(&wdt1_context);
|
||||
wdt_hal_disable(&wdt1_context);
|
||||
@ -173,7 +173,7 @@ static inline void enable_all_wdts(void)
|
||||
wdt_hal_write_protect_enable(&wdt0_context);
|
||||
}
|
||||
#if SOC_TIMER_GROUPS >= 2
|
||||
/* Interupt WDT is the Main Watchdog Timer of Timer Group 1 */
|
||||
/* Interrupt WDT is the Main Watchdog Timer of Timer Group 1 */
|
||||
if (false == wdt1_context_enabled) {
|
||||
wdt_hal_write_protect_disable(&wdt1_context);
|
||||
wdt_hal_enable(&wdt1_context);
|
||||
@ -208,7 +208,7 @@ static bool process_gdb_kill = false;
|
||||
static bool gdb_debug_int = false;
|
||||
|
||||
/**
|
||||
* @breef Handle UART interrupt
|
||||
* @brief Handle UART interrupt
|
||||
*
|
||||
* Handle UART interrupt for gdbstub. The function disable WDT.
|
||||
* If Ctrl+C combination detected (0x03), then application will start to process incoming GDB messages.
|
||||
@ -658,7 +658,8 @@ static void handle_C_command(const unsigned char *cmd, int len)
|
||||
esp_gdbstub_send_str_packet("OK");
|
||||
}
|
||||
|
||||
/** Set Register ... */
|
||||
|
||||
/* Set Register ... */
|
||||
static void handle_P_command(const unsigned char *cmd, int len)
|
||||
{
|
||||
uint32_t reg_index = 0;
|
||||
@ -684,7 +685,7 @@ static void handle_P_command(const unsigned char *cmd, int len)
|
||||
p_addr_ptr[0] = addr_ptr[3];
|
||||
|
||||
esp_gdbstub_set_register((esp_gdbstub_frame_t *)temp_regs_frame, reg_index, p_address);
|
||||
/* Convert current regioster file to GDB*/
|
||||
/* Convert current register file to GDB*/
|
||||
esp_gdbstub_frame_to_regfile((esp_gdbstub_frame_t *)temp_regs_frame, gdb_local_regfile);
|
||||
/* Sen OK response*/
|
||||
esp_gdbstub_send_str_packet("OK");
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_ipc_isr.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
#include <xtensa_context.h>
|
||||
|
||||
#if !XCHAL_HAVE_WINDOWED
|
||||
#warning "gdbstub_xtensa: revisit the implementation for Call0 ABI"
|
||||
@ -38,13 +39,54 @@ static void update_regfile_common(esp_gdbstub_gdb_regfile_t *dst)
|
||||
RSR(CONFIGID1, dst->configid1);
|
||||
}
|
||||
|
||||
#if XCHAL_HAVE_FP
|
||||
/** @brief Read FPU registers to memory
|
||||
*/
|
||||
static void gdbstub_read_fpu_regs(void *data)
|
||||
{
|
||||
float *ptr0;
|
||||
void *ptr1;
|
||||
|
||||
asm volatile ("mov %0, %1" : "=a" (ptr0) : "a" (data));
|
||||
|
||||
asm volatile ("rur.FCR %0" : "=a" (ptr1));
|
||||
asm volatile ("s32i %0, %1, 64" : "=a" (ptr1) : "a" (ptr0));
|
||||
asm volatile ("rur.FSR %0" : "=a" (ptr1));
|
||||
asm volatile ("s32i %0, %1, 68" : "=a" (ptr1) : "a" (ptr0));
|
||||
|
||||
asm volatile ("ssi f0, %0, 0" :: "a" (ptr0)); //*(ptr0 + 0) = f0;
|
||||
asm volatile ("ssi f1, %0, 4" :: "a" (ptr0)); //*(ptr0 + 4) = f1;
|
||||
asm volatile ("ssi f2, %0, 8" :: "a" (ptr0)); //...
|
||||
asm volatile ("ssi f3, %0, 12" :: "a" (ptr0));
|
||||
asm volatile ("ssi f4, %0, 16" :: "a" (ptr0));
|
||||
asm volatile ("ssi f5, %0, 20" :: "a" (ptr0));
|
||||
asm volatile ("ssi f6, %0, 24" :: "a" (ptr0));
|
||||
asm volatile ("ssi f7, %0, 28" :: "a" (ptr0));
|
||||
asm volatile ("ssi f8, %0, 32" :: "a" (ptr0));
|
||||
asm volatile ("ssi f9, %0, 36" :: "a" (ptr0));
|
||||
asm volatile ("ssi f10, %0, 40" :: "a" (ptr0));
|
||||
asm volatile ("ssi f11, %0, 44" :: "a" (ptr0));
|
||||
asm volatile ("ssi f12, %0, 48" :: "a" (ptr0));
|
||||
asm volatile ("ssi f13, %0, 52" :: "a" (ptr0));
|
||||
asm volatile ("ssi f14, %0, 56" :: "a" (ptr0));
|
||||
asm volatile ("ssi f15, %0, 60" :: "a" (ptr0));
|
||||
|
||||
}
|
||||
#endif // XCHAL_HAVE_FP
|
||||
|
||||
|
||||
extern const uint32_t offset_pxEndOfStack;
|
||||
extern const uint32_t offset_cpsa; /* Offset to start of the CPSA area on the stack. See uxInitialiseStackCPSA(). */
|
||||
extern uint32_t _xt_coproc_owner_sa[2];
|
||||
|
||||
void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_gdb_regfile_t *dst)
|
||||
{
|
||||
init_regfile(dst);
|
||||
const uint32_t *a_regs = (const uint32_t *) &frame->a0;
|
||||
|
||||
if (!(esp_ptr_executable(esp_cpu_pc_to_addr(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
|
||||
* In case 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
|
||||
*/
|
||||
dst->pc = (uint32_t)&_invalid_pc_placeholder;
|
||||
@ -59,6 +101,36 @@ void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_
|
||||
dst->a[i] = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
#if XCHAL_HAVE_FP
|
||||
|
||||
extern void *pxCurrentTCBs[2];
|
||||
void *current_tcb_ptr = pxCurrentTCBs[0];
|
||||
uint32_t *current_fpu_ptr = NULL;
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
current_tcb_ptr = pxCurrentTCBs[esp_cpu_get_core_id()];
|
||||
#endif
|
||||
uint32_t cp_enabled;
|
||||
RSR(CPENABLE, cp_enabled);
|
||||
|
||||
// Check if the co-processor is enabled
|
||||
if (cp_enabled) {
|
||||
gdbstub_read_fpu_regs(dst->f);
|
||||
} else {
|
||||
current_tcb_ptr += offset_pxEndOfStack;
|
||||
current_tcb_ptr = *(void **)current_tcb_ptr;
|
||||
current_tcb_ptr -= offset_cpsa;
|
||||
// Operation (&~0xf) required in .macro get_cpsa_from_tcb reg_A reg_B
|
||||
current_tcb_ptr = (void*)((uint32_t)current_tcb_ptr&~0xf);
|
||||
current_fpu_ptr = *(uint32_t **)(current_tcb_ptr + XT_CP_ASA);
|
||||
|
||||
dst->fcr = current_fpu_ptr[0];
|
||||
dst->fsr = current_fpu_ptr[1];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
dst->f[i] = current_fpu_ptr[i + 2];
|
||||
}
|
||||
}
|
||||
#endif //XCHAL_HAVE_FP
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
dst->lbeg = frame->lbeg;
|
||||
dst->lend = frame->lend;
|
||||
@ -72,6 +144,84 @@ void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_
|
||||
|
||||
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
|
||||
|
||||
/* Represents FreeRTOS TCB structure */
|
||||
typedef struct {
|
||||
uint8_t *top_of_stack;
|
||||
/* Other members aren't needed */
|
||||
} dummy_tcb_t;
|
||||
|
||||
void esp_gdbstub_tcb_frame_to_regfile(dummy_tcb_t *tcb, esp_gdbstub_gdb_regfile_t *dst)
|
||||
{
|
||||
const XtExcFrame *frame = (XtExcFrame *) tcb->top_of_stack;
|
||||
|
||||
init_regfile(dst);
|
||||
const uint32_t *a_regs = (const uint32_t *) &frame->a0;
|
||||
|
||||
if (!(esp_ptr_executable(esp_cpu_pc_to_addr(frame->pc)) && (frame->pc & 0xC0000000U))) {
|
||||
/* Xtensa ABI sets the 2 MSBs of the PC according to the windowed call size
|
||||
* In case 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
|
||||
*/
|
||||
dst->pc = (uint32_t)&_invalid_pc_placeholder;
|
||||
} else {
|
||||
dst->pc = (uint32_t)esp_cpu_pc_to_addr(frame->pc);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
dst->a[i] = a_regs[i];
|
||||
}
|
||||
for (int i = 16; i < 64; i++) {
|
||||
dst->a[i] = 0xDEADBEEF;
|
||||
}
|
||||
|
||||
#if XCHAL_HAVE_FP
|
||||
uint32_t *current_xt_coproc_owner_sa = (uint32_t *)_xt_coproc_owner_sa[0];
|
||||
|
||||
#if !CONFIG_FREERTOS_UNICORE
|
||||
current_xt_coproc_owner_sa = (uint32_t *)_xt_coproc_owner_sa[esp_cpu_get_core_id()];
|
||||
#endif
|
||||
|
||||
uint32_t cp_enabled;
|
||||
RSR(CPENABLE, cp_enabled);
|
||||
|
||||
void *current_tcb_ptr = tcb;
|
||||
uint32_t *current_fpu_ptr = NULL;
|
||||
{
|
||||
current_tcb_ptr += offset_pxEndOfStack;
|
||||
current_tcb_ptr = *(void **)current_tcb_ptr;
|
||||
current_tcb_ptr -= offset_cpsa;
|
||||
// Operation (&~0xf) required in .macro get_cpsa_from_tcb reg_A reg_B
|
||||
current_tcb_ptr = (void*)((uint32_t)current_tcb_ptr&~0xf);
|
||||
current_fpu_ptr = *(uint32_t **)(current_tcb_ptr + XT_CP_ASA);
|
||||
|
||||
bool use_fpu_regs = ((false == cp_enabled) && (current_xt_coproc_owner_sa[0] == 1) && (current_fpu_ptr == (uint32_t*)current_xt_coproc_owner_sa[2]));
|
||||
|
||||
dst->fcr = current_fpu_ptr[0];
|
||||
dst->fsr = current_fpu_ptr[1];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
dst->f[i] = current_fpu_ptr[i + 2];
|
||||
}
|
||||
|
||||
/* We have situation when FPU is in use, but the context not stored
|
||||
to the memory, and we have to read from CPU registers.
|
||||
*/
|
||||
if (use_fpu_regs) {
|
||||
gdbstub_read_fpu_regs(dst->f);
|
||||
}
|
||||
}
|
||||
#endif // XCHAL_HAVE_FP
|
||||
|
||||
#if XCHAL_HAVE_LOOPS
|
||||
dst->lbeg = frame->lbeg;
|
||||
dst->lend = frame->lend;
|
||||
dst->lcount = frame->lcount;
|
||||
#endif
|
||||
|
||||
dst->ps = (frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps;
|
||||
dst->sar = frame->sar;
|
||||
update_regfile_common(dst);
|
||||
}
|
||||
|
||||
static void solicited_frame_to_regfile(const XtSolFrame *frame, esp_gdbstub_gdb_regfile_t *dst)
|
||||
{
|
||||
init_regfile(dst);
|
||||
@ -94,20 +244,12 @@ static void solicited_frame_to_regfile(const XtSolFrame *frame, esp_gdbstub_gdb_
|
||||
update_regfile_common(dst);
|
||||
}
|
||||
|
||||
/* Represents FreeRTOS TCB structure */
|
||||
typedef struct {
|
||||
uint8_t *top_of_stack;
|
||||
/* Other members aren't needed */
|
||||
} dummy_tcb_t;
|
||||
|
||||
|
||||
void esp_gdbstub_tcb_to_regfile(TaskHandle_t tcb, esp_gdbstub_gdb_regfile_t *dst)
|
||||
{
|
||||
const dummy_tcb_t *dummy_tcb = (const dummy_tcb_t *) tcb;
|
||||
|
||||
dummy_tcb_t *dummy_tcb = (dummy_tcb_t *) tcb;
|
||||
const XtExcFrame *frame = (XtExcFrame *) dummy_tcb->top_of_stack;
|
||||
if (frame->exit != 0) {
|
||||
esp_gdbstub_frame_to_regfile(frame, dst);
|
||||
esp_gdbstub_tcb_frame_to_regfile(dummy_tcb, dst);
|
||||
} else {
|
||||
const XtSolFrame *taskFrame = (const XtSolFrame *) dummy_tcb->top_of_stack;
|
||||
solicited_frame_to_regfile(taskFrame, dst);
|
||||
@ -206,14 +348,80 @@ void esp_gdbstub_trigger_cpu(void)
|
||||
* Set register in frame with address to value
|
||||
*
|
||||
* */
|
||||
|
||||
void esp_gdbstub_set_register(esp_gdbstub_frame_t *frame, uint32_t reg_index, uint32_t value)
|
||||
{
|
||||
switch (reg_index) {
|
||||
case 0:
|
||||
uint32_t temp_fpu_value = value;
|
||||
float *ptr0;
|
||||
|
||||
asm volatile ("mov %0, %1" : "=a" (ptr0) : "a" (&temp_fpu_value));
|
||||
|
||||
if (reg_index == 0) {
|
||||
frame->pc = value;
|
||||
break;
|
||||
default:
|
||||
} else if (reg_index > 0 && (reg_index <= 27)) {
|
||||
(&frame->a0)[reg_index - 1] = value;
|
||||
break;
|
||||
}
|
||||
#if XCHAL_HAVE_FP
|
||||
void *ptr1;
|
||||
uint32_t cp_enabled;
|
||||
RSR(CPENABLE, cp_enabled);
|
||||
if (cp_enabled != 0) {
|
||||
if (reg_index == 87) {
|
||||
asm volatile ("lsi f0, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 88) {
|
||||
asm volatile ("lsi f1, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 89) {
|
||||
asm volatile ("lsi f2, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 90) {
|
||||
asm volatile ("lsi f3, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 91) {
|
||||
asm volatile ("lsi f4, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 92) {
|
||||
asm volatile ("lsi f5, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 93) {
|
||||
asm volatile ("lsi f6, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 94) {
|
||||
asm volatile ("lsi f7, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 95) {
|
||||
asm volatile ("lsi f8, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 96) {
|
||||
asm volatile ("lsi f9, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 97) {
|
||||
asm volatile ("lsi f10, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 98) {
|
||||
asm volatile ("lsi f11, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 99) {
|
||||
asm volatile ("lsi f12, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 100) {
|
||||
asm volatile ("lsi f13, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 101) {
|
||||
asm volatile ("lsi f14, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 102) {
|
||||
asm volatile ("lsi f15, %0, 0" :: "a" (ptr0));
|
||||
}
|
||||
if (reg_index == 103) {
|
||||
asm volatile ("l32i %0, %1, 0" : "=a" (ptr1) : "a" (ptr0));
|
||||
asm volatile ("wur.FCR %0" : "=a" (ptr1));
|
||||
}
|
||||
if (reg_index == 104) {
|
||||
asm volatile ("l32i %0, %1, 0" : "=a" (ptr1) : "a" (ptr0));
|
||||
asm volatile ("wur.FSR %0" : "=a" (ptr1));
|
||||
}
|
||||
}
|
||||
#endif // XCHAL_HAVE_FP
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user