brintos

brintos / linux-shallow public Read only

0
0
Text · 22.1 KiB · f4ac28d Raw
848 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * vgic_irq.c - Test userspace injection of IRQs4 *5 * This test validates the injection of IRQs from userspace using various6 * methods (e.g., KVM_IRQ_LINE) and modes (e.g., EOI). The guest "asks" the7 * host to inject a specific intid via a GUEST_SYNC call, and then checks that8 * it received it.9 */10#include <asm/kvm.h>11#include <asm/kvm_para.h>12#include <sys/eventfd.h>13#include <linux/sizes.h>14 15#include "processor.h"16#include "test_util.h"17#include "kvm_util.h"18#include "gic.h"19#include "gic_v3.h"20#include "vgic.h"21 22/*23 * Stores the user specified args; it's passed to the guest and to every test24 * function.25 */26struct test_args {27	uint32_t nr_irqs; /* number of KVM supported IRQs. */28	bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */29	bool level_sensitive; /* 1 is level, 0 is edge */30	int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */31	bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */32};33 34/*35 * KVM implements 32 priority levels:36 * 0x00 (highest priority) - 0xF8 (lowest priority), in steps of 837 *38 * Note that these macros will still be correct in the case that KVM implements39 * more priority levels. Also note that 32 is the minimum for GICv3 and GICv2.40 */41#define KVM_NUM_PRIOS		3242#define KVM_PRIO_SHIFT		3 /* steps of 8 = 1 << 3 */43#define KVM_PRIO_STEPS		(1 << KVM_PRIO_SHIFT) /* 8 */44#define LOWEST_PRIO		(KVM_NUM_PRIOS - 1)45#define CPU_PRIO_MASK		(LOWEST_PRIO << KVM_PRIO_SHIFT)	/* 0xf8 */46#define IRQ_DEFAULT_PRIO	(LOWEST_PRIO - 1)47#define IRQ_DEFAULT_PRIO_REG	(IRQ_DEFAULT_PRIO << KVM_PRIO_SHIFT) /* 0xf0 */48 49/*50 * The kvm_inject_* utilities are used by the guest to ask the host to inject51 * interrupts (e.g., using the KVM_IRQ_LINE ioctl).52 */53 54typedef enum {55	KVM_INJECT_EDGE_IRQ_LINE = 1,56	KVM_SET_IRQ_LINE,57	KVM_SET_IRQ_LINE_HIGH,58	KVM_SET_LEVEL_INFO_HIGH,59	KVM_INJECT_IRQFD,60	KVM_WRITE_ISPENDR,61	KVM_WRITE_ISACTIVER,62} kvm_inject_cmd;63 64struct kvm_inject_args {65	kvm_inject_cmd cmd;66	uint32_t first_intid;67	uint32_t num;68	int level;69	bool expect_failure;70};71 72/* Used on the guest side to perform the hypercall. */73static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,74		uint32_t num, int level, bool expect_failure);75 76/* Used on the host side to get the hypercall info. */77static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,78		struct kvm_inject_args *args);79 80#define _KVM_INJECT_MULTI(cmd, intid, num, expect_failure)			\81	kvm_inject_call(cmd, intid, num, -1 /* not used */, expect_failure)82 83#define KVM_INJECT_MULTI(cmd, intid, num)					\84	_KVM_INJECT_MULTI(cmd, intid, num, false)85 86#define _KVM_INJECT(cmd, intid, expect_failure)					\87	_KVM_INJECT_MULTI(cmd, intid, 1, expect_failure)88 89#define KVM_INJECT(cmd, intid)							\90	_KVM_INJECT_MULTI(cmd, intid, 1, false)91 92#define KVM_ACTIVATE(cmd, intid)						\93	kvm_inject_call(cmd, intid, 1, 1, false);94 95struct kvm_inject_desc {96	kvm_inject_cmd cmd;97	/* can inject PPIs, PPIs, and/or SPIs. */98	bool sgi, ppi, spi;99};100 101static struct kvm_inject_desc inject_edge_fns[] = {102	/*                                      sgi    ppi    spi */103	{ KVM_INJECT_EDGE_IRQ_LINE,		false, false, true },104	{ KVM_INJECT_IRQFD,			false, false, true },105	{ KVM_WRITE_ISPENDR,			true,  false, true },106	{ 0, },107};108 109static struct kvm_inject_desc inject_level_fns[] = {110	/*                                      sgi    ppi    spi */111	{ KVM_SET_IRQ_LINE_HIGH,		false, true,  true },112	{ KVM_SET_LEVEL_INFO_HIGH,		false, true,  true },113	{ KVM_INJECT_IRQFD,			false, false, true },114	{ KVM_WRITE_ISPENDR,			false, true,  true },115	{ 0, },116};117 118static struct kvm_inject_desc set_active_fns[] = {119	/*                                      sgi    ppi    spi */120	{ KVM_WRITE_ISACTIVER,			true,  true,  true },121	{ 0, },122};123 124#define for_each_inject_fn(t, f)						\125	for ((f) = (t); (f)->cmd; (f)++)126 127#define for_each_supported_inject_fn(args, t, f)				\128	for_each_inject_fn(t, f)						\129		if ((args)->kvm_supports_irqfd || (f)->cmd != KVM_INJECT_IRQFD)130 131#define for_each_supported_activate_fn(args, t, f)				\132	for_each_supported_inject_fn((args), (t), (f))133 134/* Shared between the guest main thread and the IRQ handlers. */135volatile uint64_t irq_handled;136volatile uint32_t irqnr_received[MAX_SPI + 1];137 138static void reset_stats(void)139{140	int i;141 142	irq_handled = 0;143	for (i = 0; i <= MAX_SPI; i++)144		irqnr_received[i] = 0;145}146 147static uint64_t gic_read_ap1r0(void)148{149	uint64_t reg = read_sysreg_s(SYS_ICC_AP1R0_EL1);150 151	dsb(sy);152	return reg;153}154 155static void gic_write_ap1r0(uint64_t val)156{157	write_sysreg_s(val, SYS_ICC_AP1R0_EL1);158	isb();159}160 161static void guest_set_irq_line(uint32_t intid, uint32_t level);162 163static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)164{165	uint32_t intid = gic_get_and_ack_irq();166 167	if (intid == IAR_SPURIOUS)168		return;169 170	GUEST_ASSERT(gic_irq_get_active(intid));171 172	if (!level_sensitive)173		GUEST_ASSERT(!gic_irq_get_pending(intid));174 175	if (level_sensitive)176		guest_set_irq_line(intid, 0);177 178	GUEST_ASSERT(intid < MAX_SPI);179	irqnr_received[intid] += 1;180	irq_handled += 1;181 182	gic_set_eoi(intid);183	GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);184	if (eoi_split)185		gic_set_dir(intid);186 187	GUEST_ASSERT(!gic_irq_get_active(intid));188	GUEST_ASSERT(!gic_irq_get_pending(intid));189}190 191static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,192		uint32_t num, int level, bool expect_failure)193{194	struct kvm_inject_args args = {195		.cmd = cmd,196		.first_intid = first_intid,197		.num = num,198		.level = level,199		.expect_failure = expect_failure,200	};201	GUEST_SYNC(&args);202}203 204#define GUEST_ASSERT_IAR_EMPTY()						\205do { 										\206	uint32_t _intid;							\207	_intid = gic_get_and_ack_irq();						\208	GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS);			\209} while (0)210 211#define CAT_HELPER(a, b) a ## b212#define CAT(a, b) CAT_HELPER(a, b)213#define PREFIX guest_irq_handler_214#define GUEST_IRQ_HANDLER_NAME(split, lev) CAT(PREFIX, CAT(split, lev))215#define GENERATE_GUEST_IRQ_HANDLER(split, lev)					\216static void CAT(PREFIX, CAT(split, lev))(struct ex_regs *regs)			\217{										\218	guest_irq_generic_handler(split, lev);					\219}220 221GENERATE_GUEST_IRQ_HANDLER(0, 0);222GENERATE_GUEST_IRQ_HANDLER(0, 1);223GENERATE_GUEST_IRQ_HANDLER(1, 0);224GENERATE_GUEST_IRQ_HANDLER(1, 1);225 226static void (*guest_irq_handlers[2][2])(struct ex_regs *) = {227	{GUEST_IRQ_HANDLER_NAME(0, 0), GUEST_IRQ_HANDLER_NAME(0, 1),},228	{GUEST_IRQ_HANDLER_NAME(1, 0), GUEST_IRQ_HANDLER_NAME(1, 1),},229};230 231static void reset_priorities(struct test_args *args)232{233	int i;234 235	for (i = 0; i < args->nr_irqs; i++)236		gic_set_priority(i, IRQ_DEFAULT_PRIO_REG);237}238 239static void guest_set_irq_line(uint32_t intid, uint32_t level)240{241	kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false);242}243 244static void test_inject_fail(struct test_args *args,245		uint32_t intid, kvm_inject_cmd cmd)246{247	reset_stats();248 249	_KVM_INJECT(cmd, intid, true);250	/* no IRQ to handle on entry */251 252	GUEST_ASSERT_EQ(irq_handled, 0);253	GUEST_ASSERT_IAR_EMPTY();254}255 256static void guest_inject(struct test_args *args,257		uint32_t first_intid, uint32_t num,258		kvm_inject_cmd cmd)259{260	uint32_t i;261 262	reset_stats();263 264	/* Cycle over all priorities to make things more interesting. */265	for (i = first_intid; i < num + first_intid; i++)266		gic_set_priority(i, (i % (KVM_NUM_PRIOS - 1)) << 3);267 268	asm volatile("msr daifset, #2" : : : "memory");269	KVM_INJECT_MULTI(cmd, first_intid, num);270 271	while (irq_handled < num) {272		wfi();273		local_irq_enable();274		isb(); /* handle IRQ */275		local_irq_disable();276	}277	local_irq_enable();278 279	GUEST_ASSERT_EQ(irq_handled, num);280	for (i = first_intid; i < num + first_intid; i++)281		GUEST_ASSERT_EQ(irqnr_received[i], 1);282	GUEST_ASSERT_IAR_EMPTY();283 284	reset_priorities(args);285}286 287/*288 * Restore the active state of multiple concurrent IRQs (given by289 * concurrent_irqs).  This does what a live-migration would do on the290 * destination side assuming there are some active IRQs that were not291 * deactivated yet.292 */293static void guest_restore_active(struct test_args *args,294		uint32_t first_intid, uint32_t num,295		kvm_inject_cmd cmd)296{297	uint32_t prio, intid, ap1r;298	int i;299 300	/*301	 * Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs302	 * in descending order, so intid+1 can preempt intid.303	 */304	for (i = 0, prio = (num - 1) * 8; i < num; i++, prio -= 8) {305		GUEST_ASSERT(prio >= 0);306		intid = i + first_intid;307		gic_set_priority(intid, prio);308	}309 310	/*311	 * In a real migration, KVM would restore all GIC state before running312	 * guest code.313	 */314	for (i = 0; i < num; i++) {315		intid = i + first_intid;316		KVM_ACTIVATE(cmd, intid);317		ap1r = gic_read_ap1r0();318		ap1r |= 1U << i;319		gic_write_ap1r0(ap1r);320	}321 322	/* This is where the "migration" would occur. */323 324	/* finish handling the IRQs starting with the highest priority one. */325	for (i = 0; i < num; i++) {326		intid = num - i - 1 + first_intid;327		gic_set_eoi(intid);328		if (args->eoi_split)329			gic_set_dir(intid);330	}331 332	for (i = 0; i < num; i++)333		GUEST_ASSERT(!gic_irq_get_active(i + first_intid));334	GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);335	GUEST_ASSERT_IAR_EMPTY();336}337 338/*339 * Polls the IAR until it's not a spurious interrupt.340 *341 * This function should only be used in test_inject_preemption (with IRQs342 * masked).343 */344static uint32_t wait_for_and_activate_irq(void)345{346	uint32_t intid;347 348	do {349		asm volatile("wfi" : : : "memory");350		intid = gic_get_and_ack_irq();351	} while (intid == IAR_SPURIOUS);352 353	return intid;354}355 356/*357 * Inject multiple concurrent IRQs (num IRQs starting at first_intid) and358 * handle them without handling the actual exceptions.  This is done by masking359 * interrupts for the whole test.360 */361static void test_inject_preemption(struct test_args *args,362		uint32_t first_intid, int num,363		kvm_inject_cmd cmd)364{365	uint32_t intid, prio, step = KVM_PRIO_STEPS;366	int i;367 368	/* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs369	 * in descending order, so intid+1 can preempt intid.370	 */371	for (i = 0, prio = (num - 1) * step; i < num; i++, prio -= step) {372		GUEST_ASSERT(prio >= 0);373		intid = i + first_intid;374		gic_set_priority(intid, prio);375	}376 377	local_irq_disable();378 379	for (i = 0; i < num; i++) {380		uint32_t tmp;381		intid = i + first_intid;382		KVM_INJECT(cmd, intid);383		/* Each successive IRQ will preempt the previous one. */384		tmp = wait_for_and_activate_irq();385		GUEST_ASSERT_EQ(tmp, intid);386		if (args->level_sensitive)387			guest_set_irq_line(intid, 0);388	}389 390	/* finish handling the IRQs starting with the highest priority one. */391	for (i = 0; i < num; i++) {392		intid = num - i - 1 + first_intid;393		gic_set_eoi(intid);394		if (args->eoi_split)395			gic_set_dir(intid);396	}397 398	local_irq_enable();399 400	for (i = 0; i < num; i++)401		GUEST_ASSERT(!gic_irq_get_active(i + first_intid));402	GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);403	GUEST_ASSERT_IAR_EMPTY();404 405	reset_priorities(args);406}407 408static void test_injection(struct test_args *args, struct kvm_inject_desc *f)409{410	uint32_t nr_irqs = args->nr_irqs;411 412	if (f->sgi) {413		guest_inject(args, MIN_SGI, 1, f->cmd);414		guest_inject(args, 0, 16, f->cmd);415	}416 417	if (f->ppi)418		guest_inject(args, MIN_PPI, 1, f->cmd);419 420	if (f->spi) {421		guest_inject(args, MIN_SPI, 1, f->cmd);422		guest_inject(args, nr_irqs - 1, 1, f->cmd);423		guest_inject(args, MIN_SPI, nr_irqs - MIN_SPI, f->cmd);424	}425}426 427static void test_injection_failure(struct test_args *args,428		struct kvm_inject_desc *f)429{430	uint32_t bad_intid[] = { args->nr_irqs, 1020, 1024, 1120, 5120, ~0U, };431	int i;432 433	for (i = 0; i < ARRAY_SIZE(bad_intid); i++)434		test_inject_fail(args, bad_intid[i], f->cmd);435}436 437static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)438{439	/*440	 * Test up to 4 levels of preemption. The reason is that KVM doesn't441	 * currently implement the ability to have more than the number-of-LRs442	 * number of concurrently active IRQs. The number of LRs implemented is443	 * IMPLEMENTATION DEFINED, however, it seems that most implement 4.444	 */445	if (f->sgi)446		test_inject_preemption(args, MIN_SGI, 4, f->cmd);447 448	if (f->ppi)449		test_inject_preemption(args, MIN_PPI, 4, f->cmd);450 451	if (f->spi)452		test_inject_preemption(args, MIN_SPI, 4, f->cmd);453}454 455static void test_restore_active(struct test_args *args, struct kvm_inject_desc *f)456{457	/* Test up to 4 active IRQs. Same reason as in test_preemption. */458	if (f->sgi)459		guest_restore_active(args, MIN_SGI, 4, f->cmd);460 461	if (f->ppi)462		guest_restore_active(args, MIN_PPI, 4, f->cmd);463 464	if (f->spi)465		guest_restore_active(args, MIN_SPI, 4, f->cmd);466}467 468static void guest_code(struct test_args *args)469{470	uint32_t i, nr_irqs = args->nr_irqs;471	bool level_sensitive = args->level_sensitive;472	struct kvm_inject_desc *f, *inject_fns;473 474	gic_init(GIC_V3, 1);475 476	for (i = 0; i < nr_irqs; i++)477		gic_irq_enable(i);478 479	for (i = MIN_SPI; i < nr_irqs; i++)480		gic_irq_set_config(i, !level_sensitive);481 482	gic_set_eoi_split(args->eoi_split);483 484	reset_priorities(args);485	gic_set_priority_mask(CPU_PRIO_MASK);486 487	inject_fns  = level_sensitive ? inject_level_fns488				      : inject_edge_fns;489 490	local_irq_enable();491 492	/* Start the tests. */493	for_each_supported_inject_fn(args, inject_fns, f) {494		test_injection(args, f);495		test_preemption(args, f);496		test_injection_failure(args, f);497	}498 499	/*500	 * Restore the active state of IRQs. This would happen when live501	 * migrating IRQs in the middle of being handled.502	 */503	for_each_supported_activate_fn(args, set_active_fns, f)504		test_restore_active(args, f);505 506	GUEST_DONE();507}508 509static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level,510			struct test_args *test_args, bool expect_failure)511{512	int ret;513 514	if (!expect_failure) {515		kvm_arm_irq_line(vm, intid, level);516	} else {517		/* The interface doesn't allow larger intid's. */518		if (intid > KVM_ARM_IRQ_NUM_MASK)519			return;520 521		ret = _kvm_arm_irq_line(vm, intid, level);522		TEST_ASSERT(ret != 0 && errno == EINVAL,523				"Bad intid %i did not cause KVM_IRQ_LINE "524				"error: rc: %i errno: %i", intid, ret, errno);525	}526}527 528void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level,529			bool expect_failure)530{531	if (!expect_failure) {532		kvm_irq_set_level_info(gic_fd, intid, level);533	} else {534		int ret = _kvm_irq_set_level_info(gic_fd, intid, level);535		/*536		 * The kernel silently fails for invalid SPIs and SGIs (which537		 * are not level-sensitive). It only checks for intid to not538		 * spill over 1U << 10 (the max reserved SPI). Also, callers539		 * are supposed to mask the intid with 0x3ff (1023).540		 */541		if (intid > VGIC_MAX_RESERVED)542			TEST_ASSERT(ret != 0 && errno == EINVAL,543				"Bad intid %i did not cause VGIC_GRP_LEVEL_INFO "544				"error: rc: %i errno: %i", intid, ret, errno);545		else546			TEST_ASSERT(!ret, "KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO "547				"for intid %i failed, rc: %i errno: %i",548				intid, ret, errno);549	}550}551 552static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm,553		uint32_t intid, uint32_t num, uint32_t kvm_max_routes,554		bool expect_failure)555{556	struct kvm_irq_routing *routing;557	int ret;558	uint64_t i;559 560	assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES);561 562	routing = kvm_gsi_routing_create();563	for (i = intid; i < (uint64_t)intid + num; i++)564		kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI);565 566	if (!expect_failure) {567		kvm_gsi_routing_write(vm, routing);568	} else {569		ret = _kvm_gsi_routing_write(vm, routing);570		/* The kernel only checks e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS */571		if (((uint64_t)intid + num - 1 - MIN_SPI) >= KVM_IRQCHIP_NUM_PINS)572			TEST_ASSERT(ret != 0 && errno == EINVAL,573				"Bad intid %u did not cause KVM_SET_GSI_ROUTING "574				"error: rc: %i errno: %i", intid, ret, errno);575		else576			TEST_ASSERT(ret == 0, "KVM_SET_GSI_ROUTING "577				"for intid %i failed, rc: %i errno: %i",578				intid, ret, errno);579	}580}581 582static void kvm_irq_write_ispendr_check(int gic_fd, uint32_t intid,583					struct kvm_vcpu *vcpu,584					bool expect_failure)585{586	/*587	 * Ignore this when expecting failure as invalid intids will lead to588	 * either trying to inject SGIs when we configured the test to be589	 * level_sensitive (or the reverse), or inject large intids which590	 * will lead to writing above the ISPENDR register space (and we591	 * don't want to do that either).592	 */593	if (!expect_failure)594		kvm_irq_write_ispendr(gic_fd, intid, vcpu);595}596 597static void kvm_routing_and_irqfd_check(struct kvm_vm *vm,598		uint32_t intid, uint32_t num, uint32_t kvm_max_routes,599		bool expect_failure)600{601	int fd[MAX_SPI];602	uint64_t val;603	int ret, f;604	uint64_t i;605 606	/*607	 * There is no way to try injecting an SGI or PPI as the interface608	 * starts counting from the first SPI (above the private ones), so just609	 * exit.610	 */611	if (INTID_IS_SGI(intid) || INTID_IS_PPI(intid))612		return;613 614	kvm_set_gsi_routing_irqchip_check(vm, intid, num,615			kvm_max_routes, expect_failure);616 617	/*618	 * If expect_failure, then just to inject anyway. These619	 * will silently fail. And in any case, the guest will check620	 * that no actual interrupt was injected for those cases.621	 */622 623	for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {624		fd[f] = eventfd(0, 0);625		TEST_ASSERT(fd[f] != -1, __KVM_SYSCALL_ERROR("eventfd()", fd[f]));626	}627 628	for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {629		struct kvm_irqfd irqfd = {630			.fd  = fd[f],631			.gsi = i - MIN_SPI,632		};633		assert(i <= (uint64_t)UINT_MAX);634		vm_ioctl(vm, KVM_IRQFD, &irqfd);635	}636 637	for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {638		val = 1;639		ret = write(fd[f], &val, sizeof(uint64_t));640		TEST_ASSERT(ret == sizeof(uint64_t),641			    __KVM_SYSCALL_ERROR("write()", ret));642	}643 644	for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++)645		close(fd[f]);646}647 648/* handles the valid case: intid=0xffffffff num=1 */649#define for_each_intid(first, num, tmp, i)					\650	for ((tmp) = (i) = (first);						\651		(tmp) < (uint64_t)(first) + (uint64_t)(num);			\652		(tmp)++, (i)++)653 654static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd,655			  struct kvm_inject_args *inject_args,656			  struct test_args *test_args)657{658	kvm_inject_cmd cmd = inject_args->cmd;659	uint32_t intid = inject_args->first_intid;660	uint32_t num = inject_args->num;661	int level = inject_args->level;662	bool expect_failure = inject_args->expect_failure;663	struct kvm_vm *vm = vcpu->vm;664	uint64_t tmp;665	uint32_t i;666 667	/* handles the valid case: intid=0xffffffff num=1 */668	assert(intid < UINT_MAX - num || num == 1);669 670	switch (cmd) {671	case KVM_INJECT_EDGE_IRQ_LINE:672		for_each_intid(intid, num, tmp, i)673			kvm_irq_line_check(vm, i, 1, test_args,674					expect_failure);675		for_each_intid(intid, num, tmp, i)676			kvm_irq_line_check(vm, i, 0, test_args,677					expect_failure);678		break;679	case KVM_SET_IRQ_LINE:680		for_each_intid(intid, num, tmp, i)681			kvm_irq_line_check(vm, i, level, test_args,682					expect_failure);683		break;684	case KVM_SET_IRQ_LINE_HIGH:685		for_each_intid(intid, num, tmp, i)686			kvm_irq_line_check(vm, i, 1, test_args,687					expect_failure);688		break;689	case KVM_SET_LEVEL_INFO_HIGH:690		for_each_intid(intid, num, tmp, i)691			kvm_irq_set_level_info_check(gic_fd, i, 1,692					expect_failure);693		break;694	case KVM_INJECT_IRQFD:695		kvm_routing_and_irqfd_check(vm, intid, num,696					test_args->kvm_max_routes,697					expect_failure);698		break;699	case KVM_WRITE_ISPENDR:700		for (i = intid; i < intid + num; i++)701			kvm_irq_write_ispendr_check(gic_fd, i, vcpu,702						    expect_failure);703		break;704	case KVM_WRITE_ISACTIVER:705		for (i = intid; i < intid + num; i++)706			kvm_irq_write_isactiver(gic_fd, i, vcpu);707		break;708	default:709		break;710	}711}712 713static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,714		struct kvm_inject_args *args)715{716	struct kvm_inject_args *kvm_args_hva;717	vm_vaddr_t kvm_args_gva;718 719	kvm_args_gva = uc->args[1];720	kvm_args_hva = (struct kvm_inject_args *)addr_gva2hva(vm, kvm_args_gva);721	memcpy(args, kvm_args_hva, sizeof(struct kvm_inject_args));722}723 724static void print_args(struct test_args *args)725{726	printf("nr-irqs=%d level-sensitive=%d eoi-split=%d\n",727			args->nr_irqs, args->level_sensitive,728			args->eoi_split);729}730 731static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)732{733	struct ucall uc;734	int gic_fd;735	struct kvm_vcpu *vcpu;736	struct kvm_vm *vm;737	struct kvm_inject_args inject_args;738	vm_vaddr_t args_gva;739 740	struct test_args args = {741		.nr_irqs = nr_irqs,742		.level_sensitive = level_sensitive,743		.eoi_split = eoi_split,744		.kvm_max_routes = kvm_check_cap(KVM_CAP_IRQ_ROUTING),745		.kvm_supports_irqfd = kvm_check_cap(KVM_CAP_IRQFD),746	};747 748	print_args(&args);749 750	vm = vm_create_with_one_vcpu(&vcpu, guest_code);751 752	vm_init_descriptor_tables(vm);753	vcpu_init_descriptor_tables(vcpu);754 755	/* Setup the guest args page (so it gets the args). */756	args_gva = vm_vaddr_alloc_page(vm);757	memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args));758	vcpu_args_set(vcpu, 1, args_gva);759 760	gic_fd = vgic_v3_setup(vm, 1, nr_irqs);761	__TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3, skipping");762 763	vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,764		guest_irq_handlers[args.eoi_split][args.level_sensitive]);765 766	while (1) {767		vcpu_run(vcpu);768 769		switch (get_ucall(vcpu, &uc)) {770		case UCALL_SYNC:771			kvm_inject_get_call(vm, &uc, &inject_args);772			run_guest_cmd(vcpu, gic_fd, &inject_args, &args);773			break;774		case UCALL_ABORT:775			REPORT_GUEST_ASSERT(uc);776			break;777		case UCALL_DONE:778			goto done;779		default:780			TEST_FAIL("Unknown ucall %lu", uc.cmd);781		}782	}783 784done:785	close(gic_fd);786	kvm_vm_free(vm);787}788 789static void help(const char *name)790{791	printf(792	"\n"793	"usage: %s [-n num_irqs] [-e eoi_split] [-l level_sensitive]\n", name);794	printf(" -n: specify number of IRQs to setup the vgic with. "795		"It has to be a multiple of 32 and between 64 and 1024.\n");796	printf(" -e: if 1 then EOI is split into a write to DIR on top "797		"of writing EOI.\n");798	printf(" -l: specify whether the IRQs are level-sensitive (1) or not (0).");799	puts("");800	exit(1);801}802 803int main(int argc, char **argv)804{805	uint32_t nr_irqs = 64;806	bool default_args = true;807	bool level_sensitive = false;808	int opt;809	bool eoi_split = false;810 811	while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) {812		switch (opt) {813		case 'n':814			nr_irqs = atoi_non_negative("Number of IRQs", optarg);815			if (nr_irqs > 1024 || nr_irqs % 32)816				help(argv[0]);817			break;818		case 'e':819			eoi_split = (bool)atoi_paranoid(optarg);820			default_args = false;821			break;822		case 'l':823			level_sensitive = (bool)atoi_paranoid(optarg);824			default_args = false;825			break;826		case 'h':827		default:828			help(argv[0]);829			break;830		}831	}832 833	/*834	 * If the user just specified nr_irqs and/or gic_version, then run all835	 * combinations.836	 */837	if (default_args) {838		test_vgic(nr_irqs, false /* level */, false /* eoi_split */);839		test_vgic(nr_irqs, false /* level */, true /* eoi_split */);840		test_vgic(nr_irqs, true /* level */, false /* eoi_split */);841		test_vgic(nr_irqs, true /* level */, true /* eoi_split */);842	} else {843		test_vgic(nr_irqs, level_sensitive, eoi_split);844	}845 846	return 0;847}848