perf/x86/amd: AMD support for bp_len > HW_BREAKPOINT_LEN_8
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>
This commit is contained in:
committed by
Frederic Weisbecker
parent
4e6e311e59
commit
d6d55f0b9d
@ -174,6 +174,7 @@
|
|||||||
#define X86_FEATURE_TOPOEXT ( 6*32+22) /* topology extensions CPUID leafs */
|
#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_CORE ( 6*32+23) /* core performance counter extensions */
|
||||||
#define X86_FEATURE_PERFCTR_NB ( 6*32+24) /* NB 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 */
|
#define X86_FEATURE_PERFCTR_L2 ( 6*32+28) /* L2 performance counter extensions */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -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_cx16 boot_cpu_has(X86_FEATURE_CX16)
|
||||||
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
|
#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_topoext boot_cpu_has(X86_FEATURE_TOPOEXT)
|
||||||
|
#define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT)
|
||||||
|
|
||||||
#if __GNUC__ >= 4
|
#if __GNUC__ >= 4
|
||||||
extern void warn_pre_alternatives(void);
|
extern void warn_pre_alternatives(void);
|
||||||
|
@ -114,5 +114,10 @@ static inline void debug_stack_usage_inc(void) { }
|
|||||||
static inline void debug_stack_usage_dec(void) { }
|
static inline void debug_stack_usage_dec(void) { }
|
||||||
#endif /* X86_64 */
|
#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 */
|
#endif /* _ASM_X86_DEBUGREG_H */
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
struct arch_hw_breakpoint {
|
struct arch_hw_breakpoint {
|
||||||
unsigned long address;
|
unsigned long address;
|
||||||
|
unsigned long mask;
|
||||||
u8 len;
|
u8 len;
|
||||||
u8 type;
|
u8 type;
|
||||||
};
|
};
|
||||||
|
@ -212,6 +212,10 @@
|
|||||||
/* Fam 16h MSRs */
|
/* Fam 16h MSRs */
|
||||||
#define MSR_F16H_L2I_PERF_CTL 0xc0010230
|
#define MSR_F16H_L2I_PERF_CTL 0xc0010230
|
||||||
#define MSR_F16H_L2I_PERF_CTR 0xc0010231
|
#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 */
|
/* Fam 15h MSRs */
|
||||||
#define MSR_F15H_PERF_CTL 0xc0010200
|
#define MSR_F15H_PERF_CTL 0xc0010200
|
||||||
|
@ -870,3 +870,22 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
|
|||||||
|
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -126,6 +126,8 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
|
|||||||
*dr7 |= encode_dr7(i, info->len, info->type);
|
*dr7 |= encode_dr7(i, info->len, info->type);
|
||||||
|
|
||||||
set_debugreg(*dr7, 7);
|
set_debugreg(*dr7, 7);
|
||||||
|
if (info->mask)
|
||||||
|
set_dr_addr_mask(info->mask, i);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -161,6 +163,8 @@ void arch_uninstall_hw_breakpoint(struct perf_event *bp)
|
|||||||
*dr7 &= ~__encode_dr7(i, info->len, info->type);
|
*dr7 &= ~__encode_dr7(i, info->len, info->type);
|
||||||
|
|
||||||
set_debugreg(*dr7, 7);
|
set_debugreg(*dr7, 7);
|
||||||
|
if (info->mask)
|
||||||
|
set_dr_addr_mask(0, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_hbp_len(u8 hbp_len)
|
static int get_hbp_len(u8 hbp_len)
|
||||||
@ -277,6 +281,8 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Len */
|
/* Len */
|
||||||
|
info->mask = 0;
|
||||||
|
|
||||||
switch (bp->attr.bp_len) {
|
switch (bp->attr.bp_len) {
|
||||||
case HW_BREAKPOINT_LEN_1:
|
case HW_BREAKPOINT_LEN_1:
|
||||||
info->len = X86_BREAKPOINT_LEN_1;
|
info->len = X86_BREAKPOINT_LEN_1;
|
||||||
@ -293,11 +299,17 @@ static int arch_build_bp_info(struct perf_event *bp)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate the arch-specific HW Breakpoint register settings
|
* Validate the arch-specific HW Breakpoint register settings
|
||||||
*/
|
*/
|
||||||
@ -312,11 +324,11 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = -EINVAL;
|
|
||||||
|
|
||||||
switch (info->len) {
|
switch (info->len) {
|
||||||
case X86_BREAKPOINT_LEN_1:
|
case X86_BREAKPOINT_LEN_1:
|
||||||
align = 0;
|
align = 0;
|
||||||
|
if (info->mask)
|
||||||
|
align = info->mask;
|
||||||
break;
|
break;
|
||||||
case X86_BREAKPOINT_LEN_2:
|
case X86_BREAKPOINT_LEN_2:
|
||||||
align = 1;
|
align = 1;
|
||||||
@ -330,7 +342,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
|
|||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return ret;
|
WARN_ON_ONCE(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Reference in New Issue
Block a user