arch/x86/kvm/vmx/pmu_intel.c

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

File Facts

System
Linux kernel
Corpus path
arch/x86/kvm/vmx/pmu_intel.c
Extension
.c
Size
25055 bytes
Lines
862
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 (pmu->pebs_enable != data) {
			diff = pmu->pebs_enable ^ data;
			pmu->pebs_enable = data;
			kvm_pmu_request_counters_reprogram(pmu, diff);
		}
		break;
	case MSR_IA32_DS_AREA:
		if (is_noncanonical_msr_address(data, vcpu))
			return 1;

		pmu->ds_area = data;
		break;
	case MSR_PEBS_DATA_CFG:
		if (data & pmu->pebs_data_cfg_rsvd)
			return 1;

		pmu->pebs_data_cfg = data;
		break;
	default:
		if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
		    (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) {
			if ((msr & MSR_PMC_FULL_WIDTH_BIT) &&
			    (data & ~pmu->counter_bitmask[KVM_PMC_GP]))
				return 1;

			if (!msr_info->host_initiated &&
			    !(msr & MSR_PMC_FULL_WIDTH_BIT))
				data = (s64)(s32)data;
			pmc_write_counter(pmc, data);
			break;
		} else if ((pmc = get_fixed_pmc(pmu, msr))) {
			pmc_write_counter(pmc, data);
			break;
		} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
			reserved_bits = pmu->reserved_bits;
			if ((pmc->idx == 2) &&
			    (pmu->raw_event_mask & HSW_IN_TX_CHECKPOINTED))
				reserved_bits ^= HSW_IN_TX_CHECKPOINTED;
			if (data & reserved_bits)
				return 1;

			if (data != pmc->eventsel) {
				pmc->eventsel = data;
				pmc->eventsel_hw = data;
				kvm_pmu_request_counter_reprogram(pmc);
			}
			break;
		} else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) {
			break;
		}
		/* Not a known PMU MSR. */
		return 1;
	}

	return 0;
}

/*
 * Map fixed counter events to architectural general purpose event encodings.
 * Perf doesn't provide APIs to allow KVM to directly program a fixed counter,
 * and so KVM instead programs the architectural event to effectively request
 * the fixed counter.  Perf isn't guaranteed to use a fixed counter and may
 * instead program the encoding into a general purpose counter, e.g. if a
 * different perf_event is already utilizing the requested counter, but the end
 * result is the same (ignoring the fact that using a general purpose counter
 * will likely exacerbate counter contention).
 *
 * Forcibly inlined to allow asserting on @index at build time, and there should
 * never be more than one user.
 */
static __always_inline u64 intel_get_fixed_pmc_eventsel(unsigned int index)
{
	const enum perf_hw_id fixed_pmc_perf_ids[] = {
		[0] = PERF_COUNT_HW_INSTRUCTIONS,
		[1] = PERF_COUNT_HW_CPU_CYCLES,
		[2] = PERF_COUNT_HW_REF_CPU_CYCLES,
	};
	u64 eventsel;

	BUILD_BUG_ON(ARRAY_SIZE(fixed_pmc_perf_ids) != KVM_MAX_NR_INTEL_FIXED_COUNTERS);
	BUILD_BUG_ON(index >= KVM_MAX_NR_INTEL_FIXED_COUNTERS);

	/*
	 * Yell if perf reports support for a fixed counter but perf doesn't
	 * have a known encoding for the associated general purpose event.
	 */
	eventsel = perf_get_hw_event_config(fixed_pmc_perf_ids[index]);
	WARN_ON_ONCE(!eventsel && index < kvm_pmu_cap.num_counters_fixed);
	return eventsel;
}

Annotation

Implementation Notes