KVM: vmx/pmu: Emulate legacy freezing LBRs on virtual PMI
The current vPMU only supports Architecture Version 2. According to Intel SDM "17.4.7 Freezing LBR and Performance Counters on PMI", if IA32_DEBUGCTL.Freeze_LBR_On_PMI = 1, the LBR is frozen on the virtual PMI and the KVM would emulate to clear the LBR bit (bit 0) in IA32_DEBUGCTL. Also, guest needs to re-enable IA32_DEBUGCTL.LBR to resume recording branches. Signed-off-by: Like Xu <like.xu@linux.intel.com> Reviewed-by: Andi Kleen <ak@linux.intel.com> Message-Id: <20210201051039.255478-9-like.xu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
9254beaafd
commit
e6209a3bef
@ -383,8 +383,11 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)
|
||||
|
||||
void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (lapic_in_kernel(vcpu))
|
||||
if (lapic_in_kernel(vcpu)) {
|
||||
if (kvm_x86_ops.pmu_ops->deliver_pmi)
|
||||
kvm_x86_ops.pmu_ops->deliver_pmi(vcpu);
|
||||
kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTPC);
|
||||
}
|
||||
}
|
||||
|
||||
bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
|
||||
|
@ -39,6 +39,7 @@ struct kvm_pmu_ops {
|
||||
void (*refresh)(struct kvm_vcpu *vcpu);
|
||||
void (*init)(struct kvm_vcpu *vcpu);
|
||||
void (*reset)(struct kvm_vcpu *vcpu);
|
||||
void (*deliver_pmi)(struct kvm_vcpu *vcpu);
|
||||
};
|
||||
|
||||
static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
|
||||
|
@ -21,6 +21,8 @@ extern int __read_mostly pt_mode;
|
||||
#define PMU_CAP_FW_WRITES (1ULL << 13)
|
||||
#define PMU_CAP_LBR_FMT 0x3f
|
||||
|
||||
#define DEBUGCTLMSR_LBR_MASK (DEBUGCTLMSR_LBR | DEBUGCTLMSR_FREEZE_LBRS_ON_PMI)
|
||||
|
||||
struct nested_vmx_msrs {
|
||||
/*
|
||||
* We only store the "true" versions of the VMX capability MSRs. We
|
||||
@ -390,7 +392,7 @@ static inline u64 vmx_supported_debugctl(void)
|
||||
u64 debugctl = 0;
|
||||
|
||||
if (vmx_get_perf_capabilities() & PMU_CAP_LBR_FMT)
|
||||
debugctl |= DEBUGCTLMSR_LBR;
|
||||
debugctl |= DEBUGCTLMSR_LBR_MASK;
|
||||
|
||||
return debugctl;
|
||||
}
|
||||
|
@ -586,6 +586,35 @@ static void intel_pmu_reset(struct kvm_vcpu *vcpu)
|
||||
intel_pmu_release_guest_lbr_event(vcpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate LBR_On_PMI behavior for 1 < pmu.version < 4.
|
||||
*
|
||||
* If Freeze_LBR_On_PMI = 1, the LBR is frozen on PMI and
|
||||
* the KVM emulates to clear the LBR bit (bit 0) in IA32_DEBUGCTL.
|
||||
*
|
||||
* Guest needs to re-enable LBR to resume branches recording.
|
||||
*/
|
||||
static void intel_pmu_legacy_freezing_lbrs_on_pmi(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u64 data = vmcs_read64(GUEST_IA32_DEBUGCTL);
|
||||
|
||||
if (data & DEBUGCTLMSR_FREEZE_LBRS_ON_PMI) {
|
||||
data &= ~DEBUGCTLMSR_LBR;
|
||||
vmcs_write64(GUEST_IA32_DEBUGCTL, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
u8 version = vcpu_to_pmu(vcpu)->version;
|
||||
|
||||
if (!intel_pmu_lbr_is_enabled(vcpu))
|
||||
return;
|
||||
|
||||
if (version > 1 && version < 4)
|
||||
intel_pmu_legacy_freezing_lbrs_on_pmi(vcpu);
|
||||
}
|
||||
|
||||
static void vmx_update_intercept_for_lbr_msrs(struct kvm_vcpu *vcpu, bool set)
|
||||
{
|
||||
struct x86_pmu_lbr *lbr = vcpu_to_lbr_records(vcpu);
|
||||
@ -672,4 +701,5 @@ struct kvm_pmu_ops intel_pmu_ops = {
|
||||
.refresh = intel_pmu_refresh,
|
||||
.init = intel_pmu_init,
|
||||
.reset = intel_pmu_reset,
|
||||
.deliver_pmi = intel_pmu_deliver_pmi,
|
||||
};
|
||||
|
@ -1963,7 +1963,7 @@ static u64 vcpu_supported_debugctl(struct kvm_vcpu *vcpu)
|
||||
u64 debugctl = vmx_supported_debugctl();
|
||||
|
||||
if (!intel_pmu_lbr_is_enabled(vcpu))
|
||||
debugctl &= ~DEBUGCTLMSR_LBR;
|
||||
debugctl &= ~DEBUGCTLMSR_LBR_MASK;
|
||||
|
||||
return debugctl;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user