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:
Dietmar Hahn committed 2012-03-15 15:13:00 +01:00
1 parent 3db3601531
commit 1a8aa75edc
7 files changed
+207 -41

No files matched your search

+6 -3
View File
@@ -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. "
+10 -2
View File
@@ -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();
+140 -30
View File
@@ -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(&current_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 = &current_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
View File
@@ -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;
+1
View File
@@ -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];
};
+13 -2
View File
@@ -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))
+5
View File
@@ -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
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.