File Index
Files and directories
Sign in
FILE

vmx_pmu_caps_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/x86/vmx_pmu_caps_test.c 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#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
 21static 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 */
 41static 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
 50static const union perf_capabilities format_caps = {
 51	.lbr_format = -1,
 52	.pebs_format = -1,
 53};
 54
 55static 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
 64static 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
 77KVM_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 */
 84KVM_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 */
124KVM_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
130KVM_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 */
149KVM_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 */
195KVM_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
211KVM_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
234int 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}
~/ Read-only file preview.