aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/kprobes.c')
-rw-r--r--arch/powerpc/kernel/kprobes.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 74693d91731f..4ba2af125450 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -34,6 +34,13 @@
34#include <asm/cacheflush.h> 34#include <asm/cacheflush.h>
35#include <asm/sstep.h> 35#include <asm/sstep.h>
36#include <asm/uaccess.h> 36#include <asm/uaccess.h>
37#include <asm/system.h>
38
39#ifdef CONFIG_BOOKE
40#define MSR_SINGLESTEP (MSR_DE)
41#else
42#define MSR_SINGLESTEP (MSR_SE)
43#endif
37 44
38DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; 45DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
39DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); 46DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -53,7 +60,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
53 ret = -EINVAL; 60 ret = -EINVAL;
54 } 61 }
55 62
56 /* insn must be on a special executable page on ppc64 */ 63 /* insn must be on a special executable page on ppc64. This is
64 * not explicitly required on ppc32 (right now), but it doesn't hurt */
57 if (!ret) { 65 if (!ret) {
58 p->ainsn.insn = get_insn_slot(); 66 p->ainsn.insn = get_insn_slot();
59 if (!p->ainsn.insn) 67 if (!p->ainsn.insn)
@@ -100,7 +108,11 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
100 * possible we'd get the single step reported for an exception handler 108 * possible we'd get the single step reported for an exception handler
101 * like Decrementer or External Interrupt */ 109 * like Decrementer or External Interrupt */
102 regs->msr &= ~MSR_EE; 110 regs->msr &= ~MSR_EE;
103 regs->msr |= MSR_SE; 111 regs->msr |= MSR_SINGLESTEP;
112#ifdef CONFIG_BOOKE
113 regs->msr &= ~MSR_CE;
114 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
115#endif
104 116
105 /* 117 /*
106 * On powerpc we should single step on the original 118 * On powerpc we should single step on the original
@@ -163,7 +175,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
163 kprobe_opcode_t insn = *p->ainsn.insn; 175 kprobe_opcode_t insn = *p->ainsn.insn;
164 if (kcb->kprobe_status == KPROBE_HIT_SS && 176 if (kcb->kprobe_status == KPROBE_HIT_SS &&
165 is_trap(insn)) { 177 is_trap(insn)) {
166 regs->msr &= ~MSR_SE; 178 /* Turn off 'trace' bits */
179 regs->msr &= ~MSR_SINGLESTEP;
167 regs->msr |= kcb->kprobe_saved_msr; 180 regs->msr |= kcb->kprobe_saved_msr;
168 goto no_kprobe; 181 goto no_kprobe;
169 } 182 }
@@ -404,10 +417,10 @@ out:
404 417
405 /* 418 /*
406 * if somebody else is singlestepping across a probe point, msr 419 * if somebody else is singlestepping across a probe point, msr
407 * will have SE set, in which case, continue the remaining processing 420 * will have DE/SE set, in which case, continue the remaining processing
408 * of do_debug, as if this is not a probe hit. 421 * of do_debug, as if this is not a probe hit.
409 */ 422 */
410 if (regs->msr & MSR_SE) 423 if (regs->msr & MSR_SINGLESTEP)
411 return 0; 424 return 0;
412 425
413 return 1; 426 return 1;
@@ -430,7 +443,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
430 * normal page fault. 443 * normal page fault.
431 */ 444 */
432 regs->nip = (unsigned long)cur->addr; 445 regs->nip = (unsigned long)cur->addr;
433 regs->msr &= ~MSR_SE; 446 regs->msr &= ~MSR_SINGLESTEP; /* Turn off 'trace' bits */
434 regs->msr |= kcb->kprobe_saved_msr; 447 regs->msr |= kcb->kprobe_saved_msr;
435 if (kcb->kprobe_status == KPROBE_REENTER) 448 if (kcb->kprobe_status == KPROBE_REENTER)
436 restore_previous_kprobe(kcb); 449 restore_previous_kprobe(kcb);