提交 8e983ff9 编写于 作者: F Frederic Weisbecker 提交者: Ingo Molnar

perf/hw_breakpoint: Pass arch breakpoint struct to arch_check_bp_in_kernelspace()

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: NFrederic 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.orgSigned-off-by: NIngo Molnar <mingo@kernel.org>
上级 9a4903dd
...@@ -117,7 +117,7 @@ struct pmu; ...@@ -117,7 +117,7 @@ struct pmu;
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
int *gen_len, int *gen_type); 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 arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data); unsigned long val, void *data);
......
...@@ -456,14 +456,13 @@ static int get_hbp_len(u8 hbp_len) ...@@ -456,14 +456,13 @@ static int get_hbp_len(u8 hbp_len)
/* /*
* Check whether bp virtual address is in kernel space. * 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 int len;
unsigned long va; unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
va = info->address; va = hw->address;
len = get_hbp_len(info->ctrl.len); len = get_hbp_len(hw->ctrl.len);
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
} }
...@@ -576,7 +575,7 @@ static int arch_build_bp_info(struct perf_event *bp) ...@@ -576,7 +575,7 @@ static int arch_build_bp_info(struct perf_event *bp)
/* Privilege */ /* Privilege */
info->ctrl.privilege = ARM_BREAKPOINT_USER; 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; info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
/* Enabled? */ /* Enabled? */
...@@ -640,7 +639,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ...@@ -640,7 +639,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
return -EINVAL; return -EINVAL;
/* We don't allow mismatch breakpoints in kernel space. */ /* 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; return -EPERM;
/* /*
......
...@@ -124,7 +124,7 @@ struct pmu; ...@@ -124,7 +124,7 @@ struct pmu;
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
int *gen_len, int *gen_type, int *offset); 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 arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data); unsigned long val, void *data);
......
...@@ -343,14 +343,13 @@ static int get_hbp_len(u8 hbp_len) ...@@ -343,14 +343,13 @@ static int get_hbp_len(u8 hbp_len)
/* /*
* Check whether bp virtual address is in kernel space. * 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 int len;
unsigned long va; unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
va = info->address; va = hw->address;
len = get_hbp_len(info->ctrl.len); len = get_hbp_len(hw->ctrl.len);
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
} }
...@@ -502,7 +501,7 @@ static int arch_build_bp_info(struct perf_event *bp) ...@@ -502,7 +501,7 @@ static int arch_build_bp_info(struct perf_event *bp)
* Note that we disallow combined EL0/EL1 breakpoints because * Note that we disallow combined EL0/EL1 breakpoints because
* that would complicate the stepping code. * 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; info->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
else else
info->ctrl.privilege = AARCH64_BREAKPOINT_EL0; info->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
......
...@@ -60,7 +60,7 @@ struct perf_sample_data; ...@@ -60,7 +60,7 @@ struct perf_sample_data;
extern int hw_breakpoint_slots(int type); extern int hw_breakpoint_slots(int type);
extern int arch_bp_generic_fields(int type, int *gen_bp_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 arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data); unsigned long val, void *data);
......
...@@ -119,11 +119,9 @@ void arch_unregister_hw_breakpoint(struct perf_event *bp) ...@@ -119,11 +119,9 @@ void arch_unregister_hw_breakpoint(struct perf_event *bp)
/* /*
* Check for virtual address in kernel space. * 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(hw->address);
return is_kernel_addr(info->address);
} }
int arch_bp_generic_fields(int type, int *gen_bp_type) int arch_bp_generic_fields(int type, int *gen_bp_type)
......
...@@ -54,7 +54,7 @@ static inline int hw_breakpoint_slots(int type) ...@@ -54,7 +54,7 @@ static inline int hw_breakpoint_slots(int type)
} }
/* arch/sh/kernel/hw_breakpoint.c */ /* 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 arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data); unsigned long val, void *data);
......
...@@ -124,14 +124,13 @@ static int get_hbp_len(u16 hbp_len) ...@@ -124,14 +124,13 @@ static int get_hbp_len(u16 hbp_len)
/* /*
* Check for virtual address in kernel space. * 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 int len;
unsigned long va; unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
va = info->address; va = hw->address;
len = get_hbp_len(info->len); len = get_hbp_len(hw->len);
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
} }
...@@ -346,7 +345,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args) ...@@ -346,7 +345,7 @@ static int __kprobes hw_breakpoint_handler(struct die_args *args)
perf_bp_event(bp, args->regs); perf_bp_event(bp, args->regs);
/* Deliver the signal to userspace */ /* 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, force_sig_fault(SIGTRAP, TRAP_HWBKPT,
(void __user *)NULL, current); (void __user *)NULL, current);
} }
......
...@@ -52,7 +52,7 @@ static inline int hw_breakpoint_slots(int type) ...@@ -52,7 +52,7 @@ static inline int hw_breakpoint_slots(int type)
struct perf_event; struct perf_event;
struct pmu; 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 arch_validate_hwbkpt_settings(struct perf_event *bp);
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused, extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data); unsigned long val, void *data);
......
...@@ -169,28 +169,29 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp) ...@@ -169,28 +169,29 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
set_dr_addr_mask(0, i); set_dr_addr_mask(0, i);
} }
/* static int arch_bp_generic_len(int x86_len)
* Check for virtual address in kernel space.
*/
int arch_check_bp_in_kernelspace(struct perf_event *bp)
{ {
unsigned int len; switch (x86_len) {
unsigned long va; case X86_BREAKPOINT_LEN_1:
struct arch_hw_breakpoint *info = counter_arch_bp(bp); return HW_BREAKPOINT_LEN_1;
case X86_BREAKPOINT_LEN_2:
va = info->address; return HW_BREAKPOINT_LEN_2;
len = bp->attr.bp_len; case X86_BREAKPOINT_LEN_4:
return HW_BREAKPOINT_LEN_4;
/* #ifdef CONFIG_X86_64
* We don't need to worry about va + len - 1 overflowing: case X86_BREAKPOINT_LEN_8:
* we already require that va is aligned to a multiple of len. return HW_BREAKPOINT_LEN_8;
*/ #endif
return (va >= TASK_SIZE_MAX) || ((va + len - 1) >= TASK_SIZE_MAX); default:
return -EINVAL;
}
} }
int arch_bp_generic_fields(int x86_len, int x86_type, int arch_bp_generic_fields(int x86_len, int x86_type,
int *gen_len, int *gen_type) int *gen_len, int *gen_type)
{ {
int len;
/* Type */ /* Type */
switch (x86_type) { switch (x86_type) {
case X86_BREAKPOINT_EXECUTE: case X86_BREAKPOINT_EXECUTE:
...@@ -211,28 +212,32 @@ int arch_bp_generic_fields(int x86_len, int x86_type, ...@@ -211,28 +212,32 @@ int arch_bp_generic_fields(int x86_len, int x86_type,
} }
/* Len */ /* Len */
switch (x86_len) { len = arch_bp_generic_len(x86_len);
case X86_BREAKPOINT_LEN_1: if (len < 0)
*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:
return -EINVAL; return -EINVAL;
} *gen_len = len;
return 0; 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) static int arch_build_bp_info(struct perf_event *bp)
{ {
......
...@@ -35,7 +35,7 @@ struct pt_regs; ...@@ -35,7 +35,7 @@ struct pt_regs;
struct task_struct; struct task_struct;
int hw_breakpoint_slots(int type); 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 arch_validate_hwbkpt_settings(struct perf_event *bp);
int hw_breakpoint_exceptions_notify(struct notifier_block *unused, int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
unsigned long val, void *data); unsigned long val, void *data);
......
...@@ -33,14 +33,13 @@ int hw_breakpoint_slots(int type) ...@@ -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 int len;
unsigned long va; unsigned long va;
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
va = info->address; va = hw->address;
len = bp->attr.bp_len; len = hw->len;
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE); return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
} }
......
...@@ -427,7 +427,7 @@ static int hw_breakpoint_parse(struct perf_event *bp, ...@@ -427,7 +427,7 @@ static int hw_breakpoint_parse(struct perf_event *bp,
if (err) if (err)
return err; return err;
if (arch_check_bp_in_kernelspace(bp)) { if (arch_check_bp_in_kernelspace(hw)) {
if (attr->exclude_kernel) if (attr->exclude_kernel)
return -EINVAL; return -EINVAL;
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册