aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/kernel/entry-avr32b.S
diff options
context:
space:
mode:
authorHaavard Skinnemoen <hskinnemoen@atmel.com>2007-11-28 09:04:01 -0500
committerHaavard Skinnemoen <hskinnemoen@atmel.com>2007-12-07 08:54:46 -0500
commit2507bc1338e43eadfef5b604d2c47e4f8180718f (patch)
tree4bc3c14114ba96efb8e9e4f2c0925fb92b669a19 /arch/avr32/kernel/entry-avr32b.S
parent8dfe8f29cd371affcc3c6b35658dc4bd95ee7b61 (diff)
[AVR32] Follow the rules when dealing with the OCD system
The current debug trap handling code does a number of things that are illegal according to the AVR32 Architecture manual. Most importantly, it may try to schedule from Debug Mode, thus clearing the D bit, which can lead to "undefined behaviour". It seems like this works in most cases, but several people have observed somewhat unstable behaviour when debugging programs, including soft lockups. So there's definitely something which is not right with the existing code. The new code will never schedule from Debug mode, it will always exit Debug mode with a "retd" instruction, and if something not running in Debug mode needs to do something debug-related (like doing a single step), it will enter debug mode through a "breakpoint" instruction. The monitor code will then return directly to user space, bypassing its own saved registers if necessary (since we don't actually care about the trapped context, only the one that came before.) This adds three instructions to the common exception handling code, including one branch. It does not touch super-hot paths like the TLB miss handler. Signed-off-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Diffstat (limited to 'arch/avr32/kernel/entry-avr32b.S')
-rw-r--r--arch/avr32/kernel/entry-avr32b.S275
1 files changed, 165 insertions, 110 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S
index d7b93f12d8f7..df6c747658c1 100644
--- a/arch/avr32/kernel/entry-avr32b.S
+++ b/arch/avr32/kernel/entry-avr32b.S
@@ -264,16 +264,7 @@ syscall_exit_work:
264 264
2653: bld r1, TIF_BREAKPOINT 2653: bld r1, TIF_BREAKPOINT
266 brcc syscall_exit_cont 266 brcc syscall_exit_cont
267 mfsr r3, SYSREG_TLBEHI 267 rjmp enter_monitor_mode
268 lddsp r2, sp[REG_PC]
269 andl r3, 0xff, COH
270 lsl r3, 1
271 sbr r3, 30
272 sbr r3, 0
273 mtdr OCD_BWA2A, r2
274 mtdr OCD_BWC2A, r3
275 rjmp syscall_exit_cont
276
277 268
278 /* The slow path of the TLB miss handler */ 269 /* The slow path of the TLB miss handler */
279page_table_not_present: 270page_table_not_present:
@@ -288,11 +279,16 @@ page_not_present:
288 rjmp ret_from_exception 279 rjmp ret_from_exception
289 280
290 /* This function expects to find offending PC in SYSREG_RAR_EX */ 281 /* This function expects to find offending PC in SYSREG_RAR_EX */
282 .type save_full_context_ex, @function
283 .align 2
291save_full_context_ex: 284save_full_context_ex:
285 mfsr r11, SYSREG_RAR_EX
286 sub r9, pc, . - debug_trampoline
292 mfsr r8, SYSREG_RSR_EX 287 mfsr r8, SYSREG_RSR_EX
288 cp.w r9, r11
289 breq 3f
293 mov r12, r8 290 mov r12, r8
294 andh r8, (MODE_MASK >> 16), COH 291 andh r8, (MODE_MASK >> 16), COH
295 mfsr r11, SYSREG_RAR_EX
296 brne 2f 292 brne 2f
297 293
2981: pushm r11, r12 /* PC and SR */ 2941: pushm r11, r12 /* PC and SR */
@@ -303,6 +299,21 @@ save_full_context_ex:
303 stdsp sp[4], r10 /* replace saved SP */ 299 stdsp sp[4], r10 /* replace saved SP */
304 rjmp 1b 300 rjmp 1b
305 301
302 /*
303 * The debug handler set up a trampoline to make us
304 * automatically enter monitor mode upon return, but since
305 * we're saving the full context, we must assume that the
306 * exception handler might want to alter the return address
307 * and/or status register. So we need to restore the original
308 * context and enter monitor mode manually after the exception
309 * has been handled.
310 */
3113: get_thread_info r8
312 ld.w r11, r8[TI_rar_saved]
313 ld.w r12, r8[TI_rsr_saved]
314 rjmp 1b
315 .size save_full_context_ex, . - save_full_context_ex
316
306 /* Low-level exception handlers */ 317 /* Low-level exception handlers */
307handle_critical: 318handle_critical:
308 pushm r12 319 pushm r12
@@ -439,6 +450,7 @@ do_fpe_ll:
439ret_from_exception: 450ret_from_exception:
440 mask_interrupts 451 mask_interrupts
441 lddsp r4, sp[REG_SR] 452 lddsp r4, sp[REG_SR]
453
442 andh r4, (MODE_MASK >> 16), COH 454 andh r4, (MODE_MASK >> 16), COH
443 brne fault_resume_kernel 455 brne fault_resume_kernel
444 456
@@ -515,34 +527,76 @@ fault_exit_work:
515 527
5162: bld r1, TIF_BREAKPOINT 5282: bld r1, TIF_BREAKPOINT
517 brcc fault_resume_user 529 brcc fault_resume_user
518 mfsr r3, SYSREG_TLBEHI 530 rjmp enter_monitor_mode
519 lddsp r2, sp[REG_PC] 531
520 andl r3, 0xff, COH 532 .section .kprobes.text, "ax", @progbits
521 lsl r3, 1 533 .type handle_debug, @function
522 sbr r3, 30 534handle_debug:
523 sbr r3, 0 535 sub sp, 4 /* r12_orig */
524 mtdr OCD_BWA2A, r2 536 stmts --sp, r0-lr
525 mtdr OCD_BWC2A, r3 537 mfsr r8, SYSREG_RAR_DBG
526 rjmp fault_resume_user 538 mfsr r9, SYSREG_RSR_DBG
527 539 unmask_exceptions
528 /* If we get a debug trap from privileged context we end up here */ 540 pushm r8-r9
529handle_debug_priv: 541 bfextu r9, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
530 /* Fix up LR and SP in regs. r1 contains the mode we came from */ 542 brne debug_fixup_regs
531 mfsr r2, SYSREG_SR 543
532 mov r3, r2 544.Ldebug_fixup_cont:
533 bfins r2, r1, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE 545#ifdef CONFIG_TRACE_IRQFLAGS
534 mtsr SYSREG_SR, r2 546 rcall trace_hardirqs_off
547#endif
548 mov r12, sp
549 rcall do_debug
550 mov sp, r12
551
552 lddsp r2, sp[REG_SR]
553 bfextu r3, r2, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
554 brne debug_resume_kernel
555
556 get_thread_info r0
557 ld.w r1, r0[TI_flags]
558 mov r2, _TIF_DBGWORK_MASK
559 tst r1, r2
560 brne debug_exit_work
561
562 bld r1, TIF_SINGLE_STEP
563 brcc 1f
564 mfdr r4, OCD_DC
565 sbr r4, OCD_DC_SS_BIT
566 mtdr OCD_DC, r4
567
5681: popm r10,r11
569 mask_exceptions
570 mtsr SYSREG_RSR_DBG, r11
571 mtsr SYSREG_RAR_DBG, r10
572#ifdef CONFIG_TRACE_IRQFLAGS
573 rcall trace_hardirqs_on
5741:
575#endif
576 ldmts sp++, r0-lr
577 sub sp, -4
578 retd
579 .size handle_debug, . - handle_debug
580
581 /* Mode of the trapped context is in r9 */
582 .type debug_fixup_regs, @function
583debug_fixup_regs:
584 mfsr r8, SYSREG_SR
585 mov r10, r8
586 bfins r8, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
587 mtsr SYSREG_SR, r8
535 sub pc, -2 588 sub pc, -2
536 stdsp sp[REG_LR], lr 589 stdsp sp[REG_LR], lr
537 mtsr SYSREG_SR, r3 590 mtsr SYSREG_SR, r10
538 sub pc, -2 591 sub pc, -2
539 sub r10, sp, -FRAME_SIZE_FULL 592 sub r8, sp, -FRAME_SIZE_FULL
540 stdsp sp[REG_SP], r10 593 stdsp sp[REG_SP], r8
541 mov r12, sp 594 rjmp .Ldebug_fixup_cont
542 rcall do_debug_priv 595 .size debug_fixup_regs, . - debug_fixup_regs
543 596
544 /* Now, put everything back */ 597 .type debug_resume_kernel, @function
545 ssrf SR_EM_BIT 598debug_resume_kernel:
599 mask_exceptions
546 popm r10, r11 600 popm r10, r11
547 mtsr SYSREG_RAR_DBG, r10 601 mtsr SYSREG_RAR_DBG, r10
548 mtsr SYSREG_RSR_DBG, r11 602 mtsr SYSREG_RSR_DBG, r11
@@ -553,93 +607,44 @@ handle_debug_priv:
5531: 6071:
554#endif 608#endif
555 mfsr r2, SYSREG_SR 609 mfsr r2, SYSREG_SR
556 mov r3, r2 610 mov r1, r2
557 bfins r2, r1, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE 611 bfins r2, r3, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
558 mtsr SYSREG_SR, r2 612 mtsr SYSREG_SR, r2
559 sub pc, -2 613 sub pc, -2
560 popm lr 614 popm lr
561 mtsr SYSREG_SR, r3 615 mtsr SYSREG_SR, r1
562 sub pc, -2 616 sub pc, -2
563 sub sp, -4 /* skip SP */ 617 sub sp, -4 /* skip SP */
564 popm r0-r12 618 popm r0-r12
565 sub sp, -4 619 sub sp, -4
566 retd 620 retd
621 .size debug_resume_kernel, . - debug_resume_kernel
567 622
623 .type debug_exit_work, @function
624debug_exit_work:
568 /* 625 /*
569 * At this point, everything is masked, that is, interrupts, 626 * We must return from Monitor Mode using a retd, and we must
570 * exceptions and debugging traps. We might get called from 627 * not schedule since that involves the D bit in SR getting
571 * interrupt or exception context in some rare cases, but this 628 * cleared by something other than the debug hardware. This
572 * will be taken care of by do_debug(), so we're not going to 629 * may cause undefined behaviour according to the Architecture
573 * do a 100% correct context save here. 630 * manual.
631 *
632 * So we fix up the return address and status and return to a
633 * stub below in Exception mode. From there, we can follow the
634 * normal exception return path.
635 *
636 * The real return address and status registers are stored on
637 * the stack in the way the exception return path understands,
638 * so no need to fix anything up there.
574 */ 639 */
575handle_debug: 640 sub r8, pc, . - fault_exit_work
576 sub sp, 4 /* r12_orig */ 641 mtsr SYSREG_RAR_DBG, r8
577 stmts --sp, r0-lr 642 mov r9, 0
578 mfsr r0, SYSREG_RAR_DBG 643 orh r9, hi(SR_EM | SR_GM | MODE_EXCEPTION)
579 mfsr r1, SYSREG_RSR_DBG 644 mtsr SYSREG_RSR_DBG, r9
580#ifdef CONFIG_TRACE_IRQFLAGS 645 sub pc, -2
581 rcall trace_hardirqs_off
582#endif
583 unmask_exceptions
584 stm --sp, r0, r1
585 bfextu r1, r1, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
586 brne handle_debug_priv
587
588 mov r12, sp
589 rcall do_debug
590
591 lddsp r10, sp[REG_SR]
592 andh r10, (MODE_MASK >> 16), COH
593 breq debug_resume_user
594
595debug_restore_all:
596 popm r10,r11
597 mask_exceptions
598 mtsr SYSREG_RSR_DBG, r11
599 mtsr SYSREG_RAR_DBG, r10
600#ifdef CONFIG_TRACE_IRQFLAGS
601 bld r11, SYSREG_GM_OFFSET
602 brcc 1f
603 rcall trace_hardirqs_on
6041:
605#endif
606 ldmts sp++, r0-lr
607 sub sp, -4
608 retd 646 retd
609 647 .size debug_exit_work, . - debug_exit_work
610debug_resume_user:
611 get_thread_info r0
612 mask_interrupts
613
614 ld.w r1, r0[TI_flags]
615 andl r1, _TIF_DBGWORK_MASK, COH
616 breq debug_restore_all
617
6181: bld r1, TIF_NEED_RESCHED
619 brcc 2f
620 unmask_interrupts
621 rcall schedule
622 mask_interrupts
623 ld.w r1, r0[TI_flags]
624 rjmp 1b
625
6262: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
627 tst r1, r2
628 breq 3f
629 unmask_interrupts
630 mov r12, sp
631 mov r11, r0
632 rcall do_notify_resume
633 mask_interrupts
634 ld.w r1, r0[TI_flags]
635 rjmp 1b
636
6373: bld r1, TIF_SINGLE_STEP
638 brcc debug_restore_all
639 mfdr r2, OCD_DC
640 sbr r2, OCD_DC_SS_BIT
641 mtdr OCD_DC, r2
642 rjmp debug_restore_all
643 648
644 .set rsr_int0, SYSREG_RSR_INT0 649 .set rsr_int0, SYSREG_RSR_INT0
645 .set rsr_int1, SYSREG_RSR_INT1 650 .set rsr_int1, SYSREG_RSR_INT1
@@ -764,3 +769,53 @@ cpu_idle_enable_int_and_exit:
764 IRQ_LEVEL 1 769 IRQ_LEVEL 1
765 IRQ_LEVEL 2 770 IRQ_LEVEL 2
766 IRQ_LEVEL 3 771 IRQ_LEVEL 3
772
773 .section .kprobes.text, "ax", @progbits
774 .type enter_monitor_mode, @function
775enter_monitor_mode:
776 /*
777 * We need to enter monitor mode to do a single step. The
778 * monitor code will alter the return address so that we
779 * return directly to the user instead of returning here.
780 */
781 breakpoint
782 rjmp breakpoint_failed
783
784 .size enter_monitor_mode, . - enter_monitor_mode
785
786 .type debug_trampoline, @function
787 .global debug_trampoline
788debug_trampoline:
789 /*
790 * Save the registers on the stack so that the monitor code
791 * can find them easily.
792 */
793 sub sp, 4 /* r12_orig */
794 stmts --sp, r0-lr
795 get_thread_info r0
796 ld.w r8, r0[TI_rar_saved]
797 ld.w r9, r0[TI_rsr_saved]
798 pushm r8-r9
799
800 /*
801 * The monitor code will alter the return address so we don't
802 * return here.
803 */
804 breakpoint
805 rjmp breakpoint_failed
806 .size debug_trampoline, . - debug_trampoline
807
808 .type breakpoint_failed, @function
809breakpoint_failed:
810 /*
811 * Something went wrong. Perhaps the debug hardware isn't
812 * enabled?
813 */
814 lda.w r12, msg_breakpoint_failed
815 mov r11, sp
816 mov r10, 9 /* SIGKILL */
817 call die
8181: rjmp 1b
819
820msg_breakpoint_failed:
821 .asciz "Failed to enter Debug Mode"