mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
arch/tile: enable single-step support for TILE-Gx
This is not quite the complete support, since we're not yet shipping intvec_64.S, but it is the support relevant to the set of files we are currently shipping, and makes it easier to track changes between our internal sources and our public GIT repository. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
parent
a78c942df6
commit
233325b949
@ -59,4 +59,8 @@ void do_hardwall_trap(struct pt_regs *, int fault_num);
|
||||
void do_breakpoint(struct pt_regs *, int fault_num);
|
||||
|
||||
|
||||
#ifdef __tilegx__
|
||||
void gx_singlestep_handle(struct pt_regs *, int fault_num);
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_TILE_SYSCALLS_H */
|
||||
|
@ -1472,7 +1472,12 @@ handle_ill:
|
||||
lw r26, r24
|
||||
sw r28, r26
|
||||
|
||||
/* Clear TIF_SINGLESTEP */
|
||||
/*
|
||||
* Clear TIF_SINGLESTEP to prevent recursion if we execute an ill.
|
||||
* The normal non-arch flow redundantly clears TIF_SINGLESTEP, but we
|
||||
* need to clear it here and can't really impose on all other arches.
|
||||
* So what's another write between friends?
|
||||
*/
|
||||
GET_THREAD_INFO(r0)
|
||||
|
||||
addi r1, r0, THREAD_INFO_FLAGS_OFFSET
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Derived from iLib's single-stepping code.
|
||||
*/
|
||||
|
||||
#ifndef __tilegx__ /* No support for single-step yet. */
|
||||
#ifndef __tilegx__ /* Hardware support for single step unavailable. */
|
||||
|
||||
/* These functions are only used on the TILE platform */
|
||||
#include <linux/slab.h>
|
||||
@ -660,4 +660,75 @@ void single_step_once(struct pt_regs *regs)
|
||||
regs->pc += 8;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <arch/spr_def.h>
|
||||
|
||||
static DEFINE_PER_CPU(unsigned long, ss_saved_pc);
|
||||
|
||||
|
||||
/*
|
||||
* Called directly on the occasion of an interrupt.
|
||||
*
|
||||
* If the process doesn't have single step set, then we use this as an
|
||||
* opportunity to turn single step off.
|
||||
*
|
||||
* It has been mentioned that we could conditionally turn off single stepping
|
||||
* on each entry into the kernel and rely on single_step_once to turn it
|
||||
* on for the processes that matter (as we already do), but this
|
||||
* implementation is somewhat more efficient in that we muck with registers
|
||||
* once on a bum interrupt rather than on every entry into the kernel.
|
||||
*
|
||||
* If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred,
|
||||
* so we have to run through this process again before we can say that an
|
||||
* instruction has executed.
|
||||
*
|
||||
* swint will set CANCELED, but it's a legitimate instruction. Fortunately
|
||||
* it changes the PC. If it hasn't changed, then we know that the interrupt
|
||||
* wasn't generated by swint and we'll need to run this process again before
|
||||
* we can say an instruction has executed.
|
||||
*
|
||||
* If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get
|
||||
* on with our lives.
|
||||
*/
|
||||
|
||||
void gx_singlestep_handle(struct pt_regs *regs, int fault_num)
|
||||
{
|
||||
unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
|
||||
struct thread_info *info = (void *)current_thread_info();
|
||||
int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
|
||||
unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
|
||||
|
||||
if (is_single_step == 0) {
|
||||
__insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0);
|
||||
|
||||
} else if ((*ss_pc != regs->pc) ||
|
||||
(!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) {
|
||||
|
||||
ptrace_notify(SIGTRAP);
|
||||
control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
|
||||
control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
|
||||
__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Called from need_singlestep. Set up the control registers and the enable
|
||||
* register, then return back.
|
||||
*/
|
||||
|
||||
void single_step_once(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long *ss_pc = &__get_cpu_var(ss_saved_pc);
|
||||
unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K);
|
||||
|
||||
*ss_pc = regs->pc;
|
||||
control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK;
|
||||
control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK;
|
||||
__insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control);
|
||||
__insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL);
|
||||
}
|
||||
|
||||
#endif /* !__tilegx__ */
|
||||
|
@ -260,7 +260,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
|
||||
address = regs->pc;
|
||||
break;
|
||||
case INT_UNALIGN_DATA:
|
||||
#ifndef __tilegx__ /* FIXME: GX: no single-step yet */
|
||||
#ifndef __tilegx__ /* Emulated support for single step debugging */
|
||||
if (unaligned_fixup >= 0) {
|
||||
struct single_step_state *state =
|
||||
current_thread_info()->step_state;
|
||||
|
Loading…
Reference in New Issue
Block a user