Skip to content

Commit 728fcc4

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Add test for restoring active IRQs
Add a test that restores multiple IRQs in active state, it does it by writing into ISACTIVER from the guest and using KVM ioctls. This test tries to emulate what would happen during a live migration: restore active IRQs. Signed-off-by: Ricardo Koller <[email protected]> Acked-by: Andrew Jones <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent bebd8f3 commit 728fcc4

File tree

1 file changed

+91
-0
lines changed

1 file changed

+91
-0
lines changed

tools/testing/selftests/kvm/aarch64/vgic_irq.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ typedef enum {
6666
KVM_SET_LEVEL_INFO_HIGH,
6767
KVM_INJECT_IRQFD,
6868
KVM_WRITE_ISPENDR,
69+
KVM_WRITE_ISACTIVER,
6970
} kvm_inject_cmd;
7071

7172
struct kvm_inject_args {
@@ -96,6 +97,9 @@ static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,
9697
#define KVM_INJECT(cmd, intid) \
9798
_KVM_INJECT_MULTI(cmd, intid, 1, false)
9899

100+
#define KVM_ACTIVATE(cmd, intid) \
101+
kvm_inject_call(cmd, intid, 1, 1, false);
102+
99103
struct kvm_inject_desc {
100104
kvm_inject_cmd cmd;
101105
/* can inject PPIs, PPIs, and/or SPIs. */
@@ -119,13 +123,22 @@ static struct kvm_inject_desc inject_level_fns[] = {
119123
{ 0, },
120124
};
121125

126+
static struct kvm_inject_desc set_active_fns[] = {
127+
/* sgi ppi spi */
128+
{ KVM_WRITE_ISACTIVER, true, true, true },
129+
{ 0, },
130+
};
131+
122132
#define for_each_inject_fn(t, f) \
123133
for ((f) = (t); (f)->cmd; (f)++)
124134

125135
#define for_each_supported_inject_fn(args, t, f) \
126136
for_each_inject_fn(t, f) \
127137
if ((args)->kvm_supports_irqfd || (f)->cmd != KVM_INJECT_IRQFD)
128138

139+
#define for_each_supported_activate_fn(args, t, f) \
140+
for_each_supported_inject_fn((args), (t), (f))
141+
129142
/* Shared between the guest main thread and the IRQ handlers. */
130143
volatile uint64_t irq_handled;
131144
volatile uint32_t irqnr_received[MAX_SPI + 1];
@@ -147,6 +160,12 @@ static uint64_t gic_read_ap1r0(void)
147160
return reg;
148161
}
149162

163+
static void gic_write_ap1r0(uint64_t val)
164+
{
165+
write_sysreg_s(val, SYS_ICV_AP1R0_EL1);
166+
isb();
167+
}
168+
150169
static void guest_set_irq_line(uint32_t intid, uint32_t level);
151170

152171
static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)
@@ -274,6 +293,55 @@ static void guest_inject(struct test_args *args,
274293
reset_priorities(args);
275294
}
276295

296+
/*
297+
* Restore the active state of multiple concurrent IRQs (given by
298+
* concurrent_irqs). This does what a live-migration would do on the
299+
* destination side assuming there are some active IRQs that were not
300+
* deactivated yet.
301+
*/
302+
static void guest_restore_active(struct test_args *args,
303+
uint32_t first_intid, uint32_t num,
304+
kvm_inject_cmd cmd)
305+
{
306+
uint32_t prio, intid, ap1r;
307+
int i;
308+
309+
/* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs
310+
* in descending order, so intid+1 can preempt intid.
311+
*/
312+
for (i = 0, prio = (num - 1) * 8; i < num; i++, prio -= 8) {
313+
GUEST_ASSERT(prio >= 0);
314+
intid = i + first_intid;
315+
gic_set_priority(intid, prio);
316+
}
317+
318+
/* In a real migration, KVM would restore all GIC state before running
319+
* guest code.
320+
*/
321+
for (i = 0; i < num; i++) {
322+
intid = i + first_intid;
323+
KVM_ACTIVATE(cmd, intid);
324+
ap1r = gic_read_ap1r0();
325+
ap1r |= 1U << i;
326+
gic_write_ap1r0(ap1r);
327+
}
328+
329+
/* This is where the "migration" would occur. */
330+
331+
/* finish handling the IRQs starting with the highest priority one. */
332+
for (i = 0; i < num; i++) {
333+
intid = num - i - 1 + first_intid;
334+
gic_set_eoi(intid);
335+
if (args->eoi_split)
336+
gic_set_dir(intid);
337+
}
338+
339+
for (i = 0; i < num; i++)
340+
GUEST_ASSERT(!gic_irq_get_active(i + first_intid));
341+
GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);
342+
GUEST_ASSERT_IAR_EMPTY();
343+
}
344+
277345
/*
278346
* Polls the IAR until it's not a spurious interrupt.
279347
*
@@ -391,6 +459,19 @@ static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)
391459
test_inject_preemption(args, MIN_SPI, 4, f->cmd);
392460
}
393461

462+
static void test_restore_active(struct test_args *args, struct kvm_inject_desc *f)
463+
{
464+
/* Test up to 4 active IRQs. Same reason as in test_preemption. */
465+
if (f->sgi)
466+
guest_restore_active(args, MIN_SGI, 4, f->cmd);
467+
468+
if (f->ppi)
469+
guest_restore_active(args, MIN_PPI, 4, f->cmd);
470+
471+
if (f->spi)
472+
guest_restore_active(args, MIN_SPI, 4, f->cmd);
473+
}
474+
394475
static void guest_code(struct test_args args)
395476
{
396477
uint32_t i, nr_irqs = args.nr_irqs;
@@ -422,6 +503,12 @@ static void guest_code(struct test_args args)
422503
test_injection_failure(&args, f);
423504
}
424505

506+
/* Restore the active state of IRQs. This would happen when live
507+
* migrating IRQs in the middle of being handled.
508+
*/
509+
for_each_supported_activate_fn(&args, set_active_fns, f)
510+
test_restore_active(&args, f);
511+
425512
GUEST_DONE();
426513
}
427514

@@ -619,6 +706,10 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
619706
kvm_irq_write_ispendr_check(gic_fd, i,
620707
VCPU_ID, expect_failure);
621708
break;
709+
case KVM_WRITE_ISACTIVER:
710+
for (i = intid; i < intid + num; i++)
711+
kvm_irq_write_isactiver(gic_fd, i, VCPU_ID);
712+
break;
622713
default:
623714
break;
624715
}

0 commit comments

Comments
 (0)