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 #include <sys/ioctl.h>
14
15 #include <linux/bitmap.h>
16
17 #include "kvm_test_harness.h"
18 #include "kvm_util.h"
19 #include "vmx.h"
20
21 static union perf_capabilities {
22 struct {
23 u64 lbr_format:6;
24 u64 pebs_trap:1;
25 u64 pebs_arch_reg:1;
26 u64 pebs_format:4;
27 u64 smm_freeze:1;
28 u64 full_width_write:1;
29 u64 pebs_baseline:1;
30 u64 perf_metrics:1;
31 u64 pebs_output_pt_available:1;
32 u64 pebs_timing_info:1;
33 };
34 u64 capabilities;
35 } host_cap;
36
37 /*
38 * The LBR format and most PEBS features are immutable, all other features are
39 * fungible (if supported by the host and KVM).
40 */
41 static const union perf_capabilities immutable_caps = {
42 .lbr_format = -1,
43 .pebs_trap = 1,
44 .pebs_arch_reg = 1,
45 .pebs_format = -1,
46 .pebs_baseline = 1,
47 .pebs_timing_info = 1,
48 };
49
50 static const union perf_capabilities format_caps = {
51 .lbr_format = -1,
52 .pebs_format = -1,
53 };
54
guest_test_perf_capabilities_gp(uint64_t val)55 static void guest_test_perf_capabilities_gp(uint64_t val)
56 {
57 uint8_t vector = wrmsr_safe(MSR_IA32_PERF_CAPABILITIES, val);
58
59 __GUEST_ASSERT(vector == GP_VECTOR,
60 "Expected #GP for value '0x%lx', got %s",
61 val, ex_str(vector));
62 }
63
guest_code(uint64_t current_val)64 static void guest_code(uint64_t current_val)
65 {
66 int i;
67
68 guest_test_perf_capabilities_gp(current_val);
69 guest_test_perf_capabilities_gp(0);
70
71 for (i = 0; i < 64; i++)
72 guest_test_perf_capabilities_gp(current_val ^ BIT_ULL(i));
73
74 GUEST_DONE();
75 }
76
77 KVM_ONE_VCPU_TEST_SUITE(vmx_pmu_caps);
78
79 /*
80 * Verify that guest WRMSRs to PERF_CAPABILITIES #GP regardless of the value
81 * written, that the guest always sees the userspace controlled value, and that
82 * PERF_CAPABILITIES is immutable after KVM_RUN.
83 */
KVM_ONE_VCPU_TEST(vmx_pmu_caps,guest_wrmsr_perf_capabilities,guest_code)84 KVM_ONE_VCPU_TEST(vmx_pmu_caps, guest_wrmsr_perf_capabilities, guest_code)
85 {
86 struct ucall uc;
87 int r, i;
88
89 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
90
91 vcpu_args_set(vcpu, 1, host_cap.capabilities);
92 vcpu_run(vcpu);
93
94 switch (get_ucall(vcpu, &uc)) {
95 case UCALL_ABORT:
96 REPORT_GUEST_ASSERT(uc);
97 break;
98 case UCALL_DONE:
99 break;
100 default:
101 TEST_FAIL("Unexpected ucall: %lu", uc.cmd);
102 }
103
104 TEST_ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES),
105 host_cap.capabilities);
106
107 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
108
109 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
110 TEST_ASSERT(!r, "Post-KVM_RUN write '0' didn't fail");
111
112 for (i = 0; i < 64; i++) {
113 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
114 host_cap.capabilities ^ BIT_ULL(i));
115 TEST_ASSERT(!r, "Post-KVM_RUN write '0x%llx'didn't fail",
116 host_cap.capabilities ^ BIT_ULL(i));
117 }
118 }
119
120 /*
121 * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features
122 * enabled, as well as '0' (to disable all features).
123 */
KVM_ONE_VCPU_TEST(vmx_pmu_caps,basic_perf_capabilities,guest_code)124 KVM_ONE_VCPU_TEST(vmx_pmu_caps, basic_perf_capabilities, guest_code)
125 {
126 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
127 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
128 }
129
KVM_ONE_VCPU_TEST(vmx_pmu_caps,fungible_perf_capabilities,guest_code)130 KVM_ONE_VCPU_TEST(vmx_pmu_caps, fungible_perf_capabilities, guest_code)
131 {
132 const uint64_t fungible_caps = host_cap.capabilities & ~immutable_caps.capabilities;
133 int bit;
134
135 for_each_set_bit(bit, &fungible_caps, 64) {
136 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, BIT_ULL(bit));
137 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
138 host_cap.capabilities & ~BIT_ULL(bit));
139 }
140 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
141 }
142
143 /*
144 * Verify KVM rejects attempts to set unsupported and/or immutable features in
145 * PERF_CAPABILITIES. Note, LBR format and PEBS format need to be validated
146 * separately as they are multi-bit values, e.g. toggling or setting a single
147 * bit can generate a false positive without dedicated safeguards.
148 */
KVM_ONE_VCPU_TEST(vmx_pmu_caps,immutable_perf_capabilities,guest_code)149 KVM_ONE_VCPU_TEST(vmx_pmu_caps, immutable_perf_capabilities, guest_code)
150 {
151 const uint64_t reserved_caps = (~host_cap.capabilities |
152 immutable_caps.capabilities) &
153 ~format_caps.capabilities;
154 union perf_capabilities val = host_cap;
155 int r, bit;
156
157 for_each_set_bit(bit, &reserved_caps, 64) {
158 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES,
159 host_cap.capabilities ^ BIT_ULL(bit));
160 TEST_ASSERT(!r, "%s immutable feature 0x%llx (bit %d) didn't fail",
161 host_cap.capabilities & BIT_ULL(bit) ? "Setting" : "Clearing",
162 BIT_ULL(bit), bit);
163 }
164
165 /*
166 * KVM only supports the host's native LBR format, as well as '0' (to
167 * disable LBR support). Verify KVM rejects all other LBR formats.
168 */
169 for (val.lbr_format = 1; val.lbr_format; val.lbr_format++) {
170 if (val.lbr_format == host_cap.lbr_format)
171 continue;
172
173 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val.capabilities);
174 TEST_ASSERT(!r, "Bad LBR FMT = 0x%x didn't fail, host = 0x%x",
175 val.lbr_format, host_cap.lbr_format);
176 }
177
178 /* Ditto for the PEBS format. */
179 for (val.pebs_format = 1; val.pebs_format; val.pebs_format++) {
180 if (val.pebs_format == host_cap.pebs_format)
181 continue;
182
183 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val.capabilities);
184 TEST_ASSERT(!r, "Bad PEBS FMT = 0x%x didn't fail, host = 0x%x",
185 val.pebs_format, host_cap.pebs_format);
186 }
187 }
188
189 /*
190 * Test that LBR MSRs are writable when LBRs are enabled, and then verify that
191 * disabling the vPMU via CPUID also disables LBR support. Set bits 2:0 of
192 * LBR_TOS as those bits are writable across all uarch implementations (arch
193 * LBRs will need to poke a different MSR).
194 */
KVM_ONE_VCPU_TEST(vmx_pmu_caps,lbr_perf_capabilities,guest_code)195 KVM_ONE_VCPU_TEST(vmx_pmu_caps, lbr_perf_capabilities, guest_code)
196 {
197 int r;
198
199 if (!host_cap.lbr_format)
200 return;
201
202 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
203 vcpu_set_msr(vcpu, MSR_LBR_TOS, 7);
204
205 vcpu_clear_cpuid_entry(vcpu, X86_PROPERTY_PMU_VERSION.function);
206
207 r = _vcpu_set_msr(vcpu, MSR_LBR_TOS, 7);
208 TEST_ASSERT(!r, "Writing LBR_TOS should fail after disabling vPMU");
209 }
210
KVM_ONE_VCPU_TEST(vmx_pmu_caps,perf_capabilities_unsupported,guest_code)211 KVM_ONE_VCPU_TEST(vmx_pmu_caps, perf_capabilities_unsupported, guest_code)
212 {
213 uint64_t val;
214 int i, r;
215
216 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
217 val = vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES);
218 TEST_ASSERT_EQ(val, host_cap.capabilities);
219
220 vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_PDCM);
221
222 val = vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES);
223 TEST_ASSERT_EQ(val, 0);
224
225 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
226
227 for (i = 0; i < 64; i++) {
228 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, BIT_ULL(i));
229 TEST_ASSERT(!r, "Setting PERF_CAPABILITIES bit %d (= 0x%llx) should fail without PDCM",
230 i, BIT_ULL(i));
231 }
232 }
233
main(int argc,char * argv[])234 int main(int argc, char *argv[])
235 {
236 TEST_REQUIRE(kvm_is_pmu_enabled());
237 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
238
239 TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
240 TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
241
242 host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
243
244 TEST_ASSERT(host_cap.full_width_write,
245 "Full-width writes should always be supported");
246
247 return test_harness_run(argc, argv);
248 }
249