Commit cd144573 authored by Michael Neuling's avatar Michael Neuling Committed by Benjamin Herrenschmidt

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: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 4474ef05
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
struct arch_hw_breakpoint { struct arch_hw_breakpoint {
unsigned long address; unsigned long address;
unsigned long dabrx;
int type; int type;
u8 len; /* length of the target data symbol */ u8 len; /* length of the target data symbol */
bool extraneous_interrupt; bool extraneous_interrupt;
......
...@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp) ...@@ -73,7 +73,7 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
* If so, DABR will be populated in single_step_dabr_instruction(). * If so, DABR will be populated in single_step_dabr_instruction().
*/ */
if (current->thread.last_hit_ubp != bp) if (current->thread.last_hit_ubp != bp)
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
return 0; return 0;
} }
...@@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ...@@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
info->address = bp->attr.bp_addr; info->address = bp->attr.bp_addr;
info->len = bp->attr.bp_len; info->len = bp->attr.bp_len;
info->dabrx = DABRX_ALL;
if (bp->attr.exclude_user)
info->dabrx &= ~DABRX_USER;
if (bp->attr.exclude_kernel)
info->dabrx &= ~DABRX_KERNEL;
if (bp->attr.exclude_hv)
info->dabrx &= ~DABRX_HYP;
/* /*
* Since breakpoint length can be a maximum of HW_BREAKPOINT_LEN(8) * 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,7 +204,7 @@ void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs)
info = counter_arch_bp(tsk->thread.last_hit_ubp); info = counter_arch_bp(tsk->thread.last_hit_ubp);
regs->msr &= ~MSR_SE; regs->msr &= ~MSR_SE;
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
tsk->thread.last_hit_ubp = NULL; tsk->thread.last_hit_ubp = NULL;
} }
...@@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) ...@@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
if (!info->extraneous_interrupt) if (!info->extraneous_interrupt)
perf_bp_event(bp, regs); perf_bp_event(bp, regs);
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
out: out:
rcu_read_unlock(); rcu_read_unlock();
return rc; return rc;
...@@ -313,7 +320,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) ...@@ -313,7 +320,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args)
if (!info->extraneous_interrupt) if (!info->extraneous_interrupt)
perf_bp_event(bp, regs); perf_bp_event(bp, regs);
set_dabr(info->address | info->type | DABR_TRANSLATION, DABRX_ALL); set_dabr(info->address | info->type | DABR_TRANSLATION, info->dabrx);
current->thread.last_hit_ubp = NULL; current->thread.last_hit_ubp = NULL;
/* /*
......
...@@ -425,7 +425,7 @@ static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx) ...@@ -425,7 +425,7 @@ static int pseries_set_xdabr(unsigned long dabr, unsigned long dabrx)
if (dabrx == 0 && dabr == 0) if (dabrx == 0 && dabr == 0)
dabrx = DABRX_USER; dabrx = DABRX_USER;
/* PAPR says we can only set kernel and user bits */ /* PAPR says we can only set kernel and user bits */
dabrx &= H_DABRX_KERNEL | H_DABRX_USER; dabrx &= DABRX_KERNEL | DABRX_USER;
return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx); return plpar_hcall_norets(H_SET_XDABR, dabr, dabrx);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment