diff options
Diffstat (limited to 'arch/tile/kernel/single_step.c')
-rw-r--r-- | arch/tile/kernel/single_step.c | 106 |
1 files changed, 103 insertions, 3 deletions
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 5ec4b9c651f2..4032ca8e51b6 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> |
@@ -56,7 +56,7 @@ enum mem_op { | |||
56 | MEMOP_STORE_POSTINCR | 56 | MEMOP_STORE_POSTINCR |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, int32_t offset) | 59 | static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, s32 offset) |
60 | { | 60 | { |
61 | tile_bundle_bits result; | 61 | tile_bundle_bits result; |
62 | 62 | ||
@@ -186,6 +186,8 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
186 | .si_code = SEGV_MAPERR, | 186 | .si_code = SEGV_MAPERR, |
187 | .si_addr = addr | 187 | .si_addr = addr |
188 | }; | 188 | }; |
189 | trace_unhandled_signal("segfault", regs, | ||
190 | (unsigned long)addr, SIGSEGV); | ||
189 | force_sig_info(info.si_signo, &info, current); | 191 | force_sig_info(info.si_signo, &info, current); |
190 | return (tile_bundle_bits) 0; | 192 | return (tile_bundle_bits) 0; |
191 | } | 193 | } |
@@ -196,6 +198,8 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
196 | .si_code = BUS_ADRALN, | 198 | .si_code = BUS_ADRALN, |
197 | .si_addr = addr | 199 | .si_addr = addr |
198 | }; | 200 | }; |
201 | trace_unhandled_signal("unaligned trap", regs, | ||
202 | (unsigned long)addr, SIGBUS); | ||
199 | force_sig_info(info.si_signo, &info, current); | 203 | force_sig_info(info.si_signo, &info, current); |
200 | return (tile_bundle_bits) 0; | 204 | return (tile_bundle_bits) 0; |
201 | } | 205 | } |
@@ -254,6 +258,18 @@ P("\n"); | |||
254 | return bundle; | 258 | return bundle; |
255 | } | 259 | } |
256 | 260 | ||
261 | /* | ||
262 | * Called after execve() has started the new image. This allows us | ||
263 | * to reset the info state. Note that the the mmap'ed memory, if there | ||
264 | * was any, has already been unmapped by the exec. | ||
265 | */ | ||
266 | void single_step_execve(void) | ||
267 | { | ||
268 | struct thread_info *ti = current_thread_info(); | ||
269 | kfree(ti->step_state); | ||
270 | ti->step_state = NULL; | ||
271 | } | ||
272 | |||
257 | /** | 273 | /** |
258 | * single_step_once() - entry point when single stepping has been triggered. | 274 | * single_step_once() - entry point when single stepping has been triggered. |
259 | * @regs: The machine register state | 275 | * @regs: The machine register state |
@@ -306,6 +322,14 @@ void single_step_once(struct pt_regs *regs) | |||
306 | " .popsection\n" | 322 | " .popsection\n" |
307 | ); | 323 | ); |
308 | 324 | ||
325 | /* | ||
326 | * Enable interrupts here to allow touching userspace and the like. | ||
327 | * The callers expect this: do_trap() already has interrupts | ||
328 | * enabled, and do_work_pending() handles functions that enable | ||
329 | * interrupts internally. | ||
330 | */ | ||
331 | local_irq_enable(); | ||
332 | |||
309 | if (state == NULL) { | 333 | if (state == NULL) { |
310 | /* allocate a page of writable, executable memory */ | 334 | /* allocate a page of writable, executable memory */ |
311 | state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL); | 335 | state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL); |
@@ -373,7 +397,7 @@ void single_step_once(struct pt_regs *regs) | |||
373 | /* branches */ | 397 | /* branches */ |
374 | case BRANCH_OPCODE_X1: | 398 | case BRANCH_OPCODE_X1: |
375 | { | 399 | { |
376 | int32_t offset = signExtend17(get_BrOff_X1(bundle)); | 400 | s32 offset = signExtend17(get_BrOff_X1(bundle)); |
377 | 401 | ||
378 | /* | 402 | /* |
379 | * For branches, we use a rewriting trick to let the | 403 | * For branches, we use a rewriting trick to let the |
@@ -660,4 +684,80 @@ void single_step_once(struct pt_regs *regs) | |||
660 | regs->pc += 8; | 684 | regs->pc += 8; |
661 | } | 685 | } |
662 | 686 | ||
687 | #else | ||
688 | #include <linux/smp.h> | ||
689 | #include <linux/ptrace.h> | ||
690 | #include <arch/spr_def.h> | ||
691 | |||
692 | static DEFINE_PER_CPU(unsigned long, ss_saved_pc); | ||
693 | |||
694 | |||
695 | /* | ||
696 | * Called directly on the occasion of an interrupt. | ||
697 | * | ||
698 | * If the process doesn't have single step set, then we use this as an | ||
699 | * opportunity to turn single step off. | ||
700 | * | ||
701 | * It has been mentioned that we could conditionally turn off single stepping | ||
702 | * on each entry into the kernel and rely on single_step_once to turn it | ||
703 | * on for the processes that matter (as we already do), but this | ||
704 | * implementation is somewhat more efficient in that we muck with registers | ||
705 | * once on a bum interrupt rather than on every entry into the kernel. | ||
706 | * | ||
707 | * If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred, | ||
708 | * so we have to run through this process again before we can say that an | ||
709 | * instruction has executed. | ||
710 | * | ||
711 | * swint will set CANCELED, but it's a legitimate instruction. Fortunately | ||
712 | * it changes the PC. If it hasn't changed, then we know that the interrupt | ||
713 | * wasn't generated by swint and we'll need to run this process again before | ||
714 | * we can say an instruction has executed. | ||
715 | * | ||
716 | * If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get | ||
717 | * on with our lives. | ||
718 | */ | ||
719 | |||
720 | void gx_singlestep_handle(struct pt_regs *regs, int fault_num) | ||
721 | { | ||
722 | unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc); | ||
723 | struct thread_info *info = (void *)current_thread_info(); | ||
724 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); | ||
725 | unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); | ||
726 | |||
727 | if (is_single_step == 0) { | ||
728 | __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0); | ||
729 | |||
730 | } else if ((*ss_pc != regs->pc) || | ||
731 | (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) { | ||
732 | |||
733 | ptrace_notify(SIGTRAP); | ||
734 | control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; | ||
735 | control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; | ||
736 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | |||
741 | /* | ||
742 | * Called from need_singlestep. Set up the control registers and the enable | ||
743 | * register, then return back. | ||
744 | */ | ||
745 | |||
746 | void single_step_once(struct pt_regs *regs) | ||
747 | { | ||
748 | unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc); | ||
749 | unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); | ||
750 | |||
751 | *ss_pc = regs->pc; | ||
752 | control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; | ||
753 | control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; | ||
754 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); | ||
755 | __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL); | ||
756 | } | ||
757 | |||
758 | void single_step_execve(void) | ||
759 | { | ||
760 | /* Nothing */ | ||
761 | } | ||
762 | |||
663 | #endif /* !__tilegx__ */ | 763 | #endif /* !__tilegx__ */ |