Skip to content

Commit 2bb613c

Browse files
committed
Merge branch 'feature/gdbstub_fpu' into 'master'
GDBstub: add handling of FPU for Xtensa CPU. See merge request espressif/esp-idf!25482
2 parents a02fb3c + 6b56cab commit 2bb613c

File tree

2 files changed

+232
-23
lines changed

2 files changed

+232
-23
lines changed

components/esp_gdbstub/src/gdbstub.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ void esp_gdbstub_panic_handler(void *in_frame)
6262
esp_gdbstub_send_end();
6363
} else if (s_scratch.state == GDBSTUB_NOT_STARTED) {
6464
s_scratch.state = GDBSTUB_STARTED;
65-
/* Save the paniced frame and get the list of tasks */
65+
/* Save the panicked frame and get the list of tasks */
6666
memcpy(&s_scratch.paniced_frame, frame, sizeof(*frame));
6767
init_task_info();
6868
find_paniced_task_index();
69-
/* Current task is the paniced task */
69+
/* Current task is the panicked task */
7070
if (s_scratch.paniced_task_index == GDBSTUB_CUR_TASK_INDEX_UNKNOWN) {
7171
set_active_task(0);
7272
} else {
@@ -144,7 +144,7 @@ static inline void disable_all_wdts(void)
144144
}
145145

146146
#if SOC_TIMER_GROUPS >= 2
147-
/* Interupt WDT is the Main Watchdog Timer of Timer Group 1 */
147+
/* Interrupt WDT is the Main Watchdog Timer of Timer Group 1 */
148148
if (true == wdt1_context_enabled) {
149149
wdt_hal_write_protect_disable(&wdt1_context);
150150
wdt_hal_disable(&wdt1_context);
@@ -173,7 +173,7 @@ static inline void enable_all_wdts(void)
173173
wdt_hal_write_protect_enable(&wdt0_context);
174174
}
175175
#if SOC_TIMER_GROUPS >= 2
176-
/* Interupt WDT is the Main Watchdog Timer of Timer Group 1 */
176+
/* Interrupt WDT is the Main Watchdog Timer of Timer Group 1 */
177177
if (false == wdt1_context_enabled) {
178178
wdt_hal_write_protect_disable(&wdt1_context);
179179
wdt_hal_enable(&wdt1_context);
@@ -208,7 +208,7 @@ static bool process_gdb_kill = false;
208208
static bool gdb_debug_int = false;
209209

210210
/**
211-
* @breef Handle UART interrupt
211+
* @brief Handle UART interrupt
212212
*
213213
* Handle UART interrupt for gdbstub. The function disable WDT.
214214
* 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)
658658
esp_gdbstub_send_str_packet("OK");
659659
}
660660

661-
/** Set Register ... */
661+
662+
/* Set Register ... */
662663
static void handle_P_command(const unsigned char *cmd, int len)
663664
{
664665
uint32_t reg_index = 0;
@@ -684,7 +685,7 @@ static void handle_P_command(const unsigned char *cmd, int len)
684685
p_addr_ptr[0] = addr_ptr[3];
685686

686687
esp_gdbstub_set_register((esp_gdbstub_frame_t *)temp_regs_frame, reg_index, p_address);
687-
/* Convert current regioster file to GDB*/
688+
/* Convert current register file to GDB*/
688689
esp_gdbstub_frame_to_regfile((esp_gdbstub_frame_t *)temp_regs_frame, gdb_local_regfile);
689690
/* Sen OK response*/
690691
esp_gdbstub_send_str_packet("OK");

components/esp_gdbstub/src/port/xtensa/gdbstub_xtensa.c

Lines changed: 224 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "esp_cpu.h"
1313
#include "esp_ipc_isr.h"
1414
#include "esp_private/crosscore_int.h"
15+
#include <xtensa_context.h>
1516

1617
#if !XCHAL_HAVE_WINDOWED
1718
#warning "gdbstub_xtensa: revisit the implementation for Call0 ABI"
@@ -38,13 +39,54 @@ static void update_regfile_common(esp_gdbstub_gdb_regfile_t *dst)
3839
RSR(CONFIGID1, dst->configid1);
3940
}
4041

42+
#if XCHAL_HAVE_FP
43+
/** @brief Read FPU registers to memory
44+
*/
45+
static void gdbstub_read_fpu_regs(void *data)
46+
{
47+
float *ptr0;
48+
void *ptr1;
49+
50+
asm volatile ("mov %0, %1" : "=a" (ptr0) : "a" (data));
51+
52+
asm volatile ("rur.FCR %0" : "=a" (ptr1));
53+
asm volatile ("s32i %0, %1, 64" : "=a" (ptr1) : "a" (ptr0));
54+
asm volatile ("rur.FSR %0" : "=a" (ptr1));
55+
asm volatile ("s32i %0, %1, 68" : "=a" (ptr1) : "a" (ptr0));
56+
57+
asm volatile ("ssi f0, %0, 0" :: "a" (ptr0)); //*(ptr0 + 0) = f0;
58+
asm volatile ("ssi f1, %0, 4" :: "a" (ptr0)); //*(ptr0 + 4) = f1;
59+
asm volatile ("ssi f2, %0, 8" :: "a" (ptr0)); //...
60+
asm volatile ("ssi f3, %0, 12" :: "a" (ptr0));
61+
asm volatile ("ssi f4, %0, 16" :: "a" (ptr0));
62+
asm volatile ("ssi f5, %0, 20" :: "a" (ptr0));
63+
asm volatile ("ssi f6, %0, 24" :: "a" (ptr0));
64+
asm volatile ("ssi f7, %0, 28" :: "a" (ptr0));
65+
asm volatile ("ssi f8, %0, 32" :: "a" (ptr0));
66+
asm volatile ("ssi f9, %0, 36" :: "a" (ptr0));
67+
asm volatile ("ssi f10, %0, 40" :: "a" (ptr0));
68+
asm volatile ("ssi f11, %0, 44" :: "a" (ptr0));
69+
asm volatile ("ssi f12, %0, 48" :: "a" (ptr0));
70+
asm volatile ("ssi f13, %0, 52" :: "a" (ptr0));
71+
asm volatile ("ssi f14, %0, 56" :: "a" (ptr0));
72+
asm volatile ("ssi f15, %0, 60" :: "a" (ptr0));
73+
74+
}
75+
#endif // XCHAL_HAVE_FP
76+
77+
78+
extern const uint32_t offset_pxEndOfStack;
79+
extern const uint32_t offset_cpsa; /* Offset to start of the CPSA area on the stack. See uxInitialiseStackCPSA(). */
80+
extern uint32_t _xt_coproc_owner_sa[2];
81+
4182
void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_gdb_regfile_t *dst)
4283
{
4384
init_regfile(dst);
4485
const uint32_t *a_regs = (const uint32_t *) &frame->a0;
86+
4587
if (!(esp_ptr_executable(esp_cpu_pc_to_addr(frame->pc)) && (frame->pc & 0xC0000000U))) {
4688
/* Xtensa ABI sets the 2 MSBs of the PC according to the windowed call size
47-
* Incase the PC is invalid, GDB will fail to translate addresses to function names
89+
* In case the PC is invalid, GDB will fail to translate addresses to function names
4890
* Hence replacing the PC to a placeholder address in case of invalid PC
4991
*/
5092
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_
59101
dst->a[i] = 0xDEADBEEF;
60102
}
61103

104+
#if XCHAL_HAVE_FP
105+
106+
extern void *pxCurrentTCBs[2];
107+
void *current_tcb_ptr = pxCurrentTCBs[0];
108+
uint32_t *current_fpu_ptr = NULL;
109+
110+
#if !CONFIG_FREERTOS_UNICORE
111+
current_tcb_ptr = pxCurrentTCBs[esp_cpu_get_core_id()];
112+
#endif
113+
uint32_t cp_enabled;
114+
RSR(CPENABLE, cp_enabled);
115+
116+
// Check if the co-processor is enabled
117+
if (cp_enabled) {
118+
gdbstub_read_fpu_regs(dst->f);
119+
} else {
120+
current_tcb_ptr += offset_pxEndOfStack;
121+
current_tcb_ptr = *(void **)current_tcb_ptr;
122+
current_tcb_ptr -= offset_cpsa;
123+
// Operation (&~0xf) required in .macro get_cpsa_from_tcb reg_A reg_B
124+
current_tcb_ptr = (void*)((uint32_t)current_tcb_ptr&~0xf);
125+
current_fpu_ptr = *(uint32_t **)(current_tcb_ptr + XT_CP_ASA);
126+
127+
dst->fcr = current_fpu_ptr[0];
128+
dst->fsr = current_fpu_ptr[1];
129+
for (int i = 0; i < 16; i++) {
130+
dst->f[i] = current_fpu_ptr[i + 2];
131+
}
132+
}
133+
#endif //XCHAL_HAVE_FP
62134
#if XCHAL_HAVE_LOOPS
63135
dst->lbeg = frame->lbeg;
64136
dst->lend = frame->lend;
@@ -72,6 +144,84 @@ void esp_gdbstub_frame_to_regfile(const esp_gdbstub_frame_t *frame, esp_gdbstub_
72144

73145
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
74146

147+
/* Represents FreeRTOS TCB structure */
148+
typedef struct {
149+
uint8_t *top_of_stack;
150+
/* Other members aren't needed */
151+
} dummy_tcb_t;
152+
153+
void esp_gdbstub_tcb_frame_to_regfile(dummy_tcb_t *tcb, esp_gdbstub_gdb_regfile_t *dst)
154+
{
155+
const XtExcFrame *frame = (XtExcFrame *) tcb->top_of_stack;
156+
157+
init_regfile(dst);
158+
const uint32_t *a_regs = (const uint32_t *) &frame->a0;
159+
160+
if (!(esp_ptr_executable(esp_cpu_pc_to_addr(frame->pc)) && (frame->pc & 0xC0000000U))) {
161+
/* Xtensa ABI sets the 2 MSBs of the PC according to the windowed call size
162+
* In case the PC is invalid, GDB will fail to translate addresses to function names
163+
* Hence replacing the PC to a placeholder address in case of invalid PC
164+
*/
165+
dst->pc = (uint32_t)&_invalid_pc_placeholder;
166+
} else {
167+
dst->pc = (uint32_t)esp_cpu_pc_to_addr(frame->pc);
168+
}
169+
170+
for (int i = 0; i < 16; i++) {
171+
dst->a[i] = a_regs[i];
172+
}
173+
for (int i = 16; i < 64; i++) {
174+
dst->a[i] = 0xDEADBEEF;
175+
}
176+
177+
#if XCHAL_HAVE_FP
178+
uint32_t *current_xt_coproc_owner_sa = (uint32_t *)_xt_coproc_owner_sa[0];
179+
180+
#if !CONFIG_FREERTOS_UNICORE
181+
current_xt_coproc_owner_sa = (uint32_t *)_xt_coproc_owner_sa[esp_cpu_get_core_id()];
182+
#endif
183+
184+
uint32_t cp_enabled;
185+
RSR(CPENABLE, cp_enabled);
186+
187+
void *current_tcb_ptr = tcb;
188+
uint32_t *current_fpu_ptr = NULL;
189+
{
190+
current_tcb_ptr += offset_pxEndOfStack;
191+
current_tcb_ptr = *(void **)current_tcb_ptr;
192+
current_tcb_ptr -= offset_cpsa;
193+
// Operation (&~0xf) required in .macro get_cpsa_from_tcb reg_A reg_B
194+
current_tcb_ptr = (void*)((uint32_t)current_tcb_ptr&~0xf);
195+
current_fpu_ptr = *(uint32_t **)(current_tcb_ptr + XT_CP_ASA);
196+
197+
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]));
198+
199+
dst->fcr = current_fpu_ptr[0];
200+
dst->fsr = current_fpu_ptr[1];
201+
for (int i = 0; i < 16; i++) {
202+
dst->f[i] = current_fpu_ptr[i + 2];
203+
}
204+
205+
/* We have situation when FPU is in use, but the context not stored
206+
to the memory, and we have to read from CPU registers.
207+
*/
208+
if (use_fpu_regs) {
209+
gdbstub_read_fpu_regs(dst->f);
210+
}
211+
}
212+
#endif // XCHAL_HAVE_FP
213+
214+
#if XCHAL_HAVE_LOOPS
215+
dst->lbeg = frame->lbeg;
216+
dst->lend = frame->lend;
217+
dst->lcount = frame->lcount;
218+
#endif
219+
220+
dst->ps = (frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps;
221+
dst->sar = frame->sar;
222+
update_regfile_common(dst);
223+
}
224+
75225
static void solicited_frame_to_regfile(const XtSolFrame *frame, esp_gdbstub_gdb_regfile_t *dst)
76226
{
77227
init_regfile(dst);
@@ -94,20 +244,12 @@ static void solicited_frame_to_regfile(const XtSolFrame *frame, esp_gdbstub_gdb_
94244
update_regfile_common(dst);
95245
}
96246

97-
/* Represents FreeRTOS TCB structure */
98-
typedef struct {
99-
uint8_t *top_of_stack;
100-
/* Other members aren't needed */
101-
} dummy_tcb_t;
102-
103-
104247
void esp_gdbstub_tcb_to_regfile(TaskHandle_t tcb, esp_gdbstub_gdb_regfile_t *dst)
105248
{
106-
const dummy_tcb_t *dummy_tcb = (const dummy_tcb_t *) tcb;
107-
249+
dummy_tcb_t *dummy_tcb = (dummy_tcb_t *) tcb;
108250
const XtExcFrame *frame = (XtExcFrame *) dummy_tcb->top_of_stack;
109251
if (frame->exit != 0) {
110-
esp_gdbstub_frame_to_regfile(frame, dst);
252+
esp_gdbstub_tcb_frame_to_regfile(dummy_tcb, dst);
111253
} else {
112254
const XtSolFrame *taskFrame = (const XtSolFrame *) dummy_tcb->top_of_stack;
113255
solicited_frame_to_regfile(taskFrame, dst);
@@ -206,14 +348,80 @@ void esp_gdbstub_trigger_cpu(void)
206348
* Set register in frame with address to value
207349
*
208350
* */
351+
209352
void esp_gdbstub_set_register(esp_gdbstub_frame_t *frame, uint32_t reg_index, uint32_t value)
210353
{
211-
switch (reg_index) {
212-
case 0:
354+
uint32_t temp_fpu_value = value;
355+
float *ptr0;
356+
357+
asm volatile ("mov %0, %1" : "=a" (ptr0) : "a" (&temp_fpu_value));
358+
359+
if (reg_index == 0) {
213360
frame->pc = value;
214-
break;
215-
default:
361+
} else if (reg_index > 0 && (reg_index <= 27)) {
216362
(&frame->a0)[reg_index - 1] = value;
217-
break;
218363
}
364+
#if XCHAL_HAVE_FP
365+
void *ptr1;
366+
uint32_t cp_enabled;
367+
RSR(CPENABLE, cp_enabled);
368+
if (cp_enabled != 0) {
369+
if (reg_index == 87) {
370+
asm volatile ("lsi f0, %0, 0" :: "a" (ptr0));
371+
}
372+
if (reg_index == 88) {
373+
asm volatile ("lsi f1, %0, 0" :: "a" (ptr0));
374+
}
375+
if (reg_index == 89) {
376+
asm volatile ("lsi f2, %0, 0" :: "a" (ptr0));
377+
}
378+
if (reg_index == 90) {
379+
asm volatile ("lsi f3, %0, 0" :: "a" (ptr0));
380+
}
381+
if (reg_index == 91) {
382+
asm volatile ("lsi f4, %0, 0" :: "a" (ptr0));
383+
}
384+
if (reg_index == 92) {
385+
asm volatile ("lsi f5, %0, 0" :: "a" (ptr0));
386+
}
387+
if (reg_index == 93) {
388+
asm volatile ("lsi f6, %0, 0" :: "a" (ptr0));
389+
}
390+
if (reg_index == 94) {
391+
asm volatile ("lsi f7, %0, 0" :: "a" (ptr0));
392+
}
393+
if (reg_index == 95) {
394+
asm volatile ("lsi f8, %0, 0" :: "a" (ptr0));
395+
}
396+
if (reg_index == 96) {
397+
asm volatile ("lsi f9, %0, 0" :: "a" (ptr0));
398+
}
399+
if (reg_index == 97) {
400+
asm volatile ("lsi f10, %0, 0" :: "a" (ptr0));
401+
}
402+
if (reg_index == 98) {
403+
asm volatile ("lsi f11, %0, 0" :: "a" (ptr0));
404+
}
405+
if (reg_index == 99) {
406+
asm volatile ("lsi f12, %0, 0" :: "a" (ptr0));
407+
}
408+
if (reg_index == 100) {
409+
asm volatile ("lsi f13, %0, 0" :: "a" (ptr0));
410+
}
411+
if (reg_index == 101) {
412+
asm volatile ("lsi f14, %0, 0" :: "a" (ptr0));
413+
}
414+
if (reg_index == 102) {
415+
asm volatile ("lsi f15, %0, 0" :: "a" (ptr0));
416+
}
417+
if (reg_index == 103) {
418+
asm volatile ("l32i %0, %1, 0" : "=a" (ptr1) : "a" (ptr0));
419+
asm volatile ("wur.FCR %0" : "=a" (ptr1));
420+
}
421+
if (reg_index == 104) {
422+
asm volatile ("l32i %0, %1, 0" : "=a" (ptr1) : "a" (ptr0));
423+
asm volatile ("wur.FSR %0" : "=a" (ptr1));
424+
}
425+
}
426+
#endif // XCHAL_HAVE_FP
219427
}

0 commit comments

Comments
 (0)