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