Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+37 -15
+1
Documentation/kprobes.txt
··· 172 172 - ia64 (Does not support probes on instruction slot1.) 173 173 - sparc64 (Return probes not yet implemented.) 174 174 - arm 175 + - ppc 175 176 176 177 3. Configuring Kprobes 177 178
+19 -6
arch/powerpc/kernel/kprobes.c
··· 34 34 #include <asm/cacheflush.h> 35 35 #include <asm/sstep.h> 36 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 45 DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; 39 46 DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); ··· 60 53 ret = -EINVAL; 61 54 } 62 55 63 - /* insn must be on a special executable page on ppc64 */ 56 + /* insn must be on a special executable page on ppc64. This is 57 + * not explicitly required on ppc32 (right now), but it doesn't hurt */ 64 58 if (!ret) { 65 59 p->ainsn.insn = get_insn_slot(); 66 60 if (!p->ainsn.insn) ··· 108 100 * possible we'd get the single step reported for an exception handler 109 101 * like Decrementer or External Interrupt */ 110 102 regs->msr &= ~MSR_EE; 111 - regs->msr |= MSR_SE; 103 + regs->msr |= MSR_SINGLESTEP; 104 + #ifdef CONFIG_BOOKE 105 + regs->msr &= ~MSR_CE; 106 + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM); 107 + #endif 112 108 113 109 /* 114 110 * On powerpc we should single step on the original ··· 175 163 kprobe_opcode_t insn = *p->ainsn.insn; 176 164 if (kcb->kprobe_status == KPROBE_HIT_SS && 177 165 is_trap(insn)) { 178 - regs->msr &= ~MSR_SE; 166 + /* Turn off 'trace' bits */ 167 + regs->msr &= ~MSR_SINGLESTEP; 179 168 regs->msr |= kcb->kprobe_saved_msr; 180 169 goto no_kprobe; 181 170 } ··· 417 404 418 405 /* 419 406 * if somebody else is singlestepping across a probe point, msr 420 - * will have SE set, in which case, continue the remaining processing 407 + * will have DE/SE set, in which case, continue the remaining processing 421 408 * of do_debug, as if this is not a probe hit. 422 409 */ 423 - if (regs->msr & MSR_SE) 410 + if (regs->msr & MSR_SINGLESTEP) 424 411 return 0; 425 412 426 413 return 1; ··· 443 430 * normal page fault. 444 431 */ 445 432 regs->nip = (unsigned long)cur->addr; 446 - regs->msr &= ~MSR_SE; 433 + regs->msr &= ~MSR_SINGLESTEP; /* Turn off 'trace' bits */ 447 434 regs->msr |= kcb->kprobe_saved_msr; 448 435 if (kcb->kprobe_status == KPROBE_REENTER) 449 436 restore_previous_kprobe(kcb);
+17 -9
arch/powerpc/kernel/traps.c
··· 1030 1030 1031 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 1035 if (debug_status & DBSR_IC) { /* instruction completion */ 1036 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 1051 if (user_mode(regs)) { 1038 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 1058 #endif /* CONFIG_4xx || CONFIG_BOOKE */