mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-11 17:10:13 +00:00
KVM: arm64: selftests: vgic_irq: Add asymmetric SPI deaectivation test
Add a new test case that makes an interrupt pending on a vcpu, activates it, do the priority drop, and then get *another* vcpu to do the deactivation. Special care is taken not to trigger an exit in the process, so that we are sure that the active interrupt is in an LR. Joy. Tested-by: Fuad Tabba <tabba@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Tested-by: Mark Brown <broonie@kernel.org> Link: https://msgid.link/20251120172540.2267180-48-maz@kernel.org Signed-off-by: Oliver Upton <oupton@kernel.org>
This commit is contained in:
parent
b6c68612ab
commit
d2dee2e849
@ -29,6 +29,7 @@ struct test_args {
|
||||
bool level_sensitive; /* 1 is level, 0 is edge */
|
||||
int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */
|
||||
bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */
|
||||
uint32_t shared_data;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -801,6 +802,109 @@ done:
|
||||
kvm_vm_free(vm);
|
||||
}
|
||||
|
||||
static void guest_code_asym_dir(struct test_args *args, int cpuid)
|
||||
{
|
||||
gic_init(GIC_V3, 2);
|
||||
|
||||
gic_set_eoi_split(1);
|
||||
gic_set_priority_mask(CPU_PRIO_MASK);
|
||||
|
||||
if (cpuid == 0) {
|
||||
uint32_t intid;
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
gic_set_priority(MIN_PPI, IRQ_DEFAULT_PRIO);
|
||||
gic_irq_enable(MIN_SPI);
|
||||
gic_irq_set_pending(MIN_SPI);
|
||||
|
||||
intid = wait_for_and_activate_irq();
|
||||
GUEST_ASSERT_EQ(intid, MIN_SPI);
|
||||
|
||||
gic_set_eoi(intid);
|
||||
isb();
|
||||
|
||||
WRITE_ONCE(args->shared_data, MIN_SPI);
|
||||
dsb(ishst);
|
||||
|
||||
do {
|
||||
dsb(ishld);
|
||||
} while (READ_ONCE(args->shared_data) == MIN_SPI);
|
||||
GUEST_ASSERT(!gic_irq_get_active(MIN_SPI));
|
||||
} else {
|
||||
do {
|
||||
dsb(ishld);
|
||||
} while (READ_ONCE(args->shared_data) != MIN_SPI);
|
||||
|
||||
gic_set_dir(MIN_SPI);
|
||||
isb();
|
||||
|
||||
WRITE_ONCE(args->shared_data, 0);
|
||||
dsb(ishst);
|
||||
}
|
||||
|
||||
GUEST_DONE();
|
||||
}
|
||||
|
||||
static void *test_vcpu_run(void *arg)
|
||||
{
|
||||
struct kvm_vcpu *vcpu = arg;
|
||||
struct ucall uc;
|
||||
|
||||
while (1) {
|
||||
vcpu_run(vcpu);
|
||||
|
||||
switch (get_ucall(vcpu, &uc)) {
|
||||
case UCALL_ABORT:
|
||||
REPORT_GUEST_ASSERT(uc);
|
||||
break;
|
||||
case UCALL_DONE:
|
||||
return NULL;
|
||||
default:
|
||||
TEST_FAIL("Unknown ucall %lu", uc.cmd);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_vgic_two_cpus(void *gcode)
|
||||
{
|
||||
pthread_t thr[2];
|
||||
struct kvm_vcpu *vcpus[2];
|
||||
struct test_args args = {};
|
||||
struct kvm_vm *vm;
|
||||
vm_vaddr_t args_gva;
|
||||
int gic_fd, ret;
|
||||
|
||||
vm = vm_create_with_vcpus(2, gcode, vcpus);
|
||||
|
||||
vm_init_descriptor_tables(vm);
|
||||
vcpu_init_descriptor_tables(vcpus[0]);
|
||||
vcpu_init_descriptor_tables(vcpus[1]);
|
||||
|
||||
/* Setup the guest args page (so it gets the args). */
|
||||
args_gva = vm_vaddr_alloc_page(vm);
|
||||
memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args));
|
||||
vcpu_args_set(vcpus[0], 2, args_gva, 0);
|
||||
vcpu_args_set(vcpus[1], 2, args_gva, 1);
|
||||
|
||||
gic_fd = vgic_v3_setup(vm, 2, 64);
|
||||
|
||||
ret = pthread_create(&thr[0], NULL, test_vcpu_run, vcpus[0]);
|
||||
if (ret)
|
||||
TEST_FAIL("Can't create thread for vcpu 0 (%d)\n", ret);
|
||||
ret = pthread_create(&thr[1], NULL, test_vcpu_run, vcpus[1]);
|
||||
if (ret)
|
||||
TEST_FAIL("Can't create thread for vcpu 1 (%d)\n", ret);
|
||||
|
||||
pthread_join(thr[0], NULL);
|
||||
pthread_join(thr[1], NULL);
|
||||
|
||||
close(gic_fd);
|
||||
kvm_vm_free(vm);
|
||||
}
|
||||
|
||||
static void help(const char *name)
|
||||
{
|
||||
printf(
|
||||
@ -857,6 +961,7 @@ int main(int argc, char **argv)
|
||||
test_vgic(nr_irqs, false /* level */, true /* eoi_split */);
|
||||
test_vgic(nr_irqs, true /* level */, false /* eoi_split */);
|
||||
test_vgic(nr_irqs, true /* level */, true /* eoi_split */);
|
||||
test_vgic_two_cpus(guest_code_asym_dir);
|
||||
} else {
|
||||
test_vgic(nr_irqs, level_sensitive, eoi_split);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user