Commit 8c449753 authored by Frederic Weisbecker's avatar Frederic Weisbecker Committed by Ingo Molnar

perf/arch/arm64: Implement hw_breakpoint_arch_parse()

Migrate to the new API in order to remove arch_validate_hwbkpt_settings()
that clumsily mixes up architecture validation and commit.
Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
Acked-by: default avatarWill Deacon <will.deacon@arm.com>
Acked-by: default avatarMark Rutland <mark.rutland@arm.com>
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: 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: Yoshinori Sato <ysato@users.sourceforge.jp>
Link: http://lkml.kernel.org/r/1529981939-8231-7-git-send-email-frederic@kernel.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 9d52718c
...@@ -119,13 +119,17 @@ static inline void decode_ctrl_reg(u32 reg, ...@@ -119,13 +119,17 @@ static inline void decode_ctrl_reg(u32 reg,
struct task_struct; struct task_struct;
struct notifier_block; struct notifier_block;
struct perf_event_attr;
struct perf_event; struct perf_event;
struct pmu; 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 arch_hw_breakpoint *hw); 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_arch_parse(struct perf_event *bp,
const struct perf_event_attr *attr,
struct arch_hw_breakpoint *hw);
#define hw_breakpoint_arch_parse hw_breakpoint_arch_parse
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);
......
...@@ -420,53 +420,53 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl, ...@@ -420,53 +420,53 @@ int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
/* /*
* Construct an arch_hw_breakpoint from a perf_event. * Construct an arch_hw_breakpoint from a perf_event.
*/ */
static int arch_build_bp_info(struct perf_event *bp) static int arch_build_bp_info(struct perf_event *bp,
const struct perf_event_attr *attr,
struct arch_hw_breakpoint *hw)
{ {
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
/* Type */ /* Type */
switch (bp->attr.bp_type) { switch (attr->bp_type) {
case HW_BREAKPOINT_X: case HW_BREAKPOINT_X:
info->ctrl.type = ARM_BREAKPOINT_EXECUTE; hw->ctrl.type = ARM_BREAKPOINT_EXECUTE;
break; break;
case HW_BREAKPOINT_R: case HW_BREAKPOINT_R:
info->ctrl.type = ARM_BREAKPOINT_LOAD; hw->ctrl.type = ARM_BREAKPOINT_LOAD;
break; break;
case HW_BREAKPOINT_W: case HW_BREAKPOINT_W:
info->ctrl.type = ARM_BREAKPOINT_STORE; hw->ctrl.type = ARM_BREAKPOINT_STORE;
break; break;
case HW_BREAKPOINT_RW: case HW_BREAKPOINT_RW:
info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE; hw->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
/* Len */ /* Len */
switch (bp->attr.bp_len) { switch (attr->bp_len) {
case HW_BREAKPOINT_LEN_1: case HW_BREAKPOINT_LEN_1:
info->ctrl.len = ARM_BREAKPOINT_LEN_1; hw->ctrl.len = ARM_BREAKPOINT_LEN_1;
break; break;
case HW_BREAKPOINT_LEN_2: case HW_BREAKPOINT_LEN_2:
info->ctrl.len = ARM_BREAKPOINT_LEN_2; hw->ctrl.len = ARM_BREAKPOINT_LEN_2;
break; break;
case HW_BREAKPOINT_LEN_3: case HW_BREAKPOINT_LEN_3:
info->ctrl.len = ARM_BREAKPOINT_LEN_3; hw->ctrl.len = ARM_BREAKPOINT_LEN_3;
break; break;
case HW_BREAKPOINT_LEN_4: case HW_BREAKPOINT_LEN_4:
info->ctrl.len = ARM_BREAKPOINT_LEN_4; hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
break; break;
case HW_BREAKPOINT_LEN_5: case HW_BREAKPOINT_LEN_5:
info->ctrl.len = ARM_BREAKPOINT_LEN_5; hw->ctrl.len = ARM_BREAKPOINT_LEN_5;
break; break;
case HW_BREAKPOINT_LEN_6: case HW_BREAKPOINT_LEN_6:
info->ctrl.len = ARM_BREAKPOINT_LEN_6; hw->ctrl.len = ARM_BREAKPOINT_LEN_6;
break; break;
case HW_BREAKPOINT_LEN_7: case HW_BREAKPOINT_LEN_7:
info->ctrl.len = ARM_BREAKPOINT_LEN_7; hw->ctrl.len = ARM_BREAKPOINT_LEN_7;
break; break;
case HW_BREAKPOINT_LEN_8: case HW_BREAKPOINT_LEN_8:
info->ctrl.len = ARM_BREAKPOINT_LEN_8; hw->ctrl.len = ARM_BREAKPOINT_LEN_8;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -477,37 +477,37 @@ static int arch_build_bp_info(struct perf_event *bp) ...@@ -477,37 +477,37 @@ static int arch_build_bp_info(struct perf_event *bp)
* AArch32 also requires breakpoints of length 2 for Thumb. * AArch32 also requires breakpoints of length 2 for Thumb.
* Watchpoints can be of length 1, 2, 4 or 8 bytes. * Watchpoints can be of length 1, 2, 4 or 8 bytes.
*/ */
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
if (is_compat_bp(bp)) { if (is_compat_bp(bp)) {
if (info->ctrl.len != ARM_BREAKPOINT_LEN_2 && if (hw->ctrl.len != ARM_BREAKPOINT_LEN_2 &&
info->ctrl.len != ARM_BREAKPOINT_LEN_4) hw->ctrl.len != ARM_BREAKPOINT_LEN_4)
return -EINVAL; return -EINVAL;
} else if (info->ctrl.len != ARM_BREAKPOINT_LEN_4) { } else if (hw->ctrl.len != ARM_BREAKPOINT_LEN_4) {
/* /*
* FIXME: Some tools (I'm looking at you perf) assume * FIXME: Some tools (I'm looking at you perf) assume
* that breakpoints should be sizeof(long). This * that breakpoints should be sizeof(long). This
* is nonsense. For now, we fix up the parameter * is nonsense. For now, we fix up the parameter
* but we should probably return -EINVAL instead. * but we should probably return -EINVAL instead.
*/ */
info->ctrl.len = ARM_BREAKPOINT_LEN_4; hw->ctrl.len = ARM_BREAKPOINT_LEN_4;
} }
} }
/* Address */ /* Address */
info->address = bp->attr.bp_addr; hw->address = attr->bp_addr;
/* /*
* Privilege * Privilege
* 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(info)) if (arch_check_bp_in_kernelspace(hw))
info->ctrl.privilege = AARCH64_BREAKPOINT_EL1; hw->ctrl.privilege = AARCH64_BREAKPOINT_EL1;
else else
info->ctrl.privilege = AARCH64_BREAKPOINT_EL0; hw->ctrl.privilege = AARCH64_BREAKPOINT_EL0;
/* Enabled? */ /* Enabled? */
info->ctrl.enabled = !bp->attr.disabled; hw->ctrl.enabled = !attr->disabled;
return 0; return 0;
} }
...@@ -515,14 +515,15 @@ static int arch_build_bp_info(struct perf_event *bp) ...@@ -515,14 +515,15 @@ static int arch_build_bp_info(struct perf_event *bp)
/* /*
* Validate the arch-specific HW Breakpoint register settings. * Validate the arch-specific HW Breakpoint register settings.
*/ */
int arch_validate_hwbkpt_settings(struct perf_event *bp) int hw_breakpoint_arch_parse(struct perf_event *bp,
const struct perf_event_attr *attr,
struct arch_hw_breakpoint *hw)
{ {
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
int ret; int ret;
u64 alignment_mask, offset; u64 alignment_mask, offset;
/* Build the arch_hw_breakpoint. */ /* Build the arch_hw_breakpoint. */
ret = arch_build_bp_info(bp); ret = arch_build_bp_info(bp, attr, hw);
if (ret) if (ret)
return ret; return ret;
...@@ -536,42 +537,42 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) ...@@ -536,42 +537,42 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
* that here. * that here.
*/ */
if (is_compat_bp(bp)) { if (is_compat_bp(bp)) {
if (info->ctrl.len == ARM_BREAKPOINT_LEN_8) if (hw->ctrl.len == ARM_BREAKPOINT_LEN_8)
alignment_mask = 0x7; alignment_mask = 0x7;
else else
alignment_mask = 0x3; alignment_mask = 0x3;
offset = info->address & alignment_mask; offset = hw->address & alignment_mask;
switch (offset) { switch (offset) {
case 0: case 0:
/* Aligned */ /* Aligned */
break; break;
case 1: case 1:
/* Allow single byte watchpoint. */ /* Allow single byte watchpoint. */
if (info->ctrl.len == ARM_BREAKPOINT_LEN_1) if (hw->ctrl.len == ARM_BREAKPOINT_LEN_1)
break; break;
case 2: case 2:
/* Allow halfword watchpoints and breakpoints. */ /* Allow halfword watchpoints and breakpoints. */
if (info->ctrl.len == ARM_BREAKPOINT_LEN_2) if (hw->ctrl.len == ARM_BREAKPOINT_LEN_2)
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
} else { } else {
if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) if (hw->ctrl.type == ARM_BREAKPOINT_EXECUTE)
alignment_mask = 0x3; alignment_mask = 0x3;
else else
alignment_mask = 0x7; alignment_mask = 0x7;
offset = info->address & alignment_mask; offset = hw->address & alignment_mask;
} }
info->address &= ~alignment_mask; hw->address &= ~alignment_mask;
info->ctrl.len <<= offset; hw->ctrl.len <<= offset;
/* /*
* Disallow per-task kernel breakpoints since these would * Disallow per-task kernel breakpoints since these would
* complicate the stepping code. * complicate the stepping code.
*/ */
if (info->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target) if (hw->ctrl.privilege == AARCH64_BREAKPOINT_EL1 && bp->hw.target)
return -EINVAL; return -EINVAL;
return 0; return 0;
......
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