xref: /linux/tools/testing/selftests/kvm/irq_test.c (revision 197b0cd9ac66bf28f575f2723499f6516bb56f3e)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "kvm_util.h"
3 #include "test_util.h"
4 #include "apic.h"
5 #include "processor.h"
6 #include "proc_util.h"
7 
8 #include <libvfio.h>
9 #include <linux/sizes.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <pthread.h>
14 #include <sys/eventfd.h>
15 #include <sys/sysinfo.h>
16 
17 static u64 timeout_ns = 2ULL * 1000 * 1000 * 1000;
18 static bool guest_ready_for_irqs[KVM_MAX_VCPUS];
19 static bool guest_received_irq[KVM_MAX_VCPUS];
20 static bool irq_affinity;
21 static bool done;
22 
23 #define GUEST_RECEIVED_IRQ(__vcpu)	\
24 	SYNC_FROM_GUEST_AND_READ((__vcpu)->vm, guest_received_irq[(__vcpu)->id])
25 
26 static u32 guest_get_vcpu_id(void)
27 {
28 	return x2apic_read_reg(APIC_ID);
29 }
30 
31 static void guest_irq_handler(struct ex_regs *regs)
32 {
33 	WRITE_ONCE(guest_received_irq[guest_get_vcpu_id()], true);
34 
35 	x2apic_write_reg(APIC_EOI, 0);
36 }
37 
38 static void guest_code(void)
39 {
40 	x2apic_enable();
41 
42 	sti_nop();
43 
44 	WRITE_ONCE(guest_ready_for_irqs[guest_get_vcpu_id()], true);
45 
46 	while (!READ_ONCE(done))
47 		cpu_relax();
48 
49 	GUEST_DONE();
50 }
51 
52 static void *vcpu_thread_main(void *arg)
53 {
54 	struct kvm_vcpu *vcpu = arg;
55 	struct ucall uc;
56 
57 	vcpu_run(vcpu);
58 	TEST_ASSERT_EQ(UCALL_DONE, get_ucall(vcpu, &uc));
59 
60 	return NULL;
61 }
62 
63 static int vfio_setup_msi(struct vfio_pci_device *device)
64 {
65 	const int flags = MAP_SHARED | MAP_ANONYMOUS;
66 	const int prot = PROT_READ | PROT_WRITE;
67 	struct iova_allocator *allocator;
68 	struct dma_region *region;
69 
70 	/* Sanity check that the device+driver can actually send MSIs. */
71 	TEST_REQUIRE(device->driver.ops);
72 	TEST_REQUIRE(device->driver.ops->send_msi);
73 
74 	/*
75 	 * Set up a DMA-able region for the driver to use.   Very few devices
76 	 * provide a way to arbitrarily send interrupts (MSIs), e.g. by writing
77 	 * an MMIO register.  Instead, most devices send MSIs when an action is
78 	 * completed, and practically all actions involve DMA of some form.
79 	 */
80 	allocator = iova_allocator_init(device->iommu);
81 
82 	region = &device->driver.region;
83 	region->size = SZ_2M;
84 	region->iova = iova_allocator_alloc(allocator, region->size);
85 	region->vaddr = kvm_mmap(region->size, prot, flags, -1);
86 	TEST_ASSERT(region->vaddr != MAP_FAILED, "mmap() failed\n");
87 	iommu_map(device->iommu, region);
88 
89 	iova_allocator_cleanup(allocator);
90 
91 	vfio_pci_driver_init(device);
92 
93 	return device->driver.msi;
94 }
95 
96 static void trigger_interrupt(struct vfio_pci_device *device, int eventfd)
97 {
98 	if (device)
99 		vfio_pci_driver_send_msi(device);
100 	else
101 		eventfd_write(eventfd, 1);
102 }
103 
104 
105 static void kvm_route_msi(struct kvm_vm *vm, u32 gsi, struct kvm_vcpu *vcpu,
106 			  u8 vector)
107 {
108 	struct {
109 		struct kvm_irq_routing header;
110 		struct kvm_irq_routing_entry entry;
111 	} routing = {
112 		.header.nr = 1,
113 		.entry = {
114 			.gsi = gsi,
115 			.type = KVM_IRQ_ROUTING_MSI,
116 			.u.msi.address_lo = 0xFEE00000 | (vcpu->id << 12),
117 			.u.msi.data = vector,
118 		},
119 	};
120 
121 	vm_ioctl(vm, KVM_SET_GSI_ROUTING, &routing.header);
122 }
123 
124 static const char *probe_iommu_type(void)
125 {
126 	int io_fd;
127 
128 	io_fd = open("/dev/iommu", O_RDONLY);
129 	if (io_fd >= 0) {
130 		close(io_fd);
131 		return MODE_IOMMUFD;
132 	}
133 
134 	io_fd = __open_path_or_exit("/dev/vfio/vfio", O_RDONLY,
135 				    "Is VFIO (or IOMMUFD) loaded and enabled?");
136 	close(io_fd);
137 	return MODE_VFIO_TYPE1_IOMMU;
138 }
139 
140 static void help(const char *name)
141 {
142 	printf("Usage: %s [-a] [-d <segment:bus:device.function>] [-h] [-t iommu_type]\n", name);
143 	printf("\n");
144 	printf("Tests KVM interrupt routing and delivery via irqfd.\n");
145 	printf("-a	Affine the device's host IRQ to a random physical CPU\n");
146 	printf("-d	Use a VFIO device to send MSI-X interrupts instead of manually signaling the eventfd\n");
147 	printf("-t	Override the IOMMU type to use (vfio_type1_iommu or iommufd)\n");
148 	printf("\n");
149 	exit(KSFT_FAIL);
150 }
151 
152 int main(int argc, char **argv)
153 {
154 	/*
155 	 * Pick a random vector and a random GSI to use for device IRQ.
156 	 *
157 	 * Pick an IRQ vector in range [32, UINT8_MAX]. Min value is 32 because
158 	 * Linux/x86 reserves vectors 0-31 for exceptions and architecture
159 	 * defined NMIs and interrupts.
160 	 *
161 	 * Pick a GSI in range [24, KVM_MAX_IRQ_ROUTES - 1]. The min value is 24
162 	 * because KVM reserves GSIs 0-15 for legacy ISA IRQs and 16-23 only go
163 	 * to the IOAPIC. The max is KVM_MAX_IRQ_ROUTES - 1, because
164 	 * KVM_MAX_IRQ_ROUTES is exclusive.
165 	 */
166 	u32 gsi = kvm_random_u64_in_range(&kvm_rng, 24, KVM_MAX_IRQ_ROUTES - 1);
167 	u8 vector = kvm_random_u64_in_range(&kvm_rng, 32, UINT8_MAX);
168 
169 	pthread_t vcpu_threads[KVM_MAX_VCPUS];
170 	struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
171 	struct vfio_pci_device *device = NULL;
172 	int nr_irqs = 1000, nr_vcpus = 1;
173 	const char *device_bdf = NULL;
174 	const char *iommu_type = NULL;
175 	int i, j, c, msix, eventfd;
176 	struct iommu *iommu;
177 	struct kvm_vm *vm;
178 	int irq, irq_cpu;
179 
180 	while ((c = getopt(argc, argv, "ad:ht:")) != -1) {
181 		switch (c) {
182 		case 'a':
183 			irq_affinity = true;
184 			break;
185 		case 'd':
186 			device_bdf = optarg;
187 			break;
188 		case 't':
189 			iommu_type = optarg;
190 			break;
191 		case 'h':
192 		default:
193 			help(argv[0]);
194 		}
195 	}
196 
197 	TEST_REQUIRE(kvm_arch_has_default_irqchip());
198 
199 	vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
200 	vm_install_exception_handler(vm, vector, guest_irq_handler);
201 
202 	if (device_bdf) {
203 		if (!iommu_type)
204 			iommu_type = probe_iommu_type();
205 		iommu = iommu_init(iommu_type);
206 		device = vfio_pci_device_init(device_bdf, iommu);
207 		msix = vfio_setup_msi(device);
208 		irq = vfio_msix_to_host_irq(device_bdf, msix);
209 		eventfd = device->msi_eventfds[msix];
210 		printf("Using device %s MSI-X[%d] (IRQ-%u)\n", device_bdf, msix,
211 		       irq);
212 	} else {
213 		TEST_ASSERT(!irq_affinity,
214 			    "Setting IRQ affinity (-a) requires a backing device (-d)");
215 
216 		eventfd = kvm_new_eventfd();
217 		irq = -1;
218 		irq_cpu = -1;
219 	}
220 
221 	pr_info("Injecting interrupts for GSI %d (guest vector 0x%x) %d times\n",
222 		gsi, vector, nr_irqs);
223 
224 	kvm_assign_irqfd(vm, gsi, eventfd);
225 
226 	for (i = 0; i < nr_vcpus; i++)
227 		pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
228 
229 	for (i = 0; i < nr_vcpus; i++) {
230 		struct kvm_vcpu *vcpu = vcpus[i];
231 
232 		while (!SYNC_FROM_GUEST_AND_READ(vm, guest_ready_for_irqs[vcpu->id]))
233 			continue;
234 	}
235 
236 	for (i = 0; i < nr_irqs; i++) {
237 		struct kvm_vcpu *vcpu = vcpus[i % nr_vcpus];
238 		struct timespec start;
239 
240 		kvm_route_msi(vm, gsi, vcpu, vector);
241 
242 		if (irq_affinity) {
243 			irq_cpu = kvm_random_u64(&kvm_rng) % get_nprocs();
244 			proc_irq_set_smp_affinity(irq, irq_cpu);
245 		}
246 
247 		for (j = 0; j < nr_vcpus; j++)
248 			TEST_ASSERT(!GUEST_RECEIVED_IRQ(vcpus[j]),
249 				    "IRQ flag for vCPU %d not clear prior to test",
250 				    vcpus[j]->id);
251 
252 		trigger_interrupt(device, eventfd);
253 
254 		clock_gettime(CLOCK_MONOTONIC, &start);
255 		while (!GUEST_RECEIVED_IRQ(vcpu) &&
256 		       timespec_to_ns(timespec_elapsed(start)) <= timeout_ns)
257 			cpu_relax();
258 
259 		TEST_ASSERT(GUEST_RECEIVED_IRQ(vcpu),
260 			    "vCPU %d timed out waiting for IRQ (vector 0x%x) from GSI %d (via CPU %d)\n",
261 			    vcpu->id, vector, gsi, irq_cpu);
262 
263 		WRITE_AND_SYNC_TO_GUEST(vm, guest_received_irq[vcpu->id], false);
264 	}
265 
266 	WRITE_AND_SYNC_TO_GUEST(vm, done, true);
267 
268 	for (i = 0; i < nr_vcpus; i++)
269 		pthread_join(vcpu_threads[i], NULL);
270 
271 	return 0;
272 }
273