Skip to content

Commit 7137cf7

Browse files
Jinrong Liangsean-jc
authored andcommitted
KVM: selftests: Test consistency of CPUID with num of gp counters
Add a test to verify that KVM correctly emulates MSR-based accesses to general purpose counters based on guest CPUID, e.g. that accesses to non-existent counters #GP and accesses to existent counters succeed. Note, for compatibility reasons, KVM does not emulate #GP when MSR_P6_PERFCTR[0|1] is not present (writes should be dropped). Co-developed-by: Like Xu <[email protected]> Signed-off-by: Like Xu <[email protected]> Signed-off-by: Jinrong Liang <[email protected]> Co-developed-by: Sean Christopherson <[email protected]> Tested-by: Dapeng Mi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 3e26b82 commit 7137cf7

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

tools/testing/selftests/kvm/x86_64/pmu_counters_test.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,103 @@ static void test_arch_events(uint8_t pmu_version, uint64_t perf_capabilities,
270270
kvm_vm_free(vm);
271271
}
272272

273+
/*
274+
* Limit testing to MSRs that are actually defined by Intel (in the SDM). MSRs
275+
* that aren't defined counter MSRs *probably* don't exist, but there's no
276+
* guarantee that currently undefined MSR indices won't be used for something
277+
* other than PMCs in the future.
278+
*/
279+
#define MAX_NR_GP_COUNTERS 8
280+
#define MAX_NR_FIXED_COUNTERS 3
281+
282+
#define GUEST_ASSERT_PMC_MSR_ACCESS(insn, msr, expect_gp, vector) \
283+
__GUEST_ASSERT(expect_gp ? vector == GP_VECTOR : !vector, \
284+
"Expected %s on " #insn "(0x%x), got vector %u", \
285+
expect_gp ? "#GP" : "no fault", msr, vector) \
286+
287+
#define GUEST_ASSERT_PMC_VALUE(insn, msr, val, expected) \
288+
__GUEST_ASSERT(val == expected_val, \
289+
"Expected " #insn "(0x%x) to yield 0x%lx, got 0x%lx", \
290+
msr, expected_val, val);
291+
292+
static void guest_rd_wr_counters(uint32_t base_msr, uint8_t nr_possible_counters,
293+
uint8_t nr_counters)
294+
{
295+
uint8_t i;
296+
297+
for (i = 0; i < nr_possible_counters; i++) {
298+
/*
299+
* TODO: Test a value that validates full-width writes and the
300+
* width of the counters.
301+
*/
302+
const uint64_t test_val = 0xffff;
303+
const uint32_t msr = base_msr + i;
304+
const bool expect_success = i < nr_counters;
305+
306+
/*
307+
* KVM drops writes to MSR_P6_PERFCTR[0|1] if the counters are
308+
* unsupported, i.e. doesn't #GP and reads back '0'.
309+
*/
310+
const uint64_t expected_val = expect_success ? test_val : 0;
311+
const bool expect_gp = !expect_success && msr != MSR_P6_PERFCTR0 &&
312+
msr != MSR_P6_PERFCTR1;
313+
uint8_t vector;
314+
uint64_t val;
315+
316+
vector = wrmsr_safe(msr, test_val);
317+
GUEST_ASSERT_PMC_MSR_ACCESS(WRMSR, msr, expect_gp, vector);
318+
319+
vector = rdmsr_safe(msr, &val);
320+
GUEST_ASSERT_PMC_MSR_ACCESS(RDMSR, msr, expect_gp, vector);
321+
322+
/* On #GP, the result of RDMSR is undefined. */
323+
if (!expect_gp)
324+
GUEST_ASSERT_PMC_VALUE(RDMSR, msr, val, expected_val);
325+
326+
vector = wrmsr_safe(msr, 0);
327+
GUEST_ASSERT_PMC_MSR_ACCESS(WRMSR, msr, expect_gp, vector);
328+
}
329+
GUEST_DONE();
330+
}
331+
332+
static void guest_test_gp_counters(void)
333+
{
334+
uint8_t nr_gp_counters = 0;
335+
uint32_t base_msr;
336+
337+
if (guest_get_pmu_version())
338+
nr_gp_counters = this_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS);
339+
340+
if (this_cpu_has(X86_FEATURE_PDCM) &&
341+
rdmsr(MSR_IA32_PERF_CAPABILITIES) & PMU_CAP_FW_WRITES)
342+
base_msr = MSR_IA32_PMC0;
343+
else
344+
base_msr = MSR_IA32_PERFCTR0;
345+
346+
guest_rd_wr_counters(base_msr, MAX_NR_GP_COUNTERS, nr_gp_counters);
347+
}
348+
349+
static void test_gp_counters(uint8_t pmu_version, uint64_t perf_capabilities,
350+
uint8_t nr_gp_counters)
351+
{
352+
struct kvm_vcpu *vcpu;
353+
struct kvm_vm *vm;
354+
355+
vm = pmu_vm_create_with_one_vcpu(&vcpu, guest_test_gp_counters,
356+
pmu_version, perf_capabilities);
357+
358+
vcpu_set_cpuid_property(vcpu, X86_PROPERTY_PMU_NR_GP_COUNTERS,
359+
nr_gp_counters);
360+
361+
run_vcpu(vcpu);
362+
363+
kvm_vm_free(vm);
364+
}
365+
273366
static void test_intel_counters(void)
274367
{
275368
uint8_t nr_arch_events = kvm_cpu_property(X86_PROPERTY_PMU_EBX_BIT_VECTOR_LENGTH);
369+
uint8_t nr_gp_counters = kvm_cpu_property(X86_PROPERTY_PMU_NR_GP_COUNTERS);
276370
uint8_t pmu_version = kvm_cpu_property(X86_PROPERTY_PMU_VERSION);
277371
unsigned int i;
278372
uint8_t v, j;
@@ -336,6 +430,11 @@ static void test_intel_counters(void)
336430
for (k = 0; k < nr_arch_events; k++)
337431
test_arch_events(v, perf_caps[i], j, BIT(k));
338432
}
433+
434+
pr_info("Testing GP counters, PMU version %u, perf_caps = %lx\n",
435+
v, perf_caps[i]);
436+
for (j = 0; j <= nr_gp_counters; j++)
437+
test_gp_counters(v, perf_caps[i], j);
339438
}
340439
}
341440
}

0 commit comments

Comments
 (0)