arch/xtensa: Add a pseudo save area to be able to backtrace from

interrupts

Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
This commit is contained in:
Abdelatif Guettouche 2020-12-01 16:53:57 +00:00 committed by Alan Carvalho de Assis
parent 1f96f42f1e
commit 7075c98978
3 changed files with 86 additions and 15 deletions

View File

@ -108,6 +108,13 @@ config XTENSA_BTDEPTH
---help--- ---help---
This is the depth of the backtrace. This is the depth of the backtrace.
config XTENSA_INTBACKTRACE
bool "Full backtrace from interrupts"
default n
depends on XTENSA_DUMPBT_ON_ASSERT
---help---
Add necessary logic to be able to have a full backtrace from an interrupt context.
config XTENSA_USE_SEPARATE_IMEM config XTENSA_USE_SEPARATE_IMEM
bool "Use a separate heap for internal memory" bool "Use a separate heap for internal memory"
default n default n

View File

@ -187,6 +187,29 @@ g_intstackbase:
and a6, a6, a3 /* a6 = Set of pending, enabled interrupts for this level */ and a6, a6, a3 /* a6 = Set of pending, enabled interrupts for this level */
beqz a6, 1f /* Nothing to do */ beqz a6, 1f /* Nothing to do */
/* At this point, the exception frame should have been allocated and filled,
* and current sp points to the interrupt stack (if enabled). Copy the
* pre-exception's base save area below the current SP.
*/
#ifdef CONFIG_XTENSA_INTBACKTRACE
rsr a0, EXCSAVE_1 + \level - 1 /* Get exception frame pointer stored in EXCSAVE_x */
l32i a3, a0, (4 * REG_A0) /* Copy pre-exception a0 (return address) */
s32e a3, sp, -16
l32i a3, a0, (4 * REG_A1) /* Copy pre-exception a1 (stack pointer) */
s32e a3, sp, -12
/* Backtracing only needs a0 and a1, no need to create full base save area.
* Also need to change current frame's return address to point to pre-exception's
* last run instruction.
*/
rsr a0, EPC_1 + \level - 1 /* return address */
movi a4, 0xc0000000 /* constant with top 2 bits set (call size) */
or a0, a0, a4 /* set top 2 bits */
addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */
#endif
/* Call xtensa_int_decode passing the address of the register save area /* Call xtensa_int_decode passing the address of the register save area
* as a parameter (A7). * as a parameter (A7).
*/ */
@ -270,7 +293,7 @@ g_intstackbase:
_xtensa_level1_handler: _xtensa_level1_handler:
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, PS /* Save interruptee's PS */ rsr a0, PS /* Save interruptee's PS */
@ -280,6 +303,10 @@ _xtensa_level1_handler:
rsr a0, EXCSAVE_1 /* Save interruptee's a0 */ rsr a0, EXCSAVE_1 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0) s32i a0, sp, (4 * REG_A0)
#ifdef CONFIG_XTENSA_INTBACKTRACE
wsr sp, EXCSAVE_1
#endif
/* Save rest of interrupt context. */ /* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2) s32i a2, sp, (4 * REG_A2)
@ -369,7 +396,7 @@ _xtensa_level1_handler:
_xtensa_level2_handler: _xtensa_level2_handler:
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_2 /* Save interruptee's PS */ rsr a0, EPS_2 /* Save interruptee's PS */
@ -379,6 +406,10 @@ _xtensa_level2_handler:
rsr a0, EXCSAVE_2 /* Save interruptee's a0 */ rsr a0, EXCSAVE_2 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0) s32i a0, sp, (4 * REG_A0)
#ifdef CONFIG_XTENSA_INTBACKTRACE
wsr sp, EXCSAVE_2
#endif
/* Save rest of interrupt context. */ /* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2) s32i a2, sp, (4 * REG_A2)
@ -430,7 +461,7 @@ _xtensa_level2_handler:
_xtensa_level3_handler: _xtensa_level3_handler:
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_3 /* Save interruptee's PS */ rsr a0, EPS_3 /* Save interruptee's PS */
@ -440,6 +471,10 @@ _xtensa_level3_handler:
rsr a0, EXCSAVE_3 /* Save interruptee's a0 */ rsr a0, EXCSAVE_3 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0) s32i a0, sp, (4 * REG_A0)
#ifdef CONFIG_XTENSA_INTBACKTRACE
wsr sp, EXCSAVE_3
#endif
/* Save rest of interrupt context. */ /* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2) s32i a2, sp, (4 * REG_A2)
@ -491,7 +526,7 @@ _xtensa_level3_handler:
_xtensa_level4_handler: _xtensa_level4_handler:
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_4 /* Save interruptee's PS */ rsr a0, EPS_4 /* Save interruptee's PS */
@ -501,6 +536,10 @@ _xtensa_level4_handler:
rsr a0, EXCSAVE_4 /* Save interruptee's a0 */ rsr a0, EXCSAVE_4 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0) s32i a0, sp, (4 * REG_A0)
#ifdef CONFIG_XTENSA_INTBACKTRACE
wsr sp, EXCSAVE_4
#endif
/* Save rest of interrupt context. */ /* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2) s32i a2, sp, (4 * REG_A2)
@ -552,7 +591,7 @@ _xtensa_level4_handler:
_xtensa_level5_handler: _xtensa_level5_handler:
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_5 /* Save interruptee's PS */ rsr a0, EPS_5 /* Save interruptee's PS */
@ -562,6 +601,10 @@ _xtensa_level5_handler:
rsr a0, EXCSAVE_5 /* Save interruptee's a0 */ rsr a0, EXCSAVE_5 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0) s32i a0, sp, (4 * REG_A0)
#ifdef CONFIG_XTENSA_INTBACKTRACE
wsr sp, EXCSAVE_5
#endif
/* Save rest of interrupt context. */ /* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2) s32i a2, sp, (4 * REG_A2)
@ -613,7 +656,7 @@ _xtensa_level5_handler:
_xtensa_level6_handler: _xtensa_level6_handler:
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_6 /* Save interruptee's PS */ rsr a0, EPS_6 /* Save interruptee's PS */
@ -623,6 +666,10 @@ _xtensa_level6_handler:
rsr a0, EXCSAVE_6 /* Save interruptee's a0 */ rsr a0, EXCSAVE_6 /* Save interruptee's a0 */
s32i a0, sp, (4 * REG_A0) s32i a0, sp, (4 * REG_A0)
#ifdef CONFIG_XTENSA_INTBACKTRACE
wsr sp, EXCSAVE_6
#endif
/* Save rest of interrupt context. */ /* Save rest of interrupt context. */
s32i a2, sp, (4 * REG_A2) s32i a2, sp, (4 * REG_A2)
@ -713,7 +760,7 @@ _xtensa_level2_handler:
#if 1 #if 1
/* For now, just panic */ /* For now, just panic */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_2 /* Save interruptee's PS */ rsr a0, EPS_2 /* Save interruptee's PS */
@ -747,7 +794,7 @@ _xtensa_level3_handler:
#if 1 #if 1
/* For now, just panic */ /* For now, just panic */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_3 /* Save interruptee's PS */ rsr a0, EPS_3 /* Save interruptee's PS */
@ -783,7 +830,7 @@ _xtensa_level4_handler:
#if 1 #if 1
/* For now, just panic */ /* For now, just panic */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_4 /* Save interruptee's PS */ rsr a0, EPS_4 /* Save interruptee's PS */
@ -819,7 +866,7 @@ _xtensa_level5_handler:
#if 1 #if 1
/* For now, just panic */ /* For now, just panic */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_5 /* Save interruptee's PS */ rsr a0, EPS_5 /* Save interruptee's PS */
@ -855,7 +902,7 @@ _xtensa_level6_handler:
#if 1 #if 1
/* For now, just panic */ /* For now, just panic */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, EPS_6 /* Save interruptee's PS */ rsr a0, EPS_6 /* Save interruptee's PS */

