diff options
Diffstat (limited to 'arch/avr32/kernel/entry-avr32b.S')
-rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 275 |
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 | ||
265 | 3: bld r1, TIF_BREAKPOINT | 265 | 3: 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 */ |
279 | page_table_not_present: | 270 | page_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 | ||
291 | save_full_context_ex: | 284 | save_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 | ||
298 | 1: pushm r11, r12 /* PC and SR */ | 294 | 1: 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 | */ | ||
311 | 3: 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 */ |
307 | handle_critical: | 318 | handle_critical: |
308 | pushm r12 | 319 | pushm r12 |
@@ -439,6 +450,7 @@ do_fpe_ll: | |||
439 | ret_from_exception: | 450 | ret_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 | ||
516 | 2: bld r1, TIF_BREAKPOINT | 528 | 2: 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 | 534 | handle_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 |
529 | handle_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 | |||
568 | 1: 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 | ||
574 | 1: | ||
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 | ||
583 | debug_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 | 598 | debug_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: | |||
553 | 1: | 607 | 1: |
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 | ||
624 | debug_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 | */ |
575 | handle_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 | |||
595 | debug_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 | ||
604 | 1: | ||
605 | #endif | ||
606 | ldmts sp++, r0-lr | ||
607 | sub sp, -4 | ||
608 | retd | 646 | retd |
609 | 647 | .size debug_exit_work, . - debug_exit_work | |
610 | debug_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 | |||
618 | 1: 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 | |||
626 | 2: 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 | |||
637 | 3: 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 | ||
775 | enter_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 | ||
788 | debug_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 | ||
809 | breakpoint_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 | ||
818 | 1: rjmp 1b | ||
819 | |||
820 | msg_breakpoint_failed: | ||
821 | .asciz "Failed to enter Debug Mode" | ||