From: Josh Hilke <jrhilke@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
David Matlack <dmatlack@google.com>,
Alex Williamson <alex.williamson@redhat.com>,
Josh Hilke <jrhilke@google.com>
Subject: [PATCH v5 05/21] KVM: selftests: Add IRQ injection test
Date: Thu, 4 Jun 2026 02:01:27 +0000 [thread overview]
Message-ID: <20260604020143.748245-6-jrhilke@google.com> (raw)
In-Reply-To: <20260604020143.748245-1-jrhilke@google.com>
From: David Matlack <dmatlack@google.com>
Add a new test, irq_test.c, which verifies that KVM correctly injects
interrupts into a running guest when triggered via an eventfd bound to a
GSI using the irqfd mechanism.
This test is intentionally simple. Support for IRQ bypass, receiving
interrupts from real devices, and other features will be added to this
test in future changes.
Suggested-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/kvm/20250404193923.1413163-68-seanjc@google.com/
Co-developed-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: Josh Hilke <jrhilke@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 2 +
tools/testing/selftests/kvm/irq_test.c | 174 +++++++++++++++++++++++
2 files changed, 176 insertions(+)
create mode 100644 tools/testing/selftests/kvm/irq_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 2da11e1f3d9a..b859098121c7 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -153,12 +153,14 @@ TEST_GEN_PROGS_x86 += coalesced_io_test
TEST_GEN_PROGS_x86 += dirty_log_perf_test
TEST_GEN_PROGS_x86 += guest_memfd_test
TEST_GEN_PROGS_x86 += hardware_disable_test
+TEST_GEN_PROGS_x86 += irq_test
TEST_GEN_PROGS_x86 += mmu_stress_test
TEST_GEN_PROGS_x86 += rseq_test
TEST_GEN_PROGS_x86 += steal_time
TEST_GEN_PROGS_x86 += system_counter_offset_test
TEST_GEN_PROGS_x86 += pre_fault_memory_test
+
# Compiled outputs used by test targets
TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
new file mode 100644
index 000000000000..d3fee51cf451
--- /dev/null
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "test_util.h"
+#include "apic.h"
+#include "processor.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+
+static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
+static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
+static bool guest_received_irq[KVM_MAX_VCPUS];
+static bool done;
+
+#define GUEST_RECEIVED_IRQ(__vcpu) \
+ SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
+
+static u32 guest_get_vcpu_id(void)
+{
+ return x2apic_read_reg(APIC_ID);
+}
+
+static void guest_irq_handler(struct ex_regs *regs)
+{
+ WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
+
+ x2apic_write_reg(APIC_EOI, 0);
+}
+
+static void guest_code(void)
+{
+ x2apic_enable();
+
+ sti_nop();
+
+ WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
+
+ while (!READ_ONCE(done))
+ cpu_relax();
+
+ GUEST_DONE();
+}
+
+static void *vcpu_thread_main(void *arg)
+{
+ struct kvm_vcpu *vcpu = arg;
+ struct ucall uc;
+
+ vcpu_run(vcpu);
+ TEST_ASSERT_EQ(UCALL_DONE, get_ucall(vcpu, &uc));
+
+ return NULL;
+}
+
+static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
+ u8 vector)
+{
+ struct {
+ struct kvm_irq_routing head;
+ struct kvm_irq_routing_entry entry;
+ } routing_data = {};
+
+ struct kvm_irq_routing *routes = &routing_data.head;
+
+ routes->nr = 1;
+ routes->entries[0].gsi = gsi;
+ routes->entries[0].type = KVM_IRQ_ROUTING_MSI;
+ routes->entries[0].u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12);
+ routes->entries[0].u.msi.data = vector;
+
+ vm_ioctl(vm, KVM_SET_GSI_ROUTING, routes);
+}
+
+static void help(const char *name)
+{
+ printf("Usage: %s [-h]\n", name);
+ printf("\n");
+ printf("Tests KVM IRQ injection via irqfd using an emulated eventfd.\n");
+ printf("\n");
+ exit(KSFT_FAIL);
+}
+
+int main(int argc, char **argv)
+{
+ /*
+ * Pick a random vector and a random GSI to use for device IRQ.
+ *
+ * Pick an IRQ vector in range [32, UINT8_MAX]. Min value is 32 because
+ * Linux/x86 reserves vectors 0-31 for exceptions and architecture
+ * defined NMIs and interrupts.
+ *
+ * Pick a GSI in range [24, KVM_MAX_IRQ_ROUTES - 1]. The min value is 24
+ * because KVM reserves GSIs 0-15 for legacy ISA IRQs and 16-23 only go
+ * to the IOAPIC. The max is KVM_MAX_IRQ_ROUTES - 1, because
+ * KVM_MAX_IRQ_ROUTES is exclusive.
+ */
+ u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
+ u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
+
+ struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+ pthread_t vcpu_threads[KVM_MAX_VCPUS];
+ int nr_irqs = 1000, nr_vcpus = 1;
+ int i, j, c, eventfd;
+ struct kvm_vm *vm;
+
+ while ((c = getopt(argc, argv, "h")) != -1) {
+ switch (c) {
+ case 'h':
+ default:
+ help(argv[0]);
+ }
+ }
+
+ TEST_REQUIRE(kvm_arch_has_default_irqchip());
+
+ vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
+ vm_install_exception_handler(vm, vector, guest_irq_handler);
+
+ eventfd = kvm_new_eventfd();
+
+ printf("Injecting interrupts for GSI %d (Vector 0x%x) %d times\n",
+ gsi, vector, nr_irqs);
+
+ kvm_assign_irqfd(vm, gsi, eventfd);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
+
+ for (i = 0; i < nr_vcpus; i++) {
+ struct kvm_vcpu *vcpu = vcpus[i];
+
+ while (!SYNC_FROM_GUEST_AND_READ(vm, guest_ready_for_irqs[vcpu->id]))
+ continue;
+ }
+
+ for (i = 0; i < nr_irqs; i++) {
+ struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
+ struct timespec start;
+
+ kvm_route_msi(vm, gsi, vcpu, vector);
+
+ for (j = 0; j < nr_vcpus; j++)
+ TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
+ "IRQ flag for vCPU %d not clear prior to test",
+ vcpus[j]->id);
+
+ /* Trigger interrupt */
+ eventfd_write(eventfd, 1);
+
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (;;) {
+ if (GUEST_RECEIVED_IRQ(vcpu))
+ break;
+
+ if (timespec_to_ns(timespec_elapsed(start)) > timeout_ns)
+ TEST_FAIL("vCPU %d timed out waiting for IRQ from GSI %d (Vector 0x%x) !\n",
+ vcpu->id, gsi, vector);
+ }
+
+ WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
+ }
+
+ WRITE_AND_SYNC_TO_GUEST(vm, done, true);
+
+ for (i = 0; i < nr_vcpus; i++)
+ pthread_join(vcpu_threads[i], NULL);
+
+ printf("Test passed!\n");
+
+ return 0;
+}
--
2.54.0.1032.g2f8565e1d1-goog
next prev parent reply other threads:[~2026-06-04 2:02 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-04 2:01 [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Josh Hilke
2026-06-04 2:01 ` [PATCH v5 01/21] KVM: selftests: Build and link selftests/vfio/lib into KVM selftests Josh Hilke
2026-06-04 2:01 ` [PATCH v5 02/21] KVM: selftests: Add guest read/write macros Josh Hilke
2026-06-04 2:01 ` [PATCH v5 03/21] KVM: selftests: Rename guest_rng to kvm_rng Josh Hilke
2026-06-04 2:01 ` [PATCH v5 04/21] KVM: selftests: Add helper to generate random u64 in range [min,max] Josh Hilke
2026-06-04 2:01 ` Josh Hilke [this message]
2026-06-04 16:19 ` [PATCH v5 05/21] KVM: selftests: Add IRQ injection test Sean Christopherson
2026-06-04 16:26 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 06/21] KVM: selftests: Add helper to get host IRQ from device MSIX for IRQ bypass test Josh Hilke
2026-06-04 2:01 ` [PATCH v5 07/21] KVM: selftests: Verify IRQ bypass works in IRQ test Josh Hilke
2026-06-04 16:22 ` Sean Christopherson
2026-06-04 17:56 ` Sean Christopherson
2026-06-04 19:25 ` Sean Christopherson
2026-06-04 19:52 ` Sean Christopherson
2026-06-04 23:14 ` Sean Christopherson
2026-06-04 23:35 ` David Matlack
2026-06-04 2:01 ` [PATCH v5 08/21] KVM: selftests: Add helpers to write proc IRQ affinity for " Josh Hilke
2026-06-04 19:35 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 09/21] KVM: selftests: Add helpers to print " Josh Hilke
2026-06-04 2:01 ` [PATCH v5 10/21] KVM: selftests: Verify interrupts are received when IRQ affinity changes in " Josh Hilke
2026-06-04 2:01 ` [PATCH v5 11/21] KVM: selftests: Verify IRQs wake up halted vCPUs " Josh Hilke
2026-06-04 2:01 ` [PATCH v5 12/21] KVM: selftests: Verify interrupts are received after modifying IRQ routes " Josh Hilke
2026-06-04 17:22 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 13/21] KVM: selftests: Make number of IRQs configurable " Josh Hilke
2026-06-04 17:35 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 14/21] KVM: selftests: Verify non-postable IRQ remapping " Josh Hilke
2026-06-04 17:22 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 15/21] KVM: selftests: Add kvm_gettid() wrapper and convert users Josh Hilke
2026-06-04 2:01 ` [PATCH v5 16/21] KVM: selftests: Add kvm_sched_getaffinity() " Josh Hilke
2026-06-04 17:23 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 17/21] KVM: selftests: Add pin_task_to_random_cpu() helper function for IRQ test Josh Hilke
2026-06-04 2:01 ` [PATCH v5 18/21] KVM: selftests: Verify vCPU migration during IRQ delivery in " Josh Hilke
2026-06-04 17:27 ` Sean Christopherson
2026-06-04 2:01 ` [PATCH v5 19/21] KVM: selftests: Print vCPU affinity on timeout during " Josh Hilke
2026-06-04 2:01 ` [PATCH v5 20/21] KVM: selftests: Make number of vCPUs configurable in " Josh Hilke
2026-06-04 2:01 ` [PATCH v5 21/21] KVM: selftests: Add xAPIC support " Josh Hilke
2026-06-04 20:22 ` [PATCH v5 00/21] KVM: selftests: Link with VFIO selftests lib and test device interrupts Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260604020143.748245-6-jrhilke@google.com \
--to=jrhilke@google.com \
--cc=alex.williamson@redhat.com \
--cc=dmatlack@google.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome