Commit ffb6fc84 authored by Isaku Yamahata's avatar Isaku Yamahata Committed by Paolo Bonzini
Browse files

KVM: TDX: Make pmu_intel.c ignore guest TD case



TDX KVM doesn't support PMU yet, it's future work of TDX KVM support as
another patch series. For now, handle TDX by updating vcpu_to_lbr_desc()
and vcpu_to_lbr_records() to return NULL.

Signed-off-by: default avatarIsaku Yamahata <isaku.yamahata@intel.com>
Co-developed-by: default avatarTony Lindgren <tony.lindgren@linux.intel.com>
Signed-off-by: default avatarTony Lindgren <tony.lindgren@linux.intel.com>
Signed-off-by: default avatarRick Edgecombe <rick.p.edgecombe@intel.com>
---
 - Add pragma poison for to_vmx() (Paolo)
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 0186dd29
Loading
Loading
Loading
Loading
+51 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "lapic.h"
#include "nested.h"
#include "pmu.h"
#include "tdx.h"

/*
 * Perf's "BASE" is wildly misleading, architectural PMUs use bits 31:16 of ECX
@@ -34,6 +35,24 @@

#define MSR_PMC_FULL_WIDTH_BIT      (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0)

static struct lbr_desc *vcpu_to_lbr_desc(struct kvm_vcpu *vcpu)
{
	if (is_td_vcpu(vcpu))
		return NULL;

	return &to_vmx(vcpu)->lbr_desc;
}

static struct x86_pmu_lbr *vcpu_to_lbr_records(struct kvm_vcpu *vcpu)
{
	if (is_td_vcpu(vcpu))
		return NULL;

	return &to_vmx(vcpu)->lbr_desc.records;
}

#pragma GCC poison to_vmx

static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
{
	struct kvm_pmc *pmc;
@@ -129,6 +148,22 @@ static inline struct kvm_pmc *get_fw_gp_pmc(struct kvm_pmu *pmu, u32 msr)
	return get_gp_pmc(pmu, msr, MSR_IA32_PMC0);
}

static bool intel_pmu_lbr_is_compatible(struct kvm_vcpu *vcpu)
{
	if (is_td_vcpu(vcpu))
		return false;

	return cpuid_model_is_consistent(vcpu);
}

bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu)
{
	if (is_td_vcpu(vcpu))
		return false;

	return !!vcpu_to_lbr_records(vcpu)->nr;
}

static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index)
{
	struct x86_pmu_lbr *records = vcpu_to_lbr_records(vcpu);
@@ -194,6 +229,9 @@ static inline void intel_pmu_release_guest_lbr_event(struct kvm_vcpu *vcpu)
{
	struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);

	if (!lbr_desc)
		return;

	if (lbr_desc->event) {
		perf_event_release_kernel(lbr_desc->event);
		lbr_desc->event = NULL;
@@ -235,6 +273,9 @@ int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu)
					PERF_SAMPLE_BRANCH_USER,
	};

	if (WARN_ON_ONCE(!lbr_desc))
		return 0;

	if (unlikely(lbr_desc->event)) {
		__set_bit(INTEL_PMC_IDX_FIXED_VLBR, pmu->pmc_in_use);
		return 0;
@@ -466,6 +507,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
	u64 perf_capabilities;
	u64 counter_rsvd;

	if (!lbr_desc)
		return;

	memset(&lbr_desc->records, 0, sizeof(lbr_desc->records));

	/*
@@ -542,7 +586,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
		INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters);

	perf_capabilities = vcpu_get_perf_capabilities(vcpu);
	if (cpuid_model_is_consistent(vcpu) &&
	if (intel_pmu_lbr_is_compatible(vcpu) &&
	    (perf_capabilities & PMU_CAP_LBR_FMT))
		memcpy(&lbr_desc->records, &vmx_lbr_caps, sizeof(vmx_lbr_caps));
	else
@@ -570,6 +614,9 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu)
	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
	struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);

	if (!lbr_desc)
		return;

	for (i = 0; i < KVM_MAX_NR_INTEL_GP_COUNTERS; i++) {
		pmu->gp_counters[i].type = KVM_PMC_GP;
		pmu->gp_counters[i].vcpu = vcpu;
@@ -677,6 +724,9 @@ void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu)
	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
	struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);

	if (WARN_ON_ONCE(!lbr_desc))
		return;

	if (!lbr_desc->event) {
		vmx_disable_lbr_msrs_passthrough(vcpu);
		if (vmcs_read64(GUEST_IA32_DEBUGCTL) & DEBUGCTLMSR_LBR)
+28 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KVM_X86_VMX_PMU_INTEL_H
#define  __KVM_X86_VMX_PMU_INTEL_H

#include <linux/kvm_host.h>

bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu);
int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);

struct lbr_desc {
	/* Basic info about guest LBR records. */
	struct x86_pmu_lbr records;

	/*
	 * Emulate LBR feature via passthrough LBR registers when the
	 * per-vcpu guest LBR event is scheduled on the current pcpu.
	 *
	 * The records may be inaccurate if the host reclaims the LBR.
	 */
	struct perf_event *event;

	/* True if LBRs are marked as not intercepted in the MSR bitmap */
	bool msr_passthrough;
};

extern struct x86_pmu_lbr vmx_lbr_caps;

#endif /* __KVM_X86_VMX_PMU_INTEL_H */
+1 −33
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#include "capabilities.h"
#include "../kvm_cache_regs.h"
#include "pmu_intel.h"
#include "vmcs.h"
#include "vmx_ops.h"
#include "../cpuid.h"
@@ -90,24 +91,6 @@ union vmx_exit_reason {
	u32 full;
};

struct lbr_desc {
	/* Basic info about guest LBR records. */
	struct x86_pmu_lbr records;

	/*
	 * Emulate LBR feature via passthrough LBR registers when the
	 * per-vcpu guest LBR event is scheduled on the current pcpu.
	 *
	 * The records may be inaccurate if the host reclaims the LBR.
	 */
	struct perf_event *event;

	/* True if LBRs are marked as not intercepted in the MSR bitmap */
	bool msr_passthrough;
};

extern struct x86_pmu_lbr vmx_lbr_caps;

/*
 * The nested_vmx structure is part of vcpu_vmx, and holds information we need
 * for correct emulation of VMX (i.e., nested VMX) on this vcpu.
@@ -662,21 +645,6 @@ static __always_inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
	return container_of(vcpu, struct vcpu_vmx, vcpu);
}

static inline struct lbr_desc *vcpu_to_lbr_desc(struct kvm_vcpu *vcpu)
{
	return &to_vmx(vcpu)->lbr_desc;
}

static inline struct x86_pmu_lbr *vcpu_to_lbr_records(struct kvm_vcpu *vcpu)
{
	return &vcpu_to_lbr_desc(vcpu)->records;
}

static inline bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu)
{
	return !!vcpu_to_lbr_records(vcpu)->nr;
}

void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu);
int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu);
void vmx_passthrough_lbr_msrs(struct kvm_vcpu *vcpu);