File Index
Files and directories
Sign in
FILE

xcr0_cpuid_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/x86/xcr0_cpuid_test.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * XCR0 cpuid test
  4 *
  5 * Copyright (C) 2022, Google LLC.
  6 */
  7#include <fcntl.h>
  8#include <stdio.h>
  9#include <stdlib.h>
 10#include <string.h>
 11#include <sys/ioctl.h>
 12
 13#include "test_util.h"
 14
 15#include "kvm_util.h"
 16#include "processor.h"
 17
 18/*
 19 * Assert that architectural dependency rules are satisfied, e.g. that AVX is
 20 * supported if and only if SSE is supported.
 21 */
 22#define ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0, xfeatures, dependencies)		\
 23do {											\
 24	uint64_t __supported = (supported_xcr0) & ((xfeatures) | (dependencies));	\
 25											\
 26	__GUEST_ASSERT((__supported & (xfeatures)) != (xfeatures) ||			\
 27		       __supported == ((xfeatures) | (dependencies)),			\
 28		       "supported = 0x%lx, xfeatures = 0x%llx, dependencies = 0x%llx",	\
 29		       __supported, (xfeatures), (dependencies));			\
 30} while (0)
 31
 32/*
 33 * Assert that KVM reports a sane, usable as-is XCR0.  Architecturally, a CPU
 34 * isn't strictly required to _support_ all XFeatures related to a feature, but
 35 * at the same time XSETBV will #GP if bundled XFeatures aren't enabled and
 36 * disabled coherently.  E.g. a CPU can technically enumerate supported for
 37 * XTILE_CFG but not XTILE_DATA, but attempting to enable XTILE_CFG without
 38 * XTILE_DATA will #GP.
 39 */
 40#define ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0, xfeatures)		\
 41do {									\
 42	uint64_t __supported = (supported_xcr0) & (xfeatures);		\
 43									\
 44	__GUEST_ASSERT(!__supported || __supported == (xfeatures),	\
 45		       "supported = 0x%lx, xfeatures = 0x%llx",		\
 46		       __supported, (xfeatures));			\
 47} while (0)
 48
 49static void guest_code(void)
 50{
 51	uint64_t initial_xcr0;
 52	uint64_t supported_xcr0;
 53	int i, vector;
 54
 55	set_cr4(get_cr4() | X86_CR4_OSXSAVE);
 56
 57	initial_xcr0 = xgetbv(0);
 58	supported_xcr0 = this_cpu_supported_xcr0();
 59
 60	GUEST_ASSERT(initial_xcr0 == supported_xcr0);
 61
 62	/* Check AVX */
 63	ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,
 64				     XFEATURE_MASK_YMM,
 65				     XFEATURE_MASK_SSE);
 66
 67	/* Check MPX */
 68	ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
 69				    XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR);
 70
 71	/* Check AVX-512 */
 72	ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,
 73				     XFEATURE_MASK_AVX512,
 74				     XFEATURE_MASK_SSE | XFEATURE_MASK_YMM);
 75	ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
 76				    XFEATURE_MASK_AVX512);
 77
 78	/* Check AMX */
 79	ASSERT_ALL_OR_NONE_XFEATURE(supported_xcr0,
 80				    XFEATURE_MASK_XTILE);
 81
 82	vector = xsetbv_safe(0, XFEATURE_MASK_FP);
 83	__GUEST_ASSERT(!vector,
 84		       "Expected success on XSETBV(FP), got %s",
 85		       ex_str(vector));
 86
 87	vector = xsetbv_safe(0, supported_xcr0);
 88	__GUEST_ASSERT(!vector,
 89		       "Expected success on XSETBV(0x%lx), got %s",
 90		       supported_xcr0, ex_str(vector));
 91
 92	for (i = 0; i < 64; i++) {
 93		if (supported_xcr0 & BIT_ULL(i))
 94			continue;
 95
 96		vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i));
 97		__GUEST_ASSERT(vector == GP_VECTOR,
 98			       "Expected #GP on XSETBV(0x%llx), supported XCR0 = %lx, got %s",
 99			       BIT_ULL(i), supported_xcr0, ex_str(vector));
100	}
101
102	GUEST_DONE();
103}
104
105int main(int argc, char *argv[])
106{
107	struct kvm_vcpu *vcpu;
108	struct kvm_run *run;
109	struct kvm_vm *vm;
110	struct ucall uc;
111
112	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE));
113
114	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
115	run = vcpu->run;
116
117	while (1) {
118		vcpu_run(vcpu);
119
120		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
121			    "Unexpected exit reason: %u (%s),",
122			    run->exit_reason,
123			    exit_reason_str(run->exit_reason));
124
125		switch (get_ucall(vcpu, &uc)) {
126		case UCALL_ABORT:
127			REPORT_GUEST_ASSERT(uc);
128			break;
129		case UCALL_DONE:
130			goto done;
131		default:
132			TEST_FAIL("Unknown ucall %lu", uc.cmd);
133		}
134	}
135
136done:
137	kvm_vm_free(vm);
138	return 0;
139}
~/ Read-only file preview.