KVM: selftests: Assert that full-width PMC writes are supported if PDCM=1
[linux-block.git] / tools / testing / selftests / kvm / x86_64 / vmx_pmu_caps_test.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test for VMX-pmu perf capability msr
4  *
5  * Copyright (C) 2021 Intel Corporation
6  *
7  * Test to check the effect of various CPUID settings on
8  * MSR_IA32_PERF_CAPABILITIES MSR, and check that what
9  * we write with KVM_SET_MSR is _not_ modified by the guest
10  * and check it can be retrieved with KVM_GET_MSR, also test
11  * the invalid LBR formats are rejected.
12  */
13
14 #define _GNU_SOURCE /* for program_invocation_short_name */
15 #include <sys/ioctl.h>
16
17 #include "kvm_util.h"
18 #include "vmx.h"
19
20 #define PMU_CAP_FW_WRITES       (1ULL << 13)
21 #define PMU_CAP_LBR_FMT         0x3f
22
23 union perf_capabilities {
24         struct {
25                 u64     lbr_format:6;
26                 u64     pebs_trap:1;
27                 u64     pebs_arch_reg:1;
28                 u64     pebs_format:4;
29                 u64     smm_freeze:1;
30                 u64     full_width_write:1;
31                 u64 pebs_baseline:1;
32                 u64     perf_metrics:1;
33                 u64     pebs_output_pt_available:1;
34                 u64     anythread_deprecated:1;
35         };
36         u64     capabilities;
37 };
38
39 static void guest_code(void)
40 {
41         wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
42 }
43
44 /*
45  * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features
46  * enabled, as well as '0' (to disable all features).
47  */
48 static void test_basic_perf_capabilities(union perf_capabilities host_cap)
49 {
50         struct kvm_vcpu *vcpu;
51         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
52
53         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
54         ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), 0);
55
56         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
57         ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), host_cap.capabilities);
58
59         kvm_vm_free(vm);
60 }
61
62 static void test_fungible_perf_capabilities(union perf_capabilities host_cap)
63 {
64         struct kvm_vcpu *vcpu;
65         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, guest_code);
66
67         /* testcase 1, set capabilities when we have PDCM bit */
68         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
69
70         /* check capabilities can be retrieved with KVM_GET_MSR */
71         ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
72
73         /* check whatever we write with KVM_SET_MSR is _not_ modified */
74         vcpu_run(vcpu);
75         ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
76
77         kvm_vm_free(vm);
78 }
79
80 static void test_immutable_perf_capabilities(union perf_capabilities host_cap)
81 {
82         struct kvm_vcpu *vcpu;
83         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
84         uint64_t val;
85         int ret;
86
87         /*
88          * KVM only supports the host's native LBR format, as well as '0' (to
89          * disable LBR support).  Verify KVM rejects all other LBR formats.
90          */
91         for (val = 1; val <= PMU_CAP_LBR_FMT; val++) {
92                 if (val == (host_cap.capabilities & PMU_CAP_LBR_FMT))
93                         continue;
94
95                 ret = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val);
96                 TEST_ASSERT(!ret, "Bad LBR FMT = 0x%lx didn't fail", val);
97         }
98         kvm_vm_free(vm);
99 }
100
101 int main(int argc, char *argv[])
102 {
103         union perf_capabilities host_cap;
104
105         TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
106
107         TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
108         TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
109
110         host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
111         host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT);
112
113         TEST_ASSERT(host_cap.full_width_write,
114                     "Full-width writes should always be supported");
115
116         test_basic_perf_capabilities(host_cap);
117         test_fungible_perf_capabilities(host_cap);
118         test_immutable_perf_capabilities(host_cap);
119
120         printf("Completed perf capability tests.\n");
121 }