Skip to content

Commit 751d77f

Browse files
committed
Merge tag 'kvm-x86-pmu-6.5' of https://github.com/kvm-x86/linux into HEAD
KVM x86/pmu changes for 6.5: - Add support for AMD PerfMonV2, with a variety of cleanups and minor fixes included along the way
2 parents 88de4b9 + 94cdeeb commit 751d77f

12 files changed

Lines changed: 260 additions & 118 deletions

File tree

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ BUILD_BUG_ON(1)
1313
* at the call sites.
1414
*/
1515
KVM_X86_PMU_OP(hw_event_available)
16-
KVM_X86_PMU_OP(pmc_is_enabled)
1716
KVM_X86_PMU_OP(pmc_idx_to_pmc)
1817
KVM_X86_PMU_OP(rdpmc_ecx_to_pmc)
1918
KVM_X86_PMU_OP(msr_idx_to_pmc)

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ struct kvm_pmu {
523523
u64 global_status;
524524
u64 counter_bitmask[2];
525525
u64 global_ctrl_mask;
526-
u64 global_ovf_ctrl_mask;
526+
u64 global_status_mask;
527527
u64 reserved_bits;
528528
u64 raw_event_mask;
529529
struct kvm_pmc gp_counters[KVM_INTEL_PMC_MAX_GENERIC];

arch/x86/kvm/cpuid.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,10 @@ void kvm_set_cpu_caps(void)
729729
F(NULL_SEL_CLR_BASE) | F(AUTOIBRS) | 0 /* PrefetchCtlMsr */
730730
);
731731

732+
kvm_cpu_cap_init_kvm_defined(CPUID_8000_0022_EAX,
733+
F(PERFMON_V2)
734+
);
735+
732736
/*
733737
* Synthesize "LFENCE is serializing" into the AMD-defined entry in
734738
* KVM's supported CPUID if the feature is reported as supported by the
@@ -943,7 +947,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
943947
union cpuid10_eax eax;
944948
union cpuid10_edx edx;
945949

946-
if (!static_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
950+
if (!enable_pmu || !static_cpu_has(X86_FEATURE_ARCH_PERFMON)) {
947951
entry->eax = entry->ebx = entry->ecx = entry->edx = 0;
948952
break;
949953
}
@@ -1123,7 +1127,7 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
11231127
entry->edx = 0;
11241128
break;
11251129
case 0x80000000:
1126-
entry->eax = min(entry->eax, 0x80000021);
1130+
entry->eax = min(entry->eax, 0x80000022);
11271131
/*
11281132
* Serializing LFENCE is reported in a multitude of ways, and
11291133
* NullSegClearsBase is not reported in CPUID on Zen2; help
@@ -1228,6 +1232,28 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function)
12281232
entry->ebx = entry->ecx = entry->edx = 0;
12291233
cpuid_entry_override(entry, CPUID_8000_0021_EAX);
12301234
break;
1235+
/* AMD Extended Performance Monitoring and Debug */
1236+
case 0x80000022: {
1237+
union cpuid_0x80000022_ebx ebx;
1238+
1239+
entry->ecx = entry->edx = 0;
1240+
if (!enable_pmu || !kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2)) {
1241+
entry->eax = entry->ebx;
1242+
break;
1243+
}
1244+
1245+
cpuid_entry_override(entry, CPUID_8000_0022_EAX);
1246+
1247+
if (kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
1248+
ebx.split.num_core_pmc = kvm_pmu_cap.num_counters_gp;
1249+
else if (kvm_cpu_cap_has(X86_FEATURE_PERFCTR_CORE))
1250+
ebx.split.num_core_pmc = AMD64_NUM_COUNTERS_CORE;
1251+
else
1252+
ebx.split.num_core_pmc = AMD64_NUM_COUNTERS;
1253+
1254+
entry->ebx = ebx.full;
1255+
break;
1256+
}
12311257
/*Add support for Centaur's CPUID instruction*/
12321258
case 0xC0000000:
12331259
/*Just support up to 0xC0000004 now*/

arch/x86/kvm/pmu.c

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,6 @@ void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops)
9393
#undef __KVM_X86_PMU_OP
9494
}
9595

96-
static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc)
97-
{
98-
return static_call(kvm_x86_pmu_pmc_is_enabled)(pmc);
99-
}
100-
10196
static void kvm_pmi_trigger_fn(struct irq_work *irq_work)
10297
{
10398
struct kvm_pmu *pmu = container_of(irq_work, struct kvm_pmu, irq_work);
@@ -562,6 +557,14 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu)
562557

