2023-04-27 09:59:20

by Anselm Busse

[permalink] [raw]
Subject: [PATCH 0/2] KVM support for Intel PMU v5 fixed function PMC bitmap

Starting with v5, the Intel PMU allows to indicate the available fixed
function PMCs not only through CPUID.0AH.EDX[4:0] but also through a
bit mask in CPUID.0AH.ECX. According to the SDM the OS can consider a
fix function PMC i supported for:

CPUID.0AH.ECX[i] || (CPUID.0AH.EDX[4:0] > i)

This behavior is already supported by the Intel PMU driver. However, KVM
support is missing. This patch series add the support by first
refactoring the tracking of available fixed function PMCs in KVM from a
number to a bitmap in the frist patch. The second patch populates the
bitmap accoring to the rule given by the SDM mentioned above.

Regards,
Anselm

Anselm Busse (2):
KVM: vmx/pmu: Indicate available fixed function PMCs through a bitmap
KVM: vmx/pmu: Add support for selected fixed vPMU enablement for PMU v5

arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/pmu.h | 6 ++---
arch/x86/kvm/svm/pmu.c | 2 +-
arch/x86/kvm/vmx/pmu_intel.c | 40 ++++++++++++++++++++-------------
4 files changed, 30 insertions(+), 20 deletions(-)


base-commit: 0cfd8703e7da687924371e9bc77a025bdeba9637
--
2.39.2




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879




2023-04-27 10:10:27

by Anselm Busse

[permalink] [raw]
Subject: [PATCH 2/2] KVM: vmx/pmu: Add support for selected fixed vPMU enablement for PMU v5

This commits adds virtualization support to enable slected fixed
function PMCs for Intel PMU v5 based on CPUID.0AH.ECX.

Starting with v5, the Intel PMU allows to indicate the available fixed
function PMCs not only through CPUID.0AH.EDX[4:0] but also through a
bit mask in CPUID.0AH.ECX. According to the SDM the OS can consider a
fix function PMC i supported for:

CPUID.0AH.ECX[i] || (CPUID.0AH.EDX[4:0] > i)

This behavior is already supported by the Intel PMU driver. However, KVM
support is missing. Therefore, this commit extends the KVM
implementation by also taking the values in CPUID.0AH.ECX into account
when setting the bitmap of enabled fixed function PMCs.

Signed-off-by: Anselm Busse <[email protected]>
---
arch/x86/kvm/vmx/pmu_intel.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index 55ff06a9df47..d1fd3472bfd4 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -562,6 +562,13 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
kvm_pmu_cap.bit_width_fixed);
pmu->counter_bitmask[KVM_PMC_FIXED] =
((u64)1 << edx.split.bit_width_fixed) - 1;
+
+ if (pmu->version >= 5)
+ bitmap_or(pmu->mask_arch_fixed_counters,
+ pmu->mask_arch_fixed_counters,
+ (unsigned long *)&entry->ecx,
+ INTEL_PMC_MAX_FIXED);
+
setup_fixed_pmc_eventsel(pmu);
}

--
2.39.2




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879



2023-04-27 10:16:21

by Anselm Busse

[permalink] [raw]
Subject: [PATCH 1/2] KVM: vmx/pmu: Indicate available fixed function PMCs through a bitmap

This commit changes the tracking of available fixed function counters
from a number to a bitmap.

Starting with Intel PMU v5, the available fixed function counters cannot
only be advertised through a number, but also through a bitmap in
CPUID.0AH.ECX. However, the current KVM implementation determines if a
fixed function PMC is available to a guest purely based on the number
of exposed fixed function PMCs. This makes it impossible to use this
new feature of the Intel PMU v5. Therefore, this change serves as a
preparation to seamlessly enable the virtualization of Intel PMU v5 in
the future.

No functional change intended.

