brintos

brintos / linux-shallow public Read only

0
0
Text · 26.2 KiB · a36a7e2 Raw
1063 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * arch_timer_edge_cases.c - Tests the aarch64 timer IRQ functionality.4 *5 * The test validates some edge cases related to the arch-timer:6 * - timers above the max TVAL value.7 * - timers in the past8 * - moving counters ahead and behind pending timers.9 * - reprograming timers.10 * - timers fired multiple times.11 * - masking/unmasking using the timer control mask.12 *13 * Copyright (c) 2021, Google LLC.14 */15 16#define _GNU_SOURCE17 18#include <pthread.h>19#include <sys/sysinfo.h>20 21#include "arch_timer.h"22#include "gic.h"23#include "vgic.h"24 25static const uint64_t CVAL_MAX = ~0ULL;26/* tval is a signed 32-bit int. */27static const int32_t TVAL_MAX = INT32_MAX;28static const int32_t TVAL_MIN = INT32_MIN;29 30/* After how much time we say there is no IRQ. */31static const uint32_t TIMEOUT_NO_IRQ_US = 50000;32 33/* A nice counter value to use as the starting one for most tests. */34static const uint64_t DEF_CNT = (CVAL_MAX / 2);35 36/* Number of runs. */37static const uint32_t NR_TEST_ITERS_DEF = 5;38 39/* Default wait test time in ms. */40static const uint32_t WAIT_TEST_MS = 10;41 42/* Default "long" wait test time in ms. */43static const uint32_t LONG_WAIT_TEST_MS = 100;44 45/* Shared with IRQ handler. */46struct test_vcpu_shared_data {47	atomic_t handled;48	atomic_t spurious;49} shared_data;50 51struct test_args {52	/* Virtual or physical timer and counter tests. */53	enum arch_timer timer;54	/* Delay used for most timer tests. */55	uint64_t wait_ms;56	/* Delay used in the test_long_timer_delays test. */57	uint64_t long_wait_ms;58	/* Number of iterations. */59	int iterations;60	/* Whether to test the physical timer. */61	bool test_physical;62	/* Whether to test the virtual timer. */63	bool test_virtual;64};65 66struct test_args test_args = {67	.wait_ms = WAIT_TEST_MS,68	.long_wait_ms = LONG_WAIT_TEST_MS,69	.iterations = NR_TEST_ITERS_DEF,70	.test_physical = true,71	.test_virtual = true,72};73 74static int vtimer_irq, ptimer_irq;75 76enum sync_cmd {77	SET_COUNTER_VALUE,78	USERSPACE_USLEEP,79	USERSPACE_SCHED_YIELD,80	USERSPACE_MIGRATE_SELF,81	NO_USERSPACE_CMD,82};83 84typedef void (*sleep_method_t)(enum arch_timer timer, uint64_t usec);85 86static void sleep_poll(enum arch_timer timer, uint64_t usec);87static void sleep_sched_poll(enum arch_timer timer, uint64_t usec);88static void sleep_in_userspace(enum arch_timer timer, uint64_t usec);89static void sleep_migrate(enum arch_timer timer, uint64_t usec);90 91sleep_method_t sleep_method[] = {92	sleep_poll,93	sleep_sched_poll,94	sleep_migrate,95	sleep_in_userspace,96};97 98typedef void (*irq_wait_method_t)(void);99 100static void wait_for_non_spurious_irq(void);101static void wait_poll_for_irq(void);102static void wait_sched_poll_for_irq(void);103static void wait_migrate_poll_for_irq(void);104 105irq_wait_method_t irq_wait_method[] = {106	wait_for_non_spurious_irq,107	wait_poll_for_irq,108	wait_sched_poll_for_irq,109	wait_migrate_poll_for_irq,110};111 112enum timer_view {113	TIMER_CVAL,114	TIMER_TVAL,115};116 117static void assert_irqs_handled(uint32_t n)118{119	int h = atomic_read(&shared_data.handled);120 121	__GUEST_ASSERT(h == n, "Handled %d IRQS but expected %d", h, n);122}123 124static void userspace_cmd(uint64_t cmd)125{126	GUEST_SYNC_ARGS(cmd, 0, 0, 0, 0);127}128 129static void userspace_migrate_vcpu(void)130{131	userspace_cmd(USERSPACE_MIGRATE_SELF);132}133 134static void userspace_sleep(uint64_t usecs)135{136	GUEST_SYNC_ARGS(USERSPACE_USLEEP, usecs, 0, 0, 0);137}138 139static void set_counter(enum arch_timer timer, uint64_t counter)140{141	GUEST_SYNC_ARGS(SET_COUNTER_VALUE, counter, timer, 0, 0);142}143 144static void guest_irq_handler(struct ex_regs *regs)145{146	unsigned int intid = gic_get_and_ack_irq();147	enum arch_timer timer;148	uint64_t cnt, cval;149	uint32_t ctl;150	bool timer_condition, istatus;151 152	if (intid == IAR_SPURIOUS) {153		atomic_inc(&shared_data.spurious);154		goto out;155	}156 157	if (intid == ptimer_irq)158		timer = PHYSICAL;159	else if (intid == vtimer_irq)160		timer = VIRTUAL;161	else162		goto out;163 164	ctl = timer_get_ctl(timer);165	cval = timer_get_cval(timer);166	cnt = timer_get_cntct(timer);167	timer_condition = cnt >= cval;168	istatus = (ctl & CTL_ISTATUS) && (ctl & CTL_ENABLE);169	GUEST_ASSERT_EQ(timer_condition, istatus);170 171	/* Disable and mask the timer. */172	timer_set_ctl(timer, CTL_IMASK);173 174	atomic_inc(&shared_data.handled);175 176out:177	gic_set_eoi(intid);178}179 180static void set_cval_irq(enum arch_timer timer, uint64_t cval_cycles,181			 uint32_t ctl)182{183	atomic_set(&shared_data.handled, 0);184	atomic_set(&shared_data.spurious, 0);185	timer_set_cval(timer, cval_cycles);186	timer_set_ctl(timer, ctl);187}188 189static void set_tval_irq(enum arch_timer timer, uint64_t tval_cycles,190			 uint32_t ctl)191{192	atomic_set(&shared_data.handled, 0);193	atomic_set(&shared_data.spurious, 0);194	timer_set_ctl(timer, ctl);195	timer_set_tval(timer, tval_cycles);196}197 198static void set_xval_irq(enum arch_timer timer, uint64_t xval, uint32_t ctl,199			 enum timer_view tv)200{201	switch (tv) {202	case TIMER_CVAL:203		set_cval_irq(timer, xval, ctl);204		break;205	case TIMER_TVAL:206		set_tval_irq(timer, xval, ctl);207		break;208	default:209		GUEST_FAIL("Could not get timer %d", timer);210	}211}212 213/*214 * Note that this can theoretically hang forever, so we rely on having215 * a timeout mechanism in the "runner", like:216 * tools/testing/selftests/kselftest/runner.sh.217 */218static void wait_for_non_spurious_irq(void)219{220	int h;221 222	local_irq_disable();223 224	for (h = atomic_read(&shared_data.handled); h == atomic_read(&shared_data.handled);) {225		wfi();226		local_irq_enable();227		isb(); /* handle IRQ */228		local_irq_disable();229	}230}231 232/*233 * Wait for an non-spurious IRQ by polling in the guest or in234 * userspace (e.g. userspace_cmd=USERSPACE_SCHED_YIELD).235 *236 * Note that this can theoretically hang forever, so we rely on having237 * a timeout mechanism in the "runner", like:238 * tools/testing/selftests/kselftest/runner.sh.239 */240static void poll_for_non_spurious_irq(enum sync_cmd usp_cmd)241{242	int h;243 244	local_irq_disable();245 246	h = atomic_read(&shared_data.handled);247 248	local_irq_enable();249	while (h == atomic_read(&shared_data.handled)) {250		if (usp_cmd == NO_USERSPACE_CMD)251			cpu_relax();252		else253			userspace_cmd(usp_cmd);254	}255	local_irq_disable();256}257 258static void wait_poll_for_irq(void)259{260	poll_for_non_spurious_irq(NO_USERSPACE_CMD);261}262 263static void wait_sched_poll_for_irq(void)264{265	poll_for_non_spurious_irq(USERSPACE_SCHED_YIELD);266}267 268static void wait_migrate_poll_for_irq(void)269{270	poll_for_non_spurious_irq(USERSPACE_MIGRATE_SELF);271}272 273/*274 * Sleep for usec microseconds by polling in the guest or in275 * userspace (e.g. userspace_cmd=USERSPACE_SCHEDULE).276 */277static void guest_poll(enum arch_timer test_timer, uint64_t usec,278		       enum sync_cmd usp_cmd)279{280	uint64_t cycles = usec_to_cycles(usec);281	/* Whichever timer we are testing with, sleep with the other. */282	enum arch_timer sleep_timer = 1 - test_timer;283	uint64_t start = timer_get_cntct(sleep_timer);284 285	while ((timer_get_cntct(sleep_timer) - start) < cycles) {286		if (usp_cmd == NO_USERSPACE_CMD)287			cpu_relax();288		else289			userspace_cmd(usp_cmd);290	}291}292 293static void sleep_poll(enum arch_timer timer, uint64_t usec)294{295	guest_poll(timer, usec, NO_USERSPACE_CMD);296}297 298static void sleep_sched_poll(enum arch_timer timer, uint64_t usec)299{300	guest_poll(timer, usec, USERSPACE_SCHED_YIELD);301}302 303static void sleep_migrate(enum arch_timer timer, uint64_t usec)304{305	guest_poll(timer, usec, USERSPACE_MIGRATE_SELF);306}307 308static void sleep_in_userspace(enum arch_timer timer, uint64_t usec)309{310	userspace_sleep(usec);311}312 313/*314 * Reset the timer state to some nice values like the counter not being close315 * to the edge, and the control register masked and disabled.316 */317static void reset_timer_state(enum arch_timer timer, uint64_t cnt)318{319	set_counter(timer, cnt);320	timer_set_ctl(timer, CTL_IMASK);321}322 323static void test_timer_xval(enum arch_timer timer, uint64_t xval,324			    enum timer_view tv, irq_wait_method_t wm, bool reset_state,325			    uint64_t reset_cnt)326{327	local_irq_disable();328 329	if (reset_state)330		reset_timer_state(timer, reset_cnt);331 332	set_xval_irq(timer, xval, CTL_ENABLE, tv);333 334	/* This method re-enables IRQs to handle the one we're looking for. */335	wm();336 337	assert_irqs_handled(1);338	local_irq_enable();339}340 341/*342 * The test_timer_* functions will program the timer, wait for it, and assert343 * the firing of the correct IRQ.344 *345 * These functions don't have a timeout and return as soon as they receive an346 * IRQ. They can hang (forever), so we rely on having a timeout mechanism in347 * the "runner", like: tools/testing/selftests/kselftest/runner.sh.348 */349 350static void test_timer_cval(enum arch_timer timer, uint64_t cval,351			    irq_wait_method_t wm, bool reset_state,352			    uint64_t reset_cnt)353{354	test_timer_xval(timer, cval, TIMER_CVAL, wm, reset_state, reset_cnt);355}356 357static void test_timer_tval(enum arch_timer timer, int32_t tval,358			    irq_wait_method_t wm, bool reset_state,359			    uint64_t reset_cnt)360{361	test_timer_xval(timer, (uint64_t) tval, TIMER_TVAL, wm, reset_state,362			reset_cnt);363}364 365static void test_xval_check_no_irq(enum arch_timer timer, uint64_t xval,366				   uint64_t usec, enum timer_view timer_view,367				   sleep_method_t guest_sleep)368{369	local_irq_disable();370 371	set_xval_irq(timer, xval, CTL_ENABLE | CTL_IMASK, timer_view);372	guest_sleep(timer, usec);373 374	local_irq_enable();375	isb();376 377	/* Assume success (no IRQ) after waiting usec microseconds */378	assert_irqs_handled(0);379}380 381static void test_cval_no_irq(enum arch_timer timer, uint64_t cval,382			     uint64_t usec, sleep_method_t wm)383{384	test_xval_check_no_irq(timer, cval, usec, TIMER_CVAL, wm);385}386 387static void test_tval_no_irq(enum arch_timer timer, int32_t tval, uint64_t usec,388			     sleep_method_t wm)389{390	/* tval will be cast to an int32_t in test_xval_check_no_irq */391	test_xval_check_no_irq(timer, (uint64_t) tval, usec, TIMER_TVAL, wm);392}393 394/* Test masking/unmasking a timer using the timer mask (not the IRQ mask). */395static void test_timer_control_mask_then_unmask(enum arch_timer timer)396{397	reset_timer_state(timer, DEF_CNT);398	set_tval_irq(timer, -1, CTL_ENABLE | CTL_IMASK);399 400	/* Unmask the timer, and then get an IRQ. */401	local_irq_disable();402	timer_set_ctl(timer, CTL_ENABLE);403	/* This method re-enables IRQs to handle the one we're looking for. */404	wait_for_non_spurious_irq();405 406	assert_irqs_handled(1);407	local_irq_enable();408}409 410/* Check that timer control masks actually mask a timer being fired. */411static void test_timer_control_masks(enum arch_timer timer)412{413	reset_timer_state(timer, DEF_CNT);414 415	/* Local IRQs are not masked at this point. */416 417	set_tval_irq(timer, -1, CTL_ENABLE | CTL_IMASK);418 419	/* Assume no IRQ after waiting TIMEOUT_NO_IRQ_US microseconds */420	sleep_poll(timer, TIMEOUT_NO_IRQ_US);421 422	assert_irqs_handled(0);423	timer_set_ctl(timer, CTL_IMASK);424}425 426static void test_fire_a_timer_multiple_times(enum arch_timer timer,427					     irq_wait_method_t wm, int num)428{429	int i;430 431	local_irq_disable();432	reset_timer_state(timer, DEF_CNT);433 434	set_tval_irq(timer, 0, CTL_ENABLE);435 436	for (i = 1; i <= num; i++) {437		/* This method re-enables IRQs to handle the one we're looking for. */438		wm();439 440		/* The IRQ handler masked and disabled the timer.441		 * Enable and unmmask it again.442		 */443		timer_set_ctl(timer, CTL_ENABLE);444 445		assert_irqs_handled(i);446	}447 448	local_irq_enable();449}450 451static void test_timers_fired_multiple_times(enum arch_timer timer)452{453	int i;454 455	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++)456		test_fire_a_timer_multiple_times(timer, irq_wait_method[i], 10);457}458 459/*460 * Set a timer for tval=delta_1_ms then reprogram it to461 * tval=delta_2_ms. Check that we get the timer fired. There is no462 * timeout for the wait: we use the wfi instruction.463 */464static void test_reprogramming_timer(enum arch_timer timer, irq_wait_method_t wm,465				     int32_t delta_1_ms, int32_t delta_2_ms)466{467	local_irq_disable();468	reset_timer_state(timer, DEF_CNT);469 470	/* Program the timer to DEF_CNT + delta_1_ms. */471	set_tval_irq(timer, msec_to_cycles(delta_1_ms), CTL_ENABLE);472 473	/* Reprogram the timer to DEF_CNT + delta_2_ms. */474	timer_set_tval(timer, msec_to_cycles(delta_2_ms));475 476	/* This method re-enables IRQs to handle the one we're looking for. */477	wm();478 479	/* The IRQ should arrive at DEF_CNT + delta_2_ms (or after). */480	GUEST_ASSERT(timer_get_cntct(timer) >=481		     DEF_CNT + msec_to_cycles(delta_2_ms));482 483	local_irq_enable();484	assert_irqs_handled(1);485};486 487static void test_reprogram_timers(enum arch_timer timer)488{489	int i;490	uint64_t base_wait = test_args.wait_ms;491 492	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {493		/*494		 * Ensure reprogramming works whether going from a495		 * longer time to a shorter or vice versa.496		 */497		test_reprogramming_timer(timer, irq_wait_method[i], 2 * base_wait,498					 base_wait);499		test_reprogramming_timer(timer, irq_wait_method[i], base_wait,500					 2 * base_wait);501	}502}503 504static void test_basic_functionality(enum arch_timer timer)505{506	int32_t tval = (int32_t) msec_to_cycles(test_args.wait_ms);507	uint64_t cval = DEF_CNT + msec_to_cycles(test_args.wait_ms);508	int i;509 510	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {511		irq_wait_method_t wm = irq_wait_method[i];512 513		test_timer_cval(timer, cval, wm, true, DEF_CNT);514		test_timer_tval(timer, tval, wm, true, DEF_CNT);515	}516}517 518/*519 * This test checks basic timer behavior without actually firing timers, things520 * like: the relationship between cval and tval, tval down-counting.521 */522static void timers_sanity_checks(enum arch_timer timer, bool use_sched)523{524	reset_timer_state(timer, DEF_CNT);525 526	local_irq_disable();527 528	/* cval in the past */529	timer_set_cval(timer,530		       timer_get_cntct(timer) -531		       msec_to_cycles(test_args.wait_ms));532	if (use_sched)533		userspace_migrate_vcpu();534	GUEST_ASSERT(timer_get_tval(timer) < 0);535 536	/* tval in the past */537	timer_set_tval(timer, -1);538	if (use_sched)539		userspace_migrate_vcpu();540	GUEST_ASSERT(timer_get_cval(timer) < timer_get_cntct(timer));541 542	/* tval larger than TVAL_MAX. This requires programming with543	 * timer_set_cval instead so the value is expressible544	 */545	timer_set_cval(timer,546		       timer_get_cntct(timer) + TVAL_MAX +547		       msec_to_cycles(test_args.wait_ms));548	if (use_sched)549		userspace_migrate_vcpu();550	GUEST_ASSERT(timer_get_tval(timer) <= 0);551 552	/*553	 * tval larger than 2 * TVAL_MAX.554	 * Twice the TVAL_MAX completely loops around the TVAL.555	 */556	timer_set_cval(timer,557		       timer_get_cntct(timer) + 2ULL * TVAL_MAX +558		       msec_to_cycles(test_args.wait_ms));559	if (use_sched)560		userspace_migrate_vcpu();561	GUEST_ASSERT(timer_get_tval(timer) <=562		       msec_to_cycles(test_args.wait_ms));563 564	/* negative tval that rollovers from 0. */565	set_counter(timer, msec_to_cycles(1));566	timer_set_tval(timer, -1 * msec_to_cycles(test_args.wait_ms));567	if (use_sched)568		userspace_migrate_vcpu();569	GUEST_ASSERT(timer_get_cval(timer) >= (CVAL_MAX - msec_to_cycles(test_args.wait_ms)));570 571	/* tval should keep down-counting from 0 to -1. */572	timer_set_tval(timer, 0);573	sleep_poll(timer, 1);574	GUEST_ASSERT(timer_get_tval(timer) < 0);575 576	local_irq_enable();577 578	/* Mask and disable any pending timer. */579	timer_set_ctl(timer, CTL_IMASK);580}581 582static void test_timers_sanity_checks(enum arch_timer timer)583{584	timers_sanity_checks(timer, false);585	/* Check how KVM saves/restores these edge-case values. */586	timers_sanity_checks(timer, true);587}588 589static void test_set_cnt_after_tval_max(enum arch_timer timer, irq_wait_method_t wm)590{591	local_irq_disable();592	reset_timer_state(timer, DEF_CNT);593 594	set_cval_irq(timer,595		     (uint64_t) TVAL_MAX +596		     msec_to_cycles(test_args.wait_ms) / 2, CTL_ENABLE);597 598	set_counter(timer, TVAL_MAX);599 600	/* This method re-enables IRQs to handle the one we're looking for. */601	wm();602 603	assert_irqs_handled(1);604	local_irq_enable();605}606 607/* Test timers set for: cval = now + TVAL_MAX + wait_ms / 2 */608static void test_timers_above_tval_max(enum arch_timer timer)609{610	uint64_t cval;611	int i;612 613	/*614	 * Test that the system is not implementing cval in terms of615	 * tval.  If that was the case, setting a cval to "cval = now616	 * + TVAL_MAX + wait_ms" would wrap to "cval = now +617	 * wait_ms", and the timer would fire immediately. Test that it618	 * doesn't.619	 */620	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {621		reset_timer_state(timer, DEF_CNT);622		cval = timer_get_cntct(timer) + TVAL_MAX +623			msec_to_cycles(test_args.wait_ms);624		test_cval_no_irq(timer, cval,625				 msecs_to_usecs(test_args.wait_ms) +626				 TIMEOUT_NO_IRQ_US, sleep_method[i]);627	}628 629	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {630		/* Get the IRQ by moving the counter forward. */631		test_set_cnt_after_tval_max(timer, irq_wait_method[i]);632	}633}634 635/*636 * Template function to be used by the test_move_counter_ahead_* tests.  It637 * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and638 * then waits for an IRQ.639 */640static void test_set_cnt_after_xval(enum arch_timer timer, uint64_t cnt_1,641				    uint64_t xval, uint64_t cnt_2,642				    irq_wait_method_t wm, enum timer_view tv)643{644	local_irq_disable();645 646	set_counter(timer, cnt_1);647	timer_set_ctl(timer, CTL_IMASK);648 649	set_xval_irq(timer, xval, CTL_ENABLE, tv);650	set_counter(timer, cnt_2);651	/* This method re-enables IRQs to handle the one we're looking for. */652	wm();653 654	assert_irqs_handled(1);655	local_irq_enable();656}657 658/*659 * Template function to be used by the test_move_counter_ahead_* tests.  It660 * sets the counter to cnt_1, the [c|t]val, the counter to cnt_2, and661 * then waits for an IRQ.662 */663static void test_set_cnt_after_xval_no_irq(enum arch_timer timer,664					   uint64_t cnt_1, uint64_t xval,665					   uint64_t cnt_2,666					   sleep_method_t guest_sleep,667					   enum timer_view tv)668{669	local_irq_disable();670 671	set_counter(timer, cnt_1);672	timer_set_ctl(timer, CTL_IMASK);673 674	set_xval_irq(timer, xval, CTL_ENABLE, tv);675	set_counter(timer, cnt_2);676	guest_sleep(timer, TIMEOUT_NO_IRQ_US);677 678	local_irq_enable();679	isb();680 681	/* Assume no IRQ after waiting TIMEOUT_NO_IRQ_US microseconds */682	assert_irqs_handled(0);683	timer_set_ctl(timer, CTL_IMASK);684}685 686static void test_set_cnt_after_tval(enum arch_timer timer, uint64_t cnt_1,687				    int32_t tval, uint64_t cnt_2,688				    irq_wait_method_t wm)689{690	test_set_cnt_after_xval(timer, cnt_1, tval, cnt_2, wm, TIMER_TVAL);691}692 693static void test_set_cnt_after_cval(enum arch_timer timer, uint64_t cnt_1,694				    uint64_t cval, uint64_t cnt_2,695				    irq_wait_method_t wm)696{697	test_set_cnt_after_xval(timer, cnt_1, cval, cnt_2, wm, TIMER_CVAL);698}699 700static void test_set_cnt_after_tval_no_irq(enum arch_timer timer,701					   uint64_t cnt_1, int32_t tval,702					   uint64_t cnt_2, sleep_method_t wm)703{704	test_set_cnt_after_xval_no_irq(timer, cnt_1, tval, cnt_2, wm,705				       TIMER_TVAL);706}707 708static void test_set_cnt_after_cval_no_irq(enum arch_timer timer,709					   uint64_t cnt_1, uint64_t cval,710					   uint64_t cnt_2, sleep_method_t wm)711{712	test_set_cnt_after_xval_no_irq(timer, cnt_1, cval, cnt_2, wm,713				       TIMER_CVAL);714}715 716/* Set a timer and then move the counter ahead of it. */717static void test_move_counters_ahead_of_timers(enum arch_timer timer)718{719	int i;720	int32_t tval;721 722	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {723		irq_wait_method_t wm = irq_wait_method[i];724 725		test_set_cnt_after_cval(timer, 0, DEF_CNT, DEF_CNT + 1, wm);726		test_set_cnt_after_cval(timer, CVAL_MAX, 1, 2, wm);727 728		/* Move counter ahead of negative tval. */729		test_set_cnt_after_tval(timer, 0, -1, DEF_CNT + 1, wm);730		test_set_cnt_after_tval(timer, 0, -1, TVAL_MAX, wm);731		tval = TVAL_MAX;732		test_set_cnt_after_tval(timer, 0, tval, (uint64_t) tval + 1,733					wm);734	}735 736	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {737		sleep_method_t sm = sleep_method[i];738 739		test_set_cnt_after_cval_no_irq(timer, 0, DEF_CNT, CVAL_MAX, sm);740	}741}742 743/*744 * Program a timer, mask it, and then change the tval or counter to cancel it.745 * Unmask it and check that nothing fires.746 */747static void test_move_counters_behind_timers(enum arch_timer timer)748{749	int i;750 751	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {752		sleep_method_t sm = sleep_method[i];753 754		test_set_cnt_after_cval_no_irq(timer, DEF_CNT, DEF_CNT - 1, 0,755					       sm);756		test_set_cnt_after_tval_no_irq(timer, DEF_CNT, -1, 0, sm);757	}758}759 760static void test_timers_in_the_past(enum arch_timer timer)761{762	int32_t tval = -1 * (int32_t) msec_to_cycles(test_args.wait_ms);763	uint64_t cval;764	int i;765 766	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {767		irq_wait_method_t wm = irq_wait_method[i];768 769		/* set a timer wait_ms the past. */770		cval = DEF_CNT - msec_to_cycles(test_args.wait_ms);771		test_timer_cval(timer, cval, wm, true, DEF_CNT);772		test_timer_tval(timer, tval, wm, true, DEF_CNT);773 774		/* Set a timer to counter=0 (in the past) */775		test_timer_cval(timer, 0, wm, true, DEF_CNT);776 777		/* Set a time for tval=0 (now) */778		test_timer_tval(timer, 0, wm, true, DEF_CNT);779 780		/* Set a timer to as far in the past as possible */781		test_timer_tval(timer, TVAL_MIN, wm, true, DEF_CNT);782	}783 784	/*785	 * Set the counter to wait_ms, and a tval to -wait_ms. There should be no786	 * IRQ as that tval means cval=CVAL_MAX-wait_ms.787	 */788	for (i = 0; i < ARRAY_SIZE(sleep_method); i++) {789		sleep_method_t sm = sleep_method[i];790 791		set_counter(timer, msec_to_cycles(test_args.wait_ms));792		test_tval_no_irq(timer, tval, TIMEOUT_NO_IRQ_US, sm);793	}794}795 796static void test_long_timer_delays(enum arch_timer timer)797{798	int32_t tval = (int32_t) msec_to_cycles(test_args.long_wait_ms);799	uint64_t cval = DEF_CNT + msec_to_cycles(test_args.long_wait_ms);800	int i;801 802	for (i = 0; i < ARRAY_SIZE(irq_wait_method); i++) {803		irq_wait_method_t wm = irq_wait_method[i];804 805		test_timer_cval(timer, cval, wm, true, DEF_CNT);806		test_timer_tval(timer, tval, wm, true, DEF_CNT);807	}808}809 810static void guest_run_iteration(enum arch_timer timer)811{812	test_basic_functionality(timer);813	test_timers_sanity_checks(timer);814 815	test_timers_above_tval_max(timer);816	test_timers_in_the_past(timer);817 818	test_move_counters_ahead_of_timers(timer);819	test_move_counters_behind_timers(timer);820	test_reprogram_timers(timer);821 822	test_timers_fired_multiple_times(timer);823 824	test_timer_control_mask_then_unmask(timer);825	test_timer_control_masks(timer);826}827 828static void guest_code(enum arch_timer timer)829{830	int i;831 832	local_irq_disable();833 834	gic_init(GIC_V3, 1);835 836	timer_set_ctl(VIRTUAL, CTL_IMASK);837	timer_set_ctl(PHYSICAL, CTL_IMASK);838 839	gic_irq_enable(vtimer_irq);840	gic_irq_enable(ptimer_irq);841	local_irq_enable();842 843	for (i = 0; i < test_args.iterations; i++) {844		GUEST_SYNC(i);845		guest_run_iteration(timer);846	}847 848	test_long_timer_delays(timer);849	GUEST_DONE();850}851 852static uint32_t next_pcpu(void)853{854	uint32_t max = get_nprocs();855	uint32_t cur = sched_getcpu();856	uint32_t next = cur;857	cpu_set_t cpuset;858 859	TEST_ASSERT(max > 1, "Need at least two physical cpus");860 861	sched_getaffinity(0, sizeof(cpuset), &cpuset);862 863	do {864		next = (next + 1) % CPU_SETSIZE;865	} while (!CPU_ISSET(next, &cpuset));866 867	return next;868}869 870static void migrate_self(uint32_t new_pcpu)871{872	int ret;873	cpu_set_t cpuset;874	pthread_t thread;875 876	thread = pthread_self();877 878	CPU_ZERO(&cpuset);879	CPU_SET(new_pcpu, &cpuset);880 881	pr_debug("Migrating from %u to %u\n", sched_getcpu(), new_pcpu);882 883	ret = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset);884 885	TEST_ASSERT(ret == 0, "Failed to migrate to pCPU: %u; ret: %d\n",886		    new_pcpu, ret);887}888 889static void kvm_set_cntxct(struct kvm_vcpu *vcpu, uint64_t cnt,890			   enum arch_timer timer)891{892	if (timer == PHYSICAL)893		vcpu_set_reg(vcpu, KVM_REG_ARM_PTIMER_CNT, cnt);894	else895		vcpu_set_reg(vcpu, KVM_REG_ARM_TIMER_CNT, cnt);896}897 898static void handle_sync(struct kvm_vcpu *vcpu, struct ucall *uc)899{900	enum sync_cmd cmd = uc->args[1];901	uint64_t val = uc->args[2];902	enum arch_timer timer = uc->args[3];903 904	switch (cmd) {905	case SET_COUNTER_VALUE:906		kvm_set_cntxct(vcpu, val, timer);907		break;908	case USERSPACE_USLEEP:909		usleep(val);910		break;911	case USERSPACE_SCHED_YIELD:912		sched_yield();913		break;914	case USERSPACE_MIGRATE_SELF:915		migrate_self(next_pcpu());916		break;917	default:918		break;919	}920}921 922static void test_run(struct kvm_vm *vm, struct kvm_vcpu *vcpu)923{924	struct ucall uc;925 926	/* Start on CPU 0 */927	migrate_self(0);928 929	while (true) {930		vcpu_run(vcpu);931		switch (get_ucall(vcpu, &uc)) {932		case UCALL_SYNC:933			handle_sync(vcpu, &uc);934			break;935		case UCALL_DONE:936			goto out;937		case UCALL_ABORT:938			REPORT_GUEST_ASSERT(uc);939			goto out;940		default:941			TEST_FAIL("Unexpected guest exit\n");942		}943	}944 945 out:946	return;947}948 949static void test_init_timer_irq(struct kvm_vm *vm, struct kvm_vcpu *vcpu)950{951	vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL,952			     KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq);953	vcpu_device_attr_get(vcpu, KVM_ARM_VCPU_TIMER_CTRL,954			     KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq);955 956	sync_global_to_guest(vm, ptimer_irq);957	sync_global_to_guest(vm, vtimer_irq);958 959	pr_debug("ptimer_irq: %d; vtimer_irq: %d\n", ptimer_irq, vtimer_irq);960}961 962static void test_vm_create(struct kvm_vm **vm, struct kvm_vcpu **vcpu,963			   enum arch_timer timer)964{965	*vm = vm_create_with_one_vcpu(vcpu, guest_code);966	TEST_ASSERT(*vm, "Failed to create the test VM\n");967 968	vm_init_descriptor_tables(*vm);969	vm_install_exception_handler(*vm, VECTOR_IRQ_CURRENT,970				     guest_irq_handler);971 972	vcpu_init_descriptor_tables(*vcpu);973	vcpu_args_set(*vcpu, 1, timer);974 975	test_init_timer_irq(*vm, *vcpu);976	vgic_v3_setup(*vm, 1, 64);977	sync_global_to_guest(*vm, test_args);978}979 980static void test_print_help(char *name)981{982	pr_info("Usage: %s [-h] [-b] [-i iterations] [-l long_wait_ms] [-p] [-v]\n"983		, name);984	pr_info("\t-i: Number of iterations (default: %u)\n",985		NR_TEST_ITERS_DEF);986	pr_info("\t-b: Test both physical and virtual timers (default: true)\n");987	pr_info("\t-l: Delta (in ms) used for long wait time test (default: %u)\n",988	     LONG_WAIT_TEST_MS);989	pr_info("\t-l: Delta (in ms) used for wait times (default: %u)\n",990		WAIT_TEST_MS);991	pr_info("\t-p: Test physical timer (default: true)\n");992	pr_info("\t-v: Test virtual timer (default: true)\n");993	pr_info("\t-h: Print this help message\n");994}995 996static bool parse_args(int argc, char *argv[])997{998	int opt;999 1000	while ((opt = getopt(argc, argv, "bhi:l:pvw:")) != -1) {1001		switch (opt) {1002		case 'b':1003			test_args.test_physical = true;1004			test_args.test_virtual = true;1005			break;1006		case 'i':1007			test_args.iterations =1008			    atoi_positive("Number of iterations", optarg);1009			break;1010		case 'l':1011			test_args.long_wait_ms =1012			    atoi_positive("Long wait time", optarg);1013			break;1014		case 'p':1015			test_args.test_physical = true;1016			test_args.test_virtual = false;1017			break;1018		case 'v':1019			test_args.test_virtual = true;1020			test_args.test_physical = false;1021			break;1022		case 'w':1023			test_args.wait_ms = atoi_positive("Wait time", optarg);1024			break;1025		case 'h':1026		default:1027			goto err;1028		}1029	}1030 1031	return true;1032 1033 err:1034	test_print_help(argv[0]);1035	return false;1036}1037 1038int main(int argc, char *argv[])1039{1040	struct kvm_vcpu *vcpu;1041	struct kvm_vm *vm;1042 1043	/* Tell stdout not to buffer its content */1044	setbuf(stdout, NULL);1045 1046	if (!parse_args(argc, argv))1047		exit(KSFT_SKIP);1048 1049	if (test_args.test_virtual) {1050		test_vm_create(&vm, &vcpu, VIRTUAL);1051		test_run(vm, vcpu);1052		kvm_vm_free(vm);1053	}1054 1055	if (test_args.test_physical) {1056		test_vm_create(&vm, &vcpu, PHYSICAL);1057		test_run(vm, vcpu);1058		kvm_vm_free(vm);1059	}1060 1061	return 0;1062}1063