xtensa: keep exception/interrupt stack continuous
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 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 <jcmvbkbc@gmail.com>
This commit is contained in:
parent
de7c1c7862
commit
b6569439f1
|
@ -122,6 +122,7 @@ _user_exception:
|
||||||
/* Save SAR and turn off single stepping */
|
/* Save SAR and turn off single stepping */
|
||||||
|
|
||||||
movi a2, 0
|
movi a2, 0
|
||||||
|
wsr a2, depc # terminate user stack trace with 0
|
||||||
rsr a3, sar
|
rsr a3, sar
|
||||||
xsr a2, icountlevel
|
xsr a2, icountlevel
|
||||||
s32i a3, a1, PT_SAR
|
s32i a3, a1, PT_SAR
|
||||||
|
@ -301,7 +302,18 @@ _kernel_exception:
|
||||||
s32i a14, a1, PT_AREG14
|
s32i a14, a1, PT_AREG14
|
||||||
s32i a15, a1, PT_AREG15
|
s32i a15, a1, PT_AREG15
|
||||||
|
|
||||||
|
_bnei a2, 1, 1f
|
||||||
|
|
||||||
|
/* Copy spill slots of a0 and a1 to imitate movsp
|
||||||
|
* in order to keep exception stack continuous
|
||||||
|
*/
|
||||||
|
l32i a3, a1, PT_SIZE
|
||||||
|
l32i a0, a1, PT_SIZE + 4
|
||||||
|
s32e a3, a1, -16
|
||||||
|
s32e a0, a1, -12
|
||||||
1:
|
1:
|
||||||
|
l32i a0, a1, PT_AREG0 # restore saved a0
|
||||||
|
wsr a0, depc
|
||||||
|
|
||||||
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
#ifdef KERNEL_STACK_OVERFLOW_CHECK
|
||||||
|
|
||||||
|
@ -346,12 +358,12 @@ common_exception:
|
||||||
s32i a0, a1, PT_EXCCAUSE
|
s32i a0, a1, PT_EXCCAUSE
|
||||||
s32i a3, a2, EXC_TABLE_FIXUP
|
s32i a3, a2, EXC_TABLE_FIXUP
|
||||||
|
|
||||||
/* All unrecoverable states are saved on stack, now, and a1 is valid,
|
/* All unrecoverable states are saved on stack, now, and a1 is valid.
|
||||||
* so we can allow exceptions and interrupts (*) again.
|
* Now we can allow exceptions again. In case we've got an interrupt
|
||||||
* Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
|
* PS.INTLEVEL is set to LOCKLEVEL disabling furhter interrupts,
|
||||||
|
* otherwise it's left unchanged.
|
||||||
*
|
*
|
||||||
* (*) We only allow interrupts if they were previously enabled and
|
* Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
|
||||||
* we're not handling an IRQ
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
rsr a3, ps
|
rsr a3, ps
|
||||||
|
@ -362,28 +374,30 @@ common_exception:
|
||||||
moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt
|
moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt
|
||||||
movi a2, 1 << PS_WOE_BIT
|
movi a2, 1 << PS_WOE_BIT
|
||||||
or a3, a3, a2
|
or a3, a3, a2
|
||||||
rsr a0, exccause
|
rsr a2, exccause
|
||||||
|
/* restore return address (or 0 if return to userspace) */
|
||||||
|
rsr a0, depc
|
||||||
xsr a3, ps
|
xsr a3, ps
|
||||||
|
|
||||||
s32i a3, a1, PT_PS # save ps
|
s32i a3, a1, PT_PS # save ps
|
||||||
|
|
||||||
/* Save lbeg, lend */
|
/* Save lbeg, lend */
|
||||||
|
|
||||||
rsr a2, lbeg
|
rsr a4, lbeg
|
||||||
rsr a3, lend
|
rsr a3, lend
|
||||||
s32i a2, a1, PT_LBEG
|
s32i a4, a1, PT_LBEG
|
||||||
s32i a3, a1, PT_LEND
|
s32i a3, a1, PT_LEND
|
||||||
|
|
||||||
/* Save SCOMPARE1 */
|
/* Save SCOMPARE1 */
|
||||||
|
|
||||||
#if XCHAL_HAVE_S32C1I
|
#if XCHAL_HAVE_S32C1I
|
||||||
rsr a2, scompare1
|
rsr a3, scompare1
|
||||||
s32i a2, a1, PT_SCOMPARE1
|
s32i a3, a1, PT_SCOMPARE1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Save optional registers. */
|
/* 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
|
#ifdef CONFIG_TRACE_IRQFLAGS
|
||||||
l32i a4, a1, PT_DEPC
|
l32i a4, a1, PT_DEPC
|
||||||
|
@ -391,8 +405,7 @@ common_exception:
|
||||||
* while PS.EXCM was set, i.e. interrupts disabled.
|
* while PS.EXCM was set, i.e. interrupts disabled.
|
||||||
*/
|
*/
|
||||||
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
|
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
|
||||||
l32i a4, a1, PT_EXCCAUSE
|
bnei a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f
|
||||||
bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f
|
|
||||||
/* We came here with an interrupt means interrupts were enabled
|
/* We came here with an interrupt means interrupts were enabled
|
||||||
* and we've just disabled them.
|
* and we've just disabled them.
|
||||||
*/
|
*/
|
||||||
|
@ -407,8 +420,8 @@ common_exception:
|
||||||
|
|
||||||
rsr a4, excsave1
|
rsr a4, excsave1
|
||||||
mov a6, a1 # pass stack frame
|
mov a6, a1 # pass stack frame
|
||||||
mov a7, a0 # pass EXCCAUSE
|
mov a7, a2 # pass EXCCAUSE
|
||||||
addx4 a4, a0, a4
|
addx4 a4, a2, a4
|
||||||
l32i a4, a4, EXC_TABLE_DEFAULT # load handler
|
l32i a4, a4, EXC_TABLE_DEFAULT # load handler
|
||||||
|
|
||||||
/* Call the second-level handler */
|
/* Call the second-level handler */
|
||||||
|
|
Loading…
Reference in New Issue