Signed-off-by: Anselm Busse <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 2 +-
arch/x86/kvm/pmu.h | 6 +++---
arch/x86/kvm/svm/pmu.c | 2 +-
arch/x86/kvm/vmx/pmu_intel.c | 33 ++++++++++++++++++---------------
4 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 808c292ad3f4..ea4859554678 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -516,7 +516,7 @@ struct kvm_pmc {
#define KVM_AMD_PMC_MAX_GENERIC 6
struct kvm_pmu {
unsigned nr_arch_gp_counters;
- unsigned nr_arch_fixed_counters;
+ DECLARE_BITMAP(mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED);
unsigned available_event_types;
u64 fixed_ctr_ctrl;
u64 fixed_ctr_ctrl_mask;
diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h
index be62c16f2265..11940c97f7a4 100644
--- a/arch/x86/kvm/pmu.h
+++ b/arch/x86/kvm/pmu.h
@@ -116,9 +116,9 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)
{
int base = MSR_CORE_PERF_FIXED_CTR0;

- if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) {
- u32 index = array_index_nospec(msr - base,
- pmu->nr_arch_fixed_counters);
+ if (msr >= base && msr < base + INTEL_PMC_MAX_FIXED &&
+ test_bit(msr - base, pmu->mask_arch_fixed_counters)) {
+ u32 index = array_index_nospec(msr - base, INTEL_PMC_MAX_FIXED);

return &pmu->fixed_counters[index];
}
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index cc77a0681800..ce8bd53aa6cc 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -184,7 +184,7 @@ static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
pmu->version = 1;
/* 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;
+ bitmap_zero(pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED);
pmu->global_status = 0;
bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
}
diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c
index e8a3be0b9df9..55ff06a9df47 100644
--- a/arch/x86/kvm/vmx/pmu_intel.c
+++ b/arch/x86/kvm/vmx/pmu_intel.c
@@ -47,7 +47,7 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
int i;

pmu->fixed_ctr_ctrl = data;
- for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+ for_each_set_bit(i, pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED) {
u8 new_ctrl = fixed_ctrl_field(data, i);
u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i);

@@ -125,7 +125,7 @@ static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx)

idx &= ~(3u << 30);

- return fixed ? idx < pmu->nr_arch_fixed_counters
+ return fixed ? test_bit(idx, pmu->mask_arch_fixed_counters)
: idx < pmu->nr_arch_gp_counters;
}

@@ -140,12 +140,12 @@ static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
idx &= ~(3u << 30);
if (fixed) {
counters = pmu->fixed_counters;
- num_counters = pmu->nr_arch_fixed_counters;
+ num_counters = INTEL_PMC_MAX_FIXED;
} else {
counters = pmu->gp_counters;
num_counters = pmu->nr_arch_gp_counters;
}
- if (idx >= num_counters)
+ if (idx >= num_counters || (fixed && !test_bit(idx, pmu->mask_arch_fixed_counters)))
return NULL;
*mask &= pmu->counter_bitmask[fixed ? KVM_PMC_FIXED : KVM_PMC_GP];
return &counters[array_index_nospec(idx, num_counters)];
@@ -499,7 +499,7 @@ static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu)
u32 event;
int i;

- for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+ for_each_set_bit(i, pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED) {
pmc = &pmu->fixed_counters[i];
event = fixed_pmc_events[array_index_nospec(i, size)];
pmc->eventsel = (intel_arch_events[event].unit_mask << 8) |
@@ -519,7 +519,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
int i;

pmu->nr_arch_gp_counters = 0;
- pmu->nr_arch_fixed_counters = 0;
+ bitmap_zero(pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED);
pmu->counter_bitmask[KVM_PMC_GP] = 0;
pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
pmu->version = 0;
@@ -552,12 +552,12 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
((1ull << eax.split.mask_length) - 1);

if (pmu->version == 1) {
- pmu->nr_arch_fixed_counters = 0;
+ bitmap_zero(pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED);
} else {
- pmu->nr_arch_fixed_counters =
+ bitmap_set(pmu->mask_arch_fixed_counters, 0,
min3(ARRAY_SIZE(fixed_pmc_events),
(size_t) edx.split.num_counters_fixed,
- (size_t)kvm_pmu_cap.num_counters_fixed);
+ (size_t)kvm_pmu_cap.num_counters_fixed));
edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed,
kvm_pmu_cap.bit_width_fixed);
pmu->counter_bitmask[KVM_PMC_FIXED] =
@@ -565,10 +565,13 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
setup_fixed_pmc_eventsel(pmu);
}

- for (i = 0; i < pmu->nr_arch_fixed_counters; i++)
+ counter_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1);
+
+ for_each_set_bit(i, pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED) {
pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4));
- counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) |
- (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED));
+ counter_mask &= ~(1ull << (INTEL_PMC_MAX_GENERIC + i));
+ }
+
pmu->global_ctrl_mask = counter_mask;
pmu->global_ovf_ctrl_mask = pmu->global_ctrl_mask
& ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF |
@@ -587,8 +590,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)

bitmap_set(pmu->all_valid_pmc_idx,
0, pmu->nr_arch_gp_counters);
- bitmap_set(pmu->all_valid_pmc_idx,
- INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters);
+ for_each_set_bit(i, pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED)
+ set_bit(INTEL_PMC_MAX_GENERIC + i, pmu->all_valid_pmc_idx);

perf_capabilities = vcpu_get_perf_capabilities(vcpu);
if (cpuid_model_is_consistent(vcpu) &&
@@ -604,7 +607,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
if (perf_capabilities & PERF_CAP_PEBS_BASELINE) {
pmu->pebs_enable_mask = counter_mask;
pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE;
- for (i = 0; i < pmu->nr_arch_fixed_counters; i++) {
+ for_each_set_bit(i, pmu->mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED) {
pmu->fixed_ctr_ctrl_mask &=
~(1ULL << (INTEL_PMC_IDX_FIXED + i * 4));
}
--
2.39.2




Amazon Development Center Germany GmbH
Krausenstr. 38
10117 Berlin
Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss
Eingetragen am Amtsgericht Charlottenburg unter HRB 149173 B
Sitz: Berlin
Ust-ID: DE 289 237 879



2023-05-16 13:58:25

by Like Xu

[permalink] [raw]
Subject: Re: [PATCH 0/2] KVM support for Intel PMU v5 fixed function PMC bitmap

On 27/4/2023 5:53 pm, Anselm Busse wrote:
> Starting with v5, the Intel PMU allows to indicate the available fixed
> function PMCs not only through CPUID.0AH.EDX[4:0] but also through a
> bit mask in CPUID.0AH.ECX. According to the SDM the OS can consider a
> fix function PMC i supported for:
>
> CPUID.0AH.ECX[i] || (CPUID.0AH.EDX[4:0] > i)

Yes, this feature is attractive for virtualization scenarios, and it gives
flexibility
to control which fixed counters are available or not in the virtual machine.

However, currently KVM/x86 also supports Intel PMU V2, so I would expect
that we will review the enablement code for v3 and v4 first.

Ref:
https://lore.kernel.org/kvm/CALMp9eQVnk8gkOpX5AHhaCr8-5Fe=qNuX8PUP1Gv2H5FSYmHSw@mail.gmail.com/

>
> This behavior is already supported by the Intel PMU driver. However, KVM
> support is missing. This patch series add the support by first
> refactoring the tracking of available fixed function PMCs in KVM from a
> number to a bitmap in the frist patch. The second patch populates the
> bitmap accoring to the rule given by the SDM mentioned above.
>
> Regards,
> Anselm
>
> Anselm Busse (2):
> KVM: vmx/pmu: Indicate available fixed function PMCs through a bitmap
> KVM: vmx/pmu: Add support for selected fixed vPMU enablement for PMU v5
>
> arch/x86/include/asm/kvm_host.h | 2 +-
> arch/x86/kvm/pmu.h | 6 ++---
> arch/x86/kvm/svm/pmu.c | 2 +-
> arch/x86/kvm/vmx/pmu_intel.c | 40 ++++++++++++++++++++-------------
> 4 files changed, 30 insertions(+), 20 deletions(-)
>
>
> base-commit: 0cfd8703e7da687924371e9bc77a025bdeba9637

2023-05-25 22:43:04

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH 0/2] KVM support for Intel PMU v5 fixed function PMC bitmap

On Tue, May 16, 2023, Like Xu wrote:
> On 27/4/2023 5:53 pm, Anselm Busse wrote:
> > Starting with v5, the Intel PMU allows to indicate the available fixed
> > function PMCs not only through CPUID.0AH.EDX[4:0] but also through a
> > bit mask in CPUID.0AH.ECX. According to the SDM the OS can consider a
> > fix function PMC i supported for:
> >
> > CPUID.0AH.ECX[i] || (CPUID.0AH.EDX[4:0] > i)
>
> Yes, this feature is attractive for virtualization scenarios, and it gives
> flexibility to control which fixed counters are available or not in the
> virtual machine.
>
> However, currently KVM/x86 also supports Intel PMU V2, so I would expect
> that we will review the enablement code for v3 and v4 first.

Looking at v3, I think we probably want to skip straight to v5. I don't see a sane
way for KVM to emulate/virtualize AnyThread, which comes in v3 without a separate
CPUID feature flag. The SDM even calls out that it'd be a mess to deal with in a
virtualized environment. v5 introduces a CPUID bit to allow deprecating AnyThread,
i.e. would give KVM the ability to advertise a sane vPMU model to userspace.
Amusingly, KVM advertises "edx.split.anythread_deprecated = 1" for v1+, so maybe
we don't even need to do any enabling? At glance, I don't see any other changes
in v3 that require KVM support.

v4 looks to be an entirely different story than v3 though. So I agree with Like
that we need to enable v3 and v4 before advertising support for v5. And KVM *does*
need to actually advertise v5. Emulating the fixed counter bitmap without a way to
tell userspace about the functionality will create a mess.

TL;DR: If y'all want the shiny features in v5, please enable v3 and v4 first. I'm
totally fine taking a series to go all the way to v5 (might even be preferred due
to the AnyThread crud), but I don't want to advertise v5 without supporting the
required v3/v4 features.

> Ref: https://lore.kernel.org/kvm/CALMp9eQVnk8gkOpX5AHhaCr8-5Fe=qNuX8PUP1Gv2H5FSYmHSw@mail.gmail.com/

I agree 100% with Jim, the bitmask stuff is firmly v5+.

2023-05-25 22:44:01

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH 1/2] KVM: vmx/pmu: Indicate available fixed function PMCs through a bitmap

On Thu, Apr 27, 2023, Anselm Busse wrote:
> This commit changes the tracking of available fixed function counters
> from a number to a bitmap.
>
> Starting with Intel PMU v5, the available fixed function counters cannot
> only be advertised through a number, but also through a bitmap in
> CPUID.0AH.ECX. However, the current KVM implementation determines if a
> fixed function PMC is available to a guest purely based on the number
> of exposed fixed function PMCs. This makes it impossible to use this
> new feature of the Intel PMU v5. Therefore, this change serves as a
> preparation to seamlessly enable the virtualization of Intel PMU v5 in
> the future.
>
> No functional change intended.
>
> Signed-off-by: Anselm Busse <[email protected]>
> ---
> arch/x86/include/asm/kvm_host.h | 2 +-
> arch/x86/kvm/pmu.h | 6 +++---
> arch/x86/kvm/svm/pmu.c | 2 +-
> arch/x86/kvm/vmx/pmu_intel.c | 33 ++++++++++++++++++---------------
> 4 files changed, 23 insertions(+), 20 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 808c292ad3f4..ea4859554678 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -516,7 +516,7 @@ struct kvm_pmc {
> #define KVM_AMD_PMC_MAX_GENERIC 6
> struct kvm_pmu {
> unsigned nr_arch_gp_counters;
> - unsigned nr_arch_fixed_counters;
> + DECLARE_BITMAP(mask_arch_fixed_counters, INTEL_PMC_MAX_FIXED);

Please see the feedback I gave to Like[*]. Unless I'm missing something, there's
no need for another bitmap.

[*] https://lore.kernel.org/kvm/[email protected]