mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
x86/vpmu: Add the BTS extension
Add the BTS functionality to the existing vpmu implementation for Intel CPUs. Signed-off-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com> Committed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
3db3601531
commit
1a8aa75edc
7 files changed
+207
-41
No files matched your search
@@ -363,10 +363,11 @@ struct arch_vpmu_ops amd_vpmu_ops = {
|
||||
.arch_vpmu_load = amd_vpmu_restore
|
||||
};
|
||||
|
||||
int svm_vpmu_initialise(struct vcpu *v)
|
||||
int svm_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
|
||||
{
|
||||
struct vpmu_struct *vpmu = vcpu_vpmu(v);
|
||||
uint8_t family = current_cpu_data.x86;
|
||||
int ret = 0;
|
||||
|
||||
switch ( family )
|
||||
{
|
||||
@@ -374,8 +375,10 @@ int svm_vpmu_initialise(struct vcpu *v)
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
vpmu->arch_vpmu_ops = &amd_vpmu_ops;
|
||||
return amd_vpmu_initialise(v);
|
||||
ret = amd_vpmu_initialise(v);
|
||||
if ( !ret )
|
||||
vpmu->arch_vpmu_ops = &amd_vpmu_ops;
|
||||
return ret;
|
||||
}
|
||||
|
||||
printk("VPMU: Initialization failed. "
|
||||
|
||||
@@ -1833,6 +1833,9 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
|
||||
/* Debug Trace Store is not supported. */
|
||||
*msr_content |= MSR_IA32_MISC_ENABLE_BTS_UNAVAIL |
|
||||
MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL;
|
||||
/* Perhaps vpmu will change some bits. */
|
||||
if ( vpmu_do_rdmsr(msr, msr_content) )
|
||||
goto done;
|
||||
break;
|
||||
default:
|
||||
if ( vpmu_do_rdmsr(msr, msr_content) )
|
||||
@@ -1960,9 +1963,14 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content)
|
||||
int i, rc = 0;
|
||||
uint64_t supported = IA32_DEBUGCTLMSR_LBR | IA32_DEBUGCTLMSR_BTF;
|
||||
|
||||
if ( !msr_content || (msr_content & ~supported) )
|
||||
if ( !msr_content )
|
||||
break;
|
||||
|
||||
if ( msr_content & ~supported )
|
||||
{
|
||||
/* Perhaps some other bits are supported in vpmu. */
|
||||
if ( !vpmu_do_wrmsr(msr, msr_content) )
|
||||
break;
|
||||
}
|
||||
if ( msr_content & IA32_DEBUGCTLMSR_LBR )
|
||||
{
|
||||
const struct lbr_info *lbr = last_branch_msr_get();
|
||||
|
||||
@@ -406,7 +406,27 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
|
||||
struct core2_vpmu_context *core2_vpmu_cxt = NULL;
|
||||
|
||||
if ( !core2_vpmu_msr_common_check(msr, &type, &index) )
|
||||
{
|
||||
/* Special handling for BTS */
|
||||
if ( msr == MSR_IA32_DEBUGCTLMSR )
|
||||
{
|
||||
uint64_t supported = IA32_DEBUGCTLMSR_TR | IA32_DEBUGCTLMSR_BTS |
|
||||
IA32_DEBUGCTLMSR_BTINT;
|
||||
|
||||
if ( cpu_has(¤t_cpu_data, X86_FEATURE_DSCPL) )
|
||||
supported |= IA32_DEBUGCTLMSR_BTS_OFF_OS |
|
||||
IA32_DEBUGCTLMSR_BTS_OFF_USR;
|
||||
if ( msr_content & supported )
|
||||
{
|
||||
if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) )
|
||||
return 1;
|
||||
gdprintk(XENLOG_WARNING, "Debug Store is not supported on this cpu\n");
|
||||
vmx_inject_hw_exception(TRAP_gp_fault, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
core2_vpmu_cxt = vpmu->context;
|
||||
switch ( msr )
|
||||
@@ -425,6 +445,19 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
|
||||
"which is not supported.\n");
|
||||
return 1;
|
||||
case MSR_IA32_DS_AREA:
|
||||
if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_DS) )
|
||||
{
|
||||
if ( !is_canonical_address(msr_content) )
|
||||
{
|
||||
gdprintk(XENLOG_WARNING,
|
||||
"Illegal address for IA32_DS_AREA: %#" PRIx64 "x\n",
|
||||
msr_content);
|
||||
vmx_inject_hw_exception(TRAP_gp_fault, 0);
|
||||
return 1;
|
||||
}
|
||||
core2_vpmu_cxt->pmu_enable->ds_area_enable = msr_content ? 1 : 0;
|
||||
break;
|
||||
}
|
||||
gdprintk(XENLOG_WARNING, "Guest setting of DTS is ignored.\n");
|
||||
return 1;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
@@ -471,6 +504,7 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
|
||||
pmu_enable |= core2_vpmu_cxt->pmu_enable->fixed_ctr_enable[i];
|
||||
for ( i = 0; i < core2_get_pmc_count(); i++ )
|
||||
pmu_enable |= core2_vpmu_cxt->pmu_enable->arch_pmc_enable[i];
|
||||
pmu_enable |= core2_vpmu_cxt->pmu_enable->ds_area_enable;
|
||||
if ( pmu_enable )
|
||||
vpmu_set(vpmu, VPMU_RUNNING);
|
||||
else
|
||||
@@ -496,6 +530,8 @@ static int core2_vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
|
||||
inject_gp = 1;
|
||||
break;
|
||||
case MSR_TYPE_CTRL: /* IA32_FIXED_CTR_CTRL */
|
||||
if ( msr == MSR_IA32_DS_AREA )
|
||||
break;
|
||||
/* 4 bits per counter, currently 3 fixed counters implemented. */
|
||||
mask = ~((1ull << (3 * 4)) - 1);
|
||||
if (msr_content & mask)
|
||||
@@ -525,25 +561,35 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t *msr_content)
|
||||
struct vpmu_struct *vpmu = vcpu_vpmu(v);
|
||||
struct core2_vpmu_context *core2_vpmu_cxt = NULL;
|
||||
|
||||
if ( !core2_vpmu_msr_common_check(msr, &type, &index) )
|
||||
return 0;
|
||||
|
||||
core2_vpmu_cxt = vpmu->context;
|
||||
switch ( msr )
|
||||
if ( core2_vpmu_msr_common_check(msr, &type, &index) )
|
||||
{
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
*msr_content = 0;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
*msr_content = core2_vpmu_cxt->global_ovf_status;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
|
||||
break;
|
||||
default:
|
||||
rdmsrl(msr, *msr_content);
|
||||
core2_vpmu_cxt = vpmu->context;
|
||||
switch ( msr )
|
||||
{
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
*msr_content = 0;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
*msr_content = core2_vpmu_cxt->global_ovf_status;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
vmx_read_guest_msr(MSR_CORE_PERF_GLOBAL_CTRL, msr_content);
|
||||
break;
|
||||
default:
|
||||
rdmsrl(msr, *msr_content);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Extension for BTS */
|
||||
if ( msr == MSR_IA32_MISC_ENABLE )
|
||||
{
|
||||
if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_BTS) )
|
||||
*msr_content &= ~MSR_IA32_MISC_ENABLE_BTS_UNAVAIL;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -551,6 +597,16 @@ static void core2_vpmu_do_cpuid(unsigned int input,
|
||||
unsigned int *eax, unsigned int *ebx,
|
||||
unsigned int *ecx, unsigned int *edx)
|
||||
{
|
||||
if (input == 0x1)
|
||||
{
|
||||
struct vpmu_struct *vpmu = vcpu_vpmu(current);
|
||||
|
||||
if ( vpmu_is_set(vpmu, VPMU_CPU_HAS_DS) )
|
||||
{
|
||||
/* Switch on the 'Debug Store' feature in CPUID.EAX[1]:EDX[21] */
|
||||
*edx |= cpufeat_mask(X86_FEATURE_DS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
|
||||
@@ -564,15 +620,21 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
|
||||
struct vlapic *vlapic = vcpu_vlapic(v);
|
||||
|
||||
rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, msr_content);
|
||||
if ( !msr_content )
|
||||
return 0;
|
||||
|
||||
if ( is_pmc_quirk )
|
||||
handle_pmc_quirk(msr_content);
|
||||
|
||||
core2_vpmu_cxt->global_ovf_status |= msr_content;
|
||||
msr_content = 0xC000000700000000 | ((1 << core2_get_pmc_count()) - 1);
|
||||
wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, msr_content);
|
||||
if ( msr_content )
|
||||
{
|
||||
if ( is_pmc_quirk )
|
||||
handle_pmc_quirk(msr_content);
|
||||
core2_vpmu_cxt->global_ovf_status |= msr_content;
|
||||
msr_content = 0xC000000700000000 | ((1 << core2_get_pmc_count()) - 1);
|
||||
wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, msr_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No PMC overflow but perhaps a Trace Message interrupt. */
|
||||
msr_content = __vmread(GUEST_IA32_DEBUGCTL);
|
||||
if ( !(msr_content & IA32_DEBUGCTLMSR_TR) )
|
||||
return 0;
|
||||
}
|
||||
|
||||
apic_write_around(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
|
||||
|
||||
@@ -589,8 +651,53 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int core2_vpmu_initialise(struct vcpu *v)
|
||||
static int core2_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
|
||||
{
|
||||
struct vpmu_struct *vpmu = vcpu_vpmu(v);
|
||||
u64 msr_content;
|
||||
struct cpuinfo_x86 *c = ¤t_cpu_data;
|
||||
|
||||
if ( !(vpmu_flags & VPMU_BOOT_BTS) )
|
||||
goto func_out;
|
||||
/* Check the 'Debug Store' feature in the CPUID.EAX[1]:EDX[21] */
|
||||
if ( cpu_has(c, X86_FEATURE_DS) )
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
if ( !cpu_has(c, X86_FEATURE_DTES64) )
|
||||
{
|
||||
printk(XENLOG_G_WARNING "CPU doesn't support 64-bit DS Area"
|
||||
" - Debug Store disabled for d%d:v%d\n",
|
||||
v->domain->domain_id, v->vcpu_id);
|
||||
goto func_out;
|
||||
}
|
||||
#endif
|
||||
vpmu_set(vpmu, VPMU_CPU_HAS_DS);
|
||||
rdmsrl(MSR_IA32_MISC_ENABLE, msr_content);
|
||||
if ( msr_content & MSR_IA32_MISC_ENABLE_BTS_UNAVAIL )
|
||||
{
|
||||
/* If BTS_UNAVAIL is set reset the DS feature. */
|
||||
vpmu_reset(vpmu, VPMU_CPU_HAS_DS);
|
||||
printk(XENLOG_G_WARNING "CPU has set BTS_UNAVAIL"
|
||||
" - Debug Store disabled for d%d:v%d\n",
|
||||
v->domain->domain_id, v->vcpu_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
vpmu_set(vpmu, VPMU_CPU_HAS_BTS);
|
||||
if ( !cpu_has(c, X86_FEATURE_DSCPL) )
|
||||
printk(XENLOG_G_INFO
|
||||
"vpmu: CPU doesn't support CPL-Qualified BTS\n");
|
||||
printk("******************************************************\n");
|
||||
printk("** WARNING: Emulation of BTS Feature is switched on **\n");
|
||||
printk("** Using this processor feature in a virtualized **\n");
|
||||
printk("** environment is not 100%% safe. **\n");
|
||||
printk("** Setting the DS buffer address with wrong values **\n");
|
||||
printk("** may lead to hypervisor hangs or crashes. **\n");
|
||||
printk("** It is NOT recommended for production use! **\n");
|
||||
printk("******************************************************\n");
|
||||
}
|
||||
}
|
||||
func_out:
|
||||
check_pmc_quirk();
|
||||
return 0;
|
||||
}
|
||||
@@ -620,11 +727,12 @@ struct arch_vpmu_ops core2_vpmu_ops = {
|
||||
.arch_vpmu_load = core2_vpmu_load
|
||||
};
|
||||
|
||||
int vmx_vpmu_initialise(struct vcpu *v)
|
||||
int vmx_vpmu_initialise(struct vcpu *v, unsigned int vpmu_flags)
|
||||
{
|
||||
struct vpmu_struct *vpmu = vcpu_vpmu(v);
|
||||
uint8_t family = current_cpu_data.x86;
|
||||
uint8_t cpu_model = current_cpu_data.x86_model;
|
||||
int ret = 0;
|
||||
|
||||
if ( family == 6 )
|
||||
{
|
||||
@@ -639,8 +747,10 @@ int vmx_vpmu_initialise(struct vcpu *v)
|
||||
case 46:
|
||||
case 47:
|
||||
case 58:
|
||||
vpmu->arch_vpmu_ops = &core2_vpmu_ops;
|
||||
return core2_vpmu_initialise(v);
|
||||
ret = core2_vpmu_initialise(v, vpmu_flags);
|
||||
if ( !ret )
|
||||
vpmu->arch_vpmu_ops = &core2_vpmu_ops;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+32
-4
@@ -32,8 +32,36 @@
|
||||
#include <asm/hvm/svm/svm.h>
|
||||
#include <asm/hvm/svm/vmcb.h>
|
||||
|
||||
static bool_t __read_mostly opt_vpmu_enabled;
|
||||
boolean_param("vpmu", opt_vpmu_enabled);
|
||||
|
||||
/*
|
||||
* "vpmu" : vpmu generally enabled
|
||||
* "vpmu=off" : vpmu generally disabled
|
||||
* "vpmu=bts" : vpmu enabled and Intel BTS feature switched on.
|
||||
*/
|
||||
static unsigned int __read_mostly opt_vpmu_enabled;
|
||||
static void parse_vpmu_param(char *s);
|
||||
custom_param("vpmu", parse_vpmu_param);
|
||||
|
||||
static void __init parse_vpmu_param(char *s)
|
||||
{
|
||||
switch ( parse_bool(s) )
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
if ( !strcmp(s, "bts") )
|
||||
opt_vpmu_enabled |= VPMU_BOOT_BTS;
|
||||
else if ( *s )
|
||||
{
|
||||
printk("VPMU: unknown flag: %s - vpmu disabled!\n", s);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case 1:
|
||||
opt_vpmu_enabled |= VPMU_BOOT_ENABLED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int vpmu_do_wrmsr(unsigned int msr, uint64_t msr_content)
|
||||
{
|
||||
@@ -104,12 +132,12 @@ void vpmu_initialise(struct vcpu *v)
|
||||
switch ( vendor )
|
||||
{
|
||||
case X86_VENDOR_AMD:
|
||||
if ( svm_vpmu_initialise(v) != 0 )
|
||||
if ( svm_vpmu_initialise(v, opt_vpmu_enabled) != 0 )
|
||||
opt_vpmu_enabled = 0;
|
||||
break;
|
||||
|
||||
case X86_VENDOR_INTEL:
|
||||
if ( vmx_vpmu_initialise(v) != 0 )
|
||||
if ( vmx_vpmu_initialise(v, opt_vpmu_enabled) != 0 )
|
||||
opt_vpmu_enabled = 0;
|
||||
break;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ struct arch_msr_pair {
|
||||
};
|
||||
|
||||
struct core2_pmu_enable {
|
||||
char ds_area_enable;
|
||||
char fixed_ctr_enable[3];
|
||||
char arch_pmc_enable[1];
|
||||
};
|
||||
|
||||
@@ -22,6 +22,14 @@
|
||||
#ifndef __ASM_X86_HVM_VPMU_H_
|
||||
#define __ASM_X86_HVM_VPMU_H_
|
||||
|
||||
/*
|
||||
* Flag bits given as a string on the hypervisor boot parameter 'vpmu'.
|
||||
* See arch/x86/hvm/vpmu.c.
|
||||
*/
|
||||
#define VPMU_BOOT_ENABLED 0x1 /* vpmu generally enabled. */
|
||||
#define VPMU_BOOT_BTS 0x2 /* Intel BTS feature wanted. */
|
||||
|
||||
|
||||
#define msraddr_to_bitpos(x) (((x)&0xffff) + ((x)>>31)*0x2000)
|
||||
#define vcpu_vpmu(vcpu) (&((vcpu)->arch.hvm_vcpu.vpmu))
|
||||
#define vpmu_vcpu(vpmu) (container_of((vpmu), struct vcpu, \
|
||||
@@ -48,8 +56,8 @@ struct arch_vpmu_ops {
|
||||
void (*arch_vpmu_load)(struct vcpu *v);
|
||||
};
|
||||
|
||||
int vmx_vpmu_initialise(struct vcpu *v);
|
||||
int svm_vpmu_initialise(struct vcpu *v);
|
||||
int vmx_vpmu_initialise(struct vcpu *, unsigned int flags);
|
||||
int svm_vpmu_initialise(struct vcpu *, unsigned int flags);
|
||||
|
||||
struct vpmu_struct {
|
||||
u32 flags;
|
||||
@@ -61,6 +69,9 @@ struct vpmu_struct {
|
||||
#define VPMU_CONTEXT_LOADED 0x2
|
||||
#define VPMU_RUNNING 0x4
|
||||
#define VPMU_PASSIVE_DOMAIN_ALLOCATED 0x8
|
||||
#define VPMU_CPU_HAS_DS 0x10 /* Has Debug Store */
|
||||
#define VPMU_CPU_HAS_BTS 0x20 /* Has Branch Trace Store */
|
||||
|
||||
|
||||
#define vpmu_set(_vpmu, _x) ((_vpmu)->flags |= (_x))
|
||||
#define vpmu_reset(_vpmu, _x) ((_vpmu)->flags &= ~(_x))
|
||||
|
||||
@@ -67,6 +67,11 @@
|
||||
#define MSR_IA32_DEBUGCTLMSR 0x000001d9
|
||||
#define IA32_DEBUGCTLMSR_LBR (1<<0) /* Last Branch Record */
|
||||
#define IA32_DEBUGCTLMSR_BTF (1<<1) /* Single Step on Branches */
|
||||
#define IA32_DEBUGCTLMSR_TR (1<<6) /* Trace Message Enable */
|
||||
#define IA32_DEBUGCTLMSR_BTS (1<<7) /* Branch Trace Store */
|
||||
#define IA32_DEBUGCTLMSR_BTINT (1<<8) /* Branch Trace Interrupt */
|
||||
#define IA32_DEBUGCTLMSR_BTS_OFF_OS (1<<9) /* BTS off if CPL 0 */
|
||||
#define IA32_DEBUGCTLMSR_BTS_OFF_USR (1<<10) /* BTS off if CPL > 0 */
|
||||
|
||||
#define MSR_IA32_LASTBRANCHFROMIP 0x000001db
|
||||
#define MSR_IA32_LASTBRANCHTOIP 0x000001dc
|
||||
|
||||