perf/hw_breakpoint: Pass arch breakpoint struct to arch_check_bp_in_kernelspace()
authorFrederic Weisbecker <frederic@kernel.org>
Tue, 26 Jun 2018 02:58:49 +0000 (04:58 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 26 Jun 2018 07:07:54 +0000 (09:07 +0200)
We can't pass the breakpoint directly on arch_check_bp_in_kernelspace()
anymore because its architecture internal datas (struct arch_hw_breakpoint)
are not yet filled by the time we call the function, and most
implementation need this backend to be up to date. So arrange the
function to take the probing struct instead.

Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chris Zankel <chris@zankel.net>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Joel Fernandes <joel.opensrc@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Rich Felker <dalias@libc.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Link: http://lkml.kernel.org/r/1529981939-8231-3-git-send-email-frederic@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
13 files changed:
arch/arm/include/asm/hw_breakpoint.h
arch/arm/kernel/hw_breakpoint.c
arch/arm64/include/asm/hw_breakpoint.h
arch/arm64/kernel/hw_breakpoint.c
arch/powerpc/include/asm/hw_breakpoint.h
arch/powerpc/kernel/hw_breakpoint.c
arch/sh/include/asm/hw_breakpoint.h
arch/sh/kernel/hw_breakpoint.c
arch/x86/include/asm/hw_breakpoint.h
arch/x86/kernel/hw_breakpoint.c
arch/xtensa/include/asm/hw_breakpoint.h
arch/xtensa/kernel/hw_breakpoint.c
kernel/events/hw_breakpoint.c

index e46e4e7bdba39974979b54ab137d13ba90f5d96d..d5a0f52c6755a6dfd6d266c8c3ba9aa992832a01 100644 (file)
@@ -117,7 +117,7 @@ struct pmu;
 
 extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
                                  int *gen_len, int *gen_type);
-extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
 extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
 extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                           unsigned long val, void *data);
index 629e25152c0d03e27593e22f9326db7507933c55..385dcf45d64b941167605d0c28fd59d8f19c65bc 100644 (file)
@@ -456,14 +456,13 @@ static int get_hbp_len(u8 hbp_len)
 /*
  * Check whether bp virtual address is in kernel space.
  */
-int arch_check_bp_in_kernelspace(struct perf_event *bp)
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
 {
        unsigned int len;
        unsigned long va;
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
 
-       va = info->address;
-       len = get_hbp_len(info->ctrl.len);
+       va = hw->address;
+       len = get_hbp_len(hw->ctrl.len);
 
        return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
 }
@@ -576,7 +575,7 @@ static int arch_build_bp_info(struct perf_event *bp)
 
        /* Privilege */
        info->ctrl.privilege = ARM_BREAKPOINT_USER;
-       if (arch_check_bp_in_kernelspace(bp))
+       if (arch_check_bp_in_kernelspace(info))
                info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
 
        /* Enabled? */
@@ -640,7 +639,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
                        return -EINVAL;
 
                /* We don't allow mismatch breakpoints in kernel space. */
-               if (arch_check_bp_in_kernelspace(bp))
+               if (arch_check_bp_in_kernelspace(info))
                        return -EPERM;
 
                /*
index 41770766d9648f1dd03568f5d2adc86f95f77e3a..9f4a3d48762e8ad9fcc91b84289f1bc4e1c89109 100644 (file)
@@ -124,7 +124,7 @@ struct pmu;
 
 extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
                                  int *gen_len, int *gen_type, int *offset);
-extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
 extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
 extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                           unsigned long val, void *data);
index 413dbe530da836d3dc1119830628454168921064..6a90d12e4ff2c319eab3a00f3d0624ee013e31a0 100644 (file)
@@ -343,14 +343,13 @@ static int get_hbp_len(u8 hbp_len)
 /*
  * Check whether bp virtual address is in kernel space.
  */
