diff options
| -rw-r--r-- | arch/tile/include/asm/traps.h | 4 | ||||
| -rw-r--r-- | arch/tile/kernel/intvec_32.S | 7 | ||||
| -rw-r--r-- | arch/tile/kernel/single_step.c | 73 | ||||
| -rw-r--r-- | arch/tile/kernel/traps.c | 2 |
4 files changed, 83 insertions, 3 deletions
diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h index 432a9c15c8a2..d06e35f57201 100644 --- a/arch/tile/include/asm/traps.h +++ b/arch/tile/include/asm/traps.h | |||
| @@ -59,4 +59,8 @@ void do_hardwall_trap(struct pt_regs *, int fault_num); | |||
| 59 | void do_breakpoint(struct pt_regs *, int fault_num); | 59 | void do_breakpoint(struct pt_regs *, int fault_num); |
| 60 | 60 | ||
| 61 | 61 | ||
| 62 | #ifdef __tilegx__ | ||
| 63 | void gx_singlestep_handle(struct pt_regs *, int fault_num); | ||
| 64 | #endif | ||
| 65 | |||
| 62 | #endif /* _ASM_TILE_SYSCALLS_H */ | 66 | #endif /* _ASM_TILE_SYSCALLS_H */ |
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index 206dc7e1fe36..f5821626247f 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S | |||
| @@ -1472,7 +1472,12 @@ handle_ill: | |||
| 1472 | lw r26, r24 | 1472 | lw r26, r24 |
| 1473 | sw r28, r26 | 1473 | sw r28, r26 |
| 1474 | 1474 | ||
| 1475 | /* Clear TIF_SINGLESTEP */ | 1475 | /* |
| 1476 | * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill. | ||
| 1477 | * The normal non-arch flow redundantly clears TIF_SINGLESTEP, but we | ||
| 1478 | * need to clear it here and can't really impose on all other arches. | ||
| 1479 | * So what's another write between friends? | ||
| 1480 | */ | ||
| 1476 | GET_THREAD_INFO(r0) | 1481 | GET_THREAD_INFO(r0) |
| 1477 | 1482 | ||
| 1478 | addi r1, r0, THREAD_INFO_FLAGS_OFFSET | 1483 | addi r1, r0, THREAD_INFO_FLAGS_OFFSET |
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 5ec4b9c651f2..1eb3b39e36c7 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | * Derived from iLib's single-stepping code. | 15 | * Derived from iLib's single-stepping code. |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #ifndef __tilegx__ /* No support for single-step yet. */ | 18 | #ifndef __tilegx__ /* Hardware support for single step unavailable. */ |
| 19 | 19 | ||
| 20 | /* These functions are only used on the TILE platform */ | 20 | /* These functions are only used on the TILE platform */ |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| @@ -660,4 +660,75 @@ void single_step_once(struct pt_regs *regs) | |||
| 660 | regs->pc += 8; | 660 | regs->pc += 8; |
| 661 | } | 661 | } |
| 662 | 662 | ||
| 663 | #else | ||
| 664 | #include <linux/smp.h> | ||
| 665 | #include <linux/ptrace.h> | ||
| 666 | #include <arch/spr_def.h> | ||
| 667 | |||
| 668 | static DEFINE_PER_CPU(unsigned long, ss_saved_pc); | ||
| 669 | |||
| 670 | |||
| 671 | /* | ||
| 672 | * Called directly on the occasion of an interrupt. | ||
| 673 | * | ||
| 674 | * If the process doesn't have single step set, then we use this as an | ||
| 675 | * opportunity to turn single step off. | ||
| 676 | * | ||
| 677 | * It has been mentioned that we could conditionally turn off single stepping | ||
| 678 | * on each entry into the kernel and rely on single_step_once to turn it | ||
| 679 | * on for the processes that matter (as we already do), but this | ||
| 680 | * implementation is somewhat more efficient in that we muck with registers | ||
| 681 | * once on a bum interrupt rather than on every entry into the kernel. | ||
| 682 | * | ||
| 683 | * If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred, | ||
| 684 | * so we have to run through this process again before we can say that an | ||
| 685 | * instruction has executed. | ||
| 686 | * | ||
| 687 | * swint will set CANCELED, but it's a legitimate instruction. Fortunately | ||
| 688 | * it changes the PC. If it hasn't changed, then we know that the interrupt | ||
| 689 | * wasn't generated by swint and we'll need to run this process again before | ||
| 690 | * we can say an instruction has executed. | ||
| 691 | * | ||
| 692 | * If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get | ||
| 693 | * on with our lives. | ||
| 694 | */ | ||
| 695 | |||
| 696 | void gx_singlestep_handle(struct pt_regs *regs, int fault_num) | ||
| 697 | { | ||
| 698 | unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc); | ||
| 699 | struct thread_info *info = (void *)current_thread_info(); | ||
| 700 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); | ||
| 701 | unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); | ||
| 702 | |||
| 703 | if (is_single_step == 0) { | ||
| 704 | __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0); | ||
| 705 | |||
| 706 | } else if ((*ss_pc != regs->pc) || | ||
| 707 | (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) { | ||
| 708 | |||
| 709 | ptrace_notify(SIGTRAP); | ||
| 710 | control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; | ||
| 711 | control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; | ||
| 712 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); | ||
| 713 | } | ||
| 714 | } | ||
| 715 | |||
| 716 | |||
| 717 | /* | ||
| 718 | * Called from need_singlestep. Set up the control registers and the enable | ||
| 719 | * register, then return back. | ||
| 720 | */ | ||
| 721 | |||
| 722 | void single_step_once(struct pt_regs *regs) | ||
| 723 | { | ||
| 724 | unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc); | ||
| 725 | unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); | ||
| 726 | |||
| 727 | *ss_pc = regs->pc; | ||
| 728 | control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; | ||
| 729 | control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; | ||
| 730 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); | ||
| 731 | __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL); | ||
| 732 | } | ||
| 733 | |||
| 663 | #endif /* !__tilegx__ */ | 734 | #endif /* !__tilegx__ */ |
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 7826a8b17997..5474fc2e77e8 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c | |||
| @@ -260,7 +260,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
| 260 | address = regs->pc; | 260 | address = regs->pc; |
| 261 | break; | 261 | break; |
| 262 | case INT_UNALIGN_DATA: | 262 | case INT_UNALIGN_DATA: |
| 263 | #ifndef __tilegx__ /* FIXME: GX: no single-step yet */ | 263 | #ifndef __tilegx__ /* Emulated support for single step debugging */ |
| 264 | if (unaligned_fixup >= 0) { | 264 | if (unaligned_fixup >= 0) { |
| 265 | struct single_step_state *state = | 265 | struct single_step_state *state = |
| 266 | current_thread_info()->step_state; | 266 | current_thread_info()->step_state; |
