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
CommitLineData
f88d4f2f
LX
1// SPDX-License-Identifier: GPL-2.0
2/*
825be3b5 3 * Test for VMX-pmu perf capability msr
f88d4f2f
LX
4 *
5 * Copyright (C) 2021 Intel Corporation
6 *
825be3b5
YW
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.
f88d4f2f
LX
12 */
13
14#define _GNU_SOURCE /* for program_invocation_short_name */
15#include <sys/ioctl.h>
16
37f4e79c
SC
17#include <linux/bitmap.h>
18
f88d4f2f
LX
19#include "kvm_util.h"
20#include "vmx.h"
21
f88d4f2f
LX
22#define PMU_CAP_LBR_FMT 0x3f
23
f88d4f2f
LX
24union 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
37f4e79c
SC
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 */
44static 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
a2a34d14
SC
52static const union perf_capabilities format_caps = {
53 .lbr_format = -1,
54 .pebs_format = -1,
55};
56
f88d4f2f
LX
57static void guest_code(void)
58{
59 wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
60}
61
710fb612
SC
62/*
63 * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features
64 * enabled, as well as '0' (to disable all features).
65 */
66static 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);
710fb612 72 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
710fb612
SC
73
74 kvm_vm_free(vm);
75}
76
e4d86fb9 77static void test_fungible_perf_capabilities(union perf_capabilities host_cap)
f88d4f2f 78{
37f4e79c
SC
79 const uint64_t fungible_caps = host_cap.capabilities & ~immutable_caps.capabilities;
80
d8b5b5d1 81 struct kvm_vcpu *vcpu;
e4d86fb9 82 struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, guest_code);
37f4e79c 83 int bit;
f88d4f2f 84
37f4e79c
SC
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);
f88d4f2f 91
f88d4f2f 92 /* check whatever we write with KVM_SET_MSR is _not_ modified */
768e9a61 93 vcpu_run(vcpu);
37f4e79c 94 ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), host_cap.capabilities);
f88d4f2f 95
e4d86fb9
SC
96 kvm_vm_free(vm);
97}
98
a2a34d14
SC
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 */
e4d86fb9
SC
105static void test_immutable_perf_capabilities(union perf_capabilities host_cap)
106{
a2a34d14
SC
107 const uint64_t reserved_caps = (~host_cap.capabilities |
108 immutable_caps.capabilities) &
109 ~format_caps.capabilities;
110
e4d86fb9
SC
111 struct kvm_vcpu *vcpu;
112 struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
113 uint64_t val;
a2a34d14
SC
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 }
e4d86fb9 123
9d27d461 124 /*
e4d86fb9
SC
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.
9d27d461
SC
127 */
128 for (val = 1; val <= PMU_CAP_LBR_FMT; val++) {
129 if (val == (host_cap.capabilities & PMU_CAP_LBR_FMT))
130 continue;
131
a2a34d14
SC
132 r = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val);
133 TEST_ASSERT(!r, "Bad LBR FMT = 0x%lx didn't fail", val);
9d27d461 134 }
a2a34d14 135
e4d86fb9
SC
136 kvm_vm_free(vm);
137}
138
139int 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);
e4d86fb9 149
b1b70562
SC
150 TEST_ASSERT(host_cap.full_width_write,
151 "Full-width writes should always be supported");
152
710fb612 153 test_basic_perf_capabilities(host_cap);
e4d86fb9
SC
154 test_fungible_perf_capabilities(host_cap);
155 test_immutable_perf_capabilities(host_cap);
f88d4f2f 156
825be3b5 157 printf("Completed perf capability tests.\n");
f88d4f2f 158}