563558
bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
564559
{
560+
switch (msr) {
561+
case MSR_CORE_PERF_GLOBAL_STATUS:
562+
case MSR_CORE_PERF_GLOBAL_CTRL:
563+
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
564+
return kvm_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu));
565+
default:
566+
break;
567+
}
565568
return static_call(kvm_x86_pmu_msr_idx_to_pmc)(vcpu, msr) ||
566569
static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr);
567570
}
@@ -577,13 +580,86 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr)
577580

578581
int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
579582
{
580-
return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
583+
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
584+
u32 msr = msr_info->index;
585+
586+
switch (msr) {
587+
case MSR_CORE_PERF_GLOBAL_STATUS:
588+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
589+
msr_info->data = pmu->global_status;
590+
break;
591+
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
592+
case MSR_CORE_PERF_GLOBAL_CTRL:
593+
msr_info->data = pmu->global_ctrl;
594+
break;
595+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
596+
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
597+
msr_info->data = 0;
598+
break;
599+
default:
600+
return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info);
601+
}
602+
603+
return 0;
581604
}
582605

583606
int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
584607
{
585-
kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
586-
return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
608+
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
609+
u32 msr = msr_info->index;
610+
u64 data = msr_info->data;
611+
u64 diff;
612+
613+
/*
614+
* Note, AMD ignores writes to reserved bits and read-only PMU MSRs,
615+
* whereas Intel generates #GP on attempts to write reserved/RO MSRs.
616+
*/
617+
switch (msr) {
618+
case MSR_CORE_PERF_GLOBAL_STATUS:
619+
if (!msr_info->host_initiated)
620+
return 1; /* RO MSR */
621+
fallthrough;
622+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
623+
/* Per PPR, Read-only MSR. Writes are ignored. */
624+
if (!msr_info->host_initiated)
625+
break;
626+
627+
if (data & pmu->global_status_mask)
628+
return 1;
629+
630+
pmu->global_status = data;
631+
break;
632+
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
633+
data &= ~pmu->global_ctrl_mask;
634+
fallthrough;
635+
case MSR_CORE_PERF_GLOBAL_CTRL:
636+
if (!kvm_valid_perf_global_ctrl(pmu, data))
637+
return 1;
638+
639+
if (pmu->global_ctrl != data) {
640+
diff = pmu->global_ctrl ^ data;
641+
pmu->global_ctrl = data;
642+
reprogram_counters(pmu, diff);
643+
}
644+
break;
645+
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
646+
/*
647+
* GLOBAL_OVF_CTRL, a.k.a. GLOBAL STATUS_RESET, clears bits in
648+
* GLOBAL_STATUS, and so the set of reserved bits is the same.
649+
*/
650+
if (data & pmu->global_status_mask)
651+
return 1;
652+
fallthrough;
653+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
654+
if (!msr_info->host_initiated)
655+
pmu->global_status &= ~data;
656+
break;
657+
default:
658+
kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index);
659+
return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info);
660+
}
661+
662+
return 0;
587663
}
588664

