Skip to content

Commit

Permalink
KVM: vmx/pmu: Emulate legacy freezing LBRs on virtual PMI
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Like Xu authored and Paolo Bonzini committed Feb 4, 2021
1 parent 9254bea commit e6209a3
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 3 deletions.
5 changes: 4 additions & 1 deletion arch/x86/kvm/pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kvm/pmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion arch/x86/kvm/vmx/capabilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
30 changes: 30 additions & 0 deletions arch/x86/kvm/vmx/pmu_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
};
2 changes: 1 addition & 1 deletion arch/x86/kvm/vmx/vmx.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit e6209a3

Please sign in to comment.