View File

@ -193,7 +193,7 @@ _xtensa_user_handler:
/* Allocate exception frame and save minimal context. */ /* Allocate exception frame and save minimal context. */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, PS /* Save interruptee's PS */ rsr a0, PS /* Save interruptee's PS */
@ -224,7 +224,24 @@ _xtensa_user_handler:
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
#endif #endif
wsr a0, PS wsr a0, PS
rsync
/* Create pseudo base save area. At this point, sp is still pointing to the
* allocated and filled exception stack frame.
*/
#ifdef CONFIG_XTENSA_INTBACKTRACE
l32i a3, sp, (4 * REG_A0) /* Copy pre-exception a0 (return address) */
s32e a3, sp, -16
l32i a3, sp, (4 * REG_A1) /* Copy pre-exception a1 (stack pointer) */
s32e a3, sp, -12
rsr a0, EPC_1 /* return address for debug backtrace */
movi a4, 0xc0000000 /* constant with top 2 bits set (call size) */
rsync /* wait for WSR.PS to complete */
or a0, a0, a4 /* set top 2 bits */
addx2 a0, a4, a0 /* clear top bit -- thus simulating call4 size */
#else
rsync /* wait for WSR.PS to complete */
#endif
/* Call xtensa_user, passing both the EXCCAUSE and a pointer to the /* Call xtensa_user, passing both the EXCCAUSE and a pointer to the
* beginning of the register save area. * beginning of the register save area.
@ -284,7 +301,7 @@ _xtensa_syscall_handler:
/* Allocate stack frame and save A0, A1, and PS */ /* Allocate stack frame and save A0, A1, and PS */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, PS /* Save interruptee's PS */ rsr a0, PS /* Save interruptee's PS */
@ -451,7 +468,7 @@ _xtensa_coproc_handler:
/* For now, just panic */ /* For now, just panic */
mov a0, sp /* sp == a1 */ mov a0, sp /* Save SP in A0 */
addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */ addi sp, sp, -(4 * XCPTCONTEXT_SIZE) /* Allocate interrupt stack frame */
s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */
rsr a0, PS /* Save interruptee's PS */ rsr a0, PS /* Save interruptee's PS */