Add the MSR indices for both selector and counter in each kvm_pmc. Giving convenience to mediated passthrough vPMU in scenarios of querying MSR from a given pmc. Note that legacy vPMU does not need this because it never directly accesses PMU MSRs, instead each kvm_pmc is bound to a perf_event. For actual Zen 4 and later hardware, it will never be the case that the PerfMonV2 CPUID bit is set but the PerfCtrCore bit is not. However, a guest can be booted with PerfMonV2 enabled and PerfCtrCore disabled. KVM does not clear the PerfMonV2 bit from guest CPUID as long as the host has the PerfCtrCore capability. In this case, passthrough mode will use the K7 legacy MSRs to program events but with the incorrect assumption that there are 6 such counters instead of 4 as advertised by CPUID leaf 0x80000022 EBX. The host kernel will also report unchecked MSR accesses for the absent counters while saving or restoring guest PMU contexts. Ensure that K7 legacy MSRs are not used as long as the guest CPUID has either PerfCtrCore or PerfMonV2 set. Signed-off-by: Sandipan Das <sandipan.das@xxxxxxx> Signed-off-by: Mingwei Zhang <mizhang@xxxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/svm/pmu.c | 13 +++++++++++++ arch/x86/kvm/vmx/pmu_intel.c | 13 +++++++++++++ 3 files changed, 28 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4b3ce6194bdb..603727312f9c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -522,6 +522,8 @@ struct kvm_pmc { */ u64 emulated_counter; u64 eventsel; + u64 msr_counter; + u64 msr_eventsel; struct perf_event *perf_event; struct kvm_vcpu *vcpu; /* diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 6b471b1ec9b8..64060cbd8210 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -177,6 +177,7 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); union cpuid_0x80000022_ebx ebx; + int i; pmu->version = 1; if (guest_cpuid_has(vcpu, X86_FEATURE_PERFMON_V2)) { @@ -210,6 +211,18 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu) pmu->counter_bitmask[KVM_PMC_FIXED] = 0; pmu->nr_arch_fixed_counters = 0; bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters); + + if (pmu->version > 1 || guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE)) { + for (i = 0; i < pmu->nr_arch_gp_counters; i++) { + pmu->gp_counters[i].msr_eventsel = MSR_F15H_PERF_CTL0 + 2 * i; + pmu->gp_counters[i].msr_counter = MSR_F15H_PERF_CTR0 + 2 * i; + } + } else { + for (i = 0; i < pmu->nr_arch_gp_counters; i++) { + pmu->gp_counters[i].msr_eventsel = MSR_K7_EVNTSEL0 + i; + pmu->gp_counters[i].msr_counter = MSR_K7_PERFCTR0 + i; + } + } } static void amd_pmu_init(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 737de5bf1eee..0de918dc14ea 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -562,6 +562,19 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) ~((1ull << pmu->nr_arch_gp_counters) - 1); } } + + for (i = 0; i < pmu->nr_arch_gp_counters; i++) { + pmu->gp_counters[i].msr_eventsel = MSR_P6_EVNTSEL0 + i; + if (fw_writes_is_enabled(vcpu)) + pmu->gp_counters[i].msr_counter = MSR_IA32_PMC0 + i; + else + pmu->gp_counters[i].msr_counter = MSR_IA32_PERFCTR0 + i; + } + + for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { + pmu->fixed_counters[i].msr_eventsel = MSR_CORE_PERF_FIXED_CTR_CTRL; + pmu->fixed_counters[i].msr_counter = MSR_CORE_PERF_FIXED_CTR0 + i; + } } static void intel_pmu_init(struct kvm_vcpu *vcpu) -- 2.46.0.rc1.232.g9752f9e123-goog