diff options
author | Michael Neuling <mikey@neuling.org> | 2012-09-06 23:24:57 +0200 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-09-10 01:59:13 +0200 |
commit | cd14457304c9d232267a3a76a2a43f1f791e545d (patch) | |
tree | defabdab4b813faf7bcd083f8670020cf799003c | |
parent | powerpc: Rework set_dabr so it can take a DABRX value as well (diff) | |
download | linux-cd14457304c9d232267a3a76a2a43f1f791e545d.tar.xz linux-cd14457304c9d232267a3a76a2a43f1f791e545d.zip |
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.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/hw_breakpoint.c | 15 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 2 |
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 @@ struct arch_hw_breakpoint { unsigned long address; + unsigned long dabrx; int type; u8 len; /* length of the target data symbol */ 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) * If so, DABR will be populated in single_step_dabr_instruction(). */ 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; } @@ -170,6 +170,13 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) info->address = bp->attr.bp_addr; 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) @@ -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); 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; } @@ -281,7 +288,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args) if (!info->extraneous_interrupt) 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: rcu_read_unlock(); return rc; @@ -313,7 +320,7 @@ int __kprobes single_step_dabr_instruction(struct die_args *args) if (!info->extraneous_interrupt) 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; /* 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) if (dabrx == 0 && dabr == 0) dabrx = DABRX_USER; /* 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); } |