sync_regs_test.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. void guest_code(void)
  23. {
  24. for (;;) {
  25. GUEST_SYNC(0);
  26. asm volatile ("inc %r11");
  27. }
  28. }
  29. static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
  30. {
  31. #define REG_COMPARE(reg) \
  32. TEST_ASSERT(left->reg == right->reg, \
  33. "Register " #reg \
  34. " values did not match: 0x%llx, 0x%llx\n", \
  35. left->reg, right->reg)
  36. REG_COMPARE(rax);
  37. REG_COMPARE(rbx);
  38. REG_COMPARE(rcx);
  39. REG_COMPARE(rdx);
  40. REG_COMPARE(rsi);
  41. REG_COMPARE(rdi);
  42. REG_COMPARE(rsp);
  43. REG_COMPARE(rbp);
  44. REG_COMPARE(r8);
  45. REG_COMPARE(r9);
  46. REG_COMPARE(r10);
  47. REG_COMPARE(r11);
  48. REG_COMPARE(r12);
  49. REG_COMPARE(r13);
  50. REG_COMPARE(r14);
  51. REG_COMPARE(r15);
  52. REG_COMPARE(rip);
  53. REG_COMPARE(rflags);
  54. #undef REG_COMPARE
  55. }
  56. static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right)
  57. {
  58. }
  59. static void compare_vcpu_events(struct kvm_vcpu_events *left,
  60. struct kvm_vcpu_events *right)
  61. {
  62. }
  63. #define TEST_SYNC_FIELDS (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS)
  64. #define INVALID_SYNC_FIELD 0x80000000
  65. int main(int argc, char *argv[])
  66. {
  67. struct kvm_vm *vm;
  68. struct kvm_run *run;
  69. struct kvm_regs regs;
  70. struct kvm_sregs sregs;
  71. struct kvm_vcpu_events events;
  72. int rv, cap;
  73. /* Tell stdout not to buffer its content */
  74. setbuf(stdout, NULL);
  75. cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
  76. if ((cap & TEST_SYNC_FIELDS) != TEST_SYNC_FIELDS) {
  77. fprintf(stderr, "KVM_CAP_SYNC_REGS not supported, skipping test\n");
  78. exit(KSFT_SKIP);
  79. }
  80. if ((cap & INVALID_SYNC_FIELD) != 0) {
  81. fprintf(stderr, "The \"invalid\" field is not invalid, skipping test\n");
  82. exit(KSFT_SKIP);
  83. }
  84. /* Create VM */
  85. vm = vm_create_default(VCPU_ID, 0, guest_code);
  86. run = vcpu_state(vm, VCPU_ID);
  87. /* Request reading invalid register set from VCPU. */
  88. run->kvm_valid_regs = INVALID_SYNC_FIELD;
  89. rv = _vcpu_run(vm, VCPU_ID);
  90. TEST_ASSERT(rv < 0 && errno == EINVAL,
  91. "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
  92. rv);
  93. vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
  94. run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
  95. rv = _vcpu_run(vm, VCPU_ID);
  96. TEST_ASSERT(rv < 0 && errno == EINVAL,
  97. "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
  98. rv);
  99. vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
  100. /* Request setting invalid register set into VCPU. */
  101. run->kvm_dirty_regs = INVALID_SYNC_FIELD;
  102. rv = _vcpu_run(vm, VCPU_ID);
  103. TEST_ASSERT(rv < 0 && errno == EINVAL,
  104. "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
  105. rv);
  106. vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
  107. run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
  108. rv = _vcpu_run(vm, VCPU_ID);
  109. TEST_ASSERT(rv < 0 && errno == EINVAL,
  110. "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
  111. rv);
  112. vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
  113. /* Request and verify all valid register sets. */
  114. /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */
  115. run->kvm_valid_regs = TEST_SYNC_FIELDS;
  116. rv = _vcpu_run(vm, VCPU_ID);
  117. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  118. "Unexpected exit reason: %u (%s),\n",
  119. run->exit_reason,
  120. exit_reason_str(run->exit_reason));
  121. vcpu_regs_get(vm, VCPU_ID, &regs);
  122. compare_regs(&regs, &run->s.regs.regs);
  123. vcpu_sregs_get(vm, VCPU_ID, &sregs);
  124. compare_sregs(&sregs, &run->s.regs.sregs);
  125. vcpu_events_get(vm, VCPU_ID, &events);
  126. compare_vcpu_events(&events, &run->s.regs.events);
  127. /* Set and verify various register values. */
  128. run->s.regs.regs.r11 = 0xBAD1DEA;
  129. run->s.regs.sregs.apic_base = 1 << 11;
  130. /* TODO run->s.regs.events.XYZ = ABC; */
  131. run->kvm_valid_regs = TEST_SYNC_FIELDS;
  132. run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS;
  133. rv = _vcpu_run(vm, VCPU_ID);
  134. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  135. "Unexpected exit reason: %u (%s),\n",
  136. run->exit_reason,
  137. exit_reason_str(run->exit_reason));
  138. TEST_ASSERT(run->s.regs.regs.r11 == 0xBAD1DEA + 1,
  139. "r11 sync regs value incorrect 0x%llx.",
  140. run->s.regs.regs.r11);
  141. TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11,
  142. "apic_base sync regs value incorrect 0x%llx.",
  143. run->s.regs.sregs.apic_base);
  144. vcpu_regs_get(vm, VCPU_ID, &regs);
  145. compare_regs(&regs, &run->s.regs.regs);
  146. vcpu_sregs_get(vm, VCPU_ID, &sregs);
  147. compare_sregs(&sregs, &run->s.regs.sregs);
  148. vcpu_events_get(vm, VCPU_ID, &events);
  149. compare_vcpu_events(&events, &run->s.regs.events);
  150. /* Clear kvm_dirty_regs bits, verify new s.regs values are
  151. * overwritten with existing guest values.
  152. */
  153. run->kvm_valid_regs = TEST_SYNC_FIELDS;
  154. run->kvm_dirty_regs = 0;
  155. run->s.regs.regs.r11 = 0xDEADBEEF;
  156. rv = _vcpu_run(vm, VCPU_ID);
  157. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  158. "Unexpected exit reason: %u (%s),\n",
  159. run->exit_reason,
  160. exit_reason_str(run->exit_reason));
  161. TEST_ASSERT(run->s.regs.regs.r11 != 0xDEADBEEF,
  162. "r11 sync regs value incorrect 0x%llx.",
  163. run->s.regs.regs.r11);
  164. /* Clear kvm_valid_regs bits and kvm_dirty_bits.
  165. * Verify s.regs values are not overwritten with existing guest values
  166. * and that guest values are not overwritten with kvm_sync_regs values.
  167. */
  168. run->kvm_valid_regs = 0;
  169. run->kvm_dirty_regs = 0;
  170. run->s.regs.regs.r11 = 0xAAAA;
  171. regs.r11 = 0xBAC0;
  172. vcpu_regs_set(vm, VCPU_ID, &regs);
  173. rv = _vcpu_run(vm, VCPU_ID);
  174. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  175. "Unexpected exit reason: %u (%s),\n",
  176. run->exit_reason,
  177. exit_reason_str(run->exit_reason));
  178. TEST_ASSERT(run->s.regs.regs.r11 == 0xAAAA,
  179. "r11 sync regs value incorrect 0x%llx.",
  180. run->s.regs.regs.r11);
  181. vcpu_regs_get(vm, VCPU_ID, &regs);
  182. TEST_ASSERT(regs.r11 == 0xBAC0 + 1,
  183. "r11 guest value incorrect 0x%llx.",
  184. regs.r11);
  185. /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten
  186. * with existing guest values but that guest values are overwritten
  187. * with kvm_sync_regs values.
  188. */
  189. run->kvm_valid_regs = 0;
  190. run->kvm_dirty_regs = TEST_SYNC_FIELDS;
  191. run->s.regs.regs.r11 = 0xBBBB;
  192. rv = _vcpu_run(vm, VCPU_ID);
  193. TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  194. "Unexpected exit reason: %u (%s),\n",
  195. run->exit_reason,
  196. exit_reason_str(run->exit_reason));
  197. TEST_ASSERT(run->s.regs.regs.r11 == 0xBBBB,
  198. "r11 sync regs value incorrect 0x%llx.",
  199. run->s.regs.regs.r11);
  200. vcpu_regs_get(vm, VCPU_ID, &regs);
  201. TEST_ASSERT(regs.r11 == 0xBBBB + 1,
  202. "r11 guest value incorrect 0x%llx.",
  203. regs.r11);
  204. kvm_vm_free(vm);
  205. return 0;
  206. }