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/

Reply via email to