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