Message ID | 20230901072809.640175-10-xiong.y.zhang@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Upgrade vPMU version to 5 | expand |
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@intel.com> > --- > .../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. > @@ -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. > + > + 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(); > }
> 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@intel.com> > > --- > > .../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@google.com/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(); > > }
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 @@ -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; + + 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(); }
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@intel.com> --- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+)