aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorKumar Gala <galak@kernel.crashing.org>2008-06-26 03:01:37 -0400
committerKumar Gala <galak@kernel.crashing.org>2008-06-26 04:35:46 -0400
commitf82796214a95b1ec00c2f121c1080d10f2b099a1 (patch)
treec5702217e2a482ee2f15fca17be547b9ba1a31a4 /arch/powerpc
parentb76e59d1fb086c2fdac5d243e09786d6581f2026 (diff)
powerpc/booke: Add kprobes support for booke style processors
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>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/kernel/kprobes.c25
-rw-r--r--arch/powerpc/kernel/traps.c26
2 files changed, 36 insertions, 15 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);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 4b5b7ff4f78b..b463d48145a4 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1030,21 +1030,29 @@ void SoftwareEmulation(struct pt_regs *regs)
1030 1030
1031#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) 1031#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
1032 1032
1033void DebugException(struct pt_regs *regs, unsigned long debug_status) 1033void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
1034{ 1034{
1035 if (debug_status & DBSR_IC) { /* instruction completion */ 1035 if (debug_status & DBSR_IC) { /* instruction completion */
1036 regs->msr &= ~MSR_DE; 1036 regs->msr &= ~MSR_DE;
1037
1038 /* Disable instruction completion */
1039 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
1040 /* Clear the instruction completion event */
1041 mtspr(SPRN_DBSR, DBSR_IC);
1042
1043 if (notify_die(DIE_SSTEP, "single_step", regs, 5,
1044 5, SIGTRAP) == NOTIFY_STOP) {
1045 return;
1046 }
1047
1048 if (debugger_sstep(regs))
1049 return;
1050
1037 if (user_mode(regs)) { 1051 if (user_mode(regs)) {
1038 current->thread.dbcr0 &= ~DBCR0_IC; 1052 current->thread.dbcr0 &= ~DBCR0_IC;
1039 } else {
1040 /* Disable instruction completion */
1041 mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC);
1042 /* Clear the instruction completion event */
1043 mtspr(SPRN_DBSR, DBSR_IC);
1044 if (debugger_sstep(regs))
1045 return;
1046 } 1053 }
1047 _exception(SIGTRAP, regs, TRAP_TRACE, 0); 1054
1055 _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
1048 } 1056 }
1049} 1057}
1050#endif /* CONFIG_4xx || CONFIG_BOOKE */ 1058#endif /* CONFIG_4xx || CONFIG_BOOKE */