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) \ 23 do { \ 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) \ 41 do { \ 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 49 static 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 vector '0x%x'", 85 vector); 86 87 vector = xsetbv_safe(0, supported_xcr0); 88 __GUEST_ASSERT(!vector, 89 "Expected success on XSETBV(0x%lx), got vector '0x%x'", 90 supported_xcr0, 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 vector '0x%x'", 99 BIT_ULL(i), supported_xcr0, vector); 100 } 101 102 GUEST_DONE(); 103 } 104 105 int 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 136 done: 137 kvm_vm_free(vm); 138 return 0; 139 } 140