Skip to content

Commit

Permalink
powerpc/booke: Add kprobes support for booke style processors
Browse files Browse the repository at this point in the history
This patch is based on work done by Madhvesh. R. Sulibhavi back in
March 2007.

We refactor some of the single step handling since it differs between
"classic" and "booke" powerpc cores.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
  • Loading branch information
Kumar Gala committed Jun 26, 2008
1 parent b76e59d commit f827962
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 15 deletions.
1 change: 1 addition & 0 deletions Documentation/kprobes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ architectures:
- ia64 (Does not support probes on instruction slot1.)
- sparc64 (Return probes not yet implemented.)
- arm
- ppc

3. Configuring Kprobes

Expand Down
25 changes: 19 additions & 6 deletions arch/powerpc/kernel/kprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
#include <asm/cacheflush.h>
#include <asm/sstep.h>
#include <asm/uaccess.h>
#include <asm/system.h>

#ifdef CONFIG_BOOKE
#define MSR_SINGLESTEP (MSR_DE)
#else
#define MSR_SINGLESTEP (MSR_SE)
#endif

DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
Expand All @@ -53,7 +60,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
ret = -EINVAL;
}

/* insn must be on a special executable page on ppc64 */
/* insn must be on a special executable page on ppc64. This is
* not explicitly required on ppc32 (right now), but it doesn't hurt */
if (!ret) {
p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn)
Expand Down Expand Up @@ -100,7 +108,11 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
* possible we'd get the single step reported for an exception handler
* like Decrementer or External Interrupt */
regs->msr &= ~MSR_EE;
regs->msr |= MSR_SE;
regs->msr |= MSR_SINGLESTEP;
#ifdef CONFIG_BOOKE
regs->msr &= ~MSR_CE;
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
#endif

/*
* On powerpc we should single step on the original
Expand Down Expand Up @@ -163,7 +175,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
kprobe_opcode_t insn = *p->ainsn.insn;
if (kcb->kprobe_status == KPROBE_HIT_SS &&
is_trap(insn)) {
regs->msr &= ~MSR_SE;
/* Turn off 'trace' bits */
regs->msr &= ~MSR_SINGLESTEP;
regs->msr |= kcb->kprobe_saved_msr;
goto no_kprobe;
}
Expand Down Expand Up @@ -404,10 +417,10 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)

/*
* if somebody else is singlestepping across a probe point, msr
* will have SE set, in which case, continue the remaining processing
* will have DE/SE set, in which case, continue the remaining processing
* of do_debug, as if this is not a probe hit.
*/
if (regs->msr & MSR_SE)
if (regs->msr & MSR_SINGLESTEP)
return 0;

return 1;
Expand All @@ -430,7 +443,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
* normal page fault.
*/
regs->nip = (unsigned long)cur->addr;
regs->msr &= ~MSR_SE;
regs->msr &= ~MSR_SINGLESTEP; /* Turn off 'trace' bits */
regs->msr |= kcb->kprobe_saved_msr;
if (kcb->kprobe_status == KPROBE_REENTER)
restore_previous_kprobe(kcb);
Expand Down
26 changes: 17 additions & 9 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1030,21 +1030,29 @@ void SoftwareEmulation(struct pt_regs *regs)

#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)

void DebugException(struct pt_regs *regs, unsigned long debug_status)
void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
{
if (debug_status & DBSR_IC) { /* instruction completion */
regs->msr &= ~MSR_DE;

/* Disable instruction completion */
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
/* Clear the instruction completion event */
mtspr(SPRN_DBSR, DBSR_IC);

if (notify_die(DIE_SSTEP, "single_step", regs, 5,
5, SIGTRAP) == NOTIFY_STOP) {
return;
}

if (debugger_sstep(regs))
return;

if (user_mode(regs)) {
current->thread.dbcr0 &= ~DBCR0_IC;
} else {
/* Disable instruction completion */
mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
/* Clear the instruction completion event */
mtspr(SPRN_DBSR, DBSR_IC);
if (debugger_sstep(regs))
return;
}
_exception(SIGTRAP, regs, TRAP_TRACE, 0);

_exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
}
}
#endif /* CONFIG_4xx || CONFIG_BOOKE */
Expand Down

0 comments on commit f827962

Please sign in to comment.