Skip to content

Commit b31880c

Browse files
committed
KVM: x86/pmu: Move pmc_idx => pmc translation helper to common code
Add a common helper for *internal* PMC lookups, and delete the ops hook and Intel's implementation. Keep AMD's implementation, but rename it to amd_pmu_get_pmc() to make it somewhat more obvious that it's suited for both KVM-internal and guest-initiated lookups. Because KVM tracks all counters in a single bitmap, getting a counter when iterating over a bitmap, e.g. of all valid PMCs, requires a small amount of math, that while simple, isn't super obvious and doesn't use the same semantics as PMC lookups from RDPMC! Although AMD doesn't support fixed counters, the common PMU code still behaves as if there a split, the high half of which just happens to always be empty. Opportunstically add a comment to explain both what is going on, and why KVM uses a single bitmap, e.g. the boilerplate for iterating over separate bitmaps could be done via macros, so it's not (just) about deduplicating code. Link: https://lore.kernel.org/r/20231110022857.1273836-4-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent be6b067 commit b31880c

File tree

5 files changed

+36
-24
lines changed

5 files changed

+36
-24
lines changed

arch/x86/include/asm/kvm-x86-pmu-ops.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ BUILD_BUG_ON(1)
1212
* a NULL definition, for example if "static_call_cond()" will be used
1313
* at the call sites.
1414
*/
15-
KVM_X86_PMU_OP(pmc_idx_to_pmc)
1615
KVM_X86_PMU_OP(rdpmc_ecx_to_pmc)
1716
KVM_X86_PMU_OP(msr_idx_to_pmc)
1817
KVM_X86_PMU_OP_OPTIONAL(check_rdpmc_early)

arch/x86/kvm/pmu.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu)
505505
int bit;
506506

507507
for_each_set_bit(bit, pmu->reprogram_pmi, X86_PMC_IDX_MAX) {
508-
struct kvm_pmc *pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, bit);
508+
struct kvm_pmc *pmc = kvm_pmc_idx_to_pmc(pmu, bit);
509509

510510
if (unlikely(!pmc)) {
511511
clear_bit(bit, pmu->reprogram_pmi);
@@ -725,7 +725,7 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu)
725725
bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX);
726726

727727
for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) {
728-
pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i);
728+
pmc = kvm_pmc_idx_to_pmc(pmu, i);
729729
if (!pmc)
730730
continue;
731731

@@ -801,7 +801,7 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu)
801801
pmu->pmc_in_use, X86_PMC_IDX_MAX);
802802

803803
for_each_set_bit(i, bitmask, X86_PMC_IDX_MAX) {
804-
pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i);
804+
pmc = kvm_pmc_idx_to_pmc(pmu, i);
805805

806806
if (pmc && pmc->perf_event && !pmc_speculative_in_use(pmc))
807807
pmc_stop_counter(pmc);
@@ -856,7 +856,7 @@ void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id)
856856
int i;
857857

858858
for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) {
859-
pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i);
859+
pmc = kvm_pmc_idx_to_pmc(pmu, i);
860860

861861
if (!pmc || !pmc_event_is_allowed(pmc))
862862
continue;

arch/x86/kvm/pmu.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include <linux/nospec.h>
66

7+
#include <asm/kvm_host.h>
8+
79
#define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu)
810
#define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu))
911
#define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu)
@@ -21,7 +23,6 @@
2123
#define KVM_FIXED_PMC_BASE_IDX INTEL_PMC_IDX_FIXED
2224

2325
struct kvm_pmu_ops {
24-
struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
2526
struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu,
2627
unsigned int idx, u64 *mask);
2728
struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, u32 msr);
@@ -56,6 +57,32 @@ static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
5657
return pmu->version > 1;
5758
}
5859