-int arch_check_bp_in_kernelspace(struct perf_event *bp)
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
 {
        unsigned int len;
        unsigned long va;
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
 
-       va = info->address;
-       len = get_hbp_len(info->ctrl.len);
+       va = hw->address;
+       len = get_hbp_len(hw->ctrl.len);
 
        return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
 }
@@ -502,7 +501,7 @@ static int arch_build_bp_info(struct perf_event *bp)
         * Note that we disallow combined EL0/EL1 breakpoints because
         * that would complicate the stepping code.
         */
-       if (arch_check_bp_in_kernelspace(bp))
+       if (arch_check_bp_in_kernelspace(info))
                info->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
        else
                info->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
index 8e7b09703ca45dbe2592441e5520176024baee24..4d0b1bfcdfd07f933ef65db5c6ccb4bb5382f111 100644 (file)
@@ -60,7 +60,7 @@ struct perf_sample_data;
 
 extern int hw_breakpoint_slots(int type);
 extern int arch_bp_generic_fields(int type, int *gen_bp_type);
-extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
 extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
 extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                                unsigned long val, void *data);
index 80547dad37daee37e4f05a211802ba981a515ab3..899bcec3f3c8431619058ddc9bcec3f88befd000 100644 (file)
@@ -119,11 +119,9 @@ void arch_unregister_hw_breakpoint(struct perf_event *bp)
 /*
  * Check for virtual address in kernel space.
  */
-int arch_check_bp_in_kernelspace(struct perf_event *bp)
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
 {
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
-
-       return is_kernel_addr(info->address);
+       return is_kernel_addr(hw->address);
 }
 
 int arch_bp_generic_fields(int type, int *gen_bp_type)
index 7431c172c0cb63358fe2955249203cb91642e73a..8a88ed0b3cd730d43dd3cfb91f35b59a44f3e253 100644 (file)
@@ -54,7 +54,7 @@ static inline int hw_breakpoint_slots(int type)
 }
 
 /* arch/sh/kernel/hw_breakpoint.c */
-extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
 extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
 extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                           unsigned long val, void *data);
index 8648ed05ccf00e4974237ff1fd77e5a1270dd7ca..38791fefdd0cb5637eb6578c419b9f439837948b 100644 (file)
@@ -124,14 +124,13 @@ static int get_hbp_len(u16 hbp_len)
 /*
  * Check for virtual address in kernel space.
  */
-int arch_check_bp_in_kernelspace(struct perf_event *bp)
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
 {
        unsigned int len;
        unsigned long va;
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
 
-       va = info->address;
-       len = get_hbp_len(info->len);
+       va = hw->address;
+       len = get_hbp_len(hw->len);
 
        return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
 }
@@ -346,7 +345,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
                perf_bp_event(bp, args->regs);
 
                /* Deliver the signal to userspace */
-               if (!arch_check_bp_in_kernelspace(bp)) {
+               if (!arch_check_bp_in_kernelspace(&bp->hw.info)) {
                        force_sig_fault(SIGTRAP, TRAP_HWBKPT,
                                        (void __user *)NULL, current);
                }
index f59c39835a5a93c8d12e48f335459268b229e4af..78924596f51f472a6033bb2fcfaf4a877fe42845 100644 (file)
@@ -52,7 +52,7 @@ static inline int hw_breakpoint_slots(int type)
 struct perf_event;
 struct pmu;
 
-extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
 extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
 extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                           unsigned long val, void *data);
index 8771766d46b6c3e74d914136578f0b8d6f64b5ad..c43379188f4ff0bf878a4d133658634f91141920 100644 (file)
@@ -169,28 +169,29 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
                set_dr_addr_mask(0, i);
 }
 
