Skip to content

Commit 6a08083

Browse files
Like Xusean-jc
authored andcommitted
KVM: x86/pmu: Disable vPMU if the minimum num of counters isn't met
Disable PMU support when running on AMD and perf reports fewer than four general purpose counters. All AMD PMUs must define at least four counters due to AMD's legacy architecture hardcoding the number of counters without providing a way to enumerate the number of counters to software, e.g. from AMD's APM: The legacy architecture defines four performance counters (PerfCtrn) and corresponding event-select registers (PerfEvtSeln). Virtualizing fewer than four counters can lead to guest instability as software expects four counters to be available. Rather than bleed AMD details into the common code, just define a const unsigned int and provide a convenient location to document why Intel and AMD have different mins (in particular, AMD's lack of any way to enumerate less than four counters to the guest). Keep the minimum number of counters at Intel at one, even though old P6 and Core Solo/Duo processor effectively require a minimum of two counters. KVM can, and more importantly has up until this point, supported a vPMU so long as the CPU has at least one counter. Perf's support for P6/Core CPUs does require two counters, but perf will happily chug along with a single counter when running on a modern CPU. Cc: Jim Mattson <jmattson@google.com> Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Like Xu <likexu@tencent.com> [sean: set Intel min to '1', not '2'] Link: https://lore.kernel.org/r/20230603011058.1038821-8-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 6593039 commit 6a08083

File tree

3 files changed

+12
-4
lines changed

3 files changed

+12
-4
lines changed

arch/x86/kvm/pmu.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct kvm_pmu_ops {
3636

3737
const u64 EVENTSEL_EVENT;
3838
const int MAX_NR_GP_COUNTERS;
39+
const int MIN_NR_GP_COUNTERS;
3940
};
4041

4142
void kvm_pmu_ops_update(const struct kvm_pmu_ops *pmu_ops);
@@ -174,6 +175,7 @@ extern struct x86_pmu_capability kvm_pmu_cap;
174175
static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
175176
{
176177
bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL;
178+
int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS;
177179

178180
/*
179181
* Hybrid PMUs don't play nice with virtualization without careful
@@ -188,11 +190,15 @@ static inline void kvm_init_pmu_capability(const struct kvm_pmu_ops *pmu_ops)
188190
perf_get_x86_pmu_capability(&kvm_pmu_cap);
189191

190192
/*
191-
* For Intel, only support guest architectural pmu
192-
* 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.
193197
*/
194-
if ((is_intel && !kvm_pmu_cap.version) ||
195-
!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)
196202
enable_pmu = false;
197203
}
198204

arch/x86/kvm/svm/pmu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,4 +224,5 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = {
224224
.reset = amd_pmu_reset,
225225
.EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT,
226226
.MAX_NR_GP_COUNTERS = KVM_AMD_PMC_MAX_GENERIC,
227+
.MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS,
227228
};

arch/x86/kvm/vmx/pmu_intel.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,4 +777,5 @@ struct kvm_pmu_ops intel_pmu_ops __initdata = {
777777
.cleanup = intel_pmu_cleanup,
778778
.EVENTSEL_EVENT = ARCH_PERFMON_EVENTSEL_EVENT,
779779
.MAX_NR_GP_COUNTERS = KVM_INTEL_PMC_MAX_GENERIC,
780+
.MIN_NR_GP_COUNTERS = 1,
780781
};

0 commit comments

Comments
 (0)