mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-28 21:33:52 +00:00
KVM x86/pmu changes for 6.5:
- Add support for AMD PerfMonV2, with a variety of cleanups and minor fixes included along the way -----BEGIN PGP SIGNATURE----- iQJGBAABCgAwFiEEMHr+pfEFOIzK+KY1YJEiAU0MEvkFAmSaHFgSHHNlYW5qY0Bn b29nbGUuY29tAAoJEGCRIgFNDBL5twMP/15ZJFqZVigVQoATJeeR9tWUuyJe95xM lyfnTel91Sg8XOamdwBGi7jLpaDgj34Jm0cfM7/4LbJk2/taeaCLYmJd5w9FXvaw EkytQGO85hVNe2XuY+h+XxSIxpflKxgFuUnOwcDk2QbKgASzNSG/mJ9ZBx8PNVXD FnyOqpbbYDFspWWvUOAI/RkHnr/dALjXJsSUMvuh3nz5e1NTyubjCAZg+/bse2nR s8FrcSh4B0Lg0h4r2fdJ4sAiM/qWhcCIhq5svyTAcUG0T4rMS40LrosJOw3wkBRM dyZYXy6GEENeCFJPhenF1mTE1embFyZp89PV/FCNRZXODbnM4kheJFT9gucAjlKi ZafRcutrkYIVf4lZCMofDfQGLX/GCEJnwUPKyGygIsPoDRrdR7OLrFycON5bxocr 9NBNG+2teQFbnt5irB/bBGojtIZtu3OEylkuRjQUQ3lJYQ5r6LddarI9acIu1SHt 4rRfh8QN5qmMvVblaQzggOr6BPtmPr8QqMEMFncaUMCsV/82hRAEfvj2rifGFJNo Axz1ajMfirxyM45WzredUkzzsbphiiegPBELCLRZfHmaEhJ8P7t7wvri0bXt9YdI vjSfX+6ulOgDC+xAazE0gEJO4Uh5+g3Y+1e0fr43ltWzUOWdCQskzD3LE9DkqIXj KAaCuHYbYpIZ =MwqV -----END PGP SIGNATURE----- Merge tag 'kvm-x86-pmu-6.5' of https://github.com/kvm-x86/linux into HEAD KVM x86/pmu changes for 6.5: - Add support for AMD PerfMonV2, with a variety of cleanups and minor fixes included along the way
This commit is contained in:
commit
751d77fefa
12 changed files with 260 additions and 118 deletions
|
@ -13,7 +13,6 @@ BUILD_BUG_ON(1)
|
|||
* at the call sites.
|
||||
*/
|
||||
KVM_X86_PMU_OP(hw_event_available)
|
||||
KVM_X86_PMU_OP(pmc_is_enabled)
|
||||
KVM_X86_PMU_OP(pmc_idx_to_pmc)
|
||||
KVM_X86_PMU_OP(rdpmc_ecx_to_pmc)
|
||||
KVM_X86_PMU_OP(msr_idx_to_pmc)
|
||||
|
|
|
@ -523,7 +523,7 @@ struct kvm_pmu {
|
|||
u64 global_status;
|
||||
u64 counter_bitmask[2];
|
||||
u64 global_ctrl_mask;
|
||||
u64 global_ovf_ctrl_mask;
|
||||
u64 global_status_mask;
|
||||
u64 reserved_bits;
|
||||
u64 raw_event_mask;
|
||||
struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC];
|
||||
|
|
|
@ -729,6 +729,10 @@ void kvm_set_cpu_caps(void)
|
|||
F(NULL_SEL_CLR_BASE) | F(AUTOIBRS) | 0 /* PrefetchCtlMsr */
|
||||
);
|
||||
|
||||
kvm_cpu_cap_init_kvm_defined(CPUID_8000_0022_EAX,
|
||||
F(PERFMON_V2)
|
||||
);
|
||||
|
||||
/*
|
||||
* Synthesize "LFENCE is serializing" into the AMD-defined entry in
|
||||
* KVM's supported CPUID if the feature is reported as supported by the
|
||||
|
@ -943,7 +947,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
|
|||
union cpuid10_eax eax;
|
||||
union cpuid10_edx edx;
|
||||
|
||||
if (!static_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
|
||||
if (!enable_pmu || !static_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
|
||||
entry->eax = entry->ebx = entry->ecx = entry->edx = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -1123,7 +1127,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
|
|||
entry->edx = 0;
|
||||
break;
|
||||
case 0x80000000:
|
||||
entry->eax = min(entry->eax, 0x80000021);
|
||||
entry->eax = min(entry->eax, 0x80000022);
|
||||
/*
|
||||
* Serializing LFENCE is reported in a multitude of ways, and
|
||||
* NullSegClearsBase is not reported in CPUID on Zen2; help
|
||||
|
@ -1228,6 +1232,28 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
|
|||
entry->ebx = entry->ecx = entry->edx = 0;
|
||||
cpuid_entry_override(entry, CPUID_8000_0021_EAX);
|
||||
break;
|
||||
/* AMD Extended Performance Monitoring and Debug */
|
||||
case 0x80000022: {
|
||||
union cpuid_0x80000022_ebx ebx;
|
||||
|
||||
entry->ecx = entry->edx = 0;
|
||||
if (!enable_pmu || !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2)) {
|
||||
entry->eax = entry->ebx;
|
||||
break;
|
||||
}
|
||||
|
||||
cpuid_entry_override(entry, CPUID_8000_0022_EAX);
|
||||
|
||||
if (kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
|
||||
ebx.split.num_core_pmc = kvm_pmu_cap.num_counters_gp;
|
||||
else if (kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE))
|
||||
ebx.split.num_core_pmc = AMD64_NUM_COUNTERS_CORE;
|
||||
else
|
||||
ebx.split.num_core_pmc = AMD64_NUM_COUNTERS;
|
||||
|
||||
entry->ebx = ebx.full;
|
||||
break;
|
||||
}
|
||||
/*Add support for Centaur's CPUID instruction*/
|
||||
case 0xC0000000:
|
||||
/*Just support up to 0xC0000004 now*/
|
||||
|
|
|
@ -93,11 +93,6 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
|
|||
#undef __KVM_X86_PMU_OP
|
||||
}
|
||||
|
||||
static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc)
|
||||
{
|
||||
return static_call(kvm_x86_pmu_pmc_is_enabled)(pmc);
|
||||
}
|
||||
|
||||
static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
|
||||
{
|
||||
struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
|
||||
|
@ -562,6 +557,14 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
|
|||
|
||||
bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
||||
{
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
return kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return static_call(kvm_x86_pmu_msr_idx_to_pmc)(vcpu, msr) ||
|
||||
static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr);
|
||||
}
|
||||
|
@ -577,13 +580,86 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr)
|
|||
|
||||
int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
u32 msr = msr_info->index;
|
||||
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
|
||||
msr_info->data = pmu->global_status;
|
||||
break;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
msr_info->data = pmu->global_ctrl;
|
||||
break;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
msr_info->data = 0;
|
||||
break;
|
||||
default:
|
||||
return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
|
||||
return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
u32 msr = msr_info->index;
|
||||
u64 data = msr_info->data;
|
||||
u64 diff;
|
||||
|
||||
/*
|
||||
* Note, AMD ignores writes to reserved bits and read-only PMU MSRs,
|
||||
* whereas Intel generates #GP on attempts to write reserved/RO MSRs.
|
||||
*/
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
if (!msr_info->host_initiated)
|
||||
return 1; /* RO MSR */
|
||||
fallthrough;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
|
||||
/* Per PPR, Read-only MSR. Writes are ignored. */
|
||||
if (!msr_info->host_initiated)
|
||||
break;
|
||||
|
||||
if (data & pmu->global_status_mask)
|
||||
return 1;
|
||||
|
||||
pmu->global_status = data;
|
||||
break;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
|
||||
data &= ~pmu->global_ctrl_mask;
|
||||
fallthrough;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
if (!kvm_valid_perf_global_ctrl(pmu, data))
|
||||
return 1;
|
||||
|
||||
if (pmu->global_ctrl != data) {
|
||||
diff = pmu->global_ctrl ^ data;
|
||||
pmu->global_ctrl = data;
|
||||
reprogram_counters(pmu, diff);
|
||||
}
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
/*
|
||||
* GLOBAL_OVF_CTRL, a.k.a. GLOBAL STATUS_RESET, clears bits in
|
||||
* GLOBAL_STATUS, and so the set of reserved bits is the same.
|
||||
*/
|
||||
if (data & pmu->global_status_mask)
|
||||
return 1;
|
||||
fallthrough;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
|
||||
if (!msr_info->host_initiated)
|
||||
pmu->global_status &= ~data;
|
||||
break;
|
||||
default:
|
||||
kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
|
||||
return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* refresh PMU settings. This function generally is called when underlying
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
struct kvm_pmu_ops {
|
||||
bool (*hw_event_available)(struct kvm_pmc *pmc);
|
||||
bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
|
||||
struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
|
||||
struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu,
|
||||
unsigned int idx, u64 *mask);
|
||||
|
@ -37,10 +36,25 @@ struct kvm_pmu_ops {
|
|||
|
||||
const u64 EVENTSEL_EVENT;
|
||||
const int MAX_NR_GP_COUNTERS;
|
||||
const int MIN_NR_GP_COUNTERS;
|
||||
};
|
||||
|
||||
void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops);
|
||||
|
||||
static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
|
||||
{
|
||||
/*
|
||||
* Architecturally, Intel's SDM states that IA32_PERF_GLOBAL_CTRL is
|
||||
* supported if "CPUID.0AH: EAX[7:0] > 0", i.e. if the PMU version is
|
||||
* greater than zero. However, KVM only exposes and emulates the MSR
|
||||
* to/for the guest if the guest PMU supports at least "Architectural
|
||||
* Performance Monitoring Version 2".
|
||||
*
|
||||
* AMD's version of PERF_GLOBAL_CTRL conveniently shows up with v2.
|
||||
*/
|
||||
return pmu->version > 1;
|
||||
}
|
||||
|
||||
static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
|
||||
|
@ -161,6 +175,7 @@ extern struct x86_pmu_capability kvm_pmu_cap;
|
|||
static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
|
||||
{
|
||||
bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
|
||||
int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
|
||||
|
||||
/*
|
||||
* Hybrid PMUs don't play nice with virtualization without careful
|
||||
|
@ -175,11 +190,15 @@ static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
|
|||
perf_get_x86_pmu_capability(&kvm_pmu_cap);
|
||||
|
||||
/*
|
||||
* For Intel, only support guest architectural pmu
|
||||
* on a host with architectural pmu.
|
||||
* WARN if perf did NOT disable hardware PMU if the number of
|
||||
* architecturally required GP counters aren't present, i.e. if
|
||||
* there are a non-zero number of counters, but fewer than what
|
||||
* is architecturally required.
|
||||
*/
|
||||
if ((is_intel && !kvm_pmu_cap.version) ||
|
||||
!kvm_pmu_cap.num_counters_gp)
|
||||
if (!kvm_pmu_cap.num_counters_gp ||
|
||||
WARN_ON_ONCE(kvm_pmu_cap.num_counters_gp < min_nr_gp_ctrs))
|
||||
enable_pmu = false;
|
||||
else if (is_intel && !kvm_pmu_cap.version)
|
||||
enable_pmu = false;
|
||||
}
|
||||
|
||||
|
@ -201,6 +220,33 @@ static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc)
|
|||
kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
|
||||
}
|
||||
|
||||
static inline void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (!diff)
|
||||
return;
|
||||
|
||||
for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
|
||||
set_bit(bit, pmu->reprogram_pmi);
|
||||
kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a PMC is enabled by comparing it against global_ctrl bits.
|
||||
*
|
||||
* If the vPMU doesn't have global_ctrl MSR, all vPMCs are enabled.
|
||||
*/
|
||||
static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
|
||||
|
||||
if (!kvm_pmu_has_perf_global_ctrl(pmu))
|
||||
return true;
|
||||
|
||||
return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
|
||||
}
|
||||
|
||||
void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
|
||||
void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
|
||||
int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);
|
||||
|
|
|
@ -15,6 +15,7 @@ enum kvm_only_cpuid_leafs {
|
|||
CPUID_12_EAX = NCAPINTS,
|
||||
CPUID_7_1_EDX,
|
||||
CPUID_8000_0007_EDX,
|
||||
CPUID_8000_0022_EAX,
|
||||
NR_KVM_CPU_CAPS,
|
||||
|
||||
NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS,
|
||||
|
@ -47,6 +48,9 @@ enum kvm_only_cpuid_leafs {
|
|||
/* CPUID level 0x80000007 (EDX). */
|
||||
#define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8)
|
||||
|
||||
/* CPUID level 0x80000022 (EAX) */
|
||||
#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0)
|
||||
|
||||
struct cpuid_reg {
|
||||
u32 function;
|
||||
u32 index;
|
||||
|
@ -74,6 +78,7 @@ static const struct cpuid_reg reverse_cpuid[] = {
|
|||
[CPUID_7_1_EDX] = { 7, 1, CPUID_EDX},
|
||||
[CPUID_8000_0007_EDX] = {0x80000007, 0, CPUID_EDX},
|
||||
[CPUID_8000_0021_EAX] = {0x80000021, 0, CPUID_EAX},
|
||||
[CPUID_8000_0022_EAX] = {0x80000022, 0, CPUID_EAX},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -108,6 +113,8 @@ static __always_inline u32 __feature_translate(int x86_feature)
|
|||
return KVM_X86_FEATURE_SGX_EDECCSSA;
|
||||
else if (x86_feature == X86_FEATURE_CONSTANT_TSC)
|
||||
return KVM_X86_FEATURE_CONSTANT_TSC;
|
||||
else if (x86_feature == X86_FEATURE_PERFMON_V2)
|
||||
return KVM_X86_FEATURE_PERFMON_V2;
|
||||
|
||||
return x86_feature;
|
||||
}
|
||||
|
|
|
@ -78,14 +78,6 @@ static bool amd_hw_event_available(struct kvm_pmc *pmc)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* check if a PMC is enabled by comparing it against global_ctrl bits. Because
|
||||
* AMD CPU doesn't have global_ctrl MSR, all PMCs are enabled (return TRUE).
|
||||
*/
|
||||
static bool amd_pmc_is_enabled(struct kvm_pmc *pmc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool amd_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
|
@ -102,12 +94,6 @@ static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
|
|||
return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx & ~(3u << 30));
|
||||
}
|
||||
|
||||
static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
||||
{
|
||||
/* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
|
@ -119,6 +105,29 @@ static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
|
|||
return pmc;
|
||||
}
|
||||
|
||||
static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
|
||||
switch (msr) {
|
||||
case MSR_K7_EVNTSEL0 ... MSR_K7_PERFCTR3:
|
||||
return pmu->version > 0;
|
||||
case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5:
|
||||
return guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE);
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
|
||||
return pmu->version > 1;
|
||||
default:
|
||||
if (msr > MSR_F15H_PERF_CTR5 &&
|
||||
msr < MSR_F15H_PERF_CTL0 + 2 * pmu->nr_arch_gp_counters)
|
||||
return pmu->version > 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return amd_msr_idx_to_pmc(vcpu, msr);
|
||||
}
|
||||
|
||||
static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
|
@ -172,20 +181,39 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
union cpuid_0x80000022_ebx ebx;
|
||||
|
||||
if (guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE))
|
||||
pmu->version = 1;
|
||||
if (guest_cpuid_has(vcpu, X86_FEATURE_PERFMON_V2)) {
|
||||
pmu->version = 2;
|
||||
/*
|
||||
* Note, PERFMON_V2 is also in 0x80000022.0x0, i.e. the guest
|
||||
* CPUID entry is guaranteed to be non-NULL.
|
||||
*/
|
||||
BUILD_BUG_ON(x86_feature_cpuid(X86_FEATURE_PERFMON_V2).function != 0x80000022 ||
|
||||
x86_feature_cpuid(X86_FEATURE_PERFMON_V2).index);
|
||||
ebx.full = kvm_find_cpuid_entry_index(vcpu, 0x80000022, 0)->ebx;
|
||||
pmu->nr_arch_gp_counters = ebx.split.num_core_pmc;
|
||||
} else if (guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE)) {
|
||||
pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS_CORE;
|
||||
else
|
||||
} else {
|
||||
pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
|
||||
}
|
||||
|
||||
pmu->nr_arch_gp_counters = min_t(unsigned int, pmu->nr_arch_gp_counters,
|
||||
kvm_pmu_cap.num_counters_gp);
|
||||
|
||||
if (pmu->version > 1) {
|
||||
pmu->global_ctrl_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1);
|
||||
pmu->global_status_mask = pmu->global_ctrl_mask;
|
||||
}
|
||||
|
||||
pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
|
||||
pmu->reserved_bits = 0xfffffff000280000ull;
|
||||
pmu->raw_event_mask = AMD64_RAW_EVENT_MASK;
|
||||
pmu->version = 1;
|
||||
/* not applicable to AMD; but clean them to prevent any fall out */
|
||||
pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
|
||||
pmu->nr_arch_fixed_counters = 0;
|
||||
pmu->global_status = 0;
|
||||
bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
|
||||
}
|
||||
|
||||
|
@ -216,11 +244,12 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
|
|||
pmc_stop_counter(pmc);
|
||||
pmc->counter = pmc->prev_counter = pmc->eventsel = 0;
|
||||
}
|
||||
|
||||
pmu->global_ctrl = pmu->global_status = 0;
|
||||
}
|
||||
|
||||
struct kvm_pmu_ops amd_pmu_ops __initdata = {
|
||||
.hw_event_available = amd_hw_event_available,
|
||||
.pmc_is_enabled = amd_pmc_is_enabled,
|
||||
.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
|
||||
.rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
|
||||
.msr_idx_to_pmc = amd_msr_idx_to_pmc,
|
||||
|
@ -233,4 +262,5 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = {
|
|||
.reset = amd_pmu_reset,
|
||||
.EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT,
|
||||
.MAX_NR_GP_COUNTERS = KVM_AMD_PMC_MAX_GENERIC,
|
||||
.MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS,
|
||||
};
|
||||
|
|
|
@ -5026,9 +5026,22 @@ static __init void svm_set_cpu_caps(void)
|
|||
boot_cpu_has(X86_FEATURE_AMD_SSBD))
|
||||
kvm_cpu_cap_set(X86_FEATURE_VIRT_SSBD);
|
||||
|
||||
/* AMD PMU PERFCTR_CORE CPUID */
|
||||
if (enable_pmu && boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
|
||||
kvm_cpu_cap_set(X86_FEATURE_PERFCTR_CORE);
|
||||
if (enable_pmu) {
|
||||
/*
|
||||
* Enumerate support for PERFCTR_CORE if and only if KVM has
|
||||
* access to enough counters to virtualize "core" support,
|
||||
* otherwise limit vPMU support to the legacy number of counters.
|
||||
*/
|
||||
if (kvm_pmu_cap.num_counters_gp < AMD64_NUM_COUNTERS_CORE)
|
||||
kvm_pmu_cap.num_counters_gp = min(AMD64_NUM_COUNTERS,
|
||||
kvm_pmu_cap.num_counters_gp);
|
||||
else
|
||||
kvm_cpu_cap_check_and_set(X86_FEATURE_PERFCTR_CORE);
|
||||
|
||||
if (kvm_pmu_cap.version != 2 ||
|
||||
!kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE))
|
||||
kvm_cpu_cap_clear(X86_FEATURE_PERFMON_V2);
|
||||
}
|
||||
|
||||
/* CPUID 0x8000001F (SME/SEV features) */
|
||||
sev_set_cpu_caps();
|
||||
|
|
|
@ -2649,7 +2649,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
|
|||
}
|
||||
|
||||
if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) &&
|
||||
intel_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu)) &&
|
||||
kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu)) &&
|
||||
WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL,
|
||||
vmcs12->guest_ia32_perf_global_ctrl))) {
|
||||
*entry_failure_code = ENTRY_FAIL_DEFAULT;
|
||||
|
@ -4524,7 +4524,7 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu,
|
|||
vcpu->arch.pat = vmcs12->host_ia32_pat;
|
||||
}
|
||||
if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) &&
|
||||
intel_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu)))
|
||||
kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu)))
|
||||
WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL,
|
||||
vmcs12->host_ia32_perf_global_ctrl));
|
||||
|
||||
|
|
|
@ -73,18 +73,6 @@ static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
|
|||
}
|
||||
}
|
||||
|
||||
static void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
|
||||
{
|
||||
int bit;
|
||||
|
||||
if (!diff)
|
||||
return;
|
||||
|
||||
for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
|
||||
set_bit(bit, pmu->reprogram_pmi);
|
||||
kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));
|
||||
}
|
||||
|
||||
static bool intel_hw_event_available(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
|
||||
|
@ -107,17 +95,6 @@ static bool intel_hw_event_available(struct kvm_pmc *pmc)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
|
||||
static bool intel_pmc_is_enabled(struct kvm_pmc *pmc)
|
||||
{
|
||||
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
|
||||
|
||||
if (!intel_pmu_has_perf_global_ctrl(pmu))
|
||||
return true;
|
||||
|
||||
return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
|
||||
}
|
||||
|
||||
static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)
|
||||
{
|
||||
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
|
||||
|
@ -198,11 +175,7 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
|||
|
||||
switch (msr) {
|
||||
case MSR_CORE_PERF_FIXED_CTR_CTRL:
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
return intel_pmu_has_perf_global_ctrl(pmu);
|
||||
break;
|
||||
return kvm_pmu_has_perf_global_ctrl(pmu);
|
||||
case MSR_IA32_PEBS_ENABLE:
|
||||
ret = vcpu_get_perf_capabilities(vcpu) & PERF_CAP_PEBS_FORMAT;
|
||||
break;
|
||||
|
@ -352,15 +325,6 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
case MSR_CORE_PERF_FIXED_CTR_CTRL:
|
||||
msr_info->data = pmu->fixed_ctr_ctrl;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
msr_info->data = pmu->global_status;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
msr_info->data = pmu->global_ctrl;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
msr_info->data = 0;
|
||||
break;
|
||||
case MSR_IA32_PEBS_ENABLE:
|
||||
msr_info->data = pmu->pebs_enable;
|
||||
break;
|
||||
|
@ -410,29 +374,6 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||
if (pmu->fixed_ctr_ctrl != data)
|
||||
reprogram_fixed_counters(pmu, data);
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_STATUS:
|
||||
if (!msr_info->host_initiated)
|
||||
return 1; /* RO MSR */
|
||||
|
||||
pmu->global_status = data;
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_CTRL:
|
||||
if (!kvm_valid_perf_global_ctrl(pmu, data))
|
||||
return 1;
|
||||
|
||||
if (pmu->global_ctrl != data) {
|
||||
diff = pmu->global_ctrl ^ data;
|
||||
pmu->global_ctrl = data;
|
||||
reprogram_counters(pmu, diff);
|
||||
}
|
||||
break;
|
||||
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
|
||||
if (data & pmu->global_ovf_ctrl_mask)
|
||||
return 1;
|
||||
|
||||
if (!msr_info->host_initiated)
|
||||
pmu->global_status &= ~data;
|
||||
break;
|
||||
case MSR_IA32_PEBS_ENABLE:
|
||||
if (data & pmu->pebs_enable_mask)
|
||||
return 1;
|
||||
|
@ -531,7 +472,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
|
|||
pmu->reserved_bits = 0xffffffff00200000ull;
|
||||
pmu->raw_event_mask = X86_RAW_EVENT_MASK;
|
||||
pmu->global_ctrl_mask = ~0ull;
|
||||
pmu->global_ovf_ctrl_mask = ~0ull;
|
||||
pmu->global_status_mask = ~0ull;
|
||||
pmu->fixed_ctr_ctrl_mask = ~0ull;
|
||||
pmu->pebs_enable_mask = ~0ull;
|
||||
pmu->pebs_data_cfg_mask = ~0ull;
|
||||
|
@ -585,11 +526,17 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
|
|||
counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) |
|
||||
(((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED));
|
||||
pmu->global_ctrl_mask = counter_mask;
|
||||
pmu->global_ovf_ctrl_mask = pmu->global_ctrl_mask
|
||||
|
||||
/*
|
||||
* GLOBAL_STATUS and GLOBAL_OVF_CONTROL (a.k.a. GLOBAL_STATUS_RESET)
|
||||
* share reserved bit definitions. The kernel just happens to use
|
||||
* OVF_CTRL for the names.
|
||||
*/
|
||||
pmu->global_status_mask = pmu->global_ctrl_mask
|
||||
& ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF |
|
||||
MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD);
|
||||
if (vmx_pt_mode_is_host_guest())
|
||||
pmu->global_ovf_ctrl_mask &=
|
||||
pmu->global_status_mask &=
|
||||
~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI;
|
||||
|
||||
entry = kvm_find_cpuid_entry_index(vcpu, 7, 0);
|
||||
|
@ -801,7 +748,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
|
|||
pmc = intel_pmc_idx_to_pmc(pmu, bit);
|
||||
|
||||
if (!pmc || !pmc_speculative_in_use(pmc) ||
|
||||
!intel_pmc_is_enabled(pmc) || !pmc->perf_event)
|
||||
!pmc_is_globally_enabled(pmc) || !pmc->perf_event)
|
||||
continue;
|
||||
|
||||
/*
|
||||
|
@ -816,7 +763,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
|
|||
|
||||
struct kvm_pmu_ops intel_pmu_ops __initdata = {
|
||||
.hw_event_available = intel_hw_event_available,
|
||||
.pmc_is_enabled = intel_pmc_is_enabled,
|
||||
.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
|
||||
.rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
|
||||
.msr_idx_to_pmc = intel_msr_idx_to_pmc,
|
||||
|
@ -831,4 +777,5 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = {
|
|||
.cleanup = intel_pmu_cleanup,
|
||||
.EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT,
|
||||
.MAX_NR_GP_COUNTERS = KVM_INTEL_PMC_MAX_GENERIC,
|
||||
.MIN_NR_GP_COUNTERS = 1,
|
||||
};
|
||||
|
|
|
@ -93,18 +93,6 @@ union vmx_exit_reason {
|
|||
u32 full;
|
||||
};
|
||||
|
||||
static inline bool intel_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
|
||||
{
|
||||
/*
|
||||
* Architecturally, Intel's SDM states that IA32_PERF_GLOBAL_CTRL is
|
||||
* supported if "CPUID.0AH: EAX[7:0] > 0", i.e. if the PMU version is
|
||||
* greater than zero. However, KVM only exposes and emulates the MSR
|
||||
* to/for the guest if the guest PMU supports at least "Architectural
|
||||
* Performance Monitoring Version 2".
|
||||
*/
|
||||
return pmu->version > 1;
|
||||
}
|
||||
|
||||
struct lbr_desc {
|
||||
/* Basic info about guest LBR records. */
|
||||
struct x86_pmu_lbr records;
|
||||
|
|
|
@ -1478,6 +1478,10 @@ static const u32 msrs_to_save_pmu[] = {
|
|||
MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5,
|
||||
MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2,
|
||||
MSR_F15H_PERF_CTR3, MSR_F15H_PERF_CTR4, MSR_F15H_PERF_CTR5,
|
||||
|
||||
MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
|
||||
MSR_AMD64_PERF_CNTR_GLOBAL_STATUS,
|
||||
MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
|
||||
};
|
||||
|
||||
static u32 msrs_to_save[ARRAY_SIZE(msrs_to_save_base) +
|
||||
|
@ -7154,6 +7158,12 @@ static void kvm_probe_msr_to_save(u32 msr_index)
|
|||
kvm_pmu_cap.num_counters_fixed)
|
||||
return;
|
||||
break;
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
|
||||
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
|
||||
if (!kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
|
||||
return;
|
||||
break;
|
||||
case MSR_IA32_XFD:
|
||||
case MSR_IA32_XFD_ERR:
|
||||
if (!kvm_cpu_cap_has(X86_FEATURE_XFD))
|
||||
|
|
Loading…
Reference in a new issue