cpuid_test.c 5.9 KB

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