xref: /linux/tools/testing/selftests/kvm/x86/xapic_ipi_test.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * xapic_ipi_test
4  *
5  * Copyright (C) 2020, Google LLC.
6  *
7  * This work is licensed under the terms of the GNU GPL, version 2.
8  *
9  * Test that when the APIC is in xAPIC mode, a vCPU can send an IPI to wake
10  * another vCPU that is halted when KVM's backing page for the APIC access
11  * address has been moved by mm.
12  *
13  * The test starts two vCPUs: one that sends IPIs and one that continually
14  * executes HLT. The sender checks that the halter has woken from the HLT and
15  * has reentered HLT before sending the next IPI. While the vCPUs are running,
16  * the host continually calls migrate_pages to move all of the process' pages
17  * amongst the available numa nodes on the machine.
18  *
19  * Migration is a command line option. When used on non-numa machines will
20  * exit with error. Test is still useful on non-numa for testing IPIs.
21  */
22 #include <getopt.h>
23 #include <pthread.h>
24 #include <inttypes.h>
25 #include <string.h>
26 #include <time.h>
27 
28 #include "kvm_util.h"
29 #include "numaif.h"
30 #include "processor.h"
31 #include "test_util.h"
32 #include "vmx.h"
33 
34 /* Default running time for the test */
35 #define DEFAULT_RUN_SECS 3
36 
37 /* Default delay between migrate_pages calls (microseconds) */
38 #define DEFAULT_DELAY_USECS 500000
39 
40 /*
41  * Vector for IPI from sender vCPU to halting vCPU.
42  * Value is arbitrary and was chosen for the alternating bit pattern. Any
43  * value should work.
44  */
45 #define IPI_VECTOR	 0xa5
46 
47 /*
48  * Incremented in the IPI handler. Provides evidence to the sender that the IPI
49  * arrived at the destination
50  */
51 static volatile u64 ipis_rcvd;
52 
53 /* Data struct shared between host main thread and vCPUs */
54 struct test_data_page {
55 	u32 halter_apic_id;
56 	volatile u64 hlt_count;
57 	volatile u64 wake_count;
58 	u64 ipis_sent;
59 	u64 migrations_attempted;
60 	u64 migrations_completed;
61 	u32 icr;
62 	u32 icr2;
63 	u32 halter_tpr;
64 	u32 halter_ppr;
65 
66 	/*
67 	 *  Record local version register as a cross-check that APIC access
68 	 *  worked. Value should match what KVM reports (APIC_VERSION in
69 	 *  arch/x86/kvm/lapic.c). If test is failing, check that values match
70 	 *  to determine whether APIC access exits are working.
71 	 */
72 	u32 halter_lvr;
73 };
74 
75 struct thread_params {
76 	struct test_data_page *data;
77 	struct kvm_vcpu *vcpu;
78 	u64 *pipis_rcvd; /* host address of ipis_rcvd global */
79 };
80 
81 void verify_apic_base_addr(void)
82 {
83 	u64 msr = rdmsr(MSR_IA32_APICBASE);
84 	u64 base = GET_APIC_BASE(msr);
85 
86 	GUEST_ASSERT(base == APIC_DEFAULT_GPA);
87 }
88 
89 static void halter_guest_code(struct test_data_page *data)
90 {
91 	verify_apic_base_addr();
92 	xapic_enable();
93 
94 	data->halter_apic_id = GET_APIC_ID_FIELD(xapic_read_reg(APIC_ID));
95 	data->halter_lvr = xapic_read_reg(APIC_LVR);
96 
97 	/*
98 	 * Loop forever HLTing and recording halts & wakes. Disable interrupts
99 	 * each time around to minimize window between signaling the pending
100 	 * halt to the sender vCPU and executing the halt. No need to disable on
101 	 * first run as this vCPU executes first and the host waits for it to
102 	 * signal going into first halt before starting the sender vCPU. Record
103 	 * TPR and PPR for diagnostic purposes in case the test fails.
104 	 */
105 	for (;;) {
106 		data->halter_tpr = xapic_read_reg(APIC_TASKPRI);
107 		data->halter_ppr = xapic_read_reg(APIC_PROCPRI);
108 		data->hlt_count++;
109 		safe_halt();
110 		cli();
111 		data->wake_count++;
112 	}
113 }
114 
115 /*
116  * Runs on halter vCPU when IPI arrives. Write an arbitrary non-zero value to
117  * enable diagnosing errant writes to the APIC access address backing page in
118  * case of test failure.
119  */
120 static void guest_ipi_handler(struct ex_regs *regs)
121 {
122 	ipis_rcvd++;
123 	xapic_write_reg(APIC_EOI, 77);
124 }
125 
126 static void sender_guest_code(struct test_data_page *data)
127 {
128 	u64 last_wake_count;
129 	u64 last_hlt_count;
130 	u64 last_ipis_rcvd_count;
131 	u32 icr_val;
132 	u32 icr2_val;
133 	u64 tsc_start;
134 
135 	verify_apic_base_addr();
136 	xapic_enable();
137 
138 	/*
139 	 * Init interrupt command register for sending IPIs
140 	 *
141 	 * Delivery mode=fixed, per SDM:
142 	 *   "Delivers the interrupt specified in the vector field to the target
143 	 *    processor."
144 	 *
145 	 * Destination mode=physical i.e. specify target by its local APIC
146 	 * ID. This vCPU assumes that the halter vCPU has already started and
147 	 * set data->halter_apic_id.
148 	 */
149 	icr_val = (APIC_DEST_PHYSICAL | APIC_DM_FIXED | IPI_VECTOR);
150 	icr2_val = SET_APIC_DEST_FIELD(data->halter_apic_id);
151 	data->icr = icr_val;
152 	data->icr2 = icr2_val;
153 
154 	last_wake_count = data->wake_count;
155 	last_hlt_count = data->hlt_count;
156 	last_ipis_rcvd_count = ipis_rcvd;
157 	for (;;) {
158 		/*
159 		 * Send IPI to halter vCPU.
160 		 * First IPI can be sent unconditionally because halter vCPU
161 		 * starts earlier.
162 		 */
163 		xapic_write_reg(APIC_ICR2, icr2_val);
164 		xapic_write_reg(APIC_ICR, icr_val);
165 		data->ipis_sent++;
166 
167 		/*
168 		 * Wait up to ~1 sec for halter to indicate that it has:
169 		 * 1. Received the IPI
170 		 * 2. Woken up from the halt
171 		 * 3. Gone back into halt
172 		 * Current CPUs typically run at 2.x Ghz which is ~2
173 		 * billion ticks per second.
174 		 */
175 		tsc_start = rdtsc();
176 		while (rdtsc() - tsc_start < 2000000000) {
177 			if ((ipis_rcvd != last_ipis_rcvd_count) &&
178 			    (data->wake_count != last_wake_count) &&
179 			    (data->hlt_count != last_hlt_count))
180 				break;
181 		}
182 
183 		GUEST_ASSERT((ipis_rcvd != last_ipis_rcvd_count) &&
184 			     (data->wake_count != last_wake_count) &&
185 			     (data->hlt_count != last_hlt_count));
186 
187 		last_wake_count = data->wake_count;
188 		last_hlt_count = data->hlt_count;
189 		last_ipis_rcvd_count = ipis_rcvd;
190 	}
191 }
192 
193 static void *vcpu_thread(void *arg)
194 {
195 	struct thread_params *params = (struct thread_params *)arg;
196 	struct kvm_vcpu *vcpu = params->vcpu;
197 	struct ucall uc;
198 	int old;
199 	int r;
200 
201 	r = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old);
202 	TEST_ASSERT(r == 0,
203 		    "pthread_setcanceltype failed on vcpu_id=%u with errno=%d",
204 		    vcpu->id, r);
205 
206 	fprintf(stderr, "vCPU thread running vCPU %u\n", vcpu->id);
207 	vcpu_run(vcpu);
208 
209 	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
210 
211 	if (get_ucall(vcpu, &uc) == UCALL_ABORT) {
212 		TEST_ASSERT(false,
213 			    "vCPU %u exited with error: %s.\n"
214 			    "Sending vCPU sent %lu IPIs to halting vCPU\n"
215 			    "Halting vCPU halted %lu times, woke %lu times, received %lu IPIs.\n"
216 			    "Halter TPR=%#x PPR=%#x LVR=%#x\n"
217 			    "Migrations attempted: %lu\n"
218 			    "Migrations completed: %lu",
219 			    vcpu->id, (const char *)uc.args[0],
220 			    params->data->ipis_sent, params->data->hlt_count,
221 			    params->data->wake_count,
222 			    *params->pipis_rcvd, params->data->halter_tpr,
223 			    params->data->halter_ppr, params->data->halter_lvr,
224 			    params->data->migrations_attempted,
225 			    params->data->migrations_completed);
226 	}
227 
228 	return NULL;
229 }
230 
231 void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs,
232 		   u64 *pipis_rcvd)
233 {
234 	long pages_not_moved;
235 	unsigned long nodemask = 0;
236 	unsigned long nodemasks[sizeof(nodemask) * 8];
237 	int nodes = 0;
238 	time_t start_time, last_update, now;
239 	time_t interval_secs = 1;
240 	int i;
241 	int from, to;
242 	unsigned long bit;
243 	u64 hlt_count;
244 	u64 wake_count;
245 	u64 ipis_sent;
246 
247 	fprintf(stderr, "Calling migrate_pages every %d microseconds\n",
248 		delay_usecs);
249 
250 	/* Get set of first 64 numa nodes available */
251 	kvm_get_mempolicy(NULL, &nodemask, sizeof(nodemask) * 8,
252 			  0, MPOL_F_MEMS_ALLOWED);
253 
254 	fprintf(stderr, "Numa nodes found amongst first %lu possible nodes "
255 		"(each 1-bit indicates node is present): %#lx\n",
256 		sizeof(nodemask) * 8, nodemask);
257 
258 	/* Init array of masks containing a single-bit in each, one for each
259 	 * available node. migrate_pages called below requires specifying nodes
260 	 * as bit masks.
261 	 */
262 	for (i = 0, bit = 1; i < sizeof(nodemask) * 8; i++, bit <<= 1) {
263 		if (nodemask & bit) {
264 			nodemasks[nodes] = nodemask & bit;
265 			nodes++;
266 		}
267 	}
268 
269 	TEST_ASSERT(nodes > 1,
270 		    "Did not find at least 2 numa nodes. Can't do migration");
271 
272 	fprintf(stderr, "Migrating amongst %d nodes found\n", nodes);
273 
274 	from = 0;
275 	to = 1;
276 	start_time = time(NULL);
277 	last_update = start_time;
278 
279 	ipis_sent = data->ipis_sent;
280 	hlt_count = data->hlt_count;
281 	wake_count = data->wake_count;
282 
283 	while ((int)(time(NULL) - start_time) < run_secs) {
284 		data->migrations_attempted++;
285 
286 		/*
287 		 * migrate_pages with PID=0 will migrate all pages of this
288 		 * process between the nodes specified as bitmasks. The page
289 		 * backing the APIC access address belongs to this process
290 		 * because it is allocated by KVM in the context of the
291 		 * KVM_CREATE_VCPU ioctl. If that assumption ever changes this
292 		 * test may break or give a false positive signal.
293 		 */
294 		pages_not_moved = migrate_pages(0, sizeof(nodemasks[from]),
295 						&nodemasks[from],
296 						&nodemasks[to]);
297 		if (pages_not_moved < 0)
298 			fprintf(stderr,
299 				"migrate_pages failed, errno=%d\n", errno);
300 		else if (pages_not_moved > 0)
301 			fprintf(stderr,
302 				"migrate_pages could not move %ld pages\n",
303 				pages_not_moved);
304 		else
305 			data->migrations_completed++;
306 
307 		from = to;
308 		to++;
309 		if (to == nodes)
310 			to = 0;
311 
312 		now = time(NULL);
313 		if (((now - start_time) % interval_secs == 0) &&
314 		    (now != last_update)) {
315 			last_update = now;
316 			fprintf(stderr,
317 				"%lu seconds: Migrations attempted=%lu completed=%lu, "
318 				"IPIs sent=%lu received=%lu, HLTs=%lu wakes=%lu\n",
319 				now - start_time, data->migrations_attempted,
320 				data->migrations_completed,
321 				data->ipis_sent, *pipis_rcvd,
322 				data->hlt_count, data->wake_count);
323 
324 			TEST_ASSERT(ipis_sent != data->ipis_sent &&
325 				    hlt_count != data->hlt_count &&
326 				    wake_count != data->wake_count,
327 				    "IPI, HLT and wake count have not increased "
328 				    "in the last %lu seconds. "
329 				    "HLTer is likely hung.", interval_secs);
330 
331 			ipis_sent = data->ipis_sent;
332 			hlt_count = data->hlt_count;
333 			wake_count = data->wake_count;
334 		}
335 		usleep(delay_usecs);
336 	}
337 }
338 
339 void get_cmdline_args(int argc, char *argv[], int *run_secs,
340 		      bool *migrate, int *delay_usecs)
341 {
342 	for (;;) {
343 		int opt = getopt(argc, argv, "s:d:m");
344 
345 		if (opt == -1)
346 			break;
347 		switch (opt) {
348 		case 's':
349 			*run_secs = parse_size(optarg);
350 			break;
351 		case 'm':
352 			*migrate = true;
353 			break;
354 		case 'd':
355 			*delay_usecs = parse_size(optarg);
356 			break;
357 		default:
358 			TEST_ASSERT(false,
359 				    "Usage: -s <runtime seconds>. Default is %d seconds.\n"
360 				    "-m adds calls to migrate_pages while vCPUs are running."
361 				    " Default is no migrations.\n"
362 				    "-d <delay microseconds> - delay between migrate_pages() calls."
363 				    " Default is %d microseconds.",
364 				    DEFAULT_RUN_SECS, DEFAULT_DELAY_USECS);
365 		}
366 	}
367 }
368 
369 int main(int argc, char *argv[])
370 {
371 	int wait_secs;
372 	const int max_halter_wait = 10;
373 	int run_secs = 0;
374 	int delay_usecs = 0;
375 	struct test_data_page *data;
376 	gva_t test_data_page_gva;
377 	bool migrate = false;
378 	pthread_t threads[2];
379 	struct thread_params params[2];
380 	struct kvm_vm *vm;
381 	u64 *pipis_rcvd;
382 
383 	get_cmdline_args(argc, argv, &run_secs, &migrate, &delay_usecs);
384 	if (run_secs <= 0)
385 		run_secs = DEFAULT_RUN_SECS;
386 	if (delay_usecs <= 0)
387 		delay_usecs = DEFAULT_DELAY_USECS;
388 
389 	vm = vm_create_with_one_vcpu(&params[0].vcpu, halter_guest_code);
390 
391 	vm_install_exception_handler(vm, IPI_VECTOR, guest_ipi_handler);
392 
393 	virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA);
394 
395 	params[1].vcpu = vm_vcpu_add(vm, 1, sender_guest_code);
396 
397 	test_data_page_gva = vm_alloc_page(vm);
398 	data = addr_gva2hva(vm, test_data_page_gva);
399 	memset(data, 0, sizeof(*data));
400 	params[0].data = data;
401 	params[1].data = data;
402 
403 	vcpu_args_set(params[0].vcpu, 1, test_data_page_gva);
404 	vcpu_args_set(params[1].vcpu, 1, test_data_page_gva);
405 
406 	pipis_rcvd = (u64 *)addr_gva2hva(vm, (u64)&ipis_rcvd);
407 	params[0].pipis_rcvd = pipis_rcvd;
408 	params[1].pipis_rcvd = pipis_rcvd;
409 
410 	/* Start halter vCPU thread and wait for it to execute first HLT. */
411 	kvm_pthread_create(&threads[0], NULL, vcpu_thread, &params[0]);
412 	fprintf(stderr, "Halter vCPU thread started\n");
413 
414 	wait_secs = 0;
415 	while ((wait_secs < max_halter_wait) && !data->hlt_count) {
416 		sleep(1);
417 		wait_secs++;
418 	}
419 
420 	TEST_ASSERT(data->hlt_count,
421 		    "Halter vCPU did not execute first HLT within %d seconds",
422 		    max_halter_wait);
423 
424 	fprintf(stderr,
425 		"Halter vCPU thread reported its APIC ID: %u after %d seconds.\n",
426 		data->halter_apic_id, wait_secs);
427 
428 	kvm_pthread_create(&threads[1], NULL, vcpu_thread, &params[1]);
429 
430 	fprintf(stderr,
431 		"IPI sender vCPU thread started. Letting vCPUs run for %d seconds.\n",
432 		run_secs);
433 
434 	if (!migrate)
435 		sleep(run_secs);
436 	else
437 		do_migrations(data, run_secs, delay_usecs, pipis_rcvd);
438 
439 	/*
440 	 * Cancel threads and wait for them to stop.
441 	 */
442 	kvm_pthread_cancel_join_async(threads[0]);
443 	kvm_pthread_cancel_join_async(threads[1]);
444 
445 	/*
446 	 * If the host support Idle HLT, i.e. KVM *might* be using Idle HLT,
447 	 * then the number of HLT exits may be less than the number of HLTs
448 	 * that were executed, as Idle HLT elides the exit if the vCPU has an
449 	 * unmasked, pending IRQ (or NMI).
450 	 */
451 	if (this_cpu_has(X86_FEATURE_IDLE_HLT))
452 		TEST_ASSERT(data->hlt_count >= vcpu_get_stat(params[0].vcpu, halt_exits),
453 			    "HLT insns = %lu, HLT exits = %lu",
454 			    data->hlt_count, vcpu_get_stat(params[0].vcpu, halt_exits));
455 	else
456 		TEST_ASSERT_EQ(data->hlt_count, vcpu_get_stat(params[0].vcpu, halt_exits));
457 
458 	fprintf(stderr,
459 		"Test successful after running for %d seconds.\n"
460 		"Sending vCPU sent %lu IPIs to halting vCPU\n"
461 		"Halting vCPU halted %lu times, woke %lu times, received %lu IPIs.\n"
462 		"Halter APIC ID=%#x\n"
463 		"Sender ICR value=%#x ICR2 value=%#x\n"
464 		"Halter TPR=%#x PPR=%#x LVR=%#x\n"
465 		"Migrations attempted: %lu\n"
466 		"Migrations completed: %lu\n",
467 		run_secs, data->ipis_sent,
468 		data->hlt_count, data->wake_count, *pipis_rcvd,
469 		data->halter_apic_id,
470 		data->icr, data->icr2,
471 		data->halter_tpr, data->halter_ppr, data->halter_lvr,
472 		data->migrations_attempted, data->migrations_completed);
473 
474 	kvm_vm_free(vm);
475 
476 	return 0;
477 }
478