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 <mi...@neuling.org>
---
 arch/powerpc/include/asm/hw_breakpoint.h |    1 +
 arch/powerpc/kernel/hw_breakpoint.c      |   15 +++++++++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/hw_breakpoint.h 
b/arch/powerpc/include/asm/hw_breakpoint.h
index c6f48eb..4234245 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 6891d79..a89cae4 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;
 
        /*
-- 
1.7.9.5

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to