Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Mar 24-27, 2025, special US time zones
Register
Loading...
Note: File does not exist in v3.1.
  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 xcr0_reset;
 52	uint64_t supported_xcr0;
 53	int i, vector;
 54
 55	set_cr4(get_cr4() | X86_CR4_OSXSAVE);
 56
 57	xcr0_reset = xgetbv(0);
 58	supported_xcr0 = this_cpu_supported_xcr0();
 59
 60	GUEST_ASSERT(xcr0_reset == XFEATURE_MASK_FP);
 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, supported_xcr0);
 83	__GUEST_ASSERT(!vector,
 84		       "Expected success on XSETBV(0x%lx), got vector '0x%x'",
 85		       supported_xcr0, vector);
 86
 87	for (i = 0; i < 64; i++) {
 88		if (supported_xcr0 & BIT_ULL(i))
 89			continue;
 90
 91		vector = xsetbv_safe(0, supported_xcr0 | BIT_ULL(i));
 92		__GUEST_ASSERT(vector == GP_VECTOR,
 93			       "Expected #GP on XSETBV(0x%llx), supported XCR0 = %lx, got vector '0x%x'",
 94			       BIT_ULL(i), supported_xcr0, vector);
 95	}
 96
 97	GUEST_DONE();
 98}
 99
100int main(int argc, char *argv[])
101{
102	struct kvm_vcpu *vcpu;
103	struct kvm_run *run;
104	struct kvm_vm *vm;
105	struct ucall uc;
106
107	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE));
108
109	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
110	run = vcpu->run;
111
112	vm_init_descriptor_tables(vm);
113	vcpu_init_descriptor_tables(vcpu);
114
115	while (1) {
116		vcpu_run(vcpu);
117
118		TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
119			    "Unexpected exit reason: %u (%s),",
120			    run->exit_reason,
121			    exit_reason_str(run->exit_reason));
122
123		switch (get_ucall(vcpu, &uc)) {
124		case UCALL_ABORT:
125			REPORT_GUEST_ASSERT(uc);
126			break;
127		case UCALL_DONE:
128			goto done;
129		default:
130			TEST_FAIL("Unknown ucall %lu", uc.cmd);
131		}
132	}
133
134done:
135	kvm_vm_free(vm);
136	return 0;
137}