Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

vfio: selftests: Test basic VFIO and IOMMUFD integration

Add a vfio test suite which verifies that userspace can bind and unbind
devices, allocate I/O address space, and attach a device to an IOMMU
domain using the cdev + IOMMUfd VFIO interface.

Signed-off-by: Josh Hilke <jrhilke@google.com>
Acked-by: Shuah Khan <skhan@linuxfoundation.org>
Signed-off-by: David Matlack <dmatlack@google.com>
Link: https://lore.kernel.org/r/20250822212518.4156428-5-dmatlack@google.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>

authored by

Josh Hilke and committed by
Alex Williamson
790588f0 16eadd7c

+158
+1
tools/testing/selftests/vfio/Makefile
··· 1 1 CFLAGS = $(KHDR_INCLUDES) 2 + TEST_GEN_PROGS += vfio_iommufd_setup_test 2 3 TEST_GEN_PROGS += vfio_pci_device_test 3 4 include ../lib.mk 4 5 include lib/libvfio.mk
+157
tools/testing/selftests/vfio/vfio_iommufd_setup_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <assert.h> 3 + #include <dirent.h> 4 + #include <fcntl.h> 5 + 6 + #include <uapi/linux/types.h> 7 + #include <linux/limits.h> 8 + #include <linux/sizes.h> 9 + #include <linux/vfio.h> 10 + #include <linux/iommufd.h> 11 + 12 + #include <stdint.h> 13 + #include <stdio.h> 14 + #include <string.h> 15 + #include <sys/ioctl.h> 16 + #include <unistd.h> 17 + 18 + #include <vfio_util.h> 19 + #include "../kselftest_harness.h" 20 + 21 + static const char iommu_dev_path[] = "/dev/iommu"; 22 + static char cdev_path[PATH_MAX] = { '\0' }; 23 + 24 + static void set_cdev_path(const char *bdf) 25 + { 26 + char dir_path[PATH_MAX]; 27 + DIR *dir; 28 + struct dirent *entry; 29 + 30 + snprintf(dir_path, sizeof(dir_path), "/sys/bus/pci/devices/%s/vfio-dev/", bdf); 31 + 32 + dir = opendir(dir_path); 33 + assert(dir); 34 + 35 + /* Find the file named "vfio<number>" */ 36 + while ((entry = readdir(dir)) != NULL) { 37 + if (!strncmp("vfio", entry->d_name, 4)) { 38 + snprintf(cdev_path, sizeof(cdev_path), "/dev/vfio/devices/%s", 39 + entry->d_name); 40 + break; 41 + } 42 + } 43 + 44 + assert(strlen(cdev_path) > 0); 45 + 46 + closedir(dir); 47 + } 48 + 49 + static int vfio_device_bind_iommufd_ioctl(int cdev_fd, int iommufd) 50 + { 51 + struct vfio_device_bind_iommufd bind_args = { 52 + .argsz = sizeof(bind_args), 53 + .iommufd = iommufd, 54 + }; 55 + 56 + return ioctl(cdev_fd, VFIO_DEVICE_BIND_IOMMUFD, &bind_args); 57 + } 58 + 59 + static int vfio_device_get_info_ioctl(int cdev_fd) 60 + { 61 + struct vfio_device_info info_args = { .argsz = sizeof(info_args) }; 62 + 63 + return ioctl(cdev_fd, VFIO_DEVICE_GET_INFO, &info_args); 64 + } 65 + 66 + static int vfio_device_ioas_alloc_ioctl(int iommufd, struct iommu_ioas_alloc *alloc_args) 67 + { 68 + *alloc_args = (struct iommu_ioas_alloc){ 69 + .size = sizeof(struct iommu_ioas_alloc), 70 + }; 71 + 72 + return ioctl(iommufd, IOMMU_IOAS_ALLOC, alloc_args); 73 + } 74 + 75 + static int vfio_device_attach_iommufd_pt_ioctl(int cdev_fd, u32 pt_id) 76 + { 77 + struct vfio_device_attach_iommufd_pt attach_args = { 78 + .argsz = sizeof(attach_args), 79 + .pt_id = pt_id, 80 + }; 81 + 82 + return ioctl(cdev_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &attach_args); 83 + } 84 + 85 + static int vfio_device_detach_iommufd_pt_ioctl(int cdev_fd) 86 + { 87 + struct vfio_device_detach_iommufd_pt detach_args = { 88 + .argsz = sizeof(detach_args), 89 + }; 90 + 91 + return ioctl(cdev_fd, VFIO_DEVICE_DETACH_IOMMUFD_PT, &detach_args); 92 + } 93 + 94 + FIXTURE(vfio_cdev) { 95 + int cdev_fd; 96 + int iommufd; 97 + }; 98 + 99 + FIXTURE_SETUP(vfio_cdev) 100 + { 101 + ASSERT_LE(0, (self->cdev_fd = open(cdev_path, O_RDWR, 0))); 102 + ASSERT_LE(0, (self->iommufd = open(iommu_dev_path, O_RDWR, 0))); 103 + } 104 + 105 + FIXTURE_TEARDOWN(vfio_cdev) 106 + { 107 + ASSERT_EQ(0, close(self->cdev_fd)); 108 + ASSERT_EQ(0, close(self->iommufd)); 109 + } 110 + 111 + TEST_F(vfio_cdev, bind) 112 + { 113 + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); 114 + ASSERT_EQ(0, vfio_device_get_info_ioctl(self->cdev_fd)); 115 + } 116 + 117 + TEST_F(vfio_cdev, get_info_without_bind_fails) 118 + { 119 + ASSERT_NE(0, vfio_device_get_info_ioctl(self->cdev_fd)); 120 + } 121 + 122 + TEST_F(vfio_cdev, bind_bad_iommufd_fails) 123 + { 124 + ASSERT_NE(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, -2)); 125 + } 126 + 127 + TEST_F(vfio_cdev, repeated_bind_fails) 128 + { 129 + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); 130 + ASSERT_NE(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); 131 + } 132 + 133 + TEST_F(vfio_cdev, attach_detatch_pt) 134 + { 135 + struct iommu_ioas_alloc alloc_args; 136 + 137 + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); 138 + ASSERT_EQ(0, vfio_device_ioas_alloc_ioctl(self->iommufd, &alloc_args)); 139 + ASSERT_EQ(0, vfio_device_attach_iommufd_pt_ioctl(self->cdev_fd, alloc_args.out_ioas_id)); 140 + ASSERT_EQ(0, vfio_device_detach_iommufd_pt_ioctl(self->cdev_fd)); 141 + } 142 + 143 + TEST_F(vfio_cdev, attach_invalid_pt_fails) 144 + { 145 + ASSERT_EQ(0, vfio_device_bind_iommufd_ioctl(self->cdev_fd, self->iommufd)); 146 + ASSERT_NE(0, vfio_device_attach_iommufd_pt_ioctl(self->cdev_fd, UINT32_MAX)); 147 + } 148 + 149 + int main(int argc, char *argv[]) 150 + { 151 + const char *device_bdf = vfio_selftests_get_bdf(&argc, argv); 152 + 153 + set_cdev_path(device_bdf); 154 + printf("Using cdev device %s\n", cdev_path); 155 + 156 + return test_harness_run(argc, argv); 157 + }