Path: blob/master/tools/testing/selftests/kvm/arm64/vgic_irq.c
38237 views
// SPDX-License-Identifier: GPL-2.01/*2* vgic_irq.c - Test userspace injection of IRQs3*4* This test validates the injection of IRQs from userspace using various5* methods (e.g., KVM_IRQ_LINE) and modes (e.g., EOI). The guest "asks" the6* host to inject a specific intid via a GUEST_SYNC call, and then checks that7* it received it.8*/9#include <asm/kvm.h>10#include <asm/kvm_para.h>11#include <sys/eventfd.h>12#include <linux/sizes.h>1314#include "processor.h"15#include "test_util.h"16#include "kvm_util.h"17#include "gic.h"18#include "gic_v3.h"19#include "vgic.h"2021/*22* Stores the user specified args; it's passed to the guest and to every test23* function.24*/25struct test_args {26uint32_t nr_irqs; /* number of KVM supported IRQs. */27bool eoi_split; /* 1 is eoir+dir, 0 is eoir only */28bool level_sensitive; /* 1 is level, 0 is edge */29int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */30bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */31uint32_t shared_data;32};3334/*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 */4849/*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*/5354typedef enum {55KVM_INJECT_EDGE_IRQ_LINE = 1,56KVM_SET_IRQ_LINE,57KVM_SET_IRQ_LINE_HIGH,58KVM_SET_LEVEL_INFO_HIGH,59KVM_INJECT_IRQFD,60KVM_WRITE_ISPENDR,61KVM_WRITE_ISACTIVER,62} kvm_inject_cmd;6364struct kvm_inject_args {65kvm_inject_cmd cmd;66uint32_t first_intid;67uint32_t num;68int level;69bool expect_failure;70};7172/* Used on the guest side to perform the hypercall. */73static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,74uint32_t num, int level, bool expect_failure);7576/* Used on the host side to get the hypercall info. */77static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,78struct kvm_inject_args *args);7980#define _KVM_INJECT_MULTI(cmd, intid, num, expect_failure) \81kvm_inject_call(cmd, intid, num, -1 /* not used */, expect_failure)8283#define KVM_INJECT_MULTI(cmd, intid, num) \84_KVM_INJECT_MULTI(cmd, intid, num, false)8586#define _KVM_INJECT(cmd, intid, expect_failure) \87_KVM_INJECT_MULTI(cmd, intid, 1, expect_failure)8889#define KVM_INJECT(cmd, intid) \90_KVM_INJECT_MULTI(cmd, intid, 1, false)9192#define KVM_ACTIVATE(cmd, intid) \93kvm_inject_call(cmd, intid, 1, 1, false);9495struct kvm_inject_desc {96kvm_inject_cmd cmd;97/* can inject PPIs, PPIs, and/or SPIs. */98bool sgi, ppi, spi;99};100101static 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};108109static 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};117118static struct kvm_inject_desc set_active_fns[] = {119/* sgi ppi spi */120{ KVM_WRITE_ISACTIVER, true, true, true },121{ 0, },122};123124#define for_each_inject_fn(t, f) \125for ((f) = (t); (f)->cmd; (f)++)126127#define for_each_supported_inject_fn(args, t, f) \128for_each_inject_fn(t, f) \129if ((args)->kvm_supports_irqfd || (f)->cmd != KVM_INJECT_IRQFD)130131#define for_each_supported_activate_fn(args, t, f) \132for_each_supported_inject_fn((args), (t), (f))133134/* Shared between the guest main thread and the IRQ handlers. */135volatile uint64_t irq_handled;136volatile uint32_t irqnr_received[MAX_SPI + 1];137138static void reset_stats(void)139{140int i;141142irq_handled = 0;143for (i = 0; i <= MAX_SPI; i++)144irqnr_received[i] = 0;145}146147static uint64_t gic_read_ap1r0(void)148{149uint64_t reg = read_sysreg_s(SYS_ICC_AP1R0_EL1);150151dsb(sy);152return reg;153}154155static void gic_write_ap1r0(uint64_t val)156{157write_sysreg_s(val, SYS_ICC_AP1R0_EL1);158isb();159}160161static void guest_set_irq_line(uint32_t intid, uint32_t level);162163static void guest_irq_generic_handler(bool eoi_split, bool level_sensitive)164{165uint32_t intid = gic_get_and_ack_irq();166167if (intid == IAR_SPURIOUS)168return;169170GUEST_ASSERT(gic_irq_get_active(intid));171172if (!level_sensitive)173GUEST_ASSERT(!gic_irq_get_pending(intid));174175if (level_sensitive)176guest_set_irq_line(intid, 0);177178GUEST_ASSERT(intid < MAX_SPI);179irqnr_received[intid] += 1;180irq_handled += 1;181182gic_set_eoi(intid);183GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);184if (eoi_split)185gic_set_dir(intid);186187GUEST_ASSERT(!gic_irq_get_active(intid));188GUEST_ASSERT(!gic_irq_get_pending(intid));189}190191static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,192uint32_t num, int level, bool expect_failure)193{194struct kvm_inject_args args = {195.cmd = cmd,196.first_intid = first_intid,197.num = num,198.level = level,199.expect_failure = expect_failure,200};201GUEST_SYNC(&args);202}203204#define GUEST_ASSERT_IAR_EMPTY() \205do { \206uint32_t _intid; \207_intid = gic_get_and_ack_irq(); \208GUEST_ASSERT(_intid == IAR_SPURIOUS); \209} while (0)210211#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{ \218guest_irq_generic_handler(split, lev); \219}220221GENERATE_GUEST_IRQ_HANDLER(0, 0);222GENERATE_GUEST_IRQ_HANDLER(0, 1);223GENERATE_GUEST_IRQ_HANDLER(1, 0);224GENERATE_GUEST_IRQ_HANDLER(1, 1);225226static 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};230231static void reset_priorities(struct test_args *args)232{233int i;234235for (i = 0; i < args->nr_irqs; i++)236gic_set_priority(i, IRQ_DEFAULT_PRIO_REG);237}238239static void guest_set_irq_line(uint32_t intid, uint32_t level)240{241kvm_inject_call(KVM_SET_IRQ_LINE, intid, 1, level, false);242}243244static void test_inject_fail(struct test_args *args,245uint32_t intid, kvm_inject_cmd cmd)246{247reset_stats();248249_KVM_INJECT(cmd, intid, true);250/* no IRQ to handle on entry */251252GUEST_ASSERT_EQ(irq_handled, 0);253GUEST_ASSERT_IAR_EMPTY();254}255256static void guest_inject(struct test_args *args,257uint32_t first_intid, uint32_t num,258kvm_inject_cmd cmd)259{260uint32_t i;261262reset_stats();263264/* Cycle over all priorities to make things more interesting. */265for (i = first_intid; i < num + first_intid; i++)266gic_set_priority(i, (i % (KVM_NUM_PRIOS - 1)) << 3);267268asm volatile("msr daifset, #2" : : : "memory");269KVM_INJECT_MULTI(cmd, first_intid, num);270271while (irq_handled < num) {272wfi();273local_irq_enable();274isb(); /* handle IRQ */275local_irq_disable();276}277local_irq_enable();278279GUEST_ASSERT_EQ(irq_handled, num);280for (i = first_intid; i < num + first_intid; i++)281GUEST_ASSERT_EQ(irqnr_received[i], 1);282GUEST_ASSERT_IAR_EMPTY();283284reset_priorities(args);285}286287/*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,294uint32_t first_intid, uint32_t num,295kvm_inject_cmd cmd)296{297uint32_t prio, intid, ap1r;298int i;299300/*301* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs302* in descending order, so intid+1 can preempt intid.303*/304for (i = 0, prio = (num - 1) * 8; i < num; i++, prio -= 8) {305GUEST_ASSERT(prio >= 0);306intid = i + first_intid;307gic_set_priority(intid, prio);308}309310/*311* In a real migration, KVM would restore all GIC state before running312* guest code.313*/314for (i = 0; i < num; i++) {315intid = i + first_intid;316KVM_ACTIVATE(cmd, intid);317ap1r = gic_read_ap1r0();318ap1r |= 1U << i;319gic_write_ap1r0(ap1r);320}321322/* This is where the "migration" would occur. */323324/* finish handling the IRQs starting with the highest priority one. */325for (i = 0; i < num; i++) {326intid = num - i - 1 + first_intid;327gic_set_eoi(intid);328if (args->eoi_split)329gic_set_dir(intid);330}331332for (i = 0; i < num; i++)333GUEST_ASSERT(!gic_irq_get_active(i + first_intid));334GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);335GUEST_ASSERT_IAR_EMPTY();336}337338/*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{346uint32_t intid;347348do {349asm volatile("wfi" : : : "memory");350intid = gic_get_and_ack_irq();351} while (intid == IAR_SPURIOUS);352353return intid;354}355356/*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,362uint32_t first_intid, int num,363const unsigned long *exclude,364kvm_inject_cmd cmd)365{366uint32_t intid, prio, step = KVM_PRIO_STEPS;367int i;368369/* Set the priorities of the first (KVM_NUM_PRIOS - 1) IRQs370* in descending order, so intid+1 can preempt intid.371*/372for (i = 0, prio = (num - 1) * step; i < num; i++, prio -= step) {373GUEST_ASSERT(prio >= 0);374intid = i + first_intid;375gic_set_priority(intid, prio);376}377378local_irq_disable();379380for (i = 0; i < num; i++) {381uint32_t tmp;382intid = i + first_intid;383384if (exclude && test_bit(i, exclude))385continue;386387KVM_INJECT(cmd, intid);388/* Each successive IRQ will preempt the previous one. */389tmp = wait_for_and_activate_irq();390GUEST_ASSERT_EQ(tmp, intid);391if (args->level_sensitive)392guest_set_irq_line(intid, 0);393}394395/* finish handling the IRQs starting with the highest priority one. */396for (i = 0; i < num; i++) {397intid = num - i - 1 + first_intid;398399if (exclude && test_bit(intid - first_intid, exclude))400continue;401402gic_set_eoi(intid);403}404405if (args->eoi_split) {406for (i = 0; i < num; i++) {407intid = i + first_intid;408409if (exclude && test_bit(i, exclude))410continue;411412if (args->eoi_split)413gic_set_dir(intid);414}415}416417local_irq_enable();418419for (i = 0; i < num; i++) {420if (exclude && test_bit(i, exclude))421continue;422423GUEST_ASSERT(!gic_irq_get_active(i + first_intid));424}425GUEST_ASSERT_EQ(gic_read_ap1r0(), 0);426GUEST_ASSERT_IAR_EMPTY();427428reset_priorities(args);429}430431static void test_injection(struct test_args *args, struct kvm_inject_desc *f)432{433uint32_t nr_irqs = args->nr_irqs;434435if (f->sgi) {436guest_inject(args, MIN_SGI, 1, f->cmd);437guest_inject(args, 0, 16, f->cmd);438}439440if (f->ppi)441guest_inject(args, MIN_PPI, 1, f->cmd);442443if (f->spi) {444guest_inject(args, MIN_SPI, 1, f->cmd);445guest_inject(args, nr_irqs - 1, 1, f->cmd);446guest_inject(args, MIN_SPI, nr_irqs - MIN_SPI, f->cmd);447}448}449450static void test_injection_failure(struct test_args *args,451struct kvm_inject_desc *f)452{453uint32_t bad_intid[] = { args->nr_irqs, 1020, 1024, 1120, 5120, ~0U, };454int i;455456for (i = 0; i < ARRAY_SIZE(bad_intid); i++)457test_inject_fail(args, bad_intid[i], f->cmd);458}459460static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)461{462/* Timer PPIs cannot be injected from userspace */463static const unsigned long ppi_exclude = (BIT(27 - MIN_PPI) |464BIT(30 - MIN_PPI) |465BIT(28 - MIN_PPI) |466BIT(26 - MIN_PPI));467468if (f->sgi)469test_inject_preemption(args, MIN_SGI, 16, NULL, f->cmd);470471if (f->ppi)472test_inject_preemption(args, MIN_PPI, 16, &ppi_exclude, f->cmd);473474if (f->spi)475test_inject_preemption(args, MIN_SPI, 31, NULL, f->cmd);476}477478static void test_restore_active(struct test_args *args, struct kvm_inject_desc *f)479{480if (f->sgi)481guest_restore_active(args, MIN_SGI, 16, f->cmd);482483if (f->ppi)484guest_restore_active(args, MIN_PPI, 16, f->cmd);485486if (f->spi)487guest_restore_active(args, MIN_SPI, 31, f->cmd);488}489490static void guest_code(struct test_args *args)491{492uint32_t i, nr_irqs = args->nr_irqs;493bool level_sensitive = args->level_sensitive;494struct kvm_inject_desc *f, *inject_fns;495496gic_init(GIC_V3, 1);497498for (i = MIN_SPI; i < nr_irqs; i++)499gic_irq_set_config(i, !level_sensitive);500501for (i = 0; i < nr_irqs; i++)502gic_irq_enable(i);503504gic_set_eoi_split(args->eoi_split);505506reset_priorities(args);507gic_set_priority_mask(CPU_PRIO_MASK);508509inject_fns = level_sensitive ? inject_level_fns510: inject_edge_fns;511512local_irq_enable();513514/* Start the tests. */515for_each_supported_inject_fn(args, inject_fns, f) {516test_injection(args, f);517test_preemption(args, f);518test_injection_failure(args, f);519}520521/*522* Restore the active state of IRQs. This would happen when live523* migrating IRQs in the middle of being handled.524*/525for_each_supported_activate_fn(args, set_active_fns, f)526test_restore_active(args, f);527528GUEST_DONE();529}530531static void kvm_irq_line_check(struct kvm_vm *vm, uint32_t intid, int level,532struct test_args *test_args, bool expect_failure)533{534int ret;535536if (!expect_failure) {537kvm_arm_irq_line(vm, intid, level);538} else {539/* The interface doesn't allow larger intid's. */540if (intid > KVM_ARM_IRQ_NUM_MASK)541return;542543ret = _kvm_arm_irq_line(vm, intid, level);544TEST_ASSERT(ret != 0 && errno == EINVAL,545"Bad intid %i did not cause KVM_IRQ_LINE "546"error: rc: %i errno: %i", intid, ret, errno);547}548}549550void kvm_irq_set_level_info_check(int gic_fd, uint32_t intid, int level,551bool expect_failure)552{553if (!expect_failure) {554kvm_irq_set_level_info(gic_fd, intid, level);555} else {556int ret = _kvm_irq_set_level_info(gic_fd, intid, level);557/*558* The kernel silently fails for invalid SPIs and SGIs (which559* are not level-sensitive). It only checks for intid to not560* spill over 1U << 10 (the max reserved SPI). Also, callers561* are supposed to mask the intid with 0x3ff (1023).562*/563if (intid > VGIC_MAX_RESERVED)564TEST_ASSERT(ret != 0 && errno == EINVAL,565"Bad intid %i did not cause VGIC_GRP_LEVEL_INFO "566"error: rc: %i errno: %i", intid, ret, errno);567else568TEST_ASSERT(!ret, "KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO "569"for intid %i failed, rc: %i errno: %i",570intid, ret, errno);571}572}573574static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm,575uint32_t intid, uint32_t num, uint32_t kvm_max_routes,576bool expect_failure)577{578struct kvm_irq_routing *routing;579int ret;580uint64_t i;581582assert(num <= kvm_max_routes && kvm_max_routes <= KVM_MAX_IRQ_ROUTES);583584routing = kvm_gsi_routing_create();585for (i = intid; i < (uint64_t)intid + num; i++)586kvm_gsi_routing_irqchip_add(routing, i - MIN_SPI, i - MIN_SPI);587588if (!expect_failure) {589kvm_gsi_routing_write(vm, routing);590} else {591ret = _kvm_gsi_routing_write(vm, routing);592/* The kernel only checks e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS */593if (((uint64_t)intid + num - 1 - MIN_SPI) >= KVM_IRQCHIP_NUM_PINS)594TEST_ASSERT(ret != 0 && errno == EINVAL,595"Bad intid %u did not cause KVM_SET_GSI_ROUTING "596"error: rc: %i errno: %i", intid, ret, errno);597else598TEST_ASSERT(ret == 0, "KVM_SET_GSI_ROUTING "599"for intid %i failed, rc: %i errno: %i",600intid, ret, errno);601}602}603604static void kvm_irq_write_ispendr_check(int gic_fd, uint32_t intid,605struct kvm_vcpu *vcpu,606bool expect_failure)607{608/*609* Ignore this when expecting failure as invalid intids will lead to610* either trying to inject SGIs when we configured the test to be611* level_sensitive (or the reverse), or inject large intids which612* will lead to writing above the ISPENDR register space (and we613* don't want to do that either).614*/615if (!expect_failure)616kvm_irq_write_ispendr(gic_fd, intid, vcpu);617}618619static void kvm_routing_and_irqfd_check(struct kvm_vm *vm,620uint32_t intid, uint32_t num, uint32_t kvm_max_routes,621bool expect_failure)622{623int fd[MAX_SPI];624uint64_t val;625int ret, f;626uint64_t i;627628/*629* There is no way to try injecting an SGI or PPI as the interface630* starts counting from the first SPI (above the private ones), so just631* exit.632*/633if (INTID_IS_SGI(intid) || INTID_IS_PPI(intid))634return;635636kvm_set_gsi_routing_irqchip_check(vm, intid, num,637kvm_max_routes, expect_failure);638639/*640* If expect_failure, then just to inject anyway. These641* will silently fail. And in any case, the guest will check642* that no actual interrupt was injected for those cases.643*/644645for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++)646fd[f] = kvm_new_eventfd();647648for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {649assert(i <= (uint64_t)UINT_MAX);650kvm_assign_irqfd(vm, i - MIN_SPI, fd[f]);651}652653for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) {654val = 1;655ret = write(fd[f], &val, sizeof(uint64_t));656TEST_ASSERT(ret == sizeof(uint64_t),657__KVM_SYSCALL_ERROR("write()", ret));658}659660for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++)661kvm_close(fd[f]);662}663664/* handles the valid case: intid=0xffffffff num=1 */665#define for_each_intid(first, num, tmp, i) \666for ((tmp) = (i) = (first); \667(tmp) < (uint64_t)(first) + (uint64_t)(num); \668(tmp)++, (i)++)669670static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd,671struct kvm_inject_args *inject_args,672struct test_args *test_args)673{674kvm_inject_cmd cmd = inject_args->cmd;675uint32_t intid = inject_args->first_intid;676uint32_t num = inject_args->num;677int level = inject_args->level;678bool expect_failure = inject_args->expect_failure;679struct kvm_vm *vm = vcpu->vm;680uint64_t tmp;681uint32_t i;682683/* handles the valid case: intid=0xffffffff num=1 */684assert(intid < UINT_MAX - num || num == 1);685686switch (cmd) {687case KVM_INJECT_EDGE_IRQ_LINE:688for_each_intid(intid, num, tmp, i)689kvm_irq_line_check(vm, i, 1, test_args,690expect_failure);691for_each_intid(intid, num, tmp, i)692kvm_irq_line_check(vm, i, 0, test_args,693expect_failure);694break;695case KVM_SET_IRQ_LINE:696for_each_intid(intid, num, tmp, i)697kvm_irq_line_check(vm, i, level, test_args,698expect_failure);699break;700case KVM_SET_IRQ_LINE_HIGH:701for_each_intid(intid, num, tmp, i)702kvm_irq_line_check(vm, i, 1, test_args,703expect_failure);704break;705case KVM_SET_LEVEL_INFO_HIGH:706for_each_intid(intid, num, tmp, i)707kvm_irq_set_level_info_check(gic_fd, i, 1,708expect_failure);709break;710case KVM_INJECT_IRQFD:711kvm_routing_and_irqfd_check(vm, intid, num,712test_args->kvm_max_routes,713expect_failure);714break;715case KVM_WRITE_ISPENDR:716for (i = intid; i < intid + num; i++)717kvm_irq_write_ispendr_check(gic_fd, i, vcpu,718expect_failure);719break;720case KVM_WRITE_ISACTIVER:721for (i = intid; i < intid + num; i++)722kvm_irq_write_isactiver(gic_fd, i, vcpu);723break;724default:725break;726}727}728729static void kvm_inject_get_call(struct kvm_vm *vm, struct ucall *uc,730struct kvm_inject_args *args)731{732struct kvm_inject_args *kvm_args_hva;733vm_vaddr_t kvm_args_gva;734735kvm_args_gva = uc->args[1];736kvm_args_hva = (struct kvm_inject_args *)addr_gva2hva(vm, kvm_args_gva);737memcpy(args, kvm_args_hva, sizeof(struct kvm_inject_args));738}739740static void print_args(struct test_args *args)741{742printf("nr-irqs=%d level-sensitive=%d eoi-split=%d\n",743args->nr_irqs, args->level_sensitive,744args->eoi_split);745}746747static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)748{749struct ucall uc;750int gic_fd;751struct kvm_vcpu *vcpu;752struct kvm_vm *vm;753struct kvm_inject_args inject_args;754vm_vaddr_t args_gva;755756struct test_args args = {757.nr_irqs = nr_irqs,758.level_sensitive = level_sensitive,759.eoi_split = eoi_split,760.kvm_max_routes = kvm_check_cap(KVM_CAP_IRQ_ROUTING),761.kvm_supports_irqfd = kvm_check_cap(KVM_CAP_IRQFD),762};763764print_args(&args);765766vm = vm_create_with_one_vcpu(&vcpu, guest_code);767768vm_init_descriptor_tables(vm);769vcpu_init_descriptor_tables(vcpu);770771/* Setup the guest args page (so it gets the args). */772args_gva = vm_vaddr_alloc_page(vm);773memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args));774vcpu_args_set(vcpu, 1, args_gva);775776gic_fd = vgic_v3_setup(vm, 1, nr_irqs);777778vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,779guest_irq_handlers[args.eoi_split][args.level_sensitive]);780781while (1) {782vcpu_run(vcpu);783784switch (get_ucall(vcpu, &uc)) {785case UCALL_SYNC:786kvm_inject_get_call(vm, &uc, &inject_args);787run_guest_cmd(vcpu, gic_fd, &inject_args, &args);788break;789case UCALL_ABORT:790REPORT_GUEST_ASSERT(uc);791break;792case UCALL_DONE:793goto done;794default:795TEST_FAIL("Unknown ucall %lu", uc.cmd);796}797}798799done:800close(gic_fd);801kvm_vm_free(vm);802}803804static void guest_code_asym_dir(struct test_args *args, int cpuid)805{806gic_init(GIC_V3, 2);807808gic_set_eoi_split(1);809gic_set_priority_mask(CPU_PRIO_MASK);810811if (cpuid == 0) {812uint32_t intid;813814local_irq_disable();815816gic_set_priority(MIN_PPI, IRQ_DEFAULT_PRIO);817gic_irq_enable(MIN_SPI);818gic_irq_set_pending(MIN_SPI);819820intid = wait_for_and_activate_irq();821GUEST_ASSERT_EQ(intid, MIN_SPI);822823gic_set_eoi(intid);824isb();825826WRITE_ONCE(args->shared_data, MIN_SPI);827dsb(ishst);828829do {830dsb(ishld);831} while (READ_ONCE(args->shared_data) == MIN_SPI);832GUEST_ASSERT(!gic_irq_get_active(MIN_SPI));833} else {834do {835dsb(ishld);836} while (READ_ONCE(args->shared_data) != MIN_SPI);837838gic_set_dir(MIN_SPI);839isb();840841WRITE_ONCE(args->shared_data, 0);842dsb(ishst);843}844845GUEST_DONE();846}847848static void guest_code_group_en(struct test_args *args, int cpuid)849{850uint32_t intid;851852gic_init(GIC_V3, 2);853854gic_set_eoi_split(0);855gic_set_priority_mask(CPU_PRIO_MASK);856/* SGI0 is G0, which is disabled */857gic_irq_set_group(0, 0);858859/* Configure all SGIs with decreasing priority */860for (intid = 0; intid < MIN_PPI; intid++) {861gic_set_priority(intid, (intid + 1) * 8);862gic_irq_enable(intid);863gic_irq_set_pending(intid);864}865866/* Ack and EOI all G1 interrupts */867for (int i = 1; i < MIN_PPI; i++) {868intid = wait_for_and_activate_irq();869870GUEST_ASSERT(intid < MIN_PPI);871gic_set_eoi(intid);872isb();873}874875/*876* Check that SGI0 is still pending, inactive, and that we cannot877* ack anything.878*/879GUEST_ASSERT(gic_irq_get_pending(0));880GUEST_ASSERT(!gic_irq_get_active(0));881GUEST_ASSERT_IAR_EMPTY();882GUEST_ASSERT(read_sysreg_s(SYS_ICC_IAR0_EL1) == IAR_SPURIOUS);883884/* Open the G0 gates, and verify we can ack SGI0 */885write_sysreg_s(1, SYS_ICC_IGRPEN0_EL1);886isb();887888do {889intid = read_sysreg_s(SYS_ICC_IAR0_EL1);890} while (intid == IAR_SPURIOUS);891892GUEST_ASSERT(intid == 0);893GUEST_DONE();894}895896static void guest_code_timer_spi(struct test_args *args, int cpuid)897{898uint32_t intid;899u64 val;900901gic_init(GIC_V3, 2);902903gic_set_eoi_split(1);904gic_set_priority_mask(CPU_PRIO_MASK);905906/* Add a pending SPI so that KVM starts trapping DIR */907gic_set_priority(MIN_SPI + cpuid, IRQ_DEFAULT_PRIO);908gic_irq_set_pending(MIN_SPI + cpuid);909910/* Configure the timer with a higher priority, make it pending */911gic_set_priority(27, IRQ_DEFAULT_PRIO - 8);912913isb();914val = read_sysreg(cntvct_el0);915write_sysreg(val, cntv_cval_el0);916write_sysreg(1, cntv_ctl_el0);917isb();918919GUEST_ASSERT(gic_irq_get_pending(27));920921/* Enable both interrupts */922gic_irq_enable(MIN_SPI + cpuid);923gic_irq_enable(27);924925/* The timer must fire */926intid = wait_for_and_activate_irq();927GUEST_ASSERT(intid == 27);928929/* Check that we can deassert it */930write_sysreg(0, cntv_ctl_el0);931isb();932933GUEST_ASSERT(!gic_irq_get_pending(27));934935/*936* Priority drop, deactivation -- we expect that the host937* deactivation will have been effective938*/939gic_set_eoi(27);940gic_set_dir(27);941942GUEST_ASSERT(!gic_irq_get_active(27));943944/* Do it one more time */945isb();946val = read_sysreg(cntvct_el0);947write_sysreg(val, cntv_cval_el0);948write_sysreg(1, cntv_ctl_el0);949isb();950951GUEST_ASSERT(gic_irq_get_pending(27));952953/* The timer must fire again */954intid = wait_for_and_activate_irq();955GUEST_ASSERT(intid == 27);956957GUEST_DONE();958}959960static void *test_vcpu_run(void *arg)961{962struct kvm_vcpu *vcpu = arg;963struct ucall uc;964965while (1) {966vcpu_run(vcpu);967968switch (get_ucall(vcpu, &uc)) {969case UCALL_ABORT:970REPORT_GUEST_ASSERT(uc);971break;972case UCALL_DONE:973return NULL;974default:975TEST_FAIL("Unknown ucall %lu", uc.cmd);976}977}978979return NULL;980}981982static void test_vgic_two_cpus(void *gcode)983{984pthread_t thr[2];985struct kvm_vcpu *vcpus[2];986struct test_args args = {};987struct kvm_vm *vm;988vm_vaddr_t args_gva;989int gic_fd, ret;990991vm = vm_create_with_vcpus(2, gcode, vcpus);992993vm_init_descriptor_tables(vm);994vcpu_init_descriptor_tables(vcpus[0]);995vcpu_init_descriptor_tables(vcpus[1]);996997/* Setup the guest args page (so it gets the args). */998args_gva = vm_vaddr_alloc_page(vm);999memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args));1000vcpu_args_set(vcpus[0], 2, args_gva, 0);1001vcpu_args_set(vcpus[1], 2, args_gva, 1);10021003gic_fd = vgic_v3_setup(vm, 2, 64);10041005ret = pthread_create(&thr[0], NULL, test_vcpu_run, vcpus[0]);1006if (ret)1007TEST_FAIL("Can't create thread for vcpu 0 (%d)\n", ret);1008ret = pthread_create(&thr[1], NULL, test_vcpu_run, vcpus[1]);1009if (ret)1010TEST_FAIL("Can't create thread for vcpu 1 (%d)\n", ret);10111012pthread_join(thr[0], NULL);1013pthread_join(thr[1], NULL);10141015close(gic_fd);1016kvm_vm_free(vm);1017}10181019static void help(const char *name)1020{1021printf(1022"\n"1023"usage: %s [-n num_irqs] [-e eoi_split] [-l level_sensitive]\n", name);1024printf(" -n: specify number of IRQs to setup the vgic with. "1025"It has to be a multiple of 32 and between 64 and 1024.\n");1026printf(" -e: if 1 then EOI is split into a write to DIR on top "1027"of writing EOI.\n");1028printf(" -l: specify whether the IRQs are level-sensitive (1) or not (0).");1029puts("");1030exit(1);1031}10321033int main(int argc, char **argv)1034{1035uint32_t nr_irqs = 64;1036bool default_args = true;1037bool level_sensitive = false;1038int opt;1039bool eoi_split = false;10401041TEST_REQUIRE(kvm_supports_vgic_v3());1042test_disable_default_vgic();10431044while ((opt = getopt(argc, argv, "hn:e:l:")) != -1) {1045switch (opt) {1046case 'n':1047nr_irqs = atoi_non_negative("Number of IRQs", optarg);1048if (nr_irqs > 1024 || nr_irqs % 32)1049help(argv[0]);1050break;1051case 'e':1052eoi_split = (bool)atoi_paranoid(optarg);1053default_args = false;1054break;1055case 'l':1056level_sensitive = (bool)atoi_paranoid(optarg);1057default_args = false;1058break;1059case 'h':1060default:1061help(argv[0]);1062break;1063}1064}10651066/*1067* If the user just specified nr_irqs and/or gic_version, then run all1068* combinations.1069*/1070if (default_args) {1071test_vgic(nr_irqs, false /* level */, false /* eoi_split */);1072test_vgic(nr_irqs, false /* level */, true /* eoi_split */);1073test_vgic(nr_irqs, true /* level */, false /* eoi_split */);1074test_vgic(nr_irqs, true /* level */, true /* eoi_split */);1075test_vgic_two_cpus(guest_code_asym_dir);1076test_vgic_two_cpus(guest_code_group_en);1077test_vgic_two_cpus(guest_code_timer_spi);1078} else {1079test_vgic(nr_irqs, level_sensitive, eoi_split);1080}10811082return 0;1083}108410851086