> On 9/1/2023 3:28 PM, Xiong Zhang wrote: > > vPMU v5 adds fixed counter enumeration, which allows user space to > > specify which fixed counters are supported through emulated > > CPUID.0Ah.ECX. > > > > This commit adds a test case which specify the max fixed counter > > supported only, so guest can access the max fixed counter only, #GP > > exception will be happen once guest access other fixed counters. > > > > Signed-off-by: Xiong Zhang <xiong.y.zhang@xxxxxxxxx> > > --- > > .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 84 +++++++++++++++++++ > > 1 file changed, 84 insertions(+) > > > > diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c > > b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c > > index ebbcb0a3f743..e37dc39164fe 100644 > > --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c > > +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c > > > since we added new test cases in this file, this file is not just test > 'perf_capablities' anymore, we may change the file name vmx_pmu_caps_test.c > to a more generic name like "vmx_pmu_test.c" or something else. Yes, I will move it into vmx_counters_test.c after this serial https://lore.kernel.org/lkml/ZN6sopXa8aw8DG3w@xxxxxxxxxx/T/ is merged. > > > @@ -18,6 +18,8 @@ > > #include "kvm_util.h" > > #include "vmx.h" > > > > +uint8_t fixed_counter_num; > > + > > union perf_capabilities { > > struct { > > u64 lbr_format:6; > > @@ -233,6 +235,86 @@ static void test_lbr_perf_capabilities(union > perf_capabilities host_cap) > > kvm_vm_free(vm); > > } > > > > +static void guest_v5_code(void) > > +{ > > + uint8_t vector, i; > > + uint64_t val; > > + > > + for (i = 0; i < fixed_counter_num; i++) { > > + vector = rdmsr_safe(MSR_CORE_PERF_FIXED_CTR0 + i, &val); > > + > > + /* > > + * Only the max fixed counter is supported, #GP will be > generated > > + * when guest access other fixed counters. > > + */ > > + if (i == fixed_counter_num - 1) > > + __GUEST_ASSERT(vector != GP_VECTOR, > > + "Max Fixed counter is accessible, but get > #GP"); > > + else > > + __GUEST_ASSERT(vector == GP_VECTOR, > > + "Fixed counter isn't accessible, but access is > ok"); > > + } > > + > > + GUEST_DONE(); > > +} > > + > > +#define PMU_NR_FIXED_COUNTERS_MASK 0x1f > > + > > +static void test_fixed_counter_enumeration(void) > > +{ > > + struct kvm_vcpu *vcpu; > > + struct kvm_vm *vm; > > + int r; > > + struct kvm_cpuid_entry2 *ent; > > + struct ucall uc; > > + uint32_t fixed_counter_bit_mask; > > + > > + if (kvm_cpu_property(X86_PROPERTY_PMU_VERSION) != 5) > > + return; > > > We'd better check if the version is less than 5 here, since we might have higher > version than 5 in the future. Sure, change it in next version. > > > > + > > + vm = vm_create_with_one_vcpu(&vcpu, guest_v5_code); > > + vm_init_descriptor_tables(vm); > > + vcpu_init_descriptor_tables(vcpu); > > + > > + ent = vcpu_get_cpuid_entry(vcpu, 0xa); > > + fixed_counter_num = ent->edx & PMU_NR_FIXED_COUNTERS_MASK; > > + TEST_ASSERT(fixed_counter_num > 0, "fixed counter isn't supported"); > > + fixed_counter_bit_mask = (1ul << fixed_counter_num) - 1; > > + TEST_ASSERT(ent->ecx == fixed_counter_bit_mask, > > + "cpuid.0xa.ecx != %x", fixed_counter_bit_mask); > > + > > + /* Fixed counter 0 isn't in ecx, but in edx, set_cpuid should be error. */ > > + ent->ecx &= ~0x1; > > + r = __vcpu_set_cpuid(vcpu); > > + TEST_ASSERT(r, "Setting in-consistency cpuid.0xa.ecx and edx success"); > > + > > + if (fixed_counter_num == 1) { > > + kvm_vm_free(vm); > > + return; > > + } > > + > > + /* Support the max Fixed Counter only */ > > + ent->ecx = 1UL << (fixed_counter_num - 1); > > + ent->edx &= ~(u32)PMU_NR_FIXED_COUNTERS_MASK; > > + > > + r = __vcpu_set_cpuid(vcpu); > > + TEST_ASSERT(!r, "Setting modified cpuid.0xa.ecx and edx failed"); > > + > > + vcpu_run(vcpu); > > + > > + switch (get_ucall(vcpu, &uc)) { > > + case UCALL_ABORT: > > + REPORT_GUEST_ASSERT(uc); > > + break; > > + case UCALL_DONE: > > + break; > > + default: > > + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); > > + } > > + > > + kvm_vm_free(vm); > > +} > > + > > int main(int argc, char *argv[]) > > { > > union perf_capabilities host_cap; > > @@ -253,4 +335,6 @@ int main(int argc, char *argv[]) > > test_immutable_perf_capabilities(host_cap); > > test_guest_wrmsr_perf_capabilities(host_cap); > > test_lbr_perf_capabilities(host_cap); > > + > > + test_fixed_counter_enumeration(); > > }