arch/x86/kvm/pmu.c

Source file repositories/reference/linux-study-clean/arch/x86/kvm/pmu.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kvm/pmu.c
Extension
.c
Size
41642 bytes
Lines
1425
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct kvm_pmu_emulated_event_selectors {
	u64 INSTRUCTIONS_RETIRED;
	u64 BRANCH_INSTRUCTIONS_RETIRED;
};
static struct kvm_pmu_emulated_event_selectors __read_mostly kvm_pmu_eventsel;

/* Precise Distribution of Instructions Retired (PDIR) */
static const struct x86_cpu_id vmx_pebs_pdir_cpu[] = {
	X86_MATCH_VFM(INTEL_ICELAKE_D, NULL),
	X86_MATCH_VFM(INTEL_ICELAKE_X, NULL),
	/* Instruction-Accurate PDIR (PDIR++) */
	X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, NULL),
	{}
};

/* Precise Distribution (PDist) */
static const struct x86_cpu_id vmx_pebs_pdist_cpu[] = {
	X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, NULL),
	{}
};

/* NOTE:
 * - Each perf counter is defined as "struct kvm_pmc";
 * - There are two types of perf counters: general purpose (gp) and fixed.
 *   gp counters are stored in gp_counters[] and fixed counters are stored
 *   in fixed_counters[] respectively. Both of them are part of "struct
 *   kvm_pmu";
 * - pmu.c understands the difference between gp counters and fixed counters.
 *   However AMD doesn't support fixed-counters;
 * - There are three types of index to access perf counters (PMC):
 *     1. MSR (named msr): For example Intel has MSR_IA32_PERFCTRn and AMD
 *        has MSR_K7_PERFCTRn and, for families 15H and later,
 *        MSR_F15H_PERF_CTRn, where MSR_F15H_PERF_CTR[0-3] are
 *        aliased to MSR_K7_PERFCTRn.
 *     2. MSR Index (named idx): This normally is used by RDPMC instruction.
 *        For instance AMD RDPMC instruction uses 0000_0003h in ECX to access
 *        C001_0007h (MSR_K7_PERCTR3). Intel has a similar mechanism, except
 *        that it also supports fixed counters. idx can be used to as index to
 *        gp and fixed counters.
 *     3. Global PMC Index (named pmc): pmc is an index specific to PMU
 *        code. Each pmc, stored in kvm_pmc.idx field, is unique across
 *        all perf counters (both gp and fixed). The mapping relationship
 *        between pmc and perf counters is as the following:
 *        * Intel: [0 .. KVM_MAX_NR_INTEL_GP_COUNTERS-1] <=> gp counters
 *                 [KVM_FIXED_PMC_BASE_IDX .. KVM_FIXED_PMC_BASE_IDX + 2] <=> fixed
 *        * AMD:   [0 .. AMD64_NUM_COUNTERS-1] and, for families 15H
 *          and later, [0 .. AMD64_NUM_COUNTERS_CORE-1] <=> gp counters
 */

static struct kvm_pmu_ops kvm_pmu_ops __read_mostly;

#define KVM_X86_PMU_OP(func)					     \
	DEFINE_STATIC_CALL_NULL(kvm_x86_pmu_##func,			     \
				*(((struct kvm_pmu_ops *)0)->func));
#define KVM_X86_PMU_OP_OPTIONAL KVM_X86_PMU_OP
#define KVM_X86_PMU_OP_OPTIONAL_RET0 KVM_X86_PMU_OP
#include <asm/kvm-x86-pmu-ops.h>
EXPORT_STATIC_CALL_GPL(kvm_x86_pmu_pmc_is_disabled_in_current_mode);

void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
{
	memcpy(&kvm_pmu_ops, pmu_ops, sizeof(kvm_pmu_ops));

#define __KVM_X86_PMU_OP(func) \
	static_call_update(kvm_x86_pmu_##func, kvm_pmu_ops.func);
#define KVM_X86_PMU_OP(func) \
	WARN_ON(!kvm_pmu_ops.func); __KVM_X86_PMU_OP(func)
#define KVM_X86_PMU_OP_OPTIONAL __KVM_X86_PMU_OP
#define KVM_X86_PMU_OP_OPTIONAL_RET0(func) \
	static_call_update(kvm_x86_pmu_##func, (void *)kvm_pmu_ops.func ? : \
					       (void *)__static_call_return0);
#include <asm/kvm-x86-pmu-ops.h>
#undef __KVM_X86_PMU_OP
}

void kvm_init_pmu_capability(struct kvm_pmu_ops *pmu_ops)
{
	bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
	int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;

	/*
	 * Hybrid PMUs don't play nice with virtualization without careful
	 * configuration by userspace, and KVM's APIs for reporting supported
	 * vPMU features do not account for hybrid PMUs.  Disable vPMU support
	 * for hybrid PMUs until KVM gains a way to let userspace opt-in.
	 */
	if (cpu_feature_enabled(X86_FEATURE_HYBRID_CPU)) {
		enable_pmu = false;
		memset(&kvm_host_pmu, 0, sizeof(kvm_host_pmu));
	} else {

Annotation

Implementation Notes