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 #include <asm/kvm_para.h> 8 #include <linux/kvm_para.h> 9 #include <stdint.h> 10 11 #include "test_util.h" 12 #include "kvm_util.h" 13 #include "processor.h" 14 15 struct cpuid_mask { 16 union { 17 struct { 18 u32 eax; 19 u32 ebx; 20 u32 ecx; 21 u32 edx; 22 }; 23 u32 regs[4]; 24 }; 25 }; 26 27 static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid) 28 { 29 int i; 30 u32 eax, ebx, ecx, edx; 31 32 for (i = 0; i < guest_cpuid->nent; i++) { 33 __cpuid(guest_cpuid->entries[i].function, 34 guest_cpuid->entries[i].index, 35 &eax, &ebx, &ecx, &edx); 36 37 GUEST_ASSERT_EQ(eax, guest_cpuid->entries[i].eax); 38 GUEST_ASSERT_EQ(ebx, guest_cpuid->entries[i].ebx); 39 GUEST_ASSERT_EQ(ecx, guest_cpuid->entries[i].ecx); 40 GUEST_ASSERT_EQ(edx, guest_cpuid->entries[i].edx); 41 } 42 43 } 44 45 static void guest_main(struct kvm_cpuid2 *guest_cpuid) 46 { 47 GUEST_SYNC(1); 48 49 test_guest_cpuids(guest_cpuid); 50 51 GUEST_SYNC(2); 52 53 GUEST_ASSERT_EQ(this_cpu_property(X86_PROPERTY_MAX_KVM_LEAF), 0x40000001); 54 55 GUEST_DONE(); 56 } 57 58 static struct cpuid_mask get_const_cpuid_mask(const struct kvm_cpuid_entry2 *entry) 59 { 60 struct cpuid_mask mask; 61 62 memset(&mask, 0xff, sizeof(mask)); 63 64 switch (entry->function) { 65 case 0x1: 66 mask.regs[X86_FEATURE_OSXSAVE.reg] &= ~BIT(X86_FEATURE_OSXSAVE.bit); 67 break; 68 case 0x7: 69 mask.regs[X86_FEATURE_OSPKE.reg] &= ~BIT(X86_FEATURE_OSPKE.bit); 70 break; 71 case 0xd: 72 /* 73 * CPUID.0xD.{0,1}.EBX enumerate XSAVE size based on the current 74 * XCR0 and IA32_XSS MSR values. 75 */ 76 if (entry->index < 2) 77 mask.ebx = 0; 78 break; 79 } 80 return mask; 81 } 82 83 static void compare_cpuids(const struct kvm_cpuid2 *cpuid1, 84 const struct kvm_cpuid2 *cpuid2) 85 { 86 const struct kvm_cpuid_entry2 *e1, *e2; 87 int i; 88 89 TEST_ASSERT(cpuid1->nent == cpuid2->nent, 90 "CPUID nent mismatch: %d vs. %d", cpuid1->nent, cpuid2->nent); 91 92 for (i = 0; i < cpuid1->nent; i++) { 93 struct cpuid_mask mask; 94 95 e1 = &cpuid1->entries[i]; 96 e2 = &cpuid2->entries[i]; 97 98 TEST_ASSERT(e1->function == e2->function && 99 e1->index == e2->index && e1->flags == e2->flags, 100 "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x", 101 i, e1->function, e1->index, e1->flags, 102 e2->function, e2->index, e2->flags); 103 104 /* Mask off dynamic bits, e.g. OSXSAVE, when comparing entries. */ 105 mask = get_const_cpuid_mask(e1); 106 107 TEST_ASSERT((e1->eax & mask.eax) == (e2->eax & mask.eax) && 108 (e1->ebx & mask.ebx) == (e2->ebx & mask.ebx) && 109 (e1->ecx & mask.ecx) == (e2->ecx & mask.ecx) && 110 (e1->edx & mask.edx) == (e2->edx & mask.edx), 111 "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x", 112 e1->function, e1->index, 113 e1->eax & mask.eax, e1->ebx & mask.ebx, 114 e1->ecx & mask.ecx, e1->edx & mask.edx, 115 e2->eax & mask.eax, e2->ebx & mask.ebx, 116 e2->ecx & mask.ecx, e2->edx & mask.edx); 117 } 118 } 119 120 static void run_vcpu(struct kvm_vcpu *vcpu, int stage) 121 { 122 struct ucall uc; 123 124 vcpu_run(vcpu); 125 126 switch (get_ucall(vcpu, &uc)) { 127 case UCALL_SYNC: 128 TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && 129 uc.args[1] == stage + 1, 130 "Stage %d: Unexpected register values vmexit, got %lx", 131 stage + 1, (ulong)uc.args[1]); 132 return; 133 case UCALL_DONE: 134 return; 135 case UCALL_ABORT: 136 REPORT_GUEST_ASSERT(uc); 137 default: 138 TEST_ASSERT(false, "Unexpected exit: %s", 139 exit_reason_str(vcpu->run->exit_reason)); 140 } 141 } 142 143 struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid) 144 { 145 int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]); 146 vm_vaddr_t gva = vm_vaddr_alloc(vm, size, KVM_UTIL_MIN_VADDR); 147 struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva); 148 149 memcpy(guest_cpuids, cpuid, size); 150 151 *p_gva = gva; 152 return guest_cpuids; 153 } 154 155 static void set_cpuid_after_run(struct kvm_vcpu *vcpu) 156 { 157 struct kvm_cpuid_entry2 *ent; 158 struct kvm_sregs sregs; 159 int rc; 160 u32 eax, ebx, x; 161 162 /* Setting unmodified CPUID is allowed */ 163 rc = __vcpu_set_cpuid(vcpu); 164 TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); 165 166 /* 167 * Toggle CR4 bits that affect dynamic CPUID feature flags to verify 168 * setting unmodified CPUID succeeds with runtime CPUID updates. 169 */ 170 vcpu_sregs_get(vcpu, &sregs); 171 if (kvm_cpu_has(X86_FEATURE_XSAVE)) 172 sregs.cr4 ^= X86_CR4_OSXSAVE; 173 if (kvm_cpu_has(X86_FEATURE_PKU)) 174 sregs.cr4 ^= X86_CR4_PKE; 175 vcpu_sregs_set(vcpu, &sregs); 176 177 rc = __vcpu_set_cpuid(vcpu); 178 TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); 179 180 /* Changing CPU features is forbidden */ 181 ent = vcpu_get_cpuid_entry(vcpu, 0x7); 182 ebx = ent->ebx; 183 ent->ebx--; 184 rc = __vcpu_set_cpuid(vcpu); 185 TEST_ASSERT(rc, "Changing CPU features should fail"); 186 ent->ebx = ebx; 187 188 /* Changing MAXPHYADDR is forbidden */ 189 ent = vcpu_get_cpuid_entry(vcpu, 0x80000008); 190 eax = ent->eax; 191 x = eax & 0xff; 192 ent->eax = (eax & ~0xffu) | (x - 1); 193 rc = __vcpu_set_cpuid(vcpu); 194 TEST_ASSERT(rc, "Changing MAXPHYADDR should fail"); 195 ent->eax = eax; 196 } 197 198 static void test_get_cpuid2(struct kvm_vcpu *vcpu) 199 { 200 struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(vcpu->cpuid->nent + 1); 201 int i, r; 202 203 vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); 204 TEST_ASSERT(cpuid->nent == vcpu->cpuid->nent, 205 "KVM didn't update nent on success, wanted %u, got %u", 206 vcpu->cpuid->nent, cpuid->nent); 207 208 for (i = 0; i < vcpu->cpuid->nent; i++) { 209 cpuid->nent = i; 210 r = __vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); 211 TEST_ASSERT(r && errno == E2BIG, KVM_IOCTL_ERROR(KVM_GET_CPUID2, r)); 212 TEST_ASSERT(cpuid->nent == i, "KVM modified nent on failure"); 213 } 214 free(cpuid); 215 } 216 217 int main(void) 218 { 219 struct kvm_vcpu *vcpu; 220 vm_vaddr_t cpuid_gva; 221 struct kvm_vm *vm; 222 int stage; 223 224 vm = vm_create_with_one_vcpu(&vcpu, guest_main); 225 226 compare_cpuids(kvm_get_supported_cpuid(), vcpu->cpuid); 227 228 vcpu_alloc_cpuid(vm, &cpuid_gva, vcpu->cpuid); 229 230 vcpu_args_set(vcpu, 1, cpuid_gva); 231 232 for (stage = 0; stage < 3; stage++) 233 run_vcpu(vcpu, stage); 234 235 set_cpuid_after_run(vcpu); 236 237 test_get_cpuid2(vcpu); 238 239 kvm_vm_free(vm); 240 } 241