arch/x86/kvm/svm/pmu.c

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

File Facts

System
Linux kernel
Corpus path
arch/x86/kvm/svm/pmu.c
Extension
.c
Size
8899 bytes
Lines
329
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: implementation source
Status
source 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

if (data != pmc->eventsel) {
			pmc->eventsel = data;
			pmc->eventsel_hw = (data & ~AMD64_EVENTSEL_HOSTONLY) |
					   AMD64_EVENTSEL_GUESTONLY;

			if (data & AMD64_EVENTSEL_HOST_GUEST_MASK)
				__set_bit(pmc->idx, pmu->pmc_has_mode_specific_enables);
			else
				__clear_bit(pmc->idx, pmu->pmc_has_mode_specific_enables);

			kvm_pmu_request_counter_reprogram(pmc);
		}
		return 0;
	}

	return 1;
}

static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
{
	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
	union cpuid_0x80000022_ebx ebx;

	pmu->version = 1;
	if (guest_cpu_cap_has(vcpu, X86_FEATURE_PERFMON_V2)) {
		pmu->version = 2;
		/*
		 * Note, PERFMON_V2 is also in 0x80000022.0x0, i.e. the guest
		 * CPUID entry is guaranteed to be non-NULL.
		 */
		BUILD_BUG_ON(x86_feature_cpuid(X86_FEATURE_PERFMON_V2).function != 0x80000022 ||
			     x86_feature_cpuid(X86_FEATURE_PERFMON_V2).index);
		ebx.full = kvm_find_cpuid_entry_index(vcpu, 0x80000022, 0)->ebx;
		pmu->nr_arch_gp_counters = ebx.split.num_core_pmc;
	} else if (guest_cpu_cap_has(vcpu, X86_FEATURE_PERFCTR_CORE)) {
		pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS_CORE;
	} else {
		pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
	}

	pmu->nr_arch_gp_counters = min_t(unsigned int, pmu->nr_arch_gp_counters,
					 kvm_pmu_cap.num_counters_gp);

	if (pmu->version > 1) {
		pmu->global_ctrl_rsvd = ~(BIT_ULL(pmu->nr_arch_gp_counters) - 1);
		pmu->global_status_rsvd = pmu->global_ctrl_rsvd;
	}

	pmu->counter_bitmask[KVM_PMC_GP] = BIT_ULL(48) - 1;

	pmu->reserved_bits = 0xfffffff000280000ull;
	if (guest_cpu_cap_has(vcpu, X86_FEATURE_SVM) && kvm_vcpu_has_mediated_pmu(vcpu))
		pmu->reserved_bits &= ~AMD64_EVENTSEL_HOST_GUEST_MASK;

	pmu->raw_event_mask = AMD64_RAW_EVENT_MASK;
	/* not applicable to AMD; but clean them to prevent any fall out */
	pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
	pmu->nr_arch_fixed_counters = 0;
}

static void amd_pmu_init(struct kvm_vcpu *vcpu)
{
	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
	int i;

	BUILD_BUG_ON(KVM_MAX_NR_AMD_GP_COUNTERS > AMD64_NUM_COUNTERS_CORE);

	for (i = 0; i < KVM_MAX_NR_AMD_GP_COUNTERS; i++) {
		pmu->gp_counters[i].type = KVM_PMC_GP;
		pmu->gp_counters[i].vcpu = vcpu;
		pmu->gp_counters[i].idx = i;
		pmu->gp_counters[i].current_config = 0;
	}
}

static bool amd_pmu_is_mediated_pmu_supported(struct x86_pmu_capability *host_pmu)
{
	return host_pmu->version >= 2;
}

static void amd_mediated_pmu_load(struct kvm_vcpu *vcpu)
{
	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
	u64 global_status;

	rdmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, global_status);
	/* Clear host global_status MSR if non-zero. */
	if (global_status)
		wrmsrq(MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, global_status);

Annotation

Implementation Notes