summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c
blob: 23051d84b9078a7177df9d1c505031bf2bbf0ccf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// SPDX-License-Identifier: GPL-2.0
/*
 * VMX-pmu related msrs test
 *
 * Copyright (C) 2021 Intel Corporation
 *
 * Test to check the effect of various CPUID settings
 * on the MSR_IA32_PERF_CAPABILITIES MSR, and check that
 * whatever we write with KVM_SET_MSR is _not_ modified
 * in the guest and test it can be retrieved with KVM_GET_MSR.
 *
 * Test to check that invalid LBR formats are rejected.
 */

#define _GNU_SOURCE /* for program_invocation_short_name */
#include <sys/ioctl.h>

#include "kvm_util.h"
#include "vmx.h"

#define VCPU_ID	      0

#define X86_FEATURE_PDCM	(1<<15)
#define PMU_CAP_FW_WRITES	(1ULL << 13)
#define PMU_CAP_LBR_FMT		0x3f

union cpuid10_eax {
	struct {
		unsigned int version_id:8;
		unsigned int num_counters:8;
		unsigned int bit_width:8;
		unsigned int mask_length:8;
	} split;
	unsigned int full;
};

union perf_capabilities {
	struct {
		u64	lbr_format:6;
		u64	pebs_trap:1;
		u64	pebs_arch_reg:1;
		u64	pebs_format:4;
		u64	smm_freeze:1;
		u64	full_width_write:1;
		u64 pebs_baseline:1;
		u64	perf_metrics:1;
		u64	pebs_output_pt_available:1;
		u64	anythread_deprecated:1;
	};
	u64	capabilities;
};

static void guest_code(void)
{
	wrmsr(MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
}

int main(int argc, char *argv[])
{
	struct kvm_cpuid2 *cpuid;
	struct kvm_cpuid_entry2 *entry_1_0;
	struct kvm_cpuid_entry2 *entry_a_0;
	bool pdcm_supported = false;
	struct kvm_vm *vm;
	int ret;
	union cpuid10_eax eax;
	union perf_capabilities host_cap;

	host_cap.capabilities = kvm_get_feature_msr(MSR_IA32_PERF_CAPABILITIES);
	host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT);

	/* Create VM */
	vm = vm_create_default(VCPU_ID, 0, guest_code);
	cpuid = kvm_get_supported_cpuid();

	if (kvm_get_cpuid_max_basic() >= 0xa) {
		entry_1_0 = kvm_get_supported_cpuid_index(1, 0);
		entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0);
		pdcm_supported = entry_1_0 && !!(entry_1_0->ecx & X86_FEATURE_PDCM);
		eax.full = entry_a_0->eax;
	}
	if (!pdcm_supported) {
		print_skip("MSR_IA32_PERF_CAPABILITIES is not supported by the vCPU");
		exit(KSFT_SKIP);
	}
	if (!eax.split.version_id) {
		print_skip("PMU is not supported by the vCPU");
		exit(KSFT_SKIP);
	}

	/* testcase 1, set capabilities when we have PDCM bit */
	vcpu_set_cpuid(vm, VCPU_ID, cpuid);
	vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);

	/* check capabilities can be retrieved with KVM_GET_MSR */
	ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);

	/* check whatever we write with KVM_SET_MSR is _not_ modified */
	vcpu_run(vm, VCPU_ID);
	ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES);

	/* testcase 2, check valid LBR formats are accepted */
	vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0);
	ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), 0);

	vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format);
	ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format);

	/* testcase 3, check invalid LBR format is rejected */
	ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_LBR_FMT);
	TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");

	/* testcase 4, set capabilities when we don't have PDCM bit */
	entry_1_0->ecx &= ~X86_FEATURE_PDCM;
	vcpu_set_cpuid(vm, VCPU_ID, cpuid);
	ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
	TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");

	/* testcase 5, set capabilities when we don't have PMU version bits */
	entry_1_0->ecx |= X86_FEATURE_PDCM;
	eax.split.version_id = 0;
	entry_1_0->ecx = eax.full;
	vcpu_set_cpuid(vm, VCPU_ID, cpuid);
	ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES);
	TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");

	vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0);
	ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), 0);

	kvm_vm_free(vm);
}