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%llx, 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%llx, xfeatures = 0x%llx", \ 46 __supported, (xfeatures)); \ 47 } while (0) 48 49 static 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%llx), 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 = %llx, got vector '0x%x'", 94 BIT_ULL(i), supported_xcr0, vector); 95 } 96 97 GUEST_DONE(); 98 } 99 100 int 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),\n", 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 134 done: 135 kvm_vm_free(vm); 136 return 0; 137 } 138