1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021, Red Hat Inc. 4 * 5 * Generic tests for KVM CPUID set/get ioctls 6 */ 7 #define USE_GUEST_ASSERT_PRINTF 1 8 9 #include <asm/kvm_para.h> 10 #include <linux/kvm_para.h> 11 #include <stdint.h> 12 13 #include "test_util.h" 14 #include "kvm_util.h" 15 #include "processor.h" 16 17 /* CPUIDs known to differ */ 18 struct { 19 u32 function; 20 u32 index; 21 } mangled_cpuids[] = { 22 /* 23 * These entries depend on the vCPU's XCR0 register and IA32_XSS MSR, 24 * which are not controlled for by this test. 25 */ 26 {.function = 0xd, .index = 0}, 27 {.function = 0xd, .index = 1}, 28 }; 29 30 static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid) 31 { 32 int i; 33 u32 eax, ebx, ecx, edx; 34 35 for (i = 0; i < guest_cpuid->nent; i++) { 36 __cpuid(guest_cpuid->entries[i].function, 37 guest_cpuid->entries[i].index, 38 &eax, &ebx, &ecx, &edx); 39 40 GUEST_ASSERT_EQ(eax, guest_cpuid->entries[i].eax); 41 GUEST_ASSERT_EQ(ebx, guest_cpuid->entries[i].ebx); 42 GUEST_ASSERT_EQ(ecx, guest_cpuid->entries[i].ecx); 43 GUEST_ASSERT_EQ(edx, guest_cpuid->entries[i].edx); 44 } 45 46 } 47 48 static void guest_main(struct kvm_cpuid2 *guest_cpuid) 49 { 50 GUEST_SYNC(1); 51 52 test_guest_cpuids(guest_cpuid); 53 54 GUEST_SYNC(2); 55 56 GUEST_ASSERT_EQ(this_cpu_property(X86_PROPERTY_MAX_KVM_LEAF), 0x40000001); 57 58 GUEST_DONE(); 59 } 60 61 static bool is_cpuid_mangled(const struct kvm_cpuid_entry2 *entrie) 62 { 63 int i; 64 65 for (i = 0; i < sizeof(mangled_cpuids); i++) { 66 if (mangled_cpuids[i].function == entrie->function && 67 mangled_cpuids[i].index == entrie->index) 68 return true; 69 } 70 71 return false; 72 } 73 74 static void compare_cpuids(const struct kvm_cpuid2 *cpuid1, 75 const struct kvm_cpuid2 *cpuid2) 76 { 77 const struct kvm_cpuid_entry2 *e1, *e2; 78 int i; 79 80 TEST_ASSERT(cpuid1->nent == cpuid2->nent, 81 "CPUID nent mismatch: %d vs. %d", cpuid1->nent, cpuid2->nent); 82 83 for (i = 0; i < cpuid1->nent; i++) { 84 e1 = &cpuid1->entries[i]; 85 e2 = &cpuid2->entries[i]; 86 87 TEST_ASSERT(e1->function == e2->function && 88 e1->index == e2->index && e1->flags == e2->flags, 89 "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x\n", 90 i, e1->function, e1->index, e1->flags, 91 e2->function, e2->index, e2->flags); 92 93 if (is_cpuid_mangled(e1)) 94 continue; 95 96 TEST_ASSERT(e1->eax == e2->eax && e1->ebx == e2->ebx && 97 e1->ecx == e2->ecx && e1->edx == e2->edx, 98 "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x", 99 e1->function, e1->index, 100 e1->eax, e1->ebx, e1->ecx, e1->edx, 101 e2->eax, e2->ebx, e2->ecx, e2->edx); 102 } 103 } 104 105 static void run_vcpu(struct kvm_vcpu *vcpu, int stage) 106 { 107 struct ucall uc; 108 109 vcpu_run(vcpu); 110 111 switch (get_ucall(vcpu, &uc)) { 112 case UCALL_SYNC: 113 TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && 114 uc.args[1] == stage + 1, 115 "Stage %d: Unexpected register values vmexit, got %lx", 116 stage + 1, (ulong)uc.args[1]); 117 return; 118 case UCALL_DONE: 119 return; 120 case UCALL_ABORT: 121 REPORT_GUEST_ASSERT(uc); 122 default: 123 TEST_ASSERT(false, "Unexpected exit: %s", 124 exit_reason_str(vcpu->run->exit_reason)); 125 } 126 } 127 128 struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid) 129 { 130 int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]); 131 vm_vaddr_t gva = vm_vaddr_alloc(vm, size, KVM_UTIL_MIN_VADDR); 132 struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva); 133 134 memcpy(guest_cpuids, cpuid, size); 135 136 *p_gva = gva; 137 return guest_cpuids; 138 } 139 140 static void set_cpuid_after_run(struct kvm_vcpu *vcpu) 141 { 142 struct kvm_cpuid_entry2 *ent; 143 int rc; 144 u32 eax, ebx, x; 145 146 /* Setting unmodified CPUID is allowed */ 147 rc = __vcpu_set_cpuid(vcpu); 148 TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); 149 150 /* Changing CPU features is forbidden */ 151 ent = vcpu_get_cpuid_entry(vcpu, 0x7); 152 ebx = ent->ebx; 153 ent->ebx--; 154 rc = __vcpu_set_cpuid(vcpu); 155 TEST_ASSERT(rc, "Changing CPU features should fail"); 156 ent->ebx = ebx; 157 158 /* Changing MAXPHYADDR is forbidden */ 159 ent = vcpu_get_cpuid_entry(vcpu, 0x80000008); 160 eax = ent->eax; 161 x = eax & 0xff; 162 ent->eax = (eax & ~0xffu) | (x - 1); 163 rc = __vcpu_set_cpuid(vcpu); 164 TEST_ASSERT(rc, "Changing MAXPHYADDR should fail"); 165 ent->eax = eax; 166 } 167 168 static void test_get_cpuid2(struct kvm_vcpu *vcpu) 169 { 170 struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(vcpu->cpuid->nent + 1); 171 int i, r; 172 173 vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); 174 TEST_ASSERT(cpuid->nent == vcpu->cpuid->nent, 175 "KVM didn't update nent on success, wanted %u, got %u\n", 176 vcpu->cpuid->nent, cpuid->nent); 177 178 for (i = 0; i < vcpu->cpuid->nent; i++) { 179 cpuid->nent = i; 180 r = __vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); 181 TEST_ASSERT(r && errno == E2BIG, KVM_IOCTL_ERROR(KVM_GET_CPUID2, r)); 182 TEST_ASSERT(cpuid->nent == i, "KVM modified nent on failure"); 183 } 184 free(cpuid); 185 } 186 187 int main(void) 188 { 189 struct kvm_vcpu *vcpu; 190 vm_vaddr_t cpuid_gva; 191 struct kvm_vm *vm; 192 int stage; 193 194 vm = vm_create_with_one_vcpu(&vcpu, guest_main); 195 196 compare_cpuids(kvm_get_supported_cpuid(), vcpu->cpuid); 197 198 vcpu_alloc_cpuid(vm, &cpuid_gva, vcpu->cpuid); 199 200 vcpu_args_set(vcpu, 1, cpuid_gva); 201 202 for (stage = 0; stage < 3; stage++) 203 run_vcpu(vcpu, stage); 204 205 set_cpuid_after_run(vcpu); 206 207 test_get_cpuid2(vcpu); 208 209 kvm_vm_free(vm); 210 } 211