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
guest_code(void)39 static void guest_code(void)
40 {
41 wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
42 }
43
main(int argc,char * argv[])44 int main(int argc, char *argv[])
45 {
46 struct kvm_vm *vm;
47 struct kvm_vcpu *vcpu;
48 int ret;
49 union perf_capabilities host_cap;
50 uint64_t val;
51
52 host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
53 host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT);
54
55 /* Create VM */
56 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
57
58 TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM));
59
60 TEST_REQUIRE(kvm_cpu_has_p(X86_PROPERTY_PMU_VERSION));
61 TEST_REQUIRE(kvm_cpu_property(X86_PROPERTY_PMU_VERSION) > 0);
62
63 /* testcase 1, set capabilities when we have PDCM bit */
64 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
65
66 /* check capabilities can be retrieved with KVM_GET_MSR */
67 ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
68
69 /* check whatever we write with KVM_SET_MSR is _not_ modified */
70 vcpu_run(vcpu);
71 ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);
72
73 /* testcase 2, check valid LBR formats are accepted */
74 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0);
75 ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), 0);
76
77 vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format);
78 ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format);
79
80 /*
81 * Testcase 3, check that an "invalid" LBR format is rejected. Only an
82 * exact match of the host's format (and 0/disabled) is allowed.
83 */
84 for (val = 1; val <= PMU_CAP_LBR_FMT; val++) {
85 if (val == (host_cap.capabilities & PMU_CAP_LBR_FMT))
86 continue;
87
88 ret = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, val);
89 TEST_ASSERT(!ret, "Bad LBR FMT = 0x%lx didn't fail", val);
90 }
91
92 printf("Completed perf capability tests.\n");
93 kvm_vm_free(vm);
94 }
95