diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kernel/kprobes.c | 25 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 26 |
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 | ||
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); |
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 | ||
1033 | void DebugException(struct pt_regs *regs, unsigned long debug_status) | 1033 | void __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 */ |