aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2012-09-06 17:24:57 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-09 19:59:13 -0400
commitcd14457304c9d232267a3a76a2a43f1f791e545d (patch)
treedefabdab4b813faf7bcd083f8670020cf799003c
parent4474ef055c5d8cb8eaf002d69e49af71e3aa3a88 (diff)
powerpc: Dynamically calculate the dabrx based on kernel/user/hypervisor
Currently we mark the DABRX to interrupt on all matches (hypervisor/kernel/user and then filter in software. We can be a lot smarter now that we can set the DABRX dynamically. This sets the DABRX based on the flags passed by the user. Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/hw_breakpoint.h1
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c15
-rw-r--r--arch/powerpc/platforms/pseries/setup.c2
3 files changed, 13 insertions, 5 deletions
diff --git a/arch/powerpc/include/asm/hw_breakpoint.h b/arch/powerpc/include/asm/hw_breakpoint.h
index c6f48eb5299c..423424599dad 100644
--- a/arch/powerpc/include/asm/hw_breakpoint.h
+++ b/arch/powerpc/include/asm/hw_breakpoint.h
@@ -28,6 +28,7 @@
28 28
29struct arch_hw_breakpoint { 29struct arch_hw_breakpoint {
30 unsigned long address; 30 unsigned long address;
31 unsigned long dabrx;
31 int type; 32 int type;
32 u8 len; /* length of the target data symbol */ 33 u8 len; /* length of the target data symbol */
33 bool extraneous_interrupt; 34 bool extraneous_interrupt;
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index 6891d79ecef6..a89cae481b04 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
73 * If so, DABR will be populated in single_step_dabr_instruction(). 73 * If so, DABR will be populated in single_step_dabr_instruction().
74 */ 74 */
75 if (current->thread.last_hit_ubp != bp) 75 if (current->thread.last_hit_ubp != bp)
76 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); 76 set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
77 77
78 return 0; 78 return 0;
79} 79}
@@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
170 170
171 info->address = bp->attr.bp_addr; 171 info->address = bp->attr.bp_addr;
172 info->len = bp->attr.bp_len; 172 info->len = bp->attr.bp_len;
173 info->dabrx = DABRX_ALL;
174 if (bp->attr.exclude_user)
175 info->dabrx &= ~DABRX_USER;
176 if (bp->attr.exclude_kernel)
177 info->dabrx &= ~DABRX_KERNEL;
178 if (bp->attr.exclude_hv)
179 info->dabrx &= ~DABRX_HYP;
173 180
174 /* 181 /*
175 * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8) 182 * Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8)
@@ -197,7 +204,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
197 204
198 info = counter_arch_bp(tsk->thread.last_hit_ubp); 205 info = counter_arch_bp(tsk->thread.last_hit_ubp);
199 regs->msr &= ~MSR_SE; 206 regs->msr &= ~MSR_SE;
200 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); 207 set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
201 tsk->thread.last_hit_ubp = NULL; 208 tsk->thread.last_hit_ubp = NULL;
202} 209}
203 210
@@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
281 if (!info->extraneous_interrupt) 288 if (!info->extraneous_interrupt)
282 perf_bp_event(bp, regs); 289 perf_bp_event(bp, regs);
283 290
284 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); 291 set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
285out: 292out:
286 rcu_read_unlock(); 293 rcu_read_unlock();
287 return rc; 294 return rc;
@@ -313,7 +320,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
313 if (!info->extraneous_interrupt) 320 if (!info->extraneous_interrupt)
314 perf_bp_event(bp, regs); 321 perf_bp_event(bp, regs);
315 322
316 set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); 323 set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
317 current->thread.last_hit_ubp = NULL; 324 current->thread.last_hit_ubp = NULL;
318 325
319 /* 326 /*
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index a3a69658a6ec..e3cb7ae61658 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -425,7 +425,7 @@ static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx)
425 if (dabrx == 0 && dabr == 0) 425 if (dabrx == 0 && dabr == 0)
426 dabrx = DABRX_USER; 426 dabrx = DABRX_USER;
427 /* PAPR says we can only set kernel and user bits */ 427 /* PAPR says we can only set kernel and user bits */
428 dabrx &= H_DABRX_KERNEL | H_DABRX_USER; 428 dabrx &= DABRX_KERNEL | DABRX_USER;
429 429
430 return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx); 430 return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
431} 431}