mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET"
@ 2024-03-09  1:36 Sean Christopherson
  2024-03-09  1:36 ` [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL " Sean Christopherson
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Sean Christopherson @ 2024-03-09  1:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, Babu Moger, Sandipan Das, Like Xu,
	Mingwei Zhang, Dapeng Mi

Globally enable GP counters in PERF_GLOBAL_CTRL when refreshing a vCPU's
PMU to emulate the architecturally defined post-RESET behavior of the MSR.

Extend pmu_counters_test.c to verify the behavior.

Note, this is slightly different than what I "posted" before: it keeps
PERF_GLOBAL_CTRL '0' if there are no counters.  That's technically not
what the SDM dictates, but I went with the common sense route of
interpreting the SDM to mean "globally enable all GP counters".

I figured it was much more likely that the SDM writers didn't think
about virtual CPUs that can have a PMU without any GP counters, versus
Intel really wanting to set _all_ bits in PERF_GLOBAL_CTRL :-)

Sean Christopherson (2):
  KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at
    "RESET"
  KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs
    test

 arch/x86/kvm/pmu.c                            | 16 +++++++++++++--
 .../selftests/kvm/x86_64/pmu_counters_test.c  | 20 ++++++++++++++++++-
 2 files changed, 33 insertions(+), 3 deletions(-)


base-commit: 964d0c614c7f71917305a5afdca9178fe8231434
-- 
2.44.0.278.ge034bb2e1d-goog


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at "RESET"
  2024-03-09  1:36 [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Sean Christopherson
@ 2024-03-09  1:36 ` Sean Christopherson
  2024-04-16 19:19   ` Moger, Babu
  2024-03-09  1:36 ` [PATCH 2/2] KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs test Sean Christopherson
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Sean Christopherson @ 2024-03-09  1:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, Babu Moger, Sandipan Das, Like Xu,
	Mingwei Zhang, Dapeng Mi

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 f5132b01386b ("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 f19a0c2c2e6a ("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 c49467a45fe0 ("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
f5132b01386b ("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
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/pmu.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index c397b28e3d1b..a593b03c9aed 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -775,8 +775,20 @@ void kvm_pmu_refresh(struct kvm_vcpu *vcpu)
 	pmu->pebs_data_cfg_mask = ~0ull;
 	bitmap_zero(pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX);
 
-	if (vcpu->kvm->arch.enable_pmu)
-		static_call(kvm_x86_pmu_refresh)(vcpu);
+	if (!vcpu->kvm->arch.enable_pmu)
+		return;
+
+	static_call(kvm_x86_pmu_refresh)(vcpu);
+
+	/*
+	 * At RESET, both Intel and AMD CPUs set all enable bits for general
+	 * purpose counters in IA32_PERF_GLOBAL_CTRL (so that software that
+	 * was written for v1 PMUs don't unknowingly leave GP counters disabled
+	 * in the global controls).  Emulate that behavior when refreshing the
+	 * PMU so that userspace doesn't need to manually set PERF_GLOBAL_CTRL.
+	 */
+	if (kvm_pmu_has_perf_global_ctrl(pmu) && pmu->nr_arch_gp_counters)
+		pmu->global_ctrl = GENMASK_ULL(pmu->nr_arch_gp_counters - 1, 0);
 }
 
 void kvm_pmu_init(struct kvm_vcpu *vcpu)
-- 
2.44.0.278.ge034bb2e1d-goog


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/2] KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs test
  2024-03-09  1:36 [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Sean Christopherson
  2024-03-09  1:36 ` [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL " Sean Christopherson
@ 2024-03-09  1:36 ` Sean Christopherson
  2024-03-11  1:25 ` [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Mi, Dapeng
  2024-04-09  2:01 ` Sean Christopherson
  3 siblings, 0 replies; 6+ messages in thread
From: Sean Christopherson @ 2024-03-09  1:36 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, Babu Moger, Sandipan Das, Like Xu,
	Mingwei Zhang, Dapeng Mi

Add a guest assert in the PMU counters test to verify that KVM stuffs
the vCPU's post-RESET value to globally enable all general purpose
counters.  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.

For the edge case where there are zero GP counters, follow the spirit
of the architecture, not the SDM's literal wording, which doesn't account
for this possibility and would require the CPU to set _all_ bits in
PERF_GLOBAL_CTRL.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 .../selftests/kvm/x86_64/pmu_counters_test.c  | 20 ++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c
index 29609b52f8fa..26c85815f7e9 100644
--- a/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c
+++ b/tools/testing/selftests/kvm/x86_64/pmu_counters_test.c
@@ -416,12 +416,30 @@ static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters
 
 static void guest_test_gp_counters(void)
 {
+	uint8_t pmu_version = guest_get_pmu_version();
 	uint8_t nr_gp_counters = 0;
 	uint32_t base_msr;
 
-	if (guest_get_pmu_version())
+	if (pmu_version)
 		nr_gp_counters = this_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS);
 
+	/*
+	 * For v2+ PMUs, PERF_GLOBAL_CTRL's architectural post-RESET value is
+	 * "Sets bits n-1:0 and clears the upper bits", where 'n' is the number
+	 * of GP counters.  If there are no GP counters, require KVM to leave
+	 * PERF_GLOBAL_CTRL '0'.  This edge case isn't covered by the SDM, but
+	 * follow the spirit of the architecture and only globally enable GP
+	 * counters, of which there are none.
+	 */
+	if (pmu_version > 1) {
+		uint64_t global_ctrl = rdmsr(MSR_CORE_PERF_GLOBAL_CTRL);
+
+		if (nr_gp_counters)
+			GUEST_ASSERT_EQ(global_ctrl, GENMASK_ULL(nr_gp_counters - 1, 0));
+		else
+			GUEST_ASSERT_EQ(global_ctrl, 0);
+	}
+
 	if (this_cpu_has(X86_FEATURE_PDCM) &&
 	    rdmsr(MSR_IA32_PERF_CAPABILITIES) & PMU_CAP_FW_WRITES)
 		base_msr = MSR_IA32_PMC0;
-- 
2.44.0.278.ge034bb2e1d-goog


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET"
  2024-03-09  1:36 [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Sean Christopherson
  2024-03-09  1:36 ` [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL " Sean Christopherson
  2024-03-09  1:36 ` [PATCH 2/2] KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs test Sean Christopherson
@ 2024-03-11  1:25 ` Mi, Dapeng
  2024-04-09  2:01 ` Sean Christopherson
  3 siblings, 0 replies; 6+ messages in thread
From: Mi, Dapeng @ 2024-03-11  1:25 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, Babu Moger, Sandipan Das, Like Xu, Mingwei Zhang


On 3/9/2024 9:36 AM, Sean Christopherson wrote:
> Globally enable GP counters in PERF_GLOBAL_CTRL when refreshing a vCPU's
> PMU to emulate the architecturally defined post-RESET behavior of the MSR.
>
> Extend pmu_counters_test.c to verify the behavior.
>
> Note, this is slightly different than what I "posted" before: it keeps
> PERF_GLOBAL_CTRL '0' if there are no counters.  That's technically not
> what the SDM dictates, but I went with the common sense route of
> interpreting the SDM to mean "globally enable all GP counters".
>
> I figured it was much more likely that the SDM writers didn't think
> about virtual CPUs that can have a PMU without any GP counters, versus
> Intel really wanting to set _all_ bits in PERF_GLOBAL_CTRL :-)
>
> Sean Christopherson (2):
>    KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at
>      "RESET"
>    KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs
>      test
>
>   arch/x86/kvm/pmu.c                            | 16 +++++++++++++--
>   .../selftests/kvm/x86_64/pmu_counters_test.c  | 20 ++++++++++++++++++-
>   2 files changed, 33 insertions(+), 3 deletions(-)
>
>
> base-commit: 964d0c614c7f71917305a5afdca9178fe8231434

Reviewed-by: Dapeng Mi <dapeng1.mi@linux.intel.com>

Tested-by: Dapeng Mi <dapeng1.mi@linux.intel.com>


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET"
  2024-03-09  1:36 [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Sean Christopherson
                   ` (2 preceding siblings ...)
  2024-03-11  1:25 ` [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Mi, Dapeng
@ 2024-04-09  2:01 ` Sean Christopherson
  3 siblings, 0 replies; 6+ messages in thread
From: Sean Christopherson @ 2024-04-09  2:01 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, Babu Moger, Sandipan Das, Like Xu,
	Mingwei Zhang, Dapeng Mi

On Fri, 08 Mar 2024 17:36:39 -0800, Sean Christopherson wrote:
> Globally enable GP counters in PERF_GLOBAL_CTRL when refreshing a vCPU's
> PMU to emulate the architecturally defined post-RESET behavior of the MSR.
> 
> Extend pmu_counters_test.c to verify the behavior.
> 
> Note, this is slightly different than what I "posted" before: it keeps
> PERF_GLOBAL_CTRL '0' if there are no counters.  That's technically not
> what the SDM dictates, but I went with the common sense route of
> interpreting the SDM to mean "globally enable all GP counters".
> 
> [...]

Applied to kvm-x86 fixes, thanks!

[1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at "RESET"
      https://github.com/kvm-x86/linux/commit/de120e1d692d
[2/2] KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs test
      https://github.com/kvm-x86/linux/commit/08a828249b16

--
https://github.com/kvm-x86/linux/tree/next

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL at "RESET"
  2024-03-09  1:36 ` [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL " Sean Christopherson
@ 2024-04-16 19:19   ` Moger, Babu
  0 siblings, 0 replies; 6+ messages in thread
From: Moger, Babu @ 2024-04-16 19:19 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini
  Cc: kvm, linux-kernel, Sandipan Das, Like Xu, Mingwei Zhang, Dapeng Mi



On 3/8/24 19:36, Sean Christopherson wrote:
> 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 f5132b01386b ("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 f19a0c2c2e6a ("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 c49467a45fe0 ("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
> f5132b01386b ("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
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Tested-by: Babu Moger <babu.moger@amd.com>

-- 
Thanks
Babu Moger

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-04-16 19:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-09  1:36 [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Sean Christopherson
2024-03-09  1:36 ` [PATCH 1/2] KVM: x86/pmu: Set enable bits for GP counters in PERF_GLOBAL_CTRL " Sean Christopherson
2024-04-16 19:19   ` Moger, Babu
2024-03-09  1:36 ` [PATCH 2/2] KVM: selftests: Verify post-RESET value of PERF_GLOBAL_CTRL in PMCs test Sean Christopherson
2024-03-11  1:25 ` [PATCH 0/2] KVM: x86/pmu: Globally enable GP counters at "RESET" Mi, Dapeng
2024-04-09  2:01 ` Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®