sync_regs_test.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /*
  2. * Test for x86 KVM_CAP_SYNC_REGS
  3. *
  4. * Copyright (C) 2018, Google LLC.
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2.
  7. *
  8. * Verifies expected behavior of x86 KVM_CAP_SYNC_REGS functionality,
  9. * including requesting an invalid register set, updates to/from values
  10. * in kvm_run.s.regs when kvm_valid_regs and kvm_dirty_regs are toggled.
  11. */
  12. #define _GNU_SOURCE /* for program_invocation_short_name */
  13. #include <fcntl.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <sys/ioctl.h>
  18. #include "test_util.h"
  19. #include "kvm_util.h"
  20. #include "x86.h"
  21. #define VCPU_ID 5
  22. #define PORT_HOST_SYNC 0x1000
  23. static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
  24. {
  25. __asm__ __volatile__("in %[port], %%al"
  26. :
  27. : [port]"d"(port), "D"(arg0), "S"(arg1)
  28. : "rax");
  29. }
  30. #define exit_to_l0(_port, _arg0, _arg1) \
  31. __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1))
  32. #define GUEST_ASSERT(_condition) do { \
  33. if (!(_condition)) \
  34. exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\
  35. } while (0)
  36. void guest_code(void)
  37. {
  38. for (;;) {
  39. exit_to_l0(PORT_HOST_SYNC, "hello", 0);
  40. asm volatile ("inc %r11");
  41. }
  42. }
  43. static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
  44. {
  45. #define REG_COMPARE(reg) \
  46. TEST_ASSERT(left->reg == right->reg, \
  47. "Register " #reg \
  48. " values did not match: 0x%llx, 0x%llx\n", \
  49. left->reg, right->reg)
  50. REG_COMPARE(rax);
  51. REG_COMPARE(rbx);
  52. REG_COMPARE(rcx);
  53. REG_COMPARE(rdx);
  54. REG_COMPARE(rsi);
  55. REG_COMPARE(rdi);
  56. REG_COMPARE(rsp);
  57. REG_COMPARE(rbp);
  58. REG_COMPARE(r8);
  59. REG_COMPARE(r9);
  60. REG_COMPARE(r10);
  61. REG_COMPARE(r11);
  62. REG_COMPARE(r12);
  63. REG_COMPARE(r13);
  64. REG_COMPARE(r14);
  65. REG_COMPARE(r15);
  66. REG_COMPARE(rip);
  67. REG_COMPARE(rflags);
  68. #undef REG_COMPARE
  69. }
  70. static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right)
  71. {
  72. }
  73. static void compare_vcpu_events(struct kvm_vcpu_events *left,
  74. struct kvm_vcpu_events *right)
  75. {
  76. }
  77. #define TEST_SYNC_FIELDS (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS)
  78. #define INVALID_SYNC_FIELD 0x80000000
  79. int main(int argc, char *argv[])
  80. {
  81. struct kvm_vm *vm;
  82. struct kvm_run *run;
  83. struct kvm_regs regs;
  84. struct kvm_sregs sregs;
  85. struct kvm_vcpu_events events;
  86. int rv, cap;
  87. /* Tell stdout not to buffer its content */
  88. setbuf(stdout, NULL);
  89. cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
  90. if ((cap & TEST_SYNC_FIELDS) != TEST_SYNC_FIELDS) {
  91. fprintf(stderr, "KVM_CAP_SYNC_REGS not supported, skipping test\n");
  92. exit(KSFT_SKIP);
  93. }
  94. if ((cap & INVALID_SYNC_FIELD) != 0) {
  95. fprintf(stderr, "The \"invalid\" field is not invalid, skipping test\n");
  96. exit(KSFT_SKIP);
  97. }
  98. /* Create VM */
  99. vm = vm_create_default(VCPU_ID, guest_code);
  100. run = vcpu_state(vm, VCPU_ID);
  101. /* Request reading invalid register set from VCPU. */
  102. run->kvm_valid_regs = INVALID_SYNC_FIELD;
  103. rv = _vcpu_run(vm, VCPU_ID);
  104. TEST_ASSERT(rv < 0 && errno == EINVAL,
  105. "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
  106. rv);
  107. vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
  108. run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
  109. rv = _vcpu_run(vm, VCPU_ID);
  110. TEST_ASSERT(rv < 0 && errno == EINVAL,
  111. "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
  112. rv);
  113. vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
  114. /* Request setting invalid register set into VCPU. */
  115. run->kvm_dirty_regs = INVALID_SYNC_FIELD;
  116. rv = _vcpu_run(vm, VCPU_ID);
  117. TEST_ASSERT(rv < 0 && errno == EINVAL,
  118. "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
  119. rv);
  120. vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
  121. run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
  122. rv = _vcpu_run(vm, VCPU_ID);
  123. TEST_ASSERT(rv < 0 && errno == EINVAL,
  124. "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
  125. rv);
  126. vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
  127. /* Request and verify all valid register sets. */
  128. /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */
  129. run->kvm_valid_regs = TEST_SYNC_FIELDS;
  130. rv = _vcpu_run(vm, VCPU_ID);
  131. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  132. "Unexpected exit reason: %u (%s),\n",
  133. run->exit_reason,
  134. exit_reason_str(run->exit_reason));
  135. vcpu_regs_get(vm, VCPU_ID, &regs);
  136. compare_regs(&regs, &run->s.regs.regs);
  137. vcpu_sregs_get(vm, VCPU_ID, &sregs);
  138. compare_sregs(&sregs, &run->s.regs.sregs);
  139. vcpu_events_get(vm, VCPU_ID, &events);
  140. compare_vcpu_events(&events, &run->s.regs.events);
  141. /* Set and verify various register values. */
  142. run->s.regs.regs.r11 = 0xBAD1DEA;
  143. run->s.regs.sregs.apic_base = 1 << 11;
  144. /* TODO run->s.regs.events.XYZ = ABC; */
  145. run->kvm_valid_regs = TEST_SYNC_FIELDS;
  146. run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS;
  147. rv = _vcpu_run(vm, VCPU_ID);
  148. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  149. "Unexpected exit reason: %u (%s),\n",
  150. run->exit_reason,
  151. exit_reason_str(run->exit_reason));
  152. TEST_ASSERT(run->s.regs.regs.r11 == 0xBAD1DEA + 1,
  153. "r11 sync regs value incorrect 0x%llx.",
  154. run->s.regs.regs.r11);
  155. TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11,
  156. "apic_base sync regs value incorrect 0x%llx.",
  157. run->s.regs.sregs.apic_base);
  158. vcpu_regs_get(vm, VCPU_ID, &regs);
  159. compare_regs(&regs, &run->s.regs.regs);
  160. vcpu_sregs_get(vm, VCPU_ID, &sregs);
  161. compare_sregs(&sregs, &run->s.regs.sregs);
  162. vcpu_events_get(vm, VCPU_ID, &events);
  163. compare_vcpu_events(&events, &run->s.regs.events);
  164. /* Clear kvm_dirty_regs bits, verify new s.regs values are
  165. * overwritten with existing guest values.
  166. */
  167. run->kvm_valid_regs = TEST_SYNC_FIELDS;
  168. run->kvm_dirty_regs = 0;
  169. run->s.regs.regs.r11 = 0xDEADBEEF;
  170. rv = _vcpu_run(vm, VCPU_ID);
  171. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  172. "Unexpected exit reason: %u (%s),\n",
  173. run->exit_reason,
  174. exit_reason_str(run->exit_reason));
  175. TEST_ASSERT(run->s.regs.regs.r11 != 0xDEADBEEF,
  176. "r11 sync regs value incorrect 0x%llx.",
  177. run->s.regs.regs.r11);
  178. /* Clear kvm_valid_regs bits and kvm_dirty_bits.
  179. * Verify s.regs values are not overwritten with existing guest values
  180. * and that guest values are not overwritten with kvm_sync_regs values.
  181. */
  182. run->kvm_valid_regs = 0;
  183. run->kvm_dirty_regs = 0;
  184. run->s.regs.regs.r11 = 0xAAAA;
  185. regs.r11 = 0xBAC0;
  186. vcpu_regs_set(vm, VCPU_ID, &regs);
  187. rv = _vcpu_run(vm, VCPU_ID);
  188. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  189. "Unexpected exit reason: %u (%s),\n",
  190. run->exit_reason,
  191. exit_reason_str(run->exit_reason));
  192. TEST_ASSERT(run->s.regs.regs.r11 == 0xAAAA,
  193. "r11 sync regs value incorrect 0x%llx.",
  194. run->s.regs.regs.r11);
  195. vcpu_regs_get(vm, VCPU_ID, &regs);
  196. TEST_ASSERT(regs.r11 == 0xBAC0 + 1,
  197. "r11 guest value incorrect 0x%llx.",
  198. regs.r11);
  199. /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten
  200. * with existing guest values but that guest values are overwritten
  201. * with kvm_sync_regs values.
  202. */
  203. run->kvm_valid_regs = 0;
  204. run->kvm_dirty_regs = TEST_SYNC_FIELDS;
  205. run->s.regs.regs.r11 = 0xBBBB;
  206. rv = _vcpu_run(vm, VCPU_ID);
  207. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  208. "Unexpected exit reason: %u (%s),\n",
  209. run->exit_reason,
  210. exit_reason_str(run->exit_reason));
  211. TEST_ASSERT(run->s.regs.regs.r11 == 0xBBBB,
  212. "r11 sync regs value incorrect 0x%llx.",
  213. run->s.regs.regs.r11);
  214. vcpu_regs_get(vm, VCPU_ID, &regs);
  215. TEST_ASSERT(regs.r11 == 0xBBBB + 1,
  216. "r11 guest value incorrect 0x%llx.",
  217. regs.r11);
  218. kvm_vm_free(vm);
  219. return 0;
  220. }