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