-/*
- * Check for virtual address in kernel space.
- */
-int arch_check_bp_in_kernelspace(struct perf_event *bp)
+static int arch_bp_generic_len(int x86_len)
 {
-       unsigned int len;
-       unsigned long va;
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
-
-       va = info->address;
-       len = bp->attr.bp_len;
-
-       /*
-        * We don't need to worry about va + len - 1 overflowing:
-        * we already require that va is aligned to a multiple of len.
-        */
-       return (va >= TASK_SIZE_MAX) || ((va + len - 1) >= TASK_SIZE_MAX);
+       switch (x86_len) {
+       case X86_BREAKPOINT_LEN_1:
+               return HW_BREAKPOINT_LEN_1;
+       case X86_BREAKPOINT_LEN_2:
+               return HW_BREAKPOINT_LEN_2;
+       case X86_BREAKPOINT_LEN_4:
+               return HW_BREAKPOINT_LEN_4;
+#ifdef CONFIG_X86_64
+       case X86_BREAKPOINT_LEN_8:
+               return HW_BREAKPOINT_LEN_8;
+#endif
+       default:
+               return -EINVAL;
+       }
 }
 
 int arch_bp_generic_fields(int x86_len, int x86_type,
                           int *gen_len, int *gen_type)
 {
+       int len;
+
        /* Type */
        switch (x86_type) {
        case X86_BREAKPOINT_EXECUTE:
@@ -211,28 +212,32 @@ int arch_bp_generic_fields(int x86_len, int x86_type,
        }
 
        /* Len */
-       switch (x86_len) {
-       case X86_BREAKPOINT_LEN_1:
-               *gen_len = HW_BREAKPOINT_LEN_1;
-               break;
-       case X86_BREAKPOINT_LEN_2:
-               *gen_len = HW_BREAKPOINT_LEN_2;
-               break;
-       case X86_BREAKPOINT_LEN_4:
-               *gen_len = HW_BREAKPOINT_LEN_4;
-               break;
-#ifdef CONFIG_X86_64
-       case X86_BREAKPOINT_LEN_8:
-               *gen_len = HW_BREAKPOINT_LEN_8;
-               break;
-#endif
-       default:
+       len = arch_bp_generic_len(x86_len);
+       if (len < 0)
                return -EINVAL;
-       }
+       *gen_len = len;
 
        return 0;
 }
 
+/*
+ * Check for virtual address in kernel space.
+ */
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
+{
+       unsigned long va;
+       int len;
+
+       va = hw->address;
+       len = arch_bp_generic_len(hw->len);
+       WARN_ON_ONCE(len < 0);
+
+       /*
+        * We don't need to worry about va + len - 1 overflowing:
+        * we already require that va is aligned to a multiple of len.
+        */
+       return (va >= TASK_SIZE_MAX) || ((va + len - 1) >= TASK_SIZE_MAX);
+}
 
 static int arch_build_bp_info(struct perf_event *bp)
 {
index dbe3053b284a4286970decf9f3d966f53e7c3a28..2525bf6816a6c74c07947099c67ff34b0b2a1b62 100644 (file)
@@ -35,7 +35,7 @@ struct pt_regs;
 struct task_struct;
 
 int hw_breakpoint_slots(int type);
-int arch_check_bp_in_kernelspace(struct perf_event *bp);
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
 int arch_validate_hwbkpt_settings(struct perf_event *bp);
 int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
                                    unsigned long val, void *data);
index b35656ab7dbd184ba4bb099c9f716ea4b7ee9657..6e34c3848885c84bf522d8626eaad8e509ccd08a 100644 (file)
@@ -33,14 +33,13 @@ int hw_breakpoint_slots(int type)
        }
 }
 
-int arch_check_bp_in_kernelspace(struct perf_event *bp)
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
 {
        unsigned int len;
        unsigned long va;
-       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
 
-       va = info->address;
-       len = bp->attr.bp_len;
+       va = hw->address;
+       len = hw->len;
 
        return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
 }
index 314e2a9040c71fafcec4f74c2dc8b8b8f87d8236..89fe94c9214c77cf89d0a1947ec0618c1f839941 100644 (file)
@@ -427,7 +427,7 @@ static int hw_breakpoint_parse(struct perf_event *bp,
        if (err)
                return err;
 
-       if (arch_check_bp_in_kernelspace(bp)) {
+       if (arch_check_bp_in_kernelspace(hw)) {
                if (attr->exclude_kernel)
                        return -EINVAL;
                /*