Skip to content

Commit 6a5a471

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Add tests for IRQFD in vgic_irq
Add injection tests for the KVM_IRQFD ioctl into vgic_irq. 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 88209c1 commit 6a5a471

File tree

2 files changed

+102
-1
lines changed

2 files changed

+102
-1
lines changed

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

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <asm/kvm.h>
1212
#include <asm/kvm_para.h>
13+
#include <sys/eventfd.h>
1314
#include <linux/sizes.h>
1415

1516
#include "processor.h"
@@ -31,6 +32,8 @@ struct test_args {
3132
uint32_t nr_irqs; /* number of KVM supported IRQs. */
3233
bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */
3334
bool level_sensitive; /* 1 is level, 0 is edge */
35+
int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */
36+
bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */
3437
};
3538

3639
/*
@@ -61,6 +64,7 @@ typedef enum {
6164
KVM_SET_IRQ_LINE,
6265
KVM_SET_IRQ_LINE_HIGH,
6366
KVM_SET_LEVEL_INFO_HIGH,
67+
KVM_INJECT_IRQFD,
6468
} kvm_inject_cmd;
6569

6670
struct kvm_inject_args {
@@ -100,19 +104,25 @@ struct kvm_inject_desc {
100104
static struct kvm_inject_desc inject_edge_fns[] = {
101105
/* sgi ppi spi */
102106
{ KVM_INJECT_EDGE_IRQ_LINE, false, false, true },
107+
{ KVM_INJECT_IRQFD, false, false, true },
103108
{ 0, },
104109
};
105110

106111
static struct kvm_inject_desc inject_level_fns[] = {
107112
/* sgi ppi spi */
108113
{ KVM_SET_IRQ_LINE_HIGH, false, true, true },
109114
{ KVM_SET_LEVEL_INFO_HIGH, false, true, true },
115+
{ KVM_INJECT_IRQFD, false, false, true },
110116
{ 0, },
111117
};
112118

113119
#define for_each_inject_fn(t, f) \
114120
for ((f) = (t); (f)->cmd; (f)++)
115121

122+
#define for_each_supported_inject_fn(args, t, f) \
123+
for_each_inject_fn(t, f) \
124+
if ((args)->kvm_supports_irqfd || (f)->cmd != KVM_INJECT_IRQFD)
125+
116126
/* Shared between the guest main thread and the IRQ handlers. */
117127
volatile uint64_t irq_handled;
118128
volatile uint32_t irqnr_received[MAX_SPI + 1];
@@ -403,7 +413,7 @@ static void guest_code(struct test_args args)
403413
local_irq_enable();
404414

405415
/* Start the tests. */
406-
for_each_inject_fn(inject_fns, f) {
416+
for_each_supported_inject_fn(&args, inject_fns, f) {
407417
test_injection(&args, f);
408418
test_preemption(&args, f);
409419
test_injection_failure(&args, f);
@@ -455,6 +465,88 @@ void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level,
455465
}
456466
}
457467

468+
static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm,
469+
uint32_t intid, uint32_t num, uint32_t kvm_max_routes,
470+
bool expect_failure)
471+
{
472+
struct kvm_irq_routing *routing;
473+
int ret;
474+
uint64_t i;
475+
476+
assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES);
477+
478+
routing = kvm_gsi_routing_create();
479+
for (i = intid; i < (uint64_t)intid + num; i++)
480+
kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI);
481+
482+
if (!expect_failure) {
483+
kvm_gsi_routing_write(vm, routing);
484+
} else {
485+
ret = _kvm_gsi_routing_write(vm, routing);
486+
/* The kernel only checks for KVM_IRQCHIP_NUM_PINS. */
487+
if (intid >= KVM_IRQCHIP_NUM_PINS)
488+
TEST_ASSERT(ret != 0 && errno == EINVAL,
489+
"Bad intid %u did not cause KVM_SET_GSI_ROUTING "
490+
"error: rc: %i errno: %i", intid, ret, errno);
491+
else
492+
TEST_ASSERT(ret == 0, "KVM_SET_GSI_ROUTING "
493+
"for intid %i failed, rc: %i errno: %i",
494+
intid, ret, errno);
495+
}
496+
}
497+
498+
static void kvm_routing_and_irqfd_check(struct kvm_vm *vm,
499+
uint32_t intid, uint32_t num, uint32_t kvm_max_routes,
500+
bool expect_failure)
501+
{
502+
int fd[MAX_SPI];
503+
uint64_t val;
504+
int ret, f;
505+
uint64_t i;
506+
507+
/*
508+
* There is no way to try injecting an SGI or PPI as the interface
509+
* starts counting from the first SPI (above the private ones), so just
510+
* exit.
511+
*/
512+
if (INTID_IS_SGI(intid) || INTID_IS_PPI(intid))
513+
return;
514+
515+
kvm_set_gsi_routing_irqchip_check(vm, intid, num,
516+
kvm_max_routes, expect_failure);
517+
518+
/*
519+
* If expect_failure, then just to inject anyway. These
520+
* will silently fail. And in any case, the guest will check
521+
* that no actual interrupt was injected for those cases.
522+
*/
523+
524+
for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {
525+
fd[f] = eventfd(0, 0);
526+
TEST_ASSERT(fd[f] != -1,
527+
"eventfd failed, errno: %i\n", errno);
528+
}
529+
530+
for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {
531+
struct kvm_irqfd irqfd = {
532+
.fd = fd[f],
533+
.gsi = i - MIN_SPI,
534+
};
535+
assert(i <= (uint64_t)UINT_MAX);
536+
vm_ioctl(vm, KVM_IRQFD, &irqfd);
537+
}
538+
539+
for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {
540+
val = 1;
541+
ret = write(fd[f], &val, sizeof(uint64_t));
542+
TEST_ASSERT(ret == sizeof(uint64_t),
543+
"Write to KVM_IRQFD failed with ret: %d\n", ret);
544+
}
545+
546+
for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++)
547+
close(fd[f]);
548+
}
549+
458550
/* handles the valid case: intid=0xffffffff num=1 */
459551
#define for_each_intid(first, num, tmp, i) \
460552
for ((tmp) = (i) = (first); \
@@ -500,6 +592,11 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
500592
kvm_irq_set_level_info_check(gic_fd, i, 1,
501593
expect_failure);
502594
break;
595+
case KVM_INJECT_IRQFD:
596+
kvm_routing_and_irqfd_check(vm, intid, num,
597+
test_args->kvm_max_routes,
598+
expect_failure);
599+
break;
503600
default:
504601
break;
505602
}
@@ -534,6 +631,8 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)
534631
.nr_irqs = nr_irqs,
535632
.level_sensitive = level_sensitive,
536633
.eoi_split = eoi_split,
634+
.kvm_max_routes = kvm_check_cap(KVM_CAP_IRQ_ROUTING),
635+
.kvm_supports_irqfd = kvm_check_cap(KVM_CAP_IRQFD),
537636
};
538637

539638
print_args(&args);

tools/testing/selftests/kvm/include/aarch64/vgic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ int _kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level);
2929
void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, uint32_t vcpu);
3030
void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, uint32_t vcpu);
3131

32+
#define KVM_IRQCHIP_NUM_PINS (1020 - 32)
33+
3234
#endif // SELFTEST_KVM_VGIC_H

0 commit comments

Comments
 (0)