589665
/* refresh PMU settings. This function generally is called when underlying

arch/x86/kvm/pmu.h

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
struct kvm_pmu_ops {
2222
bool (*hw_event_available)(struct kvm_pmc *pmc);
23-
bool (*pmc_is_enabled)(struct kvm_pmc *pmc);
2423
struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx);
2524
struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu,
2625
unsigned int idx, u64 *mask);
@@ -37,10 +36,25 @@ struct kvm_pmu_ops {
3736

3837
const u64 EVENTSEL_EVENT;
3938
const int MAX_NR_GP_COUNTERS;
39+
const int MIN_NR_GP_COUNTERS;
4040
};
4141

4242
void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops);
4343

44+
static inline bool kvm_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu)
45+
{
46+
/*
47+
* Architecturally, Intel's SDM states that IA32_PERF_GLOBAL_CTRL is
48+
* supported if "CPUID.0AH: EAX[7:0] > 0", i.e. if the PMU version is
49+
* greater than zero. However, KVM only exposes and emulates the MSR
50+
* to/for the guest if the guest PMU supports at least "Architectural
51+
* Performance Monitoring Version 2".
52+
*
53+
* AMD's version of PERF_GLOBAL_CTRL conveniently shows up with v2.
54+
*/
55+
return pmu->version > 1;
56+
}
57+
4458
static inline u64 pmc_bitmask(struct kvm_pmc *pmc)
4559
{
4660
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
@@ -161,6 +175,7 @@ extern struct x86_pmu_capability kvm_pmu_cap;
161175
static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
162176
{
163177
bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
178+
int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
164179

165180
/*
166181
* Hybrid PMUs don't play nice with virtualization without careful
@@ -175,11 +190,15 @@ static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
175190
perf_get_x86_pmu_capability(&kvm_pmu_cap);
176191

177192
/*
178-
* For Intel, only support guest architectural pmu
179-
* on a host with architectural pmu.
193+
* WARN if perf did NOT disable hardware PMU if the number of
194+
* architecturally required GP counters aren't present, i.e. if
195+
* there are a non-zero number of counters, but fewer than what
196+
* is architecturally required.
180197
*/
181-
if ((is_intel && !kvm_pmu_cap.version) ||
182-
!kvm_pmu_cap.num_counters_gp)
198+
if (!kvm_pmu_cap.num_counters_gp ||
199+
WARN_ON_ONCE(kvm_pmu_cap.num_counters_gp < min_nr_gp_ctrs))
200+
enable_pmu = false;
201+
else if (is_intel && !kvm_pmu_cap.version)
183202
enable_pmu = false;
184203
}
185204

@@ -201,6 +220,33 @@ static inline void kvm_pmu_request_counter_reprogram(struct kvm_pmc *pmc)
201220
kvm_make_request(KVM_REQ_PMU, pmc->vcpu);
202221
}
203222

223+
static inline void reprogram_counters(struct kvm_pmu *pmu, u64 diff)
224+
{
225+
int bit;
226+
227+
if (!diff)
228+
return;
229+
230+
for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX)
231+
set_bit(bit, pmu->reprogram_pmi);
232+
kvm_make_request(KVM_REQ_PMU, pmu_to_vcpu(pmu));
233+
}
234+
235+
/*
236+
* Check if a PMC is enabled by comparing it against global_ctrl bits.
237+
*
238+
* If the vPMU doesn't have global_ctrl MSR, all vPMCs are enabled.
239+
*/
240+
static inline bool pmc_is_globally_enabled(struct kvm_pmc *pmc)
241+
{
242+
struct kvm_pmu *pmu = pmc_to_pmu(pmc);
243+
244+
if (!kvm_pmu_has_perf_global_ctrl(pmu))
245+
return true;
246+
247+
return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl);
248+
}
249+
204250
void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu);
205251
void kvm_pmu_handle_event(struct kvm_vcpu *vcpu);
206252
int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data);

arch/x86/kvm/reverse_cpuid.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum kvm_only_cpuid_leafs {
1515
CPUID_12_EAX = NCAPINTS,
1616
CPUID_7_1_EDX,
1717
CPUID_8000_0007_EDX,
18+
CPUID_8000_0022_EAX,
1819
NR_KVM_CPU_CAPS,
1920

2021
NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS,
@@ -47,6 +48,9 @@ enum kvm_only_cpuid_leafs {
4748
/* CPUID level 0x80000007 (EDX). */
4849
#define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8)
4950

51+
/* CPUID level 0x80000022 (EAX) */
52+
#define KVM_X86_FEATURE_PERFMON_V2 KVM_X86_FEATURE(CPUID_8000_0022_EAX, 0)
53+
5054
struct cpuid_reg {
5155
u32 function;
5256
u32 index;
@@ -74,6 +78,7 @@ static const struct cpuid_reg reverse_cpuid[] = {
7478
[CPUID_7_1_EDX] = { 7, 1, CPUID_EDX},
7579
[CPUID_8000_0007_EDX] = {0x80000007, 0, CPUID_EDX},
7680
[CPUID_8000_0021_EAX] = {0x80000021, 0, CPUID_EAX},
81+
[CPUID_8000_0022_EAX] = {0x80000022, 0, CPUID_EAX},
7782
};
7883

7984
/*
@@ -108,6 +113,8 @@ static __always_inline u32 __feature_translate(int x86_feature)
108113
return KVM_X86_FEATURE_SGX_EDECCSSA;
109114
else if (x86_feature == X86_FEATURE_CONSTANT_TSC)
110115
return KVM_X86_FEATURE_CONSTANT_TSC;
116+
else if (x86_feature == X86_FEATURE_PERFMON_V2)
117+
return KVM_X86_FEATURE_PERFMON_V2;
111118

112119
return x86_feature;
113120
}

0 commit comments

Comments
 (0)