diff options
Diffstat (limited to 'arch/powerpc/kernel/kprobes.c')
-rw-r--r-- | arch/powerpc/kernel/kprobes.c | 25 |
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 | ||
38 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 45 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
39 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 46 | DEFINE_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); |