When mediated PMU is enabled, the guest PMU state is currently saved and restored in software. On capable processors, this can be offloaded to hardware. Hence, introduce the notion of VM-scoped mediated PMU capabilities to help KVM determine the available hardware assists. When set, the KVM_MEDIATED_PMU_CAP_HW_SWITCHED flag indicates that hardware is responsible for switching the guest PMU state. When software-switched, the guest PMU state continues to reside in struct kvm_pmu. However, when hardware-switched, the guest PMU state resides in a vendor save area. While KVM_MEDIATED_PMU_CAP_HW_FILTERED remains unused currently, when set, it indicates that hardware is also responsible for assisting in guest event filtering for further reduction of overhead resulting from intercepting event selector writes. The capabilities are expected to be set in the vm_init() call. All capabilities are cleared if kvm_arch_vcpu_precreate() fails to create mediated PMU. Signed-off-by: Sandipan Das --- arch/x86/include/asm/kvm_host.h | 11 +++++++++++ arch/x86/kvm/pmu.h | 20 ++++++++++++++++++++ arch/x86/kvm/x86.c | 2 ++ 3 files changed, 33 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 283847619ff8..338df11e2a4d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -715,6 +715,16 @@ enum kvm_only_cpuid_leafs { NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS, }; +/* + * Track how the guest PMU state is saved and restored, as this can be done + * either by software or, if capable, by hardware. When hardware manages the + * guest PMU state, the state resides in a vendor save area. + */ +#define KVM_MEDIATED_PMU_CAP_HW_SWITCHED BIT(0) +#define KVM_MEDIATED_PMU_CAP_HW_FILTERED BIT(1) +#define KVM_MEDIATED_PMU_CAP_VALID (KVM_MEDIATED_PMU_CAP_HW_SWITCHED | \ + KVM_MEDIATED_PMU_CAP_HW_FILTERED) + struct kvm_vcpu_arch { /* * rip and regs accesses must go through @@ -1284,6 +1294,7 @@ struct kvm_arch { bool bus_lock_detection_enabled; bool enable_pmu; bool created_mediated_pmu; + u32 mediated_pmu_caps; u32 notify_window; u32 notify_vmexit_flags; diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 090c9bbb74f4..1aa46d3e2339 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -88,6 +88,26 @@ static inline bool kvm_vcpu_has_mediated_pmu(struct kvm_vcpu *vcpu) return enable_mediated_pmu && vcpu_to_pmu(vcpu)->version; } +static inline bool kvm_vcpu_has_mediated_pmu_caps(struct kvm_vcpu *vcpu, u32 caps) +{ + return kvm_vcpu_has_mediated_pmu(vcpu) && + !!(vcpu->kvm->arch.mediated_pmu_caps & caps); +} + +#define kvm_set_mediated_pmu_caps(kvm, caps) \ +do { \ + BUILD_BUG_ON(!__builtin_constant_p(caps) || \ + ((caps) & ~KVM_MEDIATED_PMU_CAP_VALID)); \ + (kvm)->arch.mediated_pmu_caps |= (caps); \ +} while (0) + +#define kvm_clr_mediated_pmu_caps(kvm, caps) \ +do { \ + BUILD_BUG_ON(!__builtin_constant_p(caps) || \ + ((caps) & ~KVM_MEDIATED_PMU_CAP_VALID)); \ + (kvm)->arch.mediated_pmu_caps &= ~(caps); \ +} while (0) + /* * KVM tracks all counters in 64-bit bitmaps, with general purpose counters * mapped to bits 31:0 and fixed counters mapped to 63:32, e.g. fixed counter 0 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d94b59140c45..4287982638b6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9326,6 +9326,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) if (irqchip_in_kernel(kvm)) { r = perf_create_mediated_pmu(); if (r) { + kvm->arch.mediated_pmu_caps = 0; pr_warn_ratelimited(PERF_MEDIATED_PMU_MSG); return r; } @@ -9334,6 +9335,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) kvm->arch.enable_pmu = false; } } + return 0; } -- 2.53.0