Commit de884232 authored by Marc Zyngier's avatar Marc Zyngier Committed by Oliver Upton
Browse files

KVM: arm64: selftests: vgic_irq: Add timer deactivation test



Add a new test case that triggers the HW deactivation emulation path
when trapping ICV_DIR_EL1. This is obviously tied to the way KVM
works now, but the test follows the expected architectural behaviour.

Tested-by: default avatarFuad Tabba <tabba@google.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Tested-by: default avatarMark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-50-maz@kernel.org


Signed-off-by: default avatarOliver Upton <oupton@kernel.org>
parent 1c9c71ac
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -894,6 +894,70 @@ static void guest_code_group_en(struct test_args *args, int cpuid)
	GUEST_DONE();
}

static void guest_code_timer_spi(struct test_args *args, int cpuid)
{
	uint32_t intid;
	u64 val;

	gic_init(GIC_V3, 2);

	gic_set_eoi_split(1);
	gic_set_priority_mask(CPU_PRIO_MASK);

	/* Add a pending SPI so that KVM starts trapping DIR */
	gic_set_priority(MIN_SPI + cpuid, IRQ_DEFAULT_PRIO);
	gic_irq_set_pending(MIN_SPI + cpuid);

	/* Configure the timer with a higher priority, make it pending */
	gic_set_priority(27, IRQ_DEFAULT_PRIO - 8);

	isb();
	val = read_sysreg(cntvct_el0);
	write_sysreg(val, cntv_cval_el0);
	write_sysreg(1, cntv_ctl_el0);
	isb();

	GUEST_ASSERT(gic_irq_get_pending(27));

	/* Enable both interrupts */
	gic_irq_enable(MIN_SPI + cpuid);
	gic_irq_enable(27);

	/* The timer must fire */
	intid = wait_for_and_activate_irq();
	GUEST_ASSERT(intid == 27);

	/* Check that we can deassert it */
	write_sysreg(0, cntv_ctl_el0);
	isb();

	GUEST_ASSERT(!gic_irq_get_pending(27));

	/*
	 * Priority drop, deactivation -- we expect that the host
	 * deactivation will have been effective
	 */
	gic_set_eoi(27);
	gic_set_dir(27);

	GUEST_ASSERT(!gic_irq_get_active(27));

	/* Do it one more time */
	isb();
	val = read_sysreg(cntvct_el0);
	write_sysreg(val, cntv_cval_el0);
	write_sysreg(1, cntv_ctl_el0);
	isb();

	GUEST_ASSERT(gic_irq_get_pending(27));

	/* The timer must fire again */
	intid = wait_for_and_activate_irq();
	GUEST_ASSERT(intid == 27);

	GUEST_DONE();
}

static void *test_vcpu_run(void *arg)
{
	struct kvm_vcpu *vcpu = arg;
@@ -1011,6 +1075,7 @@ int main(int argc, char **argv)
		test_vgic(nr_irqs, true /* level */, true /* eoi_split */);
		test_vgic_two_cpus(guest_code_asym_dir);
		test_vgic_two_cpus(guest_code_group_en);
		test_vgic_two_cpus(guest_code_timer_spi);
	} else {
		test_vgic(nr_irqs, level_sensitive, eoi_split);
	}