linux-stable/arch/x86/kvm
Sean Christopherson a770ff7bff KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at "RESET"
[ Upstream commit de120e1d69 ]

Set the enable bits for general purpose counters in IA32_PERF_GLOBAL_CTRL
when refreshing the PMU to emulate the MSR's architecturally defined
post-RESET behavior.  Per Intel's SDM:

  IA32_PERF_GLOBAL_CTRL:  Sets bits n-1:0 and clears the upper bits.

and

  Where "n" is the number of general-purpose counters available in the processor.

AMD also documents this behavior for PerfMonV2 CPUs in one of AMD's many
PPRs.

Do not set any PERF_GLOBAL_CTRL bits if there are no general purpose
counters, although a literal reading of the SDM would require the CPU to
set either bits 63:0 or 31:0.  The intent of the behavior is to globally
enable all GP counters; honor the intent, if not the letter of the law.

Leaving PERF_GLOBAL_CTRL '0' effectively breaks PMU usage in guests that
haven't been updated to work with PMUs that support PERF_GLOBAL_CTRL.
This bug was recently exposed when KVM added supported for AMD's
PerfMonV2, i.e. when KVM started exposing a vPMU with PERF_GLOBAL_CTRL to
guest software that only knew how to program v1 PMUs (that don't support
PERF_GLOBAL_CTRL).

Failure to emulate the post-RESET behavior results in such guests
unknowingly leaving all general purpose counters globally disabled (the
entire reason the post-RESET value sets the GP counter enable bits is to
maintain backwards compatibility).

The bug has likely gone unnoticed because PERF_GLOBAL_CTRL has been
supported on Intel CPUs for as long as KVM has existed, i.e. hardly anyone
is running guest software that isn't aware of PERF_GLOBAL_CTRL on Intel
PMUs.  And because up until v6.0, KVM _did_ emulate the behavior for Intel
CPUs, although the old behavior was likely dumb luck.

Because (a) that old code was also broken in its own way (the history of
this code is a comedy of errors), and (b) PERF_GLOBAL_CTRL was documented
as having a value of '0' post-RESET in all SDMs before March 2023.

Initial vPMU support in commit f5132b0138 ("KVM: Expose a version 2
architectural PMU to a guests") *almost* got it right (again likely by
dumb luck), but for some reason only set the bits if the guest PMU was
advertised as v1:

        if (pmu->version == 1) {
                pmu->global_ctrl = (1 << pmu->nr_arch_gp_counters) - 1;
                return;
        }

Commit f19a0c2c2e ("KVM: PMU emulation: GLOBAL_CTRL MSR should be
enabled on reset") then tried to remedy that goof, presumably because
guest PMUs were leaving PERF_GLOBAL_CTRL '0', i.e. weren't enabling
counters.

        pmu->global_ctrl = ((1 << pmu->nr_arch_gp_counters) - 1) |
                (((1ull << pmu->nr_arch_fixed_counters) - 1) << X86_PMC_IDX_FIXED);
        pmu->global_ctrl_mask = ~pmu->global_ctrl;

That was KVM's behavior up until commit c49467a45f ("KVM: x86/pmu:
Don't overwrite the pmu->global_ctrl when refreshing") removed
*everything*.  However, it did so based on the behavior defined by the
SDM , which at the time stated that "Global Perf Counter Controls" is
'0' at Power-Up and RESET.

But then the March 2023 SDM (325462-079US), stealthily changed its
"IA-32 and Intel 64 Processor States Following Power-up, Reset, or INIT"
table to say:

  IA32_PERF_GLOBAL_CTRL: Sets bits n-1:0 and clears the upper bits.

Note, kvm_pmu_refresh() can be invoked multiple times, i.e. it's not a
"pure" RESET flow.  But it can only be called prior to the first KVM_RUN,
i.e. the guest will only ever observe the final value.

Note #2, KVM has always cleared global_ctrl during refresh (see commit
f5132b0138 ("KVM: Expose a version 2 architectural PMU to a guests")),
i.e. there is no danger of breaking existing setups by clobbering a value
set by userspace.

