xref: /linux/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c (revision 1f2bbbbbda57f1939d757f5021ec0e3ea782ccf6)
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