When hardware-switched mediated PMU is enabled, the guest PMU state resides in a vendor save area. Because of this, after every VMEXIT, the state inside struct kvm_pmu can go out of sync with the vendor save area. Since KVM expects struct kvm_pmu to have the correct guest PMU state during event filtering and instruction emulation, introduce new PMU ops to opportunistically synchronize the state of PMU MSRs between the two backing stores. The new ops are directional. get_vendor_state() copies data from the vendor save area to the corresponding member of struct kvm_pmu while set_vendor_state() does the opposite. Signed-off-by: Sandipan Das --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 3 +++ arch/x86/kvm/pmu.c | 5 ++++- arch/x86/kvm/pmu.h | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index 4a223c2793e3..4a617162d4c0 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -29,6 +29,9 @@ KVM_X86_PMU_OP_OPTIONAL_RET0(pmc_is_disabled_in_current_mode) KVM_X86_PMU_OP_OPTIONAL(write_global_ctrl) KVM_X86_PMU_OP(mediated_load) KVM_X86_PMU_OP(mediated_put) + +KVM_X86_PMU_OP_OPTIONAL_RET0(get_vendor_state) +KVM_X86_PMU_OP_OPTIONAL_RET0(set_vendor_state) #endif #undef KVM_X86_PMU_OP diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index a7d60c8785cd..5ede3ee968e3 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -166,8 +166,11 @@ void kvm_init_pmu_capability(struct kvm_pmu_ops *pmu_ops) !pmu_ops->is_mediated_pmu_supported(&kvm_host_pmu)) enable_mediated_pmu = false; - if (!enable_mediated_pmu) + if (!enable_mediated_pmu) { pmu_ops->write_global_ctrl = NULL; + pmu_ops->get_vendor_state = NULL; + pmu_ops->set_vendor_state = NULL; + } if (!enable_pmu) { memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 1aa46d3e2339..5d6f6863ad40 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -42,6 +42,8 @@ struct kvm_pmu_ops { void (*mediated_load)(struct kvm_vcpu *vcpu); void (*mediated_put)(struct kvm_vcpu *vcpu); void (*write_global_ctrl)(u64 global_ctrl); + int (*get_vendor_state)(struct kvm_vcpu *vcpu, u32 msr); + int (*set_vendor_state)(struct kvm_vcpu *vcpu, u32 msr); const u64 EVENTSEL_EVENT; const int MAX_NR_GP_COUNTERS; -- 2.53.0