60+
/*
61+
* KVM tracks all counters in 64-bit bitmaps, with general purpose counters
62+
* mapped to bits 31:0 and fixed counters mapped to 63:32, e.g. fixed counter 0
63+
* is tracked internally via index 32. On Intel, (AMD doesn't support fixed
64+
* counters), this mirrors how fixed counters are mapped to PERF_GLOBAL_CTRL
65+
* and similar MSRs, i.e. tracking fixed counters at base index 32 reduces the
66+
* amounter of boilerplate needed to iterate over PMCs *and* simplifies common
67+
* enabling/disable/reset operations.
68+
*
69+
* WARNING! This helper is only for lookups that are initiated by KVM, it is
70+
* NOT safe for guest lookups, e.g. will do the wrong thing if passed a raw
71+
* ECX value from RDPMC (fixed counters are accessed by setting bit 30 in ECX
72+
* for RDPMC, not by adding 32 to the fixed counter index).
73+
*/
74+
static inline struct kvm_pmc *kvm_pmc_idx_to_pmc(struct kvm_pmu *pmu, int idx)
75+
{
76+
if (idx < pmu->nr_arch_gp_counters)
77+
return &pmu->gp_counters[idx];
78+
79+
idx -= KVM_FIXED_PMC_BASE_IDX;
80+
if (idx >= 0 && idx < pmu->nr_arch_fixed_counters)
81+
return &pmu->fixed_counters[idx];
82+
83+
return NULL;
84+
}
85+
5986
static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
6087
{
6188
struct kvm_pmu *pmu = pmc_to_pmu(pmc);

arch/x86/kvm/svm/pmu.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ enum pmu_type {
2525
PMU_TYPE_EVNTSEL,
2626
};
2727

28-
static struct kvm_pmc *amd_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
28+
static struct kvm_pmc *amd_pmu_get_pmc(struct kvm_pmu *pmu, int pmc_idx)
2929
{
3030
unsigned int num_counters = pmu->nr_arch_gp_counters;
3131

@@ -70,7 +70,7 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr,
7070
return NULL;
7171
}
7272

73-
return amd_pmc_idx_to_pmc(pmu, idx);
73+
return amd_pmu_get_pmc(pmu, idx);
7474
}
7575

7676
static int amd_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx)
@@ -87,7 +87,7 @@ static int amd_check_rdpmc_early(struct kvm_vcpu *vcpu, unsigned int idx)
8787
static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
8888
unsigned int idx, u64 *mask)
8989
{
90-
return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx);
90+
return amd_pmu_get_pmc(vcpu_to_pmu(vcpu), idx);
9191
}
9292

9393
static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
@@ -229,7 +229,6 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu)
229229
}
230230

231231
struct kvm_pmu_ops amd_pmu_ops __initdata = {
232-
.pmc_idx_to_pmc = amd_pmc_idx_to_pmc,
233232
.rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc,
234233
.msr_idx_to_pmc = amd_msr_idx_to_pmc,
235234
.check_rdpmc_early = amd_check_rdpmc_early,

arch/x86/kvm/vmx/pmu_intel.c

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,6 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data)
5555
}
5656
}
5757

58-
static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx)
59-
{
60-
if (pmc_idx < KVM_FIXED_PMC_BASE_IDX) {
61-
return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx,
62-
MSR_P6_EVNTSEL0);
63-
} else {
64-
u32 idx = pmc_idx - KVM_FIXED_PMC_BASE_IDX;
65-
66-
return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0);
67-
}
68-
}
69-
7058
static struct kvm_pmc *intel_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
7159
unsigned int idx, u64 *mask)
7260
{
@@ -718,7 +706,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
718706

719707
for_each_set_bit(bit, (unsigned long *)&pmu->global_ctrl,
720708
X86_PMC_IDX_MAX) {
721-
pmc = intel_pmc_idx_to_pmc(pmu, bit);
709+
pmc = kvm_pmc_idx_to_pmc(pmu, bit);
722710

723711
if (!pmc || !pmc_speculative_in_use(pmc) ||
724712
!pmc_is_globally_enabled(pmc) || !pmc->perf_event)
@@ -735,7 +723,6 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu)
735723
}
736724

737725
struct kvm_pmu_ops intel_pmu_ops __initdata = {
738-
.pmc_idx_to_pmc = intel_pmc_idx_to_pmc,
739726
.rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc,
740727
.msr_idx_to_pmc = intel_msr_idx_to_pmc,
741728
.is_valid_msr = intel_is_valid_msr,

0 commit comments

Comments
 (0)