xapic_state_test.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <fcntl.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <sys/ioctl.h>
  7. #include "apic.h"
  8. #include "kvm_util.h"
  9. #include "processor.h"
  10. #include "test_util.h"
  11. struct xapic_vcpu {
  12. struct kvm_vcpu *vcpu;
  13. bool is_x2apic;
  14. bool has_xavic_errata;
  15. };
  16. static void xapic_guest_code(void)
  17. {
  18. cli();
  19. xapic_enable();
  20. while (1) {
  21. uint64_t val = (u64)xapic_read_reg(APIC_IRR) |
  22. (u64)xapic_read_reg(APIC_IRR + 0x10) << 32;
  23. xapic_write_reg(APIC_ICR2, val >> 32);
  24. xapic_write_reg(APIC_ICR, val);
  25. GUEST_SYNC(val);
  26. }
  27. }
  28. #define X2APIC_RSVD_BITS_MASK (GENMASK_ULL(31, 20) | \
  29. GENMASK_ULL(17, 16) | \
  30. GENMASK_ULL(13, 13))
  31. static void x2apic_guest_code(void)
  32. {
  33. cli();
  34. x2apic_enable();
  35. do {
  36. uint64_t val = x2apic_read_reg(APIC_IRR) |
  37. x2apic_read_reg(APIC_IRR + 0x10) << 32;
  38. if (val & X2APIC_RSVD_BITS_MASK) {
  39. x2apic_write_reg_fault(APIC_ICR, val);
  40. } else {
  41. x2apic_write_reg(APIC_ICR, val);
  42. GUEST_ASSERT_EQ(x2apic_read_reg(APIC_ICR), val);
  43. }
  44. GUEST_SYNC(val);
  45. } while (1);
  46. }
  47. static void ____test_icr(struct xapic_vcpu *x, uint64_t val)
  48. {
  49. struct kvm_vcpu *vcpu = x->vcpu;
  50. struct kvm_lapic_state xapic;
  51. struct ucall uc;
  52. uint64_t icr;
  53. /*
  54. * Tell the guest what ICR value to write. Use the IRR to pass info,
  55. * all bits are valid and should not be modified by KVM (ignoring the
  56. * fact that vectors 0-15 are technically illegal).
  57. */
  58. vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic);
  59. *((u32 *)&xapic.regs[APIC_IRR]) = val;
  60. *((u32 *)&xapic.regs[APIC_IRR + 0x10]) = val >> 32;
  61. vcpu_ioctl(vcpu, KVM_SET_LAPIC, &xapic);
  62. vcpu_run(vcpu);
  63. TEST_ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC);
  64. TEST_ASSERT_EQ(uc.args[1], val);
  65. vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic);
  66. icr = (u64)(*((u32 *)&xapic.regs[APIC_ICR])) |
  67. (u64)(*((u32 *)&xapic.regs[APIC_ICR2])) << 32;
  68. if (!x->is_x2apic) {
  69. if (!x->has_xavic_errata)
  70. val &= (-1u | (0xffull << (32 + 24)));
  71. } else if (val & X2APIC_RSVD_BITS_MASK) {
  72. return;
  73. }
  74. if (x->has_xavic_errata)
  75. TEST_ASSERT_EQ(icr & ~APIC_ICR_BUSY, val & ~APIC_ICR_BUSY);
  76. else
  77. TEST_ASSERT_EQ(icr, val & ~APIC_ICR_BUSY);
  78. }
  79. static void __test_icr(struct xapic_vcpu *x, uint64_t val)
  80. {
  81. /*
  82. * The BUSY bit is reserved on both AMD and Intel, but only AMD treats
  83. * it is as _must_ be zero. Intel simply ignores the bit. Don't test
  84. * the BUSY bit for x2APIC, as there is no single correct behavior.
  85. */
  86. if (!x->is_x2apic)
  87. ____test_icr(x, val | APIC_ICR_BUSY);
  88. ____test_icr(x, val & ~(u64)APIC_ICR_BUSY);
  89. }
  90. static void test_icr(struct xapic_vcpu *x)
  91. {
  92. struct kvm_vcpu *vcpu = x->vcpu;
  93. uint64_t icr, i, j;
  94. icr = APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_FIXED;
  95. for (i = 0; i <= 0xff; i++)
  96. __test_icr(x, icr | i);
  97. icr = APIC_INT_ASSERT | APIC_DM_FIXED;
  98. for (i = 0; i <= 0xff; i++)
  99. __test_icr(x, icr | i);
  100. /*
  101. * Send all flavors of IPIs to non-existent vCPUs. Arbitrarily use
  102. * vector 0xff.
  103. */
  104. icr = APIC_INT_ASSERT | 0xff;
  105. for (i = 0; i < 0xff; i++) {
  106. if (i == vcpu->id)
  107. continue;
  108. for (j = 0; j < 8; j++)
  109. __test_icr(x, i << (32 + 24) | icr | (j << 8));
  110. }
  111. /* And again with a shorthand destination for all types of IPIs. */
  112. icr = APIC_DEST_ALLBUT | APIC_INT_ASSERT;
  113. for (i = 0; i < 8; i++)
  114. __test_icr(x, icr | (i << 8));
  115. /* And a few garbage value, just make sure it's an IRQ (blocked). */
  116. __test_icr(x, 0xa5a5a5a5a5a5a5a5 & ~APIC_DM_FIXED_MASK);
  117. __test_icr(x, 0x5a5a5a5a5a5a5a5a & ~APIC_DM_FIXED_MASK);
  118. __test_icr(x, -1ull & ~APIC_DM_FIXED_MASK);
  119. }
  120. static void __test_apic_id(struct kvm_vcpu *vcpu, uint64_t apic_base)
  121. {
  122. uint32_t apic_id, expected;
  123. struct kvm_lapic_state xapic;
  124. vcpu_set_msr(vcpu, MSR_IA32_APICBASE, apic_base);
  125. vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic);
  126. expected = apic_base & X2APIC_ENABLE ? vcpu->id : vcpu->id << 24;
  127. apic_id = *((u32 *)&xapic.regs[APIC_ID]);
  128. TEST_ASSERT(apic_id == expected,
  129. "APIC_ID not set back to %s format; wanted = %x, got = %x",
  130. (apic_base & X2APIC_ENABLE) ? "x2APIC" : "xAPIC",
  131. expected, apic_id);
  132. }
  133. /*
  134. * Verify that KVM switches the APIC_ID between xAPIC and x2APIC when userspace
  135. * stuffs MSR_IA32_APICBASE. Setting the APIC_ID when x2APIC is enabled and
  136. * when the APIC transitions for DISABLED to ENABLED is architectural behavior
  137. * (on Intel), whereas the x2APIC => xAPIC transition behavior is KVM ABI since
  138. * attempted to transition from x2APIC to xAPIC without disabling the APIC is
  139. * architecturally disallowed.
  140. */
  141. static void test_apic_id(void)
  142. {
  143. const uint32_t NR_VCPUS = 3;
  144. struct kvm_vcpu *vcpus[NR_VCPUS];
  145. uint64_t apic_base;
  146. struct kvm_vm *vm;
  147. int i;
  148. vm = vm_create_with_vcpus(NR_VCPUS, NULL, vcpus);
  149. vm_enable_cap(vm, KVM_CAP_X2APIC_API, KVM_X2APIC_API_USE_32BIT_IDS);
  150. for (i = 0; i < NR_VCPUS; i++) {
  151. apic_base = vcpu_get_msr(vcpus[i], MSR_IA32_APICBASE);
  152. TEST_ASSERT(apic_base & MSR_IA32_APICBASE_ENABLE,
  153. "APIC not in ENABLED state at vCPU RESET");
  154. TEST_ASSERT(!(apic_base & X2APIC_ENABLE),
  155. "APIC not in xAPIC mode at vCPU RESET");
  156. __test_apic_id(vcpus[i], apic_base);
  157. __test_apic_id(vcpus[i], apic_base | X2APIC_ENABLE);
  158. __test_apic_id(vcpus[i], apic_base);
  159. }
  160. kvm_vm_free(vm);
  161. }
  162. static void test_x2apic_id(void)
  163. {
  164. struct kvm_lapic_state lapic = {};
  165. struct kvm_vcpu *vcpu;
  166. struct kvm_vm *vm;
  167. int i;
  168. vm = vm_create_with_one_vcpu(&vcpu, NULL);
  169. vcpu_set_msr(vcpu, MSR_IA32_APICBASE, MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE);
  170. /*
  171. * Try stuffing a modified x2APIC ID, KVM should ignore the value and
  172. * always return the vCPU's default/readonly x2APIC ID.
  173. */
  174. for (i = 0; i <= 0xff; i++) {
  175. *(u32 *)(lapic.regs + APIC_ID) = i << 24;
  176. *(u32 *)(lapic.regs + APIC_SPIV) = APIC_SPIV_APIC_ENABLED;
  177. vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic);
  178. vcpu_ioctl(vcpu, KVM_GET_LAPIC, &lapic);
  179. TEST_ASSERT(*((u32 *)&lapic.regs[APIC_ID]) == vcpu->id << 24,
  180. "x2APIC ID should be fully readonly");
  181. }
  182. kvm_vm_free(vm);
  183. }
  184. int main(int argc, char *argv[])
  185. {
  186. struct xapic_vcpu x = {
  187. .vcpu = NULL,
  188. .is_x2apic = true,
  189. };
  190. struct kvm_vm *vm;
  191. vm = vm_create_with_one_vcpu(&x.vcpu, x2apic_guest_code);
  192. test_icr(&x);
  193. kvm_vm_free(vm);
  194. /*
  195. * Use a second VM for the xAPIC test so that x2APIC can be hidden from
  196. * the guest in order to test AVIC. KVM disallows changing CPUID after
  197. * KVM_RUN and AVIC is disabled if _any_ vCPU is allowed to use x2APIC.
  198. */
  199. vm = vm_create_with_one_vcpu(&x.vcpu, xapic_guest_code);
  200. x.is_x2apic = false;
  201. /*
  202. * AMD's AVIC implementation is buggy (fails to clear the ICR BUSY bit),
  203. * and also diverges from KVM with respect to ICR2[23:0] (KVM and Intel
  204. * drops writes, AMD does not). Account for the errata when checking
  205. * that KVM reads back what was written.
  206. */
  207. x.has_xavic_errata = host_cpu_is_amd &&
  208. get_kvm_amd_param_bool("avic");
  209. vcpu_clear_cpuid_feature(x.vcpu, X86_FEATURE_X2APIC);
  210. virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
  211. test_icr(&x);
  212. kvm_vm_free(vm);
  213. test_apic_id();
  214. test_x2apic_id();
  215. }