coalesced_io_test.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <signal.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <sys/ioctl.h>
  7. #include <linux/sizes.h>
  8. #include <kvm_util.h>
  9. #include <processor.h>
  10. #include "ucall_common.h"
  11. struct kvm_coalesced_io {
  12. struct kvm_coalesced_mmio_ring *ring;
  13. uint32_t ring_size;
  14. uint64_t mmio_gpa;
  15. uint64_t *mmio;
  16. /*
  17. * x86-only, but define pio_port for all architectures to minimize the
  18. * amount of #ifdeffery and complexity, without having to sacrifice
  19. * verbose error messages.
  20. */
  21. uint8_t pio_port;
  22. };
  23. static struct kvm_coalesced_io kvm_builtin_io_ring;
  24. #ifdef __x86_64__
  25. static const int has_pio = 1;
  26. #else
  27. static const int has_pio = 0;
  28. #endif
  29. static void guest_code(struct kvm_coalesced_io *io)
  30. {
  31. int i, j;
  32. for (;;) {
  33. for (j = 0; j < 1 + has_pio; j++) {
  34. /*
  35. * KVM always leaves one free entry, i.e. exits to
  36. * userspace before the last entry is filled.
  37. */
  38. for (i = 0; i < io->ring_size - 1; i++) {
  39. #ifdef __x86_64__
  40. if (i & 1)
  41. outl(io->pio_port, io->pio_port + i);
  42. else
  43. #endif
  44. WRITE_ONCE(*io->mmio, io->mmio_gpa + i);
  45. }
  46. #ifdef __x86_64__
  47. if (j & 1)
  48. outl(io->pio_port, io->pio_port + i);
  49. else
  50. #endif
  51. WRITE_ONCE(*io->mmio, io->mmio_gpa + i);
  52. }
  53. GUEST_SYNC(0);
  54. WRITE_ONCE(*io->mmio, io->mmio_gpa + i);
  55. #ifdef __x86_64__
  56. outl(io->pio_port, io->pio_port + i);
  57. #endif
  58. }
  59. }
  60. static void vcpu_run_and_verify_io_exit(struct kvm_vcpu *vcpu,
  61. struct kvm_coalesced_io *io,
  62. uint32_t ring_start,
  63. uint32_t expected_exit)
  64. {
  65. const bool want_pio = expected_exit == KVM_EXIT_IO;
  66. struct kvm_coalesced_mmio_ring *ring = io->ring;
  67. struct kvm_run *run = vcpu->run;
  68. uint32_t pio_value;
  69. WRITE_ONCE(ring->first, ring_start);
  70. WRITE_ONCE(ring->last, ring_start);
  71. vcpu_run(vcpu);
  72. /*
  73. * Annoyingly, reading PIO data is safe only for PIO exits, otherwise
  74. * data_offset is garbage, e.g. an MMIO gpa.
  75. */
  76. if (run->exit_reason == KVM_EXIT_IO)
  77. pio_value = *(uint32_t *)((void *)run + run->io.data_offset);
  78. else
  79. pio_value = 0;
  80. TEST_ASSERT((!want_pio && (run->exit_reason == KVM_EXIT_MMIO && run->mmio.is_write &&
  81. run->mmio.phys_addr == io->mmio_gpa && run->mmio.len == 8 &&
  82. *(uint64_t *)run->mmio.data == io->mmio_gpa + io->ring_size - 1)) ||
  83. (want_pio && (run->exit_reason == KVM_EXIT_IO && run->io.port == io->pio_port &&
  84. run->io.direction == KVM_EXIT_IO_OUT && run->io.count == 1 &&
  85. pio_value == io->pio_port + io->ring_size - 1)),
  86. "For start = %u, expected exit on %u-byte %s write 0x%llx = %lx, got exit_reason = %u (%s)\n "
  87. "(MMIO addr = 0x%llx, write = %u, len = %u, data = %lx)\n "
  88. "(PIO port = 0x%x, write = %u, len = %u, count = %u, data = %x",
  89. ring_start, want_pio ? 4 : 8, want_pio ? "PIO" : "MMIO",
  90. want_pio ? (unsigned long long)io->pio_port : io->mmio_gpa,
  91. (want_pio ? io->pio_port : io->mmio_gpa) + io->ring_size - 1, run->exit_reason,
  92. run->exit_reason == KVM_EXIT_MMIO ? "MMIO" : run->exit_reason == KVM_EXIT_IO ? "PIO" : "other",
  93. run->mmio.phys_addr, run->mmio.is_write, run->mmio.len, *(uint64_t *)run->mmio.data,
  94. run->io.port, run->io.direction, run->io.size, run->io.count, pio_value);
  95. }
  96. static void vcpu_run_and_verify_coalesced_io(struct kvm_vcpu *vcpu,
  97. struct kvm_coalesced_io *io,
  98. uint32_t ring_start,
  99. uint32_t expected_exit)
  100. {
  101. struct kvm_coalesced_mmio_ring *ring = io->ring;
  102. int i;
  103. vcpu_run_and_verify_io_exit(vcpu, io, ring_start, expected_exit);
  104. TEST_ASSERT((ring->last + 1) % io->ring_size == ring->first,
  105. "Expected ring to be full (minus 1), first = %u, last = %u, max = %u, start = %u",
  106. ring->first, ring->last, io->ring_size, ring_start);
  107. for (i = 0; i < io->ring_size - 1; i++) {
  108. uint32_t idx = (ring->first + i) % io->ring_size;
  109. struct kvm_coalesced_mmio *entry = &ring->coalesced_mmio[idx];
  110. #ifdef __x86_64__
  111. if (i & 1)
  112. TEST_ASSERT(entry->phys_addr == io->pio_port &&
  113. entry->len == 4 && entry->pio &&
  114. *(uint32_t *)entry->data == io->pio_port + i,
  115. "Wanted 4-byte port I/O 0x%x = 0x%x in entry %u, got %u-byte %s 0x%llx = 0x%x",
  116. io->pio_port, io->pio_port + i, i,
  117. entry->len, entry->pio ? "PIO" : "MMIO",
  118. entry->phys_addr, *(uint32_t *)entry->data);
  119. else
  120. #endif
  121. TEST_ASSERT(entry->phys_addr == io->mmio_gpa &&
  122. entry->len == 8 && !entry->pio,
  123. "Wanted 8-byte MMIO to 0x%lx = %lx in entry %u, got %u-byte %s 0x%llx = 0x%lx",
  124. io->mmio_gpa, io->mmio_gpa + i, i,
  125. entry->len, entry->pio ? "PIO" : "MMIO",
  126. entry->phys_addr, *(uint64_t *)entry->data);
  127. }
  128. }
  129. static void test_coalesced_io(struct kvm_vcpu *vcpu,
  130. struct kvm_coalesced_io *io, uint32_t ring_start)
  131. {
  132. struct kvm_coalesced_mmio_ring *ring = io->ring;
  133. kvm_vm_register_coalesced_io(vcpu->vm, io->mmio_gpa, 8, false /* pio */);
  134. #ifdef __x86_64__
  135. kvm_vm_register_coalesced_io(vcpu->vm, io->pio_port, 8, true /* pio */);
  136. #endif
  137. vcpu_run_and_verify_coalesced_io(vcpu, io, ring_start, KVM_EXIT_MMIO);
  138. #ifdef __x86_64__
  139. vcpu_run_and_verify_coalesced_io(vcpu, io, ring_start, KVM_EXIT_IO);
  140. #endif
  141. /*
  142. * Verify ucall, which may use non-coalesced MMIO or PIO, generates an
  143. * immediate exit.
  144. */
  145. WRITE_ONCE(ring->first, ring_start);
  146. WRITE_ONCE(ring->last, ring_start);
  147. vcpu_run(vcpu);
  148. TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_SYNC);
  149. TEST_ASSERT_EQ(ring->first, ring_start);
  150. TEST_ASSERT_EQ(ring->last, ring_start);
  151. /* Verify that non-coalesced MMIO/PIO generates an exit to userspace. */
  152. kvm_vm_unregister_coalesced_io(vcpu->vm, io->mmio_gpa, 8, false /* pio */);
  153. vcpu_run_and_verify_io_exit(vcpu, io, ring_start, KVM_EXIT_MMIO);
  154. #ifdef __x86_64__
  155. kvm_vm_unregister_coalesced_io(vcpu->vm, io->pio_port, 8, true /* pio */);
  156. vcpu_run_and_verify_io_exit(vcpu, io, ring_start, KVM_EXIT_IO);
  157. #endif
  158. }
  159. int main(int argc, char *argv[])
  160. {
  161. struct kvm_vcpu *vcpu;
  162. struct kvm_vm *vm;
  163. int i;
  164. TEST_REQUIRE(kvm_has_cap(KVM_CAP_COALESCED_MMIO));
  165. #ifdef __x86_64__
  166. TEST_REQUIRE(kvm_has_cap(KVM_CAP_COALESCED_PIO));
  167. #endif
  168. vm = vm_create_with_one_vcpu(&vcpu, guest_code);
  169. kvm_builtin_io_ring = (struct kvm_coalesced_io) {
  170. /*
  171. * The I/O ring is a kernel-allocated page whose address is
  172. * relative to each vCPU's run page, with the page offset
  173. * provided by KVM in the return of KVM_CAP_COALESCED_MMIO.
  174. */
  175. .ring = (void *)vcpu->run +
  176. (kvm_check_cap(KVM_CAP_COALESCED_MMIO) * getpagesize()),
  177. /*
  178. * The size of the I/O ring is fixed, but KVM defines the sized
  179. * based on the kernel's PAGE_SIZE. Thus, userspace must query
  180. * the host's page size at runtime to compute the ring size.
  181. */
  182. .ring_size = (getpagesize() - sizeof(struct kvm_coalesced_mmio_ring)) /
  183. sizeof(struct kvm_coalesced_mmio),
  184. /*
  185. * Arbitrary address+port (MMIO mustn't overlap memslots), with
  186. * the MMIO GPA identity mapped in the guest.
  187. */
  188. .mmio_gpa = 4ull * SZ_1G,
  189. .mmio = (uint64_t *)(4ull * SZ_1G),
  190. .pio_port = 0x80,
  191. };
  192. virt_map(vm, (uint64_t)kvm_builtin_io_ring.mmio, kvm_builtin_io_ring.mmio_gpa, 1);
  193. sync_global_to_guest(vm, kvm_builtin_io_ring);
  194. vcpu_args_set(vcpu, 1, &kvm_builtin_io_ring);
  195. for (i = 0; i < kvm_builtin_io_ring.ring_size; i++)
  196. test_coalesced_io(vcpu, &kvm_builtin_io_ring, i);
  197. kvm_vm_free(vm);
  198. return 0;
  199. }