Reported-by: Babu Moger <babu.moger@amd.com>
Cc: Sandipan Das <sandipan.das@amd.com>
Cc: Like Xu <like.xu.linux@gmail.com>
Cc: Mingwei Zhang <mizhang@google.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: stable@vger.kernel.org
Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Tested-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Link: https://lore.kernel.org/r/20240309013641.1413400-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-05-02 16:35:23 +02:00
..
mmu KVM: x86/mmu: Write-protect L2 SPTEs in TDP MMU when clearing dirty status 2024-04-27 17:13:01 +02:00
svm KVM: SVM: Add support for allowing zero SEV ASIDs 2024-04-10 16:38:09 +02:00
vmx KVM: x86/pmu: Zero out PMU metadata on AMD if PMU is disabled 2024-05-02 16:35:23 +02:00
.gitignore
cpuid.c KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible 2024-04-27 17:13:01 +02:00
cpuid.h KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible 2024-04-27 17:13:01 +02:00
debugfs.c LoongArch KVM changes for v6.8 2024-01-02 13:16:29 -05:00
emulate.c KVM: x86: Introduce get_untagged_addr() in kvm_x86_ops and call it in emulator 2023-11-28 17:54:06 -08:00
fpu.h
governed_features.h KVM: x86: Use KVM-governed feature framework to track "LAM enabled" 2023-11-28 17:54:09 -08:00
hyperv.c KVM: x86: Give a hint when Win2016 might fail to boot due to XSAVES erratum 2024-01-31 16:21:00 -05:00
hyperv.h KVM: x86: Give a hint when Win2016 might fail to boot due to XSAVES erratum 2024-01-31 16:21:00 -05:00
i8254.c
i8254.h
i8259.c
ioapic.c
ioapic.h
irq.c KVM: x86/xen: Remove unneeded xen context from kvm_arch when !CONFIG_KVM_XEN 2023-12-07 09:33:42 -08:00
irq.h
irq_comm.c KVM: x86: Make Hyper-V emulation optional 2023-12-07 09:34:57 -08:00
Kconfig KVM: x86: Update KVM_SW_PROTECTED_VM docs to make it clear they're a WIP 2024-02-22 17:07:06 -08:00
kvm-asm-offsets.c
kvm_cache_regs.h
kvm_emulate.h KVM: x86: Introduce get_untagged_addr() in kvm_x86_ops and call it in emulator 2023-11-28 17:54:06 -08:00
kvm_onhyperv.c
kvm_onhyperv.h KVM: x86: Move Hyper-V partition assist page out of Hyper-V emulation context 2023-12-07 09:34:01 -08:00
lapic.c KVM: x86/pmu: Do not mask LVTPC when handling a PMI on AMD platforms 2024-04-27 17:13:01 +02:00
lapic.h
Makefile KVM: x86: Make Hyper-V emulation optional 2023-12-07 09:34:57 -08:00
mmu.h KVM: x86: Use KVM-governed feature framework to track "LAM enabled" 2023-11-28 17:54:09 -08:00
mtrr.c
pmu.c KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at "RESET" 2024-05-02 16:35:23 +02:00
pmu.h KVM: x86/pmu: Track emulated counter events instead of previous counter 2023-11-30 12:52:55 -08:00
reverse_cpuid.h x86/bhi: Define SPEC_CTRL_BHI_DIS_S 2024-04-10 16:38:24 +02:00
smm.c
smm.h
trace.h KVM: SVM: Use unsigned integers when dealing with ASIDs 2024-04-10 16:38:09 +02:00
tss.h
x86.c KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible 2024-04-27 17:13:01 +02:00
x86.h KVM: x86: Virtualize LAM for supervisor pointer 2023-11-28 17:54:07 -08:00
xen.c KVM: x86/xen: inject vCPU upcall vector when local APIC is enabled 2024-04-03 15:32:11 +02:00
xen.h KVM: x86/xen: inject vCPU upcall vector when local APIC is enabled 2024-04-03 15:32:11 +02:00