Re: [PATCH 16/23] KVM: x86/pmu: Handle FIXED_CTR_CTRL under PerfMon masking
From: Mi, Dapeng
Date: Wed Aug 26 2026 - 04:46:30 EST
On 8/22/2026 6:19 AM, Zide Chen wrote:
> PerfMon masking affects reads from and writes to this MSR. The effective
> mask is defined as bits 4n+3:4n and bits 4n+35:4n+32 being set if and
> only if bit 32+n of the PerfMon mask is set (for 0 <= n <= 7).
>
> KVM doesn't support some fixed-counter features, and
> pmu->fixed_ctr_ctrl_rsvd is a subset of the effective mask above, so the
> existing gating in intel_pmu_set_msr() is sufficient even under PerfMon
> masking.
>
> Upon guest PMU context load, OR the guest-owned bits with whatever the
> hardware currently holds for every fixed-counter index the guest does
> not own, before writing the result to the MSR.
>
> During PMU context put, host-owned fixed counters may still be scheduled
> for system-wide host events, so the host-owned bits should remain
> unchanged.
>
> Signed-off-by: Zide Chen <zide.chen@xxxxxxxxx>
> ---
> arch/x86/kvm/vmx/pmu_intel.c | 40 +++++++++++++++++++++++++++++++++---
> 1 file changed, 37 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
> index 19ccc7cd319c..9236bfa15c41 100644
> --- a/arch/x86/kvm/vmx/pmu_intel.c
> +++ b/arch/x86/kvm/vmx/pmu_intel.c
> @@ -920,6 +920,33 @@ static void intel_pmu_write_global_ctrl(u64 global_ctrl)
> vmcs_write64(GUEST_IA32_PERF_GLOBAL_CTRL, global_ctrl);
> }
>
> +static u64 intel_fixed_ctrl_host_bits(struct kvm_pmu *pmu)
> +{
> + unsigned long fixed_mask;
> + u64 fixed_ctl;
> + int i;
> +
> + if (!kvm_vcpu_has_perfmon_mask(pmu_to_vcpu(pmu)))
> + return 0;
> +
> + fixed_mask = kvm_fixed_pmc_mask(pmu);
> +
> + rdmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctl);
> +
> + /*
> + * Use the full per-counter nibbles (bits 4n+3:4n and 4n+35:4n+32) to
> + * strip all bits belonging to guest-owned counters.
> + *
> + * pmu->fixed_ctr_ctrl_rsvd can't be used here since it can't gate bits
> + * that are not supported by KVM.
> + */
> + kvm_for_each_fixed_counter(i, fixed_mask)
> + fixed_ctl &= ~intel_fixed_bits_by_idx(i, GENMASK_ULL(3, 0) |
> + GENMASK_ULL(35, 32));
> +
> + return fixed_ctl;
> +}
Strictly speaking, this should be a perf/x86/intel function and then
exposed to KVM. Perf host side may also need this function.
> +
> static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu)
> {
> struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
> @@ -935,7 +962,8 @@ static void intel_mediated_pmu_load(struct kvm_vcpu *vcpu)
> if (pmu->global_status & toggle)
> wrmsrq(MSR_CORE_PERF_GLOBAL_STATUS_SET, pmu->global_status & toggle);
>
> - wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl_hw);
> + wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL,
> + pmu->fixed_ctr_ctrl_hw | intel_fixed_ctrl_host_bits(pmu));
> }
>
> static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
> @@ -953,9 +981,15 @@ static void intel_mediated_pmu_put(struct kvm_vcpu *vcpu)
> * Clear hardware FIXED_CTR_CTRL MSR to avoid information leakage and
> * also to avoid accidentally enabling fixed counters (based on guest
> * state) while running in the host, e.g. when setting global ctrl.
> + *
> + * Keep the host-owned counters unchanged.
> */
> - if (pmu->fixed_ctr_ctrl_hw)
> - wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
> + if (pmu->fixed_ctr_ctrl_hw) {
> + u64 fixed_ctl = intel_fixed_ctrl_host_bits(pmu);
> +
> + fixed_ctl &= ~pmu->fixed_ctr_ctrl_hw;
> + wrmsrq(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctl);
> + }
>
> if (kvm_vcpu_has_perf_metrics(vcpu)) {
> pmu->perf_metrics = rdpmc(INTEL_PMC_FIXED_RDPMC_METRICS);