hyperv_tlb_flush.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Hyper-V HvFlushVirtualAddress{List,Space}{,Ex} tests
  4. *
  5. * Copyright (C) 2022, Red Hat, Inc.
  6. *
  7. */
  8. #include <asm/barrier.h>
  9. #include <pthread.h>
  10. #include <inttypes.h>
  11. #include "kvm_util.h"
  12. #include "processor.h"
  13. #include "hyperv.h"
  14. #include "test_util.h"
  15. #include "vmx.h"
  16. #define WORKER_VCPU_ID_1 2
  17. #define WORKER_VCPU_ID_2 65
  18. #define NTRY 100
  19. #define NTEST_PAGES 2
  20. struct hv_vpset {
  21. u64 format;
  22. u64 valid_bank_mask;
  23. u64 bank_contents[];
  24. };
  25. enum HV_GENERIC_SET_FORMAT {
  26. HV_GENERIC_SET_SPARSE_4K,
  27. HV_GENERIC_SET_ALL,
  28. };
  29. #define HV_FLUSH_ALL_PROCESSORS BIT(0)
  30. #define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1)
  31. #define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2)
  32. #define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3)
  33. /* HvFlushVirtualAddressSpace, HvFlushVirtualAddressList hypercalls */
  34. struct hv_tlb_flush {
  35. u64 address_space;
  36. u64 flags;
  37. u64 processor_mask;
  38. u64 gva_list[];
  39. } __packed;
  40. /* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */
  41. struct hv_tlb_flush_ex {
  42. u64 address_space;
  43. u64 flags;
  44. struct hv_vpset hv_vp_set;
  45. u64 gva_list[];
  46. } __packed;
  47. /*
  48. * Pass the following info to 'workers' and 'sender'
  49. * - Hypercall page's GVA
  50. * - Hypercall page's GPA
  51. * - Test pages GVA
  52. * - GVAs of the test pages' PTEs
  53. */
  54. struct test_data {
  55. vm_vaddr_t hcall_gva;
  56. vm_paddr_t hcall_gpa;
  57. vm_vaddr_t test_pages;
  58. vm_vaddr_t test_pages_pte[NTEST_PAGES];
  59. };
  60. /* 'Worker' vCPU code checking the contents of the test page */
  61. static void worker_guest_code(vm_vaddr_t test_data)
  62. {
  63. struct test_data *data = (struct test_data *)test_data;
  64. u32 vcpu_id = rdmsr(HV_X64_MSR_VP_INDEX);
  65. void *exp_page = (void *)data->test_pages + PAGE_SIZE * NTEST_PAGES;
  66. u64 *this_cpu = (u64 *)(exp_page + vcpu_id * sizeof(u64));
  67. u64 expected, val;
  68. x2apic_enable();
  69. wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID);
  70. for (;;) {
  71. cpu_relax();
  72. expected = READ_ONCE(*this_cpu);
  73. /*
  74. * Make sure the value in the test page is read after reading
  75. * the expectation for the first time. Pairs with wmb() in
  76. * prepare_to_test().
  77. */
  78. rmb();
  79. val = READ_ONCE(*(u64 *)data->test_pages);
  80. /*
  81. * Make sure the value in the test page is read after before
  82. * reading the expectation for the second time. Pairs with wmb()
  83. * post_test().
  84. */
  85. rmb();
  86. /*
  87. * '0' indicates the sender is between iterations, wait until
  88. * the sender is ready for this vCPU to start checking again.
  89. */
  90. if (!expected)
  91. continue;
  92. /*
  93. * Re-read the per-vCPU byte to ensure the sender didn't move
  94. * onto a new iteration.
  95. */
  96. if (expected != READ_ONCE(*this_cpu))
  97. continue;
  98. GUEST_ASSERT(val == expected);
  99. }
  100. }
  101. /*
  102. * Write per-CPU info indicating what each 'worker' CPU is supposed to see in
  103. * test page. '0' means don't check.
  104. */
  105. static void set_expected_val(void *addr, u64 val, int vcpu_id)
  106. {
  107. void *exp_page = addr + PAGE_SIZE * NTEST_PAGES;
  108. *(u64 *)(exp_page + vcpu_id * sizeof(u64)) = val;
  109. }
  110. /*
  111. * Update PTEs swapping two test pages.
  112. * TODO: use swap()/xchg() when these are provided.
  113. */
  114. static void swap_two_test_pages(vm_paddr_t pte_gva1, vm_paddr_t pte_gva2)
  115. {
  116. uint64_t tmp = *(uint64_t *)pte_gva1;
  117. *(uint64_t *)pte_gva1 = *(uint64_t *)pte_gva2;
  118. *(uint64_t *)pte_gva2 = tmp;
  119. }
  120. /*
  121. * TODO: replace the silly NOP loop with a proper udelay() implementation.
  122. */
  123. static inline void do_delay(void)
  124. {
  125. int i;
  126. for (i = 0; i < 1000000; i++)
  127. asm volatile("nop");
  128. }
  129. /*
  130. * Prepare to test: 'disable' workers by setting the expectation to '0',
  131. * clear hypercall input page and then swap two test pages.
  132. */
  133. static inline void prepare_to_test(struct test_data *data)
  134. {
  135. /* Clear hypercall input page */
  136. memset((void *)data->hcall_gva, 0, PAGE_SIZE);
  137. /* 'Disable' workers */
  138. set_expected_val((void *)data->test_pages, 0x0, WORKER_VCPU_ID_1);
  139. set_expected_val((void *)data->test_pages, 0x0, WORKER_VCPU_ID_2);
  140. /* Make sure workers are 'disabled' before we swap PTEs. */
  141. wmb();
  142. /* Make sure workers have enough time to notice */
  143. do_delay();
  144. /* Swap test page mappings */
  145. swap_two_test_pages(data->test_pages_pte[0], data->test_pages_pte[1]);
  146. }
  147. /*
  148. * Finalize the test: check hypercall resule set the expected val for
  149. * 'worker' CPUs and give them some time to test.
  150. */
  151. static inline void post_test(struct test_data *data, u64 exp1, u64 exp2)
  152. {
  153. /* Make sure we change the expectation after swapping PTEs */
  154. wmb();
  155. /* Set the expectation for workers, '0' means don't test */
  156. set_expected_val((void *)data->test_pages, exp1, WORKER_VCPU_ID_1);
  157. set_expected_val((void *)data->test_pages, exp2, WORKER_VCPU_ID_2);
  158. /* Make sure workers have enough time to test */
  159. do_delay();
  160. }
  161. #define TESTVAL1 0x0101010101010101
  162. #define TESTVAL2 0x0202020202020202
  163. /* Main vCPU doing the test */
  164. static void sender_guest_code(vm_vaddr_t test_data)
  165. {
  166. struct test_data *data = (struct test_data *)test_data;
  167. struct hv_tlb_flush *flush = (struct hv_tlb_flush *)data->hcall_gva;
  168. struct hv_tlb_flush_ex *flush_ex = (struct hv_tlb_flush_ex *)data->hcall_gva;
  169. vm_paddr_t hcall_gpa = data->hcall_gpa;
  170. int i, stage = 1;
  171. wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID);
  172. wrmsr(HV_X64_MSR_HYPERCALL, data->hcall_gpa);
  173. /* "Slow" hypercalls */
  174. GUEST_SYNC(stage++);
  175. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE for WORKER_VCPU_ID_1 */
  176. for (i = 0; i < NTRY; i++) {
  177. prepare_to_test(data);
  178. flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  179. flush->processor_mask = BIT(WORKER_VCPU_ID_1);
  180. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE, hcall_gpa,
  181. hcall_gpa + PAGE_SIZE);
  182. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2, 0x0);
  183. }
  184. GUEST_SYNC(stage++);
  185. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST for WORKER_VCPU_ID_1 */
  186. for (i = 0; i < NTRY; i++) {
  187. prepare_to_test(data);
  188. flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  189. flush->processor_mask = BIT(WORKER_VCPU_ID_1);
  190. flush->gva_list[0] = (u64)data->test_pages;
  191. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST |
  192. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  193. hcall_gpa, hcall_gpa + PAGE_SIZE);
  194. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2, 0x0);
  195. }
  196. GUEST_SYNC(stage++);
  197. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE for HV_FLUSH_ALL_PROCESSORS */
  198. for (i = 0; i < NTRY; i++) {
  199. prepare_to_test(data);
  200. flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES |
  201. HV_FLUSH_ALL_PROCESSORS;
  202. flush->processor_mask = 0;
  203. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE, hcall_gpa,
  204. hcall_gpa + PAGE_SIZE);
  205. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2, i % 2 ? TESTVAL1 : TESTVAL2);
  206. }
  207. GUEST_SYNC(stage++);
  208. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST for HV_FLUSH_ALL_PROCESSORS */
  209. for (i = 0; i < NTRY; i++) {
  210. prepare_to_test(data);
  211. flush->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES |
  212. HV_FLUSH_ALL_PROCESSORS;
  213. flush->gva_list[0] = (u64)data->test_pages;
  214. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST |
  215. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  216. hcall_gpa, hcall_gpa + PAGE_SIZE);
  217. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  218. i % 2 ? TESTVAL1 : TESTVAL2);
  219. }
  220. GUEST_SYNC(stage++);
  221. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX for WORKER_VCPU_ID_2 */
  222. for (i = 0; i < NTRY; i++) {
  223. prepare_to_test(data);
  224. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  225. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  226. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_2 / 64);
  227. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  228. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX |
  229. (1 << HV_HYPERCALL_VARHEAD_OFFSET),
  230. hcall_gpa, hcall_gpa + PAGE_SIZE);
  231. post_test(data, 0x0, i % 2 ? TESTVAL1 : TESTVAL2);
  232. }
  233. GUEST_SYNC(stage++);
  234. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX for WORKER_VCPU_ID_2 */
  235. for (i = 0; i < NTRY; i++) {
  236. prepare_to_test(data);
  237. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  238. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  239. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_2 / 64);
  240. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  241. /* bank_contents and gva_list occupy the same space, thus [1] */
  242. flush_ex->gva_list[1] = (u64)data->test_pages;
  243. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX |
  244. (1 << HV_HYPERCALL_VARHEAD_OFFSET) |
  245. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  246. hcall_gpa, hcall_gpa + PAGE_SIZE);
  247. post_test(data, 0x0, i % 2 ? TESTVAL1 : TESTVAL2);
  248. }
  249. GUEST_SYNC(stage++);
  250. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX for both vCPUs */
  251. for (i = 0; i < NTRY; i++) {
  252. prepare_to_test(data);
  253. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  254. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  255. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_2 / 64) |
  256. BIT_ULL(WORKER_VCPU_ID_1 / 64);
  257. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_1 % 64);
  258. flush_ex->hv_vp_set.bank_contents[1] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  259. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX |
  260. (2 << HV_HYPERCALL_VARHEAD_OFFSET),
  261. hcall_gpa, hcall_gpa + PAGE_SIZE);
  262. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  263. i % 2 ? TESTVAL1 : TESTVAL2);
  264. }
  265. GUEST_SYNC(stage++);
  266. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX for both vCPUs */
  267. for (i = 0; i < NTRY; i++) {
  268. prepare_to_test(data);
  269. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  270. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  271. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_1 / 64) |
  272. BIT_ULL(WORKER_VCPU_ID_2 / 64);
  273. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_1 % 64);
  274. flush_ex->hv_vp_set.bank_contents[1] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  275. /* bank_contents and gva_list occupy the same space, thus [2] */
  276. flush_ex->gva_list[2] = (u64)data->test_pages;
  277. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX |
  278. (2 << HV_HYPERCALL_VARHEAD_OFFSET) |
  279. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  280. hcall_gpa, hcall_gpa + PAGE_SIZE);
  281. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  282. i % 2 ? TESTVAL1 : TESTVAL2);
  283. }
  284. GUEST_SYNC(stage++);
  285. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX for HV_GENERIC_SET_ALL */
  286. for (i = 0; i < NTRY; i++) {
  287. prepare_to_test(data);
  288. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  289. flush_ex->hv_vp_set.format = HV_GENERIC_SET_ALL;
  290. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX,
  291. hcall_gpa, hcall_gpa + PAGE_SIZE);
  292. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  293. i % 2 ? TESTVAL1 : TESTVAL2);
  294. }
  295. GUEST_SYNC(stage++);
  296. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX for HV_GENERIC_SET_ALL */
  297. for (i = 0; i < NTRY; i++) {
  298. prepare_to_test(data);
  299. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  300. flush_ex->hv_vp_set.format = HV_GENERIC_SET_ALL;
  301. flush_ex->gva_list[0] = (u64)data->test_pages;
  302. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX |
  303. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  304. hcall_gpa, hcall_gpa + PAGE_SIZE);
  305. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  306. i % 2 ? TESTVAL1 : TESTVAL2);
  307. }
  308. /* "Fast" hypercalls */
  309. GUEST_SYNC(stage++);
  310. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE for WORKER_VCPU_ID_1 */
  311. for (i = 0; i < NTRY; i++) {
  312. prepare_to_test(data);
  313. flush->processor_mask = BIT(WORKER_VCPU_ID_1);
  314. hyperv_write_xmm_input(&flush->processor_mask, 1);
  315. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE |
  316. HV_HYPERCALL_FAST_BIT, 0x0,
  317. HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  318. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2, 0x0);
  319. }
  320. GUEST_SYNC(stage++);
  321. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST for WORKER_VCPU_ID_1 */
  322. for (i = 0; i < NTRY; i++) {
  323. prepare_to_test(data);
  324. flush->processor_mask = BIT(WORKER_VCPU_ID_1);
  325. flush->gva_list[0] = (u64)data->test_pages;
  326. hyperv_write_xmm_input(&flush->processor_mask, 1);
  327. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST |
  328. HV_HYPERCALL_FAST_BIT |
  329. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  330. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  331. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2, 0x0);
  332. }
  333. GUEST_SYNC(stage++);
  334. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE for HV_FLUSH_ALL_PROCESSORS */
  335. for (i = 0; i < NTRY; i++) {
  336. prepare_to_test(data);
  337. hyperv_write_xmm_input(&flush->processor_mask, 1);
  338. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE |
  339. HV_HYPERCALL_FAST_BIT, 0x0,
  340. HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES |
  341. HV_FLUSH_ALL_PROCESSORS);
  342. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  343. i % 2 ? TESTVAL1 : TESTVAL2);
  344. }
  345. GUEST_SYNC(stage++);
  346. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST for HV_FLUSH_ALL_PROCESSORS */
  347. for (i = 0; i < NTRY; i++) {
  348. prepare_to_test(data);
  349. flush->gva_list[0] = (u64)data->test_pages;
  350. hyperv_write_xmm_input(&flush->processor_mask, 1);
  351. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST |
  352. HV_HYPERCALL_FAST_BIT |
  353. (1UL << HV_HYPERCALL_REP_COMP_OFFSET), 0x0,
  354. HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES |
  355. HV_FLUSH_ALL_PROCESSORS);
  356. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  357. i % 2 ? TESTVAL1 : TESTVAL2);
  358. }
  359. GUEST_SYNC(stage++);
  360. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX for WORKER_VCPU_ID_2 */
  361. for (i = 0; i < NTRY; i++) {
  362. prepare_to_test(data);
  363. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  364. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_2 / 64);
  365. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  366. hyperv_write_xmm_input(&flush_ex->hv_vp_set, 2);
  367. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX |
  368. HV_HYPERCALL_FAST_BIT |
  369. (1 << HV_HYPERCALL_VARHEAD_OFFSET),
  370. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  371. post_test(data, 0x0, i % 2 ? TESTVAL1 : TESTVAL2);
  372. }
  373. GUEST_SYNC(stage++);
  374. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX for WORKER_VCPU_ID_2 */
  375. for (i = 0; i < NTRY; i++) {
  376. prepare_to_test(data);
  377. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  378. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_2 / 64);
  379. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  380. /* bank_contents and gva_list occupy the same space, thus [1] */
  381. flush_ex->gva_list[1] = (u64)data->test_pages;
  382. hyperv_write_xmm_input(&flush_ex->hv_vp_set, 2);
  383. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX |
  384. HV_HYPERCALL_FAST_BIT |
  385. (1 << HV_HYPERCALL_VARHEAD_OFFSET) |
  386. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  387. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  388. post_test(data, 0x0, i % 2 ? TESTVAL1 : TESTVAL2);
  389. }
  390. GUEST_SYNC(stage++);
  391. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX for both vCPUs */
  392. for (i = 0; i < NTRY; i++) {
  393. prepare_to_test(data);
  394. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  395. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_2 / 64) |
  396. BIT_ULL(WORKER_VCPU_ID_1 / 64);
  397. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_1 % 64);
  398. flush_ex->hv_vp_set.bank_contents[1] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  399. hyperv_write_xmm_input(&flush_ex->hv_vp_set, 2);
  400. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX |
  401. HV_HYPERCALL_FAST_BIT |
  402. (2 << HV_HYPERCALL_VARHEAD_OFFSET),
  403. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  404. post_test(data, i % 2 ? TESTVAL1 :
  405. TESTVAL2, i % 2 ? TESTVAL1 : TESTVAL2);
  406. }
  407. GUEST_SYNC(stage++);
  408. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX for both vCPUs */
  409. for (i = 0; i < NTRY; i++) {
  410. prepare_to_test(data);
  411. flush_ex->hv_vp_set.format = HV_GENERIC_SET_SPARSE_4K;
  412. flush_ex->hv_vp_set.valid_bank_mask = BIT_ULL(WORKER_VCPU_ID_1 / 64) |
  413. BIT_ULL(WORKER_VCPU_ID_2 / 64);
  414. flush_ex->hv_vp_set.bank_contents[0] = BIT_ULL(WORKER_VCPU_ID_1 % 64);
  415. flush_ex->hv_vp_set.bank_contents[1] = BIT_ULL(WORKER_VCPU_ID_2 % 64);
  416. /* bank_contents and gva_list occupy the same space, thus [2] */
  417. flush_ex->gva_list[2] = (u64)data->test_pages;
  418. hyperv_write_xmm_input(&flush_ex->hv_vp_set, 3);
  419. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX |
  420. HV_HYPERCALL_FAST_BIT |
  421. (2 << HV_HYPERCALL_VARHEAD_OFFSET) |
  422. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  423. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  424. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  425. i % 2 ? TESTVAL1 : TESTVAL2);
  426. }
  427. GUEST_SYNC(stage++);
  428. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX for HV_GENERIC_SET_ALL */
  429. for (i = 0; i < NTRY; i++) {
  430. prepare_to_test(data);
  431. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  432. flush_ex->hv_vp_set.format = HV_GENERIC_SET_ALL;
  433. hyperv_write_xmm_input(&flush_ex->hv_vp_set, 2);
  434. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX |
  435. HV_HYPERCALL_FAST_BIT,
  436. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  437. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  438. i % 2 ? TESTVAL1 : TESTVAL2);
  439. }
  440. GUEST_SYNC(stage++);
  441. /* HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX for HV_GENERIC_SET_ALL */
  442. for (i = 0; i < NTRY; i++) {
  443. prepare_to_test(data);
  444. flush_ex->flags = HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES;
  445. flush_ex->hv_vp_set.format = HV_GENERIC_SET_ALL;
  446. flush_ex->gva_list[0] = (u64)data->test_pages;
  447. hyperv_write_xmm_input(&flush_ex->hv_vp_set, 2);
  448. hyperv_hypercall(HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX |
  449. HV_HYPERCALL_FAST_BIT |
  450. (1UL << HV_HYPERCALL_REP_COMP_OFFSET),
  451. 0x0, HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES);
  452. post_test(data, i % 2 ? TESTVAL1 : TESTVAL2,
  453. i % 2 ? TESTVAL1 : TESTVAL2);
  454. }
  455. GUEST_DONE();
  456. }
  457. static void *vcpu_thread(void *arg)
  458. {
  459. struct kvm_vcpu *vcpu = (struct kvm_vcpu *)arg;
  460. struct ucall uc;
  461. int old;
  462. int r;
  463. r = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
  464. TEST_ASSERT(!r, "pthread_setcanceltype failed on vcpu_id=%u with errno=%d",
  465. vcpu->id, r);
  466. vcpu_run(vcpu);
  467. TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
  468. switch (get_ucall(vcpu, &uc)) {
  469. case UCALL_ABORT:
  470. REPORT_GUEST_ASSERT(uc);
  471. /* NOT REACHED */
  472. default:
  473. TEST_FAIL("Unexpected ucall %lu, vCPU %d", uc.cmd, vcpu->id);
  474. }
  475. return NULL;
  476. }
  477. static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)
  478. {
  479. void *retval;
  480. int r;
  481. r = pthread_cancel(thread);
  482. TEST_ASSERT(!r, "pthread_cancel on vcpu_id=%d failed with errno=%d",
  483. vcpu->id, r);
  484. r = pthread_join(thread, &retval);
  485. TEST_ASSERT(!r, "pthread_join on vcpu_id=%d failed with errno=%d",
  486. vcpu->id, r);
  487. TEST_ASSERT(retval == PTHREAD_CANCELED,
  488. "expected retval=%p, got %p", PTHREAD_CANCELED,
  489. retval);
  490. }
  491. int main(int argc, char *argv[])
  492. {
  493. struct kvm_vm *vm;
  494. struct kvm_vcpu *vcpu[3];
  495. pthread_t threads[2];
  496. vm_vaddr_t test_data_page, gva;
  497. vm_paddr_t gpa;
  498. uint64_t *pte;
  499. struct test_data *data;
  500. struct ucall uc;
  501. int stage = 1, r, i;
  502. TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TLBFLUSH));
  503. vm = vm_create_with_one_vcpu(&vcpu[0], sender_guest_code);
  504. /* Test data page */
  505. test_data_page = vm_vaddr_alloc_page(vm);
  506. data = (struct test_data *)addr_gva2hva(vm, test_data_page);
  507. /* Hypercall input/output */
  508. data->hcall_gva = vm_vaddr_alloc_pages(vm, 2);
  509. data->hcall_gpa = addr_gva2gpa(vm, data->hcall_gva);
  510. memset(addr_gva2hva(vm, data->hcall_gva), 0x0, 2 * PAGE_SIZE);
  511. /*
  512. * Test pages: the first one is filled with '0x01's, the second with '0x02's
  513. * and the test will swap their mappings. The third page keeps the indication
  514. * about the current state of mappings.
  515. */
  516. data->test_pages = vm_vaddr_alloc_pages(vm, NTEST_PAGES + 1);
  517. for (i = 0; i < NTEST_PAGES; i++)
  518. memset(addr_gva2hva(vm, data->test_pages + PAGE_SIZE * i),
  519. (u8)(i + 1), PAGE_SIZE);
  520. set_expected_val(addr_gva2hva(vm, data->test_pages), 0x0, WORKER_VCPU_ID_1);
  521. set_expected_val(addr_gva2hva(vm, data->test_pages), 0x0, WORKER_VCPU_ID_2);
  522. /*
  523. * Get PTE pointers for test pages and map them inside the guest.
  524. * Use separate page for each PTE for simplicity.
  525. */
  526. gva = vm_vaddr_unused_gap(vm, NTEST_PAGES * PAGE_SIZE, KVM_UTIL_MIN_VADDR);
  527. for (i = 0; i < NTEST_PAGES; i++) {
  528. pte = vm_get_pte(vm, data->test_pages + i * PAGE_SIZE);
  529. gpa = addr_hva2gpa(vm, pte);
  530. virt_pg_map(vm, gva + PAGE_SIZE * i, gpa & PAGE_MASK);
  531. data->test_pages_pte[i] = gva + (gpa & ~PAGE_MASK);
  532. }
  533. /*
  534. * Sender vCPU which performs the test: swaps test pages, sets expectation
  535. * for 'workers' and issues TLB flush hypercalls.
  536. */
  537. vcpu_args_set(vcpu[0], 1, test_data_page);
  538. vcpu_set_hv_cpuid(vcpu[0]);
  539. /* Create worker vCPUs which check the contents of the test pages */
  540. vcpu[1] = vm_vcpu_add(vm, WORKER_VCPU_ID_1, worker_guest_code);
  541. vcpu_args_set(vcpu[1], 1, test_data_page);
  542. vcpu_set_msr(vcpu[1], HV_X64_MSR_VP_INDEX, WORKER_VCPU_ID_1);
  543. vcpu_set_hv_cpuid(vcpu[1]);
  544. vcpu[2] = vm_vcpu_add(vm, WORKER_VCPU_ID_2, worker_guest_code);
  545. vcpu_args_set(vcpu[2], 1, test_data_page);
  546. vcpu_set_msr(vcpu[2], HV_X64_MSR_VP_INDEX, WORKER_VCPU_ID_2);
  547. vcpu_set_hv_cpuid(vcpu[2]);
  548. r = pthread_create(&threads[0], NULL, vcpu_thread, vcpu[1]);
  549. TEST_ASSERT(!r, "pthread_create() failed");
  550. r = pthread_create(&threads[1], NULL, vcpu_thread, vcpu[2]);
  551. TEST_ASSERT(!r, "pthread_create() failed");
  552. while (true) {
  553. vcpu_run(vcpu[0]);
  554. TEST_ASSERT_KVM_EXIT_REASON(vcpu[0], KVM_EXIT_IO);
  555. switch (get_ucall(vcpu[0], &uc)) {
  556. case UCALL_SYNC:
  557. TEST_ASSERT(uc.args[1] == stage,
  558. "Unexpected stage: %ld (%d expected)",
  559. uc.args[1], stage);
  560. break;
  561. case UCALL_ABORT:
  562. REPORT_GUEST_ASSERT(uc);
  563. /* NOT REACHED */
  564. case UCALL_DONE:
  565. goto done;
  566. default:
  567. TEST_FAIL("Unknown ucall %lu", uc.cmd);
  568. }
  569. stage++;
  570. }
  571. done:
  572. cancel_join_vcpu_thread(threads[0], vcpu[1]);
  573. cancel_join_vcpu_thread(threads[1], vcpu[2]);
  574. kvm_vm_free(vm);
  575. return 0;
  576. }