aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Filippov <jcmvbkbc@gmail.com>2015-06-25 16:03:29 -0400
committerMax Filippov <jcmvbkbc@gmail.com>2015-08-17 00:32:48 -0400
commitb6569439f1cec0ce15f647e2ba814431b5930b82 (patch)
treeb821980f450559146b93175f5ff381996d27c4f0
parentde7c1c7862c4072bc93155da2cd6921137cb87ae (diff)
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>
-rw-r--r--arch/xtensa/kernel/entry.S43
1 files changed, 28 insertions, 15 deletions
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 51e9877ced06..e955f6098f64 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -122,6 +122,7 @@ _user_exception:
122 /* Save SAR and turn off single stepping */ 122 /* Save SAR and turn off single stepping */
123 123
124 movi a2, 0 124 movi a2, 0
125 wsr a2, depc # terminate user stack trace with 0
125 rsr a3, sar 126 rsr a3, sar
126 xsr a2, icountlevel 127 xsr a2, icountlevel
127 s32i a3, a1, PT_SAR 128 s32i a3, a1, PT_SAR
@@ -301,7 +302,18 @@ _kernel_exception:
301 s32i a14, a1, PT_AREG14 302 s32i a14, a1, PT_AREG14
302 s32i a15, a1, PT_AREG15 303 s32i a15, a1, PT_AREG15
303 304
305 _bnei a2, 1, 1f
306
307 /* Copy spill slots of a0 and a1 to imitate movsp
308 * in order to keep exception stack continuous
309 */
310 l32i a3, a1, PT_SIZE
311 l32i a0, a1, PT_SIZE + 4
312 s32e a3, a1, -16
313 s32e a0, a1, -12
3041: 3141:
315 l32i a0, a1, PT_AREG0 # restore saved a0
316 wsr a0, depc
305 317
306#ifdef KERNEL_STACK_OVERFLOW_CHECK 318#ifdef KERNEL_STACK_OVERFLOW_CHECK
307 319
@@ -346,12 +358,12 @@ common_exception:
346 s32i a0, a1, PT_EXCCAUSE 358 s32i a0, a1, PT_EXCCAUSE
347 s32i a3, a2, EXC_TABLE_FIXUP 359 s32i a3, a2, EXC_TABLE_FIXUP
348 360
349 /* All unrecoverable states are saved on stack, now, and a1 is valid, 361 /* All unrecoverable states are saved on stack, now, and a1 is valid.
350 * so we can allow exceptions and interrupts (*) again. 362 * Now we can allow exceptions again. In case we've got an interrupt
351 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X) 363 * PS.INTLEVEL is set to LOCKLEVEL disabling furhter interrupts,
364 * otherwise it's left unchanged.
352 * 365 *
353 * (*) We only allow interrupts if they were previously enabled and 366 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
354 * we're not handling an IRQ
355 */ 367 */
356 368
357 rsr a3, ps 369 rsr a3, ps
@@ -362,28 +374,30 @@ common_exception:
362 moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt 374 moveqz a3, a2, a0 # a3 = LOCKLEVEL iff interrupt
363 movi a2, 1 << PS_WOE_BIT 375 movi a2, 1 << PS_WOE_BIT
364 or a3, a3, a2 376 or a3, a3, a2
365 rsr a0, exccause 377 rsr a2, exccause
378 /* restore return address (or 0 if return to userspace) */
379 rsr a0, depc
366 xsr a3, ps 380 xsr a3, ps
367 381
368 s32i a3, a1, PT_PS # save ps 382 s32i a3, a1, PT_PS # save ps
369 383
370 /* Save lbeg, lend */ 384 /* Save lbeg, lend */
371 385
372 rsr a2, lbeg 386 rsr a4, lbeg
373 rsr a3, lend 387 rsr a3, lend
374 s32i a2, a1, PT_LBEG 388 s32i a4, a1, PT_LBEG
375 s32i a3, a1, PT_LEND 389 s32i a3, a1, PT_LEND
376 390
377 /* Save SCOMPARE1 */ 391 /* Save SCOMPARE1 */
378 392
379#if XCHAL_HAVE_S32C1I 393#if XCHAL_HAVE_S32C1I
380 rsr a2, scompare1 394 rsr a3, scompare1
381 s32i a2, a1, PT_SCOMPARE1 395 s32i a3, a1, PT_SCOMPARE1
382#endif 396#endif
383 397
384 /* Save optional registers. */ 398 /* Save optional registers. */
385 399
386 save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT 400 save_xtregs_opt a1 a3 a4 a5 a6 a7 PT_XTREGS_OPT
387 401
388#ifdef CONFIG_TRACE_IRQFLAGS 402#ifdef CONFIG_TRACE_IRQFLAGS
389 l32i a4, a1, PT_DEPC 403 l32i a4, a1, PT_DEPC
@@ -391,8 +405,7 @@ common_exception:
391 * while PS.EXCM was set, i.e. interrupts disabled. 405 * while PS.EXCM was set, i.e. interrupts disabled.
392 */ 406 */
393 bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f 407 bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
394 l32i a4, a1, PT_EXCCAUSE 408 bnei a2, EXCCAUSE_LEVEL1_INTERRUPT, 1f
395 bnei a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f
396 /* We came here with an interrupt means interrupts were enabled 409 /* We came here with an interrupt means interrupts were enabled
397 * and we've just disabled them. 410 * and we've just disabled them.
398 */ 411 */
@@ -407,8 +420,8 @@ common_exception:
407 420
408 rsr a4, excsave1 421 rsr a4, excsave1
409 mov a6, a1 # pass stack frame 422 mov a6, a1 # pass stack frame
410 mov a7, a0 # pass EXCCAUSE 423 mov a7, a2 # pass EXCCAUSE
411 addx4 a4, a0, a4 424 addx4 a4, a2, a4
412 l32i a4, a4, EXC_TABLE_DEFAULT # load handler 425 l32i a4, a4, EXC_TABLE_DEFAULT # load handler
413 426
414 /* Call the second-level handler */ 427 /* Call the second-level handler */