KVM: selftests: Test all immutable non-format bits in PERF_CAPABILITIES
[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 <linux/bitmap.h>
18
19 #include "kvm_util.h"
20 #include "vmx.h"
21
22 #define PMU_CAP_LBR_FMT         0x3f
23
24 union perf_capabilities {
25         struct {
26                 u64     lbr_format:6;
27                 u64     pebs_trap:1;
28                 u64     pebs_arch_reg:1;
29                 u64     pebs_format:4;
30                 u64     smm_freeze:1;
31                 u64     full_width_write:1;
32                 u64 pebs_baseline:1;
33                 u64     perf_metrics:1;
34                 u64     pebs_output_pt_available:1;
35                 u64     anythread_deprecated:1;
36         };
37         u64     capabilities;
38 };
39
40 /*
41  * The LBR format and most PEBS features are immutable, all other features are
42  * fungible (if supported by the host and KVM).
43  */
44 static const union perf_capabilities immutable_caps = {
45         .lbr_format = -1,
46         .pebs_trap  = 1,
47         .pebs_arch_reg = 1,
48         .pebs_format = -1,
49         .pebs_baseline = 1,
50 };
51
52 static const union perf_capabilities format_caps = {
53         .lbr_format = -1,
54         .pebs_format = -1,
55 };
56
57 static void guest_code(void)
58 {
59         wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
60 }
61
62 /*
63  * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features
64  * enabled, as well as '0' (to disable all features).
65  */
66 static void test_basic_perf_capabilities(union perf_capabilities host_cap)
67 {
68         struct kvm_vcpu *vcpu;
69         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
70
71         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
72         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
73
74         kvm_vm_free(vm);
75 }
76
77 static void test_fungible_perf_capabilities(union perf_capabilities host_cap)
78 {
79         const uint64_t fungible_caps = host_cap.capabilities & ~immutable_caps.capabilities;
80
81         struct kvm_vcpu *vcpu;
82         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, guest_code);
83         int bit;
84
85         for_each_set_bit(bit, &fungible_caps, 64) {
86                 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, BIT_ULL(bit));
87                 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
88                              host_cap.capabilities & ~BIT_ULL(bit));
89         }
90         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
91
92         /* check whatever we write with KVM_SET_MSR is _not_ modified */
93         vcpu_run(vcpu);
94         ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), host_cap.capabilities);
95
96         kvm_vm_free(vm);
97 }
98
99 /*
100  * Verify KVM rejects attempts to set unsupported and/or immutable features in
101  * PERF_CAPABILITIES.  Note, LBR format and PEBS format need to be validated
102  * separately as they are multi-bit values, e.g. toggling or setting a single
103  * bit can generate a false positive without dedicated safeguards.
104  */
105 static void test_immutable_perf_capabilities(union perf_capabilities host_cap)
106 {
107         const uint64_t reserved_caps = (~host_cap.capabilities |
108                                         immutable_caps.capabilities) &
109                                        ~format_caps.capabilities;
110
111         struct kvm_vcpu *vcpu;
112         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
113         uint64_t val;
114         int r, bit;
115
116         for_each_set_bit(bit, &reserved_caps, 64) {
117                 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
118                                   host_cap.capabilities ^ BIT_ULL(bit));
119                 TEST_ASSERT(!r, "%s immutable feature 0x%llx (bit %d) didn't fail",
120                             host_cap.capabilities & BIT_ULL(bit) ? "Setting" : "Clearing",
121                             BIT_ULL(bit), bit);
122         }
123
124         /*
125          * KVM only supports the host's native LBR format, as well as '0' (to
126          * disable LBR support).  Verify KVM rejects all other LBR formats.
127          */
128         for (val = 1; val <= PMU_CAP_LBR_FMT; val++) {
129                 if (val == (host_cap.capabilities & PMU_CAP_LBR_FMT))
130                         continue;
131
132                 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val);
133                 TEST_ASSERT(!r, "Bad LBR FMT = 0x%lx didn't fail", val);
134         }
135
136         kvm_vm_free(vm);
137 }
138
139 int main(int argc, char *argv[])
140 {
141         union perf_capabilities host_cap;
142
143         TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
144
145         TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
146         TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
147
148         host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
149
150         TEST_ASSERT(host_cap.full_width_write,
151                     "Full-width writes should always be supported");
152
153         test_basic_perf_capabilities(host_cap);
154         test_fungible_perf_capabilities(host_cap);
155         test_immutable_perf_capabilities(host_cap);
156
157         printf("Completed perf capability tests.\n");
158 }