10
10
11
11
#include <asm/kvm.h>
12
12
#include <asm/kvm_para.h>
13
+ #include <sys/eventfd.h>
13
14
#include <linux/sizes.h>
14
15
15
16
#include "processor.h"
@@ -31,6 +32,8 @@ struct test_args {
31
32
uint32_t nr_irqs ; /* number of KVM supported IRQs. */
32
33
bool eoi_split ; /* 1 is eoir+dir, 0 is eoir only */
33
34
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 */
34
37
};
35
38
36
39
/*
@@ -61,6 +64,7 @@ typedef enum {
61
64
KVM_SET_IRQ_LINE ,
62
65
KVM_SET_IRQ_LINE_HIGH ,
63
66
KVM_SET_LEVEL_INFO_HIGH ,
67
+ KVM_INJECT_IRQFD ,
64
68
} kvm_inject_cmd ;
65
69
66
70
struct kvm_inject_args {
@@ -100,19 +104,25 @@ struct kvm_inject_desc {
100
104
static struct kvm_inject_desc inject_edge_fns [] = {
101
105
/* sgi ppi spi */
102
106
{ KVM_INJECT_EDGE_IRQ_LINE , false, false, true },
107
+ { KVM_INJECT_IRQFD , false, false, true },
103
108
{ 0 , },
104
109
};
105
110
106
111
static struct kvm_inject_desc inject_level_fns [] = {
107
112
/* sgi ppi spi */
108
113
{ KVM_SET_IRQ_LINE_HIGH , false, true, true },
109
114
{ KVM_SET_LEVEL_INFO_HIGH , false, true, true },
115
+ { KVM_INJECT_IRQFD , false, false, true },
110
116
{ 0 , },
111
117
};
112
118
113
119
#define for_each_inject_fn (t , f ) \
114
120
for ((f) = (t); (f)->cmd; (f)++)
115
121
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
+
116
126
/* Shared between the guest main thread and the IRQ handlers. */
117
127
volatile uint64_t irq_handled ;
118
128
volatile uint32_t irqnr_received [MAX_SPI + 1 ];
@@ -403,7 +413,7 @@ static void guest_code(struct test_args args)
403
413
local_irq_enable ();
404
414
405
415
/* Start the tests. */
406
- for_each_inject_fn ( inject_fns , f ) {
416
+ for_each_supported_inject_fn ( & args , inject_fns , f ) {
407
417
test_injection (& args , f );
408
418
test_preemption (& args , f );
409
419
test_injection_failure (& args , f );
@@ -455,6 +465,88 @@ void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level,
455
465
}
456
466
}
457
467
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
+
458
550
/* handles the valid case: intid=0xffffffff num=1 */
459
551
#define for_each_intid (first , num , tmp , i ) \
460
552
for ((tmp) = (i) = (first); \
@@ -500,6 +592,11 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd,
500
592
kvm_irq_set_level_info_check (gic_fd , i , 1 ,
501
593
expect_failure );
502
594
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 ;
503
600
default :
504
601
break ;
505
602
}
@@ -534,6 +631,8 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)
534
631
.nr_irqs = nr_irqs ,
535
632
.level_sensitive = level_sensitive ,
536
633
.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 ),
537
636
};
538
637
539
638
print_args (& args );
0 commit comments