Without filtering, a guest with PMC virtualization programs its event-selects itself, so the PMU event filter doesn't apply to it. Only advertise SVM_SEV_FEAT_PERFCTR_VIRT when the hardware supports PMC filtering. SEV-ES and SNP guests then forward trapped event-select writes with SVM_VMGEXIT_PMC_FILTER for KVM to filter. sev_hardware_setup() now checks vpmc, so call it after vpmc gets its final value. Signed-off-by: Manali Shukla --- arch/x86/kvm/svm/sev.c | 11 +++++++---- arch/x86/kvm/svm/svm.c | 14 +++++++------- arch/x86/kvm/svm/svm.h | 2 ++ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index b73484620e2a3..acd761c7437d9 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -544,10 +544,8 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, sev->vmsa_features |= SVM_SEV_FEAT_SNP_ACTIVE; if (es_active && !sev_es_is_perfctr_virt_enabled(kvm)) - kvm_clr_mediated_pmu_caps(kvm, KVM_MEDIATED_PMU_CAP_HW_SWITCHED); - - if (es_active) - kvm_clr_mediated_pmu_caps(kvm, KVM_MEDIATED_PMU_CAP_HW_FILTERED); + kvm_clr_mediated_pmu_caps(kvm, KVM_MEDIATED_PMU_CAP_HW_SWITCHED | + KVM_MEDIATED_PMU_CAP_HW_FILTERED); ret = sev_asid_new(sev, vm_type); if (ret) @@ -3258,6 +3256,11 @@ void __init sev_hardware_setup(void) if (sev_snp_enabled && tsc_khz && cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC)) sev_supported_vmsa_features |= SVM_SEV_FEAT_SECURE_TSC; + + /* KVM must filter the events of a guest with PMC virtualization. */ + if (sev_es_enabled && svm_pmc_filter_supported() && + cpu_feature_enabled(X86_FEATURE_SEV_PERFCTR_VIRT)) + sev_supported_vmsa_features |= SVM_SEV_FEAT_PERFCTR_VIRT; } void sev_hardware_unsetup(void) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index cdd102c761994..0784ce62dd672 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -186,7 +186,7 @@ module_param(vpmc, bool, 0444); * TODO: Support nested. vmcb02 doesn't enable PMC filtering, so L2 could * program denied events through vmcb01's passthrough event-selects. */ -static bool svm_pmc_filter_supported(void) +bool svm_pmc_filter_supported(void) { return vpmc && !nested && cpu_feature_enabled(X86_FEATURE_PMCFILTER); } @@ -5779,12 +5779,6 @@ static __init int svm_hardware_setup(void) iopm_base = __sme_set(__pa(iopm_va)); - /* - * Note, SEV setup consumes npt_enabled and enable_mmio_caching (which - * may be modified by svm_adjust_mmio_mask()), as well as nrips. - */ - sev_hardware_setup(); - svm_hv_hardware_setup(); enable_apicv = avic_hardware_setup(); @@ -5842,6 +5836,12 @@ static __init int svm_hardware_setup(void) if (svm_pmc_filter_supported()) pr_info("PMC filtering virtualization supported\n"); + /* + * Note, SEV setup consumes npt_enabled and enable_mmio_caching (which + * may be modified by svm_adjust_mmio_mask()), as well as nrips and vpmc. + */ + sev_hardware_setup(); + svm_set_cpu_caps(); kvm_caps.inapplicable_quirks &= ~KVM_X86_QUIRK_CD_NW_CLEARED; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 3615997b339ec..d44e4f4829fc1 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -867,6 +867,8 @@ static inline void svm_enable_intercept_for_msr(struct kvm_vcpu *vcpu, #define SVM_PMC_FILTER_MASK (AMD64_EVENTSEL_EVENT | ARCH_PERFMON_EVENTSEL_UMASK) +bool svm_pmc_filter_supported(void); + int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu); /* nested.c */ -- 2.43.0