Skip to content

Commit

Permalink
perf/x86/amd: AMD support for bp_len > HW_BREAKPOINT_LEN_8
Browse files Browse the repository at this point in the history
Implement hardware breakpoint address mask for AMD Family 16h and
above processors. CPUID feature bit indicates hardware support for
DRn_ADDR_MASK MSRs. These masks further qualify DRn/DR7 hardware
breakpoint addresses to allow matching of larger addresses ranges.

Valuable advice and pseudo code from Oleg Nesterov <oleg@redhat.com>

Signed-off-by: Jacob Shin <jacob.w.shin@gmail.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Reviewed-by: Oleg Nesterov <oleg@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: xiakaixu <xiakaixu@huawei.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
  • Loading branch information
Jacob Shin authored and Frederic Weisbecker committed Dec 3, 2014
1 parent 4e6e311 commit d6d55f0
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 4 deletions.
2 changes: 2 additions & 0 deletions arch/x86/include/asm/cpufeature.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */
#define X86_FEATURE_PERFCTR_CORE ( 6*32+23) /* core performance counter extensions */
#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB performance counter extensions */
#define X86_FEATURE_BPEXT (6*32+26) /* data breakpoint extension */
#define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */

/*
Expand Down Expand Up @@ -383,6 +384,7 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
#define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT)
#define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT)

#if __GNUC__ >= 4
extern void warn_pre_alternatives(void);
Expand Down
5 changes: 5 additions & 0 deletions arch/x86/include/asm/debugreg.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,10 @@ static inline void debug_stack_usage_inc(void) { }
static inline void debug_stack_usage_dec(void) { }
#endif /* X86_64 */

#ifdef CONFIG_CPU_SUP_AMD
extern void set_dr_addr_mask(unsigned long mask, int dr);
#else
static inline void set_dr_addr_mask(unsigned long mask, int dr) { }
#endif

#endif /* _ASM_X86_DEBUGREG_H */
1 change: 1 addition & 0 deletions arch/x86/include/asm/hw_breakpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
struct arch_hw_breakpoint {
unsigned long address;
unsigned long mask;
u8 len;
u8 type;
};
Expand Down
4 changes: 4 additions & 0 deletions arch/x86/include/uapi/asm/msr-index.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@
/* Fam 16h MSRs */
#define MSR_F16H_L2I_PERF_CTL 0xc0010230
#define MSR_F16H_L2I_PERF_CTR 0xc0010231
#define MSR_F16H_DR1_ADDR_MASK 0xc0011019
#define MSR_F16H_DR2_ADDR_MASK 0xc001101a
#define MSR_F16H_DR3_ADDR_MASK 0xc001101b
#define MSR_F16H_DR0_ADDR_MASK 0xc0011027

/* Fam 15h MSRs */
#define MSR_F15H_PERF_CTL 0xc0010200
Expand Down
19 changes: 19 additions & 0 deletions arch/x86/kernel/cpu/amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,3 +870,22 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)

return false;
}

void set_dr_addr_mask(unsigned long mask, int dr)
{
if (!cpu_has_bpext)
return;

switch (dr) {
case 0:
wrmsr(MSR_F16H_DR0_ADDR_MASK, mask, 0);
break;
case 1:
case 2:
case 3:
wrmsr(MSR_F16H_DR1_ADDR_MASK - 1 + dr, mask, 0);
break;
default:
break;
}
}
20 changes: 16 additions & 4 deletions arch/x86/kernel/hw_breakpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
*dr7 |= encode_dr7(i, info->len, info->type);

set_debugreg(*dr7, 7);
if (info->mask)
set_dr_addr_mask(info->mask, i);

return 0;
}
Expand Down Expand Up @@ -161,6 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
*dr7 &= ~__encode_dr7(i, info->len, info->type);

set_debugreg(*dr7, 7);
if (info->mask)
set_dr_addr_mask(0, i);
}

static int get_hbp_len(u8 hbp_len)
Expand Down Expand Up @@ -277,6 +281,8 @@ static int arch_build_bp_info(struct perf_event *bp)
}

/* Len */
info->mask = 0;

switch (bp->attr.bp_len) {
case HW_BREAKPOINT_LEN_1:
info->len = X86_BREAKPOINT_LEN_1;
Expand All @@ -293,11 +299,17 @@ static int arch_build_bp_info(struct perf_event *bp)
break;
#endif
default:
return -EINVAL;
if (!is_power_of_2(bp->attr.bp_len))
return -EINVAL;
if (!cpu_has_bpext)
return -EOPNOTSUPP;
info->mask = bp->attr.bp_len - 1;
info->len = X86_BREAKPOINT_LEN_1;
}

return 0;
}

/*
* Validate the arch-specific HW Breakpoint register settings
*/
Expand All @@ -312,11 +324,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
if (ret)
return ret;

ret = -EINVAL;

switch (info->len) {
case X86_BREAKPOINT_LEN_1:
align = 0;
if (info->mask)
align = info->mask;
break;
case X86_BREAKPOINT_LEN_2:
align = 1;
Expand All @@ -330,7 +342,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
break;
#endif
default:
return ret;
WARN_ON_ONCE(1);
}

/*
Expand Down

0 comments on commit d6d55f0

Please sign in to comment.