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