Restore original a0 in the kernel exception stack frame. This way it looks like the frame that got interrupt/exception did alloca (copy a0 and a1 potentially spilled under old stack to the new location as well) to save registers and then did a call to handler. The point where interrupt/exception was taken is not in the stack chain, only in pt_regs (call4 from that address can be simulated to keep it in the stack trace).
Signed-off-by: Max Filippov <[email protected]> --- Changes v1->v2: - make continuous stack changes conditional; - replace l32i/s32i + add used to access spilled registers with l32e/s32e. arch/xtensa/kernel/entry.S | 59 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S index 82bbfa5..b64075f 100644 --- a/arch/xtensa/kernel/entry.S +++ b/arch/xtensa/kernel/entry.S @@ -28,6 +28,10 @@ #include <asm/tlbflush.h> #include <variant/tie-asm.h> +#if defined(CONFIG_DEBUG_KERNEL) || defined(CONFIG_STACKTRACE_SUPPORT) +#define XTENSA_CONTINUOUS_STACK +#endif + /* Unimplemented features. */ #undef KERNEL_STACK_OVERFLOW_CHECK @@ -219,6 +223,10 @@ _user_exception: 2: /* Now, jump to the common exception handler. */ +#ifdef XTENSA_CONTINUOUS_STACK + movi a0, 0 # terminate user stack trace with 0 + wsr a0, depc +#endif j common_exception ENDPROC(user_exception) @@ -264,6 +272,24 @@ ENTRY(kernel_exception) .globl _kernel_exception _kernel_exception: + /* Copy spill slots of a0 and a1 to imitate movsp + * in order to keep exception stack continuous + */ +#ifdef XTENSA_CONTINUOUS_STACK + /* Reload previous stack pointer: l32e relative to the current stack + * won't reach it, because kernel exception stack frame is definitely + * larger than l32e range (64 bytes). + */ + l32i a0, a1, PT_AREG1 + l32e a3, a0, -16 + l32e a0, a0, -12 + s32e a3, a1, -16 + s32e a0, a1, -12 + + l32i a0, a1, PT_AREG0 # restore saved a0 + wsr a0, depc +#endif + /* Save SAR and turn off single stepping */ movi a2, 0 @@ -346,12 +372,12 @@ common_exception: s32i a0, a1, PT_EXCCAUSE s32i a3, a2, EXC_TABLE_FIXUP - /* All unrecoverable states are saved on stack, now, and a1 is valid, - * so we can allow exceptions and interrupts (*) again. - * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) + /* All unrecoverable states are saved on stack, now, and a1 is valid. + * Now we can allow exceptions again. In case we've got an interrupt + * PS.INTLEVEL is set to LOCKLEVEL disabling furhter interrupts, + * otherwise it's left unchanged. * - * (*) We only allow interrupts if they were previously enabled and - * we're not handling an IRQ + * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) */ rsr a3, ps @@ -362,28 +388,32 @@ common_exception: moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt movi a2, 1 << PS_WOE_BIT or a3, a3, a2 - rsr a0, exccause + rsr a2, exccause +#ifdef XTENSA_CONTINUOUS_STACK + /* restore return address (or 0 if return to userspace) */ + rsr a0, depc +#endif xsr a3, ps s32i a3, a1, PT_PS # save ps /* Save lbeg, lend */ - rsr a2, lbeg + rsr a4, lbeg rsr a3, lend - s32i a2, a1, PT_LBEG + s32i a4, a1, PT_LBEG s32i a3, a1, PT_LEND /* Save SCOMPARE1 */ #if XCHAL_HAVE_S32C1I - rsr a2, scompare1 - s32i a2, a1, PT_SCOMPARE1 + rsr a3, scompare1 + s32i a3, a1, PT_SCOMPARE1 #endif /* Save optional registers. */ - save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT + save_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT #ifdef CONFIG_TRACE_IRQFLAGS l32i a4, a1, PT_DEPC @@ -391,8 +421,7 @@ common_exception: * while PS.EXCM was set, i.e. interrupts disabled. */ bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f - l32i a4, a1, PT_EXCCAUSE - bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f + bnei a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f /* We came here with an interrupt means interrupts were enabled * and we've just disabled them. */ @@ -407,8 +436,8 @@ common_exception: rsr a4, excsave1 mov a6, a1 # pass stack frame - mov a7, a0 # pass EXCCAUSE - addx4 a4, a0, a4 + mov a7, a2 # pass EXCCAUSE + addx4 a4, a2, a4 l32i a4, a4, EXC_TABLE_DEFAULT # load handler /* Call the second-level handler */ -- 1.8.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

