Skip to content

Commit f827962

Browse files
committed
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 <[email protected]>
1 parent b76e59d commit f827962

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

Documentation/kprobes.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ architectures:
172172
- ia64 (Does not support probes on instruction slot1.)
173173
- sparc64 (Return probes not yet implemented.)
174174
- arm
175+
- ppc
175176

176177
3. Configuring Kprobes
177178

arch/powerpc/kernel/kprobes.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
#include <asm/cacheflush.h>
3535
#include <asm/sstep.h>
3636
#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
3744

3845
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
3946
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -53,7 +60,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
5360
ret = -EINVAL;
5461
}
5562

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 */
5765
if (!ret) {
5866
p->ainsn.insn = get_insn_slot();
5967
if (!p->ainsn.insn)
@@ -100,7 +108,11 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
100108
* possible we'd get the single step reported for an exception handler
101109
* like Decrementer or External Interrupt */
102110
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
104116

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

405418
/*
406419
* 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
408421
* of do_debug, as if this is not a probe hit.
409422
*/
410-
if (regs->msr & MSR_SE)
423+
if (regs->msr & MSR_SINGLESTEP)
411424
return 0;
412425

413426
return 1;
@@ -430,7 +443,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
430443
* normal page fault.
431444
*/
432445
regs->nip = (unsigned long)cur->addr;
433-
regs->msr &= ~MSR_SE;
446+
regs->msr &= ~MSR_SINGLESTEP; /* Turn off 'trace' bits */
434447
regs->msr |= kcb->kprobe_saved_msr;
435448
if (kcb->kprobe_status == KPROBE_REENTER)
436449
restore_previous_kprobe(kcb);

arch/powerpc/kernel/traps.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,21 +1030,29 @@ void SoftwareEmulation(struct pt_regs *regs)
10301030

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

1033-
void DebugException(struct pt_regs *regs, unsigned long debug_status)
1033+
void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status)
10341034
{
10351035
if (debug_status & DBSR_IC) { /* instruction completion */
10361036
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+
10371051
if (user_mode(regs)) {
10381052
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;
10461053
}
1047-
_exception(SIGTRAP, regs, TRAP_TRACE, 0);
1054+
1055+
_exception(SIGTRAP, regs, TRAP_TRACE, regs->nip);
10481056
}
10491057
}
10501058
#endif /* CONFIG_4xx || CONFIG_BOOKE */

0 commit comments

Comments
 (0)