848 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * vgic_irq.c - Test userspace injection of IRQs4 *5 * This test validates the injection of IRQs from userspace using various6 * methods (e.g., KVM_IRQ_LINE) and modes (e.g., EOI). The guest "asks" the7 * host to inject a specific intid via a GUEST_SYNC call, and then checks that8 * it received it.9 */10#include <asm/kvm.h>11#include <asm/kvm_para.h>12#include <sys/eventfd.h>13#include <linux/sizes.h>14 15#include "processor.h"16#include "test_util.h"17#include "kvm_util.h"18#include "gic.h"19#include "gic_v3.h"20#include "vgic.h"21 22/*23 * Stores the user specified args; it's passed to the guest and to every test24 * function.25 */26struct test_args {27 uint32_t nr_irqs; /* number of KVM supported IRQs. */28 bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */29 bool level_sensitive; /* 1 is level, 0 is edge */30 int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */31 bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */32};33 34/*35 * KVM implements 32 priority levels:36 * 0x00 (highest priority) - 0xF8 (lowest priority), in steps of 837 *38 * Note that these macros will still be correct in the case that KVM implements39 * more priority levels. Also note that 32 is the minimum for GICv3 and GICv2.40 */41#define KVM_NUM_PRIOS 3242#define KVM_PRIO_SHIFT 3 /* steps of 8 = 1 << 3 */43#define KVM_PRIO_STEPS (1 << KVM_PRIO_SHIFT) /* 8 */44#define LOWEST_PRIO (KVM_NUM_PRIOS - 1)45#define CPU_PRIO_MASK (LOWEST_PRIO << KVM_PRIO_SHIFT) /* 0xf8 */46#define IRQ_DEFAULT_PRIO (LOWEST_PRIO - 1)47#define IRQ_DEFAULT_PRIO_REG (IRQ_DEFAULT_PRIO << KVM_PRIO_SHIFT) /* 0xf0 */48 49/*50 * The kvm_inject_* utilities are used by the guest to ask the host to inject51 * interrupts (e.g., using the KVM_IRQ_LINE ioctl).52 */53 54typedef enum {55 KVM_INJECT_EDGE_IRQ_LINE = 1,56 KVM_SET_IRQ_LINE,57 KVM_SET_IRQ_LINE_HIGH,58 KVM_SET_LEVEL_INFO_HIGH,59 KVM_INJECT_IRQFD,60 KVM_WRITE_ISPENDR,61 KVM_WRITE_ISACTIVER,62} kvm_inject_cmd;63 64struct kvm_inject_args {65 kvm_inject_cmd cmd;66 uint32_t first_intid;67 uint32_t num;68 int level;69 bool expect_failure;70};71 72/* Used on the guest side to perform the hypercall. */73static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,74 uint32_t num, int level, bool expect_failure);75 76/* Used on the host side to get the hypercall info. */77static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,78 struct kvm_inject_args *args);79 80#define _KVM_INJECT_MULTI(cmd, intid, num, expect_failure) \81 kvm_inject_call(cmd, intid, num, -1 /* not used */, expect_failure)82 83#define KVM_INJECT_MULTI(cmd, intid, num) \84 _KVM_INJECT_MULTI(cmd, intid, num, false)85 86#define _KVM_INJECT(cmd, intid, expect_failure) \87 _KVM_INJECT_MULTI(cmd, intid, 1, expect_failure)88 89#define KVM_INJECT(cmd, intid) \90 _KVM_INJECT_MULTI(cmd, intid, 1, false)91 92#define KVM_ACTIVATE(cmd, intid) \93 kvm_inject_call(cmd, intid, 1, 1, false);94 95struct kvm_inject_desc {96 kvm_inject_cmd cmd;97 /* can inject PPIs, PPIs, and/or SPIs. */98 bool sgi, ppi, spi;99};100 101static struct kvm_inject_desc inject_edge_fns[] = {102 /* sgi ppi spi */103 { KVM_INJECT_EDGE_IRQ_LINE, false, false, true },104 { KVM_INJECT_IRQFD, false, false, true },105 { KVM_WRITE_ISPENDR, true, false, true },106 { 0, },107};108 109static struct kvm_inject_desc inject_level_fns[] = {110 /* sgi ppi spi */111 { KVM_SET_IRQ_LINE_HIGH, false, true, true },112 { KVM_SET_LEVEL_INFO_HIGH, false, true, true },113 { KVM_INJECT_IRQFD, false, false, true },114 { KVM_WRITE_ISPENDR, false, true, true },115 { 0, },116};117 118static struct kvm_inject_desc set_active_fns[] = {119 /* sgi ppi spi */120 { KVM_WRITE_ISACTIVER, true, true, true },121 { 0, },122};123 124#define for_each_inject_fn(t, f) \125 for ((f) = (t); (f)->cmd; (f)++)126 127#define for_each_supported_inject_fn(args, t, f) \128 for_each_inject_fn(t, f) \129 if ((args)->kvm_supports_irqfd || (f)->cmd != KVM_INJECT_IRQFD)130 131#define for_each_supported_activate_fn(args, t, f) \132 for_each_supported_inject_fn((args), (t), (f))133 134/* Shared between the guest main thread and the IRQ handlers. */135volatile uint64_t irq_handled;136volatile uint32_t irqnr_received[MAX_SPI + 1];137 138static void reset_stats(void)139{140 int i;141 142 irq_handled = 0;143 for (i = 0; i <= MAX_SPI; i++)144 irqnr_received[i] = 0;145}146 147static uint64_t gic_read_ap1r0(void)148{149 uint64_t reg = read_sysreg_s(SYS_ICC_AP1R0_EL1);150 151 dsb(sy);152 return reg;153}154 155static void gic_write_ap1r0(uint64_t val)156{157 write_sysreg_s(val, SYS_ICC_AP1R0_EL1);158 isb();159}160 161static void guest_set_irq_line(uint32_t intid, uint32_t level);162 163static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)164{165 uint32_t intid = gic_get_and_ack_irq();166 167 if (intid == IAR_SPURIOUS)168 return;169 170 GUEST_ASSERT(gic_irq_get_active(intid));171 172 if (!level_sensitive)173 GUEST_ASSERT(!gic_irq_get_pending(intid));174 175 if (level_sensitive)176 guest_set_irq_line(intid, 0);177 178 GUEST_ASSERT(intid < MAX_SPI);179 irqnr_received[intid] += 1;180 irq_handled += 1;181 182 gic_set_eoi(intid);183 GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);184 if (eoi_split)185 gic_set_dir(intid);186 187 GUEST_ASSERT(!gic_irq_get_active(intid));188 GUEST_ASSERT(!gic_irq_get_pending(intid));189}190 191static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,192 uint32_t num, int level, bool expect_failure)193{194 struct kvm_inject_args args = {195 .cmd = cmd,196 .first_intid = first_intid,197 .num = num,198 .level = level,199 .expect_failure = expect_failure,200 };201 GUEST_SYNC(&args);202}203 204#define GUEST_ASSERT_IAR_EMPTY() \205do { \206 uint32_t _intid; \207 _intid = gic_get_and_ack_irq(); \208 GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS); \209} while (0)210 211#define CAT_HELPER(a, b) a ## b212#define CAT(a, b) CAT_HELPER(a, b)213#define PREFIX guest_irq_handler_214#define GUEST_IRQ_HANDLER_NAME(split, lev) CAT(PREFIX, CAT(split, lev))215#define GENERATE_GUEST_IRQ_HANDLER(split, lev) \216static void CAT(PREFIX, CAT(split, lev))(struct ex_regs *regs) \217{ \218 guest_irq_generic_handler(split, lev); \219}220 221GENERATE_GUEST_IRQ_HANDLER(0, 0);222GENERATE_GUEST_IRQ_HANDLER(0, 1);223GENERATE_GUEST_IRQ_HANDLER(1, 0);224GENERATE_GUEST_IRQ_HANDLER(1, 1);225 226static void (*guest_irq_handlers[2][2])(struct ex_regs *) = {227 {GUEST_IRQ_HANDLER_NAME(0, 0), GUEST_IRQ_HANDLER_NAME(0, 1),},228 {GUEST_IRQ_HANDLER_NAME(1, 0), GUEST_IRQ_HANDLER_NAME(1, 1),},229};230 231static void reset_priorities(struct test_args *args)232{233 int i;234 235 for (i = 0; i < args->nr_irqs; i++)236 gic_set_priority(i, IRQ_DEFAULT_PRIO_REG);237}238 239static void guest_set_irq_line(uint32_t intid, uint32_t level)240{241 kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false);242}243 244static void test_inject_fail(struct test_args *args,245 uint32_t intid, kvm_inject_cmd cmd)246{247 reset_stats();248 249 _KVM_INJECT(cmd, intid, true);250 /* no IRQ to handle on entry */251 252 GUEST_ASSERT_EQ(irq_handled, 0);253 GUEST_ASSERT_IAR_EMPTY();254}255 256static void guest_inject(struct test_args *args,257 uint32_t first_intid, uint32_t num,258 kvm_inject_cmd cmd)259{260 uint32_t i;261 262 reset_stats();263 264 /* Cycle over all priorities to make things more interesting. */265 for (i = first_intid; i < num + first_intid; i++)266 gic_set_priority(i, (i % (KVM_NUM_PRIOS - 1)) << 3);267 268 asm volatile("msr daifset, #2" : : : "memory");269 KVM_INJECT_MULTI(cmd, first_intid, num);270 271 while (irq_handled < num) {272 wfi();273 local_irq_enable();274 isb(); /* handle IRQ */275 local_irq_disable();276 }277 local_irq_enable();278 279 GUEST_ASSERT_EQ(irq_handled, num);280 for (i = first_intid; i < num + first_intid; i++)281 GUEST_ASSERT_EQ(irqnr_received[i], 1);282 GUEST_ASSERT_IAR_EMPTY();283 284 reset_priorities(args);285}286 287/*288 * Restore the active state of multiple concurrent IRQs (given by289 * concurrent_irqs). This does what a live-migration would do on the290 * destination side assuming there are some active IRQs that were not291 * deactivated yet.292 */293static void guest_restore_active(struct test_args *args,294 uint32_t first_intid, uint32_t num,295 kvm_inject_cmd cmd)296{297 uint32_t prio, intid, ap1r;298 int i;299 300 /*301 * Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs302 * in descending order, so intid+1 can preempt intid.303 */304 for (i = 0, prio = (num - 1) * 8; i < num; i++, prio -= 8) {305 GUEST_ASSERT(prio >= 0);306 intid = i + first_intid;307 gic_set_priority(intid, prio);308 }309 310 /*311 * In a real migration, KVM would restore all GIC state before running312 * guest code.313 */314 for (i = 0; i < num; i++) {315 intid = i + first_intid;316 KVM_ACTIVATE(cmd, intid);317 ap1r = gic_read_ap1r0();318 ap1r |= 1U << i;319 gic_write_ap1r0(ap1r);320 }321 322 /* This is where the "migration" would occur. */323 324 /* finish handling the IRQs starting with the highest priority one. */325 for (i = 0; i < num; i++) {326 intid = num - i - 1 + first_intid;327 gic_set_eoi(intid);328 if (args->eoi_split)329 gic_set_dir(intid);330 }331 332 for (i = 0; i < num; i++)333 GUEST_ASSERT(!gic_irq_get_active(i + first_intid));334 GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);335 GUEST_ASSERT_IAR_EMPTY();336}337 338/*339 * Polls the IAR until it's not a spurious interrupt.340 *341 * This function should only be used in test_inject_preemption (with IRQs342 * masked).343 */344static uint32_t wait_for_and_activate_irq(void)345{346 uint32_t intid;347 348 do {349 asm volatile("wfi" : : : "memory");350 intid = gic_get_and_ack_irq();351 } while (intid == IAR_SPURIOUS);352 353 return intid;354}355 356/*357 * Inject multiple concurrent IRQs (num IRQs starting at first_intid) and358 * handle them without handling the actual exceptions. This is done by masking359 * interrupts for the whole test.360 */361static void test_inject_preemption(struct test_args *args,362 uint32_t first_intid, int num,363 kvm_inject_cmd cmd)364{365 uint32_t intid, prio, step = KVM_PRIO_STEPS;366 int i;367 368 /* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs369 * in descending order, so intid+1 can preempt intid.370 */371 for (i = 0, prio = (num - 1) * step; i < num; i++, prio -= step) {372 GUEST_ASSERT(prio >= 0);373 intid = i + first_intid;374 gic_set_priority(intid, prio);375 }376 377 local_irq_disable();378 379 for (i = 0; i < num; i++) {380 uint32_t tmp;381 intid = i + first_intid;382 KVM_INJECT(cmd, intid);383 /* Each successive IRQ will preempt the previous one. */384 tmp = wait_for_and_activate_irq();385 GUEST_ASSERT_EQ(tmp, intid);386 if (args->level_sensitive)387 guest_set_irq_line(intid, 0);388 }389 390 /* finish handling the IRQs starting with the highest priority one. */391 for (i = 0; i < num; i++) {392 intid = num - i - 1 + first_intid;393 gic_set_eoi(intid);394 if (args->eoi_split)395 gic_set_dir(intid);396 }397 398 local_irq_enable();399 400 for (i = 0; i < num; i++)401 GUEST_ASSERT(!gic_irq_get_active(i + first_intid));402 GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);403 GUEST_ASSERT_IAR_EMPTY();404 405 reset_priorities(args);406}407 408static void test_injection(struct test_args *args, struct kvm_inject_desc *f)409{410 uint32_t nr_irqs = args->nr_irqs;411 412 if (f->sgi) {413 guest_inject(args, MIN_SGI, 1, f->cmd);414 guest_inject(args, 0, 16, f->cmd);415 }416 417 if (f->ppi)418 guest_inject(args, MIN_PPI, 1, f->cmd);419 420 if (f->spi) {421 guest_inject(args, MIN_SPI, 1, f->cmd);422 guest_inject(args, nr_irqs - 1, 1, f->cmd);423 guest_inject(args, MIN_SPI, nr_irqs - MIN_SPI, f->cmd);424 }425}426 427static void test_injection_failure(struct test_args *args,428 struct kvm_inject_desc *f)429{430 uint32_t bad_intid[] = { args->nr_irqs, 1020, 1024, 1120, 5120, ~0U, };431 int i;432 433 for (i = 0; i < ARRAY_SIZE(bad_intid); i++)434 test_inject_fail(args, bad_intid[i], f->cmd);435}436 437static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)438{439 /*440 * Test up to 4 levels of preemption. The reason is that KVM doesn't441 * currently implement the ability to have more than the number-of-LRs442 * number of concurrently active IRQs. The number of LRs implemented is443 * IMPLEMENTATION DEFINED, however, it seems that most implement 4.444 */445 if (f->sgi)446 test_inject_preemption(args, MIN_SGI, 4, f->cmd);447 448 if (f->ppi)449 test_inject_preemption(args, MIN_PPI, 4, f->cmd);450 451 if (f->spi)452 test_inject_preemption(args, MIN_SPI, 4, f->cmd);453}454 455static void test_restore_active(struct test_args *args, struct kvm_inject_desc *f)456{457 /* Test up to 4 active IRQs. Same reason as in test_preemption. */458 if (f->sgi)459 guest_restore_active(args, MIN_SGI, 4, f->cmd);460 461 if (f->ppi)462 guest_restore_active(args, MIN_PPI, 4, f->cmd);463 464 if (f->spi)465 guest_restore_active(args, MIN_SPI, 4, f->cmd);466}467 468static void guest_code(struct test_args *args)469{470 uint32_t i, nr_irqs = args->nr_irqs;471 bool level_sensitive = args->level_sensitive;472 struct kvm_inject_desc *f, *inject_fns;473 474 gic_init(GIC_V3, 1);475 476 for (i = 0; i < nr_irqs; i++)477 gic_irq_enable(i);478 479 for (i = MIN_SPI; i < nr_irqs; i++)480 gic_irq_set_config(i, !level_sensitive);481 482 gic_set_eoi_split(args->eoi_split);483 484 reset_priorities(args);485 gic_set_priority_mask(CPU_PRIO_MASK);486 487 inject_fns = level_sensitive ? inject_level_fns488 : inject_edge_fns;489 490 local_irq_enable();491 492 /* Start the tests. */493 for_each_supported_inject_fn(args, inject_fns, f) {494 test_injection(args, f);495 test_preemption(args, f);496 test_injection_failure(args, f);497 }498 499 /*500 * Restore the active state of IRQs. This would happen when live501 * migrating IRQs in the middle of being handled.502 */503 for_each_supported_activate_fn(args, set_active_fns, f)504 test_restore_active(args, f);505 506 GUEST_DONE();507}508 509static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level,510 struct test_args *test_args, bool expect_failure)511{512 int ret;513 514 if (!expect_failure) {515 kvm_arm_irq_line(vm, intid, level);516 } else {517 /* The interface doesn't allow larger intid's. */518 if (intid > KVM_ARM_IRQ_NUM_MASK)519 return;520 521 ret = _kvm_arm_irq_line(vm, intid, level);522 TEST_ASSERT(ret != 0 && errno == EINVAL,523 "Bad intid %i did not cause KVM_IRQ_LINE "524 "error: rc: %i errno: %i", intid, ret, errno);525 }526}527 528void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level,529 bool expect_failure)530{531 if (!expect_failure) {532 kvm_irq_set_level_info(gic_fd, intid, level);533 } else {534 int ret = _kvm_irq_set_level_info(gic_fd, intid, level);535 /*536 * The kernel silently fails for invalid SPIs and SGIs (which537 * are not level-sensitive). It only checks for intid to not538 * spill over 1U << 10 (the max reserved SPI). Also, callers539 * are supposed to mask the intid with 0x3ff (1023).540 */541 if (intid > VGIC_MAX_RESERVED)542 TEST_ASSERT(ret != 0 && errno == EINVAL,543 "Bad intid %i did not cause VGIC_GRP_LEVEL_INFO "544 "error: rc: %i errno: %i", intid, ret, errno);545 else546 TEST_ASSERT(!ret, "KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO "547 "for intid %i failed, rc: %i errno: %i",548 intid, ret, errno);549 }550}551 552static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm,553 uint32_t intid, uint32_t num, uint32_t kvm_max_routes,554 bool expect_failure)555{556 struct kvm_irq_routing *routing;557 int ret;558 uint64_t i;559 560 assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES);561 562 routing = kvm_gsi_routing_create();563 for (i = intid; i < (uint64_t)intid + num; i++)564 kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI);565 566 if (!expect_failure) {567 kvm_gsi_routing_write(vm, routing);568 } else {569 ret = _kvm_gsi_routing_write(vm, routing);570 /* The kernel only checks e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS */571 if (((uint64_t)intid + num - 1 - MIN_SPI) >= KVM_IRQCHIP_NUM_PINS)572 TEST_ASSERT(ret != 0 && errno == EINVAL,573 "Bad intid %u did not cause KVM_SET_GSI_ROUTING "574 "error: rc: %i errno: %i", intid, ret, errno);575 else576 TEST_ASSERT(ret == 0, "KVM_SET_GSI_ROUTING "577 "for intid %i failed, rc: %i errno: %i",578 intid, ret, errno);579 }580}581 582static void kvm_irq_write_ispendr_check(int gic_fd, uint32_t intid,583 struct kvm_vcpu *vcpu,584 bool expect_failure)585{586 /*587 * Ignore this when expecting failure as invalid intids will lead to588 * either trying to inject SGIs when we configured the test to be589 * level_sensitive (or the reverse), or inject large intids which590 * will lead to writing above the ISPENDR register space (and we591 * don't want to do that either).592 */593 if (!expect_failure)594 kvm_irq_write_ispendr(gic_fd, intid, vcpu);595}596 597static void kvm_routing_and_irqfd_check(struct kvm_vm *vm,598 uint32_t intid, uint32_t num, uint32_t kvm_max_routes,599 bool expect_failure)600{601 int fd[MAX_SPI];602 uint64_t val;603 int ret, f;604 uint64_t i;605 606 /*607 * There is no way to try injecting an SGI or PPI as the interface608 * starts counting from the first SPI (above the private ones), so just609 * exit.610 */611 if (INTID_IS_SGI(intid) || INTID_IS_PPI(intid))612 return;613 614 kvm_set_gsi_routing_irqchip_check(vm, intid, num,615 kvm_max_routes, expect_failure);616 617 /*618 * If expect_failure, then just to inject anyway. These619 * will silently fail. And in any case, the guest will check620 * that no actual interrupt was injected for those cases.621 */622 623 for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {624 fd[f] = eventfd(0, 0);625 TEST_ASSERT(fd[f] != -1, __KVM_SYSCALL_ERROR("eventfd()", fd[f]));626 }627 628 for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {629 struct kvm_irqfd irqfd = {630 .fd = fd[f],631 .gsi = i - MIN_SPI,632 };633 assert(i <= (uint64_t)UINT_MAX);634 vm_ioctl(vm, KVM_IRQFD, &irqfd);635 }636 637 for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {638 val = 1;639 ret = write(fd[f], &val, sizeof(uint64_t));640 TEST_ASSERT(ret == sizeof(uint64_t),641 __KVM_SYSCALL_ERROR("write()", ret));642 }643 644 for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++)645 close(fd[f]);646}647 648/* handles the valid case: intid=0xffffffff num=1 */649#define for_each_intid(first, num, tmp, i) \650 for ((tmp) = (i) = (first); \651 (tmp) < (uint64_t)(first) + (uint64_t)(num); \652 (tmp)++, (i)++)653 654static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd,655 struct kvm_inject_args *inject_args,656 struct test_args *test_args)657{658 kvm_inject_cmd cmd = inject_args->cmd;659 uint32_t intid = inject_args->first_intid;660 uint32_t num = inject_args->num;661 int level = inject_args->level;662 bool expect_failure = inject_args->expect_failure;663 struct kvm_vm *vm = vcpu->vm;664 uint64_t tmp;665 uint32_t i;666 667 /* handles the valid case: intid=0xffffffff num=1 */668 assert(intid < UINT_MAX - num || num == 1);669 670 switch (cmd) {671 case KVM_INJECT_EDGE_IRQ_LINE:672 for_each_intid(intid, num, tmp, i)673 kvm_irq_line_check(vm, i, 1, test_args,674 expect_failure);675 for_each_intid(intid, num, tmp, i)676 kvm_irq_line_check(vm, i, 0, test_args,677 expect_failure);678 break;679 case KVM_SET_IRQ_LINE:680 for_each_intid(intid, num, tmp, i)681 kvm_irq_line_check(vm, i, level, test_args,682 expect_failure);683 break;684 case KVM_SET_IRQ_LINE_HIGH:685 for_each_intid(intid, num, tmp, i)686 kvm_irq_line_check(vm, i, 1, test_args,687 expect_failure);688 break;689 case KVM_SET_LEVEL_INFO_HIGH:690 for_each_intid(intid, num, tmp, i)691 kvm_irq_set_level_info_check(gic_fd, i, 1,692 expect_failure);693 break;694 case KVM_INJECT_IRQFD:695 kvm_routing_and_irqfd_check(vm, intid, num,696 test_args->kvm_max_routes,697 expect_failure);698 break;699 case KVM_WRITE_ISPENDR:700 for (i = intid; i < intid + num; i++)701 kvm_irq_write_ispendr_check(gic_fd, i, vcpu,702 expect_failure);703 break;704 case KVM_WRITE_ISACTIVER:705 for (i = intid; i < intid + num; i++)706 kvm_irq_write_isactiver(gic_fd, i, vcpu);707 break;708 default:709 break;710 }711}712 713static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,714 struct kvm_inject_args *args)715{716 struct kvm_inject_args *kvm_args_hva;717 vm_vaddr_t kvm_args_gva;718 719 kvm_args_gva = uc->args[1];720 kvm_args_hva = (struct kvm_inject_args *)addr_gva2hva(vm, kvm_args_gva);721 memcpy(args, kvm_args_hva, sizeof(struct kvm_inject_args));722}723 724static void print_args(struct test_args *args)725{726 printf("nr-irqs=%d level-sensitive=%d eoi-split=%d\n",727 args->nr_irqs, args->level_sensitive,728 args->eoi_split);729}730 731static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)732{733 struct ucall uc;734 int gic_fd;735 struct kvm_vcpu *vcpu;736 struct kvm_vm *vm;737 struct kvm_inject_args inject_args;738 vm_vaddr_t args_gva;739 740 struct test_args args = {741 .nr_irqs = nr_irqs,742 .level_sensitive = level_sensitive,743 .eoi_split = eoi_split,744 .kvm_max_routes = kvm_check_cap(KVM_CAP_IRQ_ROUTING),745 .kvm_supports_irqfd = kvm_check_cap(KVM_CAP_IRQFD),746 };747 748 print_args(&args);749 750 vm = vm_create_with_one_vcpu(&vcpu, guest_code);751 752 vm_init_descriptor_tables(vm);753 vcpu_init_descriptor_tables(vcpu);754 755 /* Setup the guest args page (so it gets the args). */756 args_gva = vm_vaddr_alloc_page(vm);757 memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args));758 vcpu_args_set(vcpu, 1, args_gva);759 760 gic_fd = vgic_v3_setup(vm, 1, nr_irqs);761 __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3, skipping");762 763 vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,764 guest_irq_handlers[args.eoi_split][args.level_sensitive]);765 766 while (1) {767 vcpu_run(vcpu);768 769 switch (get_ucall(vcpu, &uc)) {770 case UCALL_SYNC:771 kvm_inject_get_call(vm, &uc, &inject_args);772 run_guest_cmd(vcpu, gic_fd, &inject_args, &args);773 break;774 case UCALL_ABORT:775 REPORT_GUEST_ASSERT(uc);776 break;777 case UCALL_DONE:778 goto done;779 default:780 TEST_FAIL("Unknown ucall %lu", uc.cmd);781 }782 }783 784done:785 close(gic_fd);786 kvm_vm_free(vm);787}788 789static void help(const char *name)790{791 printf(792 "\n"793 "usage: %s [-n num_irqs] [-e eoi_split] [-l level_sensitive]\n", name);794 printf(" -n: specify number of IRQs to setup the vgic with. "795 "It has to be a multiple of 32 and between 64 and 1024.\n");796 printf(" -e: if 1 then EOI is split into a write to DIR on top "797 "of writing EOI.\n");798 printf(" -l: specify whether the IRQs are level-sensitive (1) or not (0).");799 puts("");800 exit(1);801}802 803int main(int argc, char **argv)804{805 uint32_t nr_irqs = 64;806 bool default_args = true;807 bool level_sensitive = false;808 int opt;809 bool eoi_split = false;810 811 while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) {812 switch (opt) {813 case 'n':814 nr_irqs = atoi_non_negative("Number of IRQs", optarg);815 if (nr_irqs > 1024 || nr_irqs % 32)816 help(argv[0]);817 break;818 case 'e':819 eoi_split = (bool)atoi_paranoid(optarg);820 default_args = false;821 break;822 case 'l':823 level_sensitive = (bool)atoi_paranoid(optarg);824 default_args = false;825 break;826 case 'h':827 default:828 help(argv[0]);829 break;830 }831 }832 833 /*834 * If the user just specified nr_irqs and/or gic_version, then run all835 * combinations.836 */837 if (default_args) {838 test_vgic(nr_irqs, false /* level */, false /* eoi_split */);839 test_vgic(nr_irqs, false /* level */, true /* eoi_split */);840 test_vgic(nr_irqs, true /* level */, false /* eoi_split */);841 test_vgic(nr_irqs, true /* level */, true /* eoi_split */);842 } else {843 test_vgic(nr_irqs, level_sensitive, eoi_split);844 }845 846 return 0;847}848