From 7075c989781d7a058d9bbc456c1507475fa57790 Mon Sep 17 00:00:00 2001 From: Abdelatif Guettouche Date: Tue, 1 Dec 2020 16:53:57 +0000 Subject: [PATCH] arch/xtensa: Add a pseudo save area to be able to backtrace from interrupts Signed-off-by: Abdelatif Guettouche --- arch/xtensa/Kconfig | 7 ++ arch/xtensa/src/common/xtensa_int_handlers.S | 69 ++++++++++++++++---- arch/xtensa/src/common/xtensa_user_handler.S | 25 +++++-- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 19864577fa..6253c77126 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -108,6 +108,13 @@ config XTENSA_BTDEPTH ---help--- 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 bool "Use a separate heap for internal memory" default n diff --git a/arch/xtensa/src/common/xtensa_int_handlers.S b/arch/xtensa/src/common/xtensa_int_handlers.S index 16b4a0f637..c75fefa602 100644 --- a/arch/xtensa/src/common/xtensa_int_handlers.S +++ b/arch/xtensa/src/common/xtensa_int_handlers.S @@ -187,6 +187,29 @@ g_intstackbase: and a6, a6, a3 /* a6 = Set of pending, enabled interrupts for this level */ 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 * as a parameter (A7). */ @@ -270,7 +293,7 @@ g_intstackbase: _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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, PS /* Save interruptee's PS */ @@ -280,6 +303,10 @@ _xtensa_level1_handler: rsr a0, EXCSAVE_1 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) +#ifdef CONFIG_XTENSA_INTBACKTRACE + wsr sp, EXCSAVE_1 +#endif + /* Save rest of interrupt context. */ s32i a2, sp, (4 * REG_A2) @@ -369,7 +396,7 @@ _xtensa_level1_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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_2 /* Save interruptee's PS */ @@ -379,6 +406,10 @@ _xtensa_level2_handler: rsr a0, EXCSAVE_2 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) +#ifdef CONFIG_XTENSA_INTBACKTRACE + wsr sp, EXCSAVE_2 +#endif + /* Save rest of interrupt context. */ s32i a2, sp, (4 * REG_A2) @@ -430,7 +461,7 @@ _xtensa_level2_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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_3 /* Save interruptee's PS */ @@ -440,6 +471,10 @@ _xtensa_level3_handler: rsr a0, EXCSAVE_3 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) +#ifdef CONFIG_XTENSA_INTBACKTRACE + wsr sp, EXCSAVE_3 +#endif + /* Save rest of interrupt context. */ s32i a2, sp, (4 * REG_A2) @@ -491,7 +526,7 @@ _xtensa_level3_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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_4 /* Save interruptee's PS */ @@ -501,6 +536,10 @@ _xtensa_level4_handler: rsr a0, EXCSAVE_4 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) +#ifdef CONFIG_XTENSA_INTBACKTRACE + wsr sp, EXCSAVE_4 +#endif + /* Save rest of interrupt context. */ s32i a2, sp, (4 * REG_A2) @@ -552,7 +591,7 @@ _xtensa_level4_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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_5 /* Save interruptee's PS */ @@ -562,6 +601,10 @@ _xtensa_level5_handler: rsr a0, EXCSAVE_5 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) +#ifdef CONFIG_XTENSA_INTBACKTRACE + wsr sp, EXCSAVE_5 +#endif + /* Save rest of interrupt context. */ s32i a2, sp, (4 * REG_A2) @@ -613,7 +656,7 @@ _xtensa_level5_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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_6 /* Save interruptee's PS */ @@ -623,6 +666,10 @@ _xtensa_level6_handler: rsr a0, EXCSAVE_6 /* Save interruptee's a0 */ s32i a0, sp, (4 * REG_A0) +#ifdef CONFIG_XTENSA_INTBACKTRACE + wsr sp, EXCSAVE_6 +#endif + /* Save rest of interrupt context. */ s32i a2, sp, (4 * REG_A2) @@ -713,7 +760,7 @@ _xtensa_level2_handler: #if 1 /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_2 /* Save interruptee's PS */ @@ -747,7 +794,7 @@ _xtensa_level3_handler: #if 1 /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_3 /* Save interruptee's PS */ @@ -783,7 +830,7 @@ _xtensa_level4_handler: #if 1 /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_4 /* Save interruptee's PS */ @@ -819,7 +866,7 @@ _xtensa_level5_handler: #if 1 /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_5 /* Save interruptee's PS */ @@ -855,7 +902,7 @@ _xtensa_level6_handler: #if 1 /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, EPS_6 /* Save interruptee's PS */ diff --git a/arch/xtensa/src/common/xtensa_user_handler.S b/arch/xtensa/src/common/xtensa_user_handler.S index bc01f5355c..5fb94f6f14 100644 --- a/arch/xtensa/src/common/xtensa_user_handler.S +++ b/arch/xtensa/src/common/xtensa_user_handler.S @@ -193,7 +193,7 @@ _xtensa_user_handler: /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ 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 #endif 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 * beginning of the register save area. @@ -284,7 +301,7 @@ _xtensa_syscall_handler: /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, PS /* Save interruptee's PS */ @@ -451,7 +468,7 @@ _xtensa_coproc_handler: /* 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 */ s32i a0, sp, (4 * REG_A1) /* Save pre-interrupt SP */ rsr a0, PS /* Save interruptee's PS */