f7a27b5c949b02320936a41fee77dfae29e93195
[linux-block.git] / tools / testing / selftests / kvm / x86_64 / vmx_pmu_caps_test.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
14 #define _GNU_SOURCE /* for program_invocation_short_name */
15 #include <sys/ioctl.h>
16
17 #include "kvm_util.h"
18 #include "vmx.h"
19
20 #define PMU_CAP_FW_WRITES       (1ULL << 13)
21 #define PMU_CAP_LBR_FMT         0x3f
22
23 union perf_capabilities {
24         struct {
25                 u64     lbr_format:6;
26                 u64     pebs_trap:1;
27                 u64     pebs_arch_reg:1;
28                 u64     pebs_format:4;
29                 u64     smm_freeze:1;
30                 u64     full_width_write:1;
31                 u64 pebs_baseline:1;
32                 u64     perf_metrics:1;
33                 u64     pebs_output_pt_available:1;
34                 u64     anythread_deprecated:1;
35         };
36         u64     capabilities;
37 };
38
39 static void guest_code(void)
40 {
41         wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
42 }
43
44 /*
45  * Verify KVM allows writing PERF_CAPABILITIES with all KVM-supported features
46  * enabled, as well as '0' (to disable all features).
47  */
48 static void test_basic_perf_capabilities(union perf_capabilities host_cap)
49 {
50         struct kvm_vcpu *vcpu;
51         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
52
53         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
54         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
55
56         kvm_vm_free(vm);
57 }
58
59 static void test_fungible_perf_capabilities(union perf_capabilities host_cap)
60 {
61         struct kvm_vcpu *vcpu;
62         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, guest_code);
63
64         /* testcase 1, set capabilities when we have PDCM bit */
65         vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
66
67         /* check whatever we write with KVM_SET_MSR is _not_ modified */
68         vcpu_run(vcpu);
69         ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
70
71         kvm_vm_free(vm);
72 }
73
74 static void test_immutable_perf_capabilities(union perf_capabilities host_cap)
75 {
76         struct kvm_vcpu *vcpu;
77         struct kvm_vm *vm = vm_create_with_one_vcpu(&vcpu, NULL);
78         uint64_t val;
79         int ret;
80
81         /*
82          * KVM only supports the host's native LBR format, as well as '0' (to
83          * disable LBR support).  Verify KVM rejects all other LBR formats.
84          */
85         for (val = 1; val <= PMU_CAP_LBR_FMT; val++) {
86                 if (val == (host_cap.capabilities & PMU_CAP_LBR_FMT))
87                         continue;
88
89                 ret = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val);
90                 TEST_ASSERT(!ret, "Bad LBR FMT = 0x%lx didn't fail", val);
91         }
92         kvm_vm_free(vm);
93 }
94
95 int main(int argc, char *argv[])
96 {
97         union perf_capabilities host_cap;
98
99         TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
100
101         TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
102         TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
103
104         host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
105         host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT);
106
107         TEST_ASSERT(host_cap.full_width_write,
108                     "Full-width writes should always be supported");
109
110         test_basic_perf_capabilities(host_cap);
111         test_fungible_perf_capabilities(host_cap);
112         test_immutable_perf_capabilities(host_cap);
113
114         printf("Completed perf capability tests.\n");
115 }