diff options
Diffstat (limited to 'samples')
-rw-r--r-- | samples/CMakeLists.txt | 4 | ||||
-rw-r--r-- | samples/client.c | 5 | ||||
-rw-r--r-- | samples/gpio-pci-idio-16.c | 5 | ||||
-rw-r--r-- | samples/server.c | 28 | ||||
-rw-r--r-- | samples/test_dma_map.c | 216 | ||||
-rw-r--r-- | samples/test_mmap.c | 199 | ||||
-rw-r--r-- | samples/test_read.c | 263 |
7 files changed, 23 insertions, 697 deletions
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 49a9201..bb963da 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -28,10 +28,6 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -add_executable(test_read test_read.c) -add_executable(test_mmap test_mmap.c) -add_executable(test_dma_map test_dma_map.c) - add_executable(server server.c) target_link_libraries(server muser ssl crypto) add_executable(client client.c ../lib/muser_ctx.c ../lib/muser_pci.c ../lib/dma.c ../lib/cap.c) diff --git a/samples/client.c b/samples/client.c index d6be91d..bd8d2b3 100644 --- a/samples/client.c +++ b/samples/client.c @@ -550,7 +550,7 @@ static int handle_dma_io(int sock, struct vfio_user_dma_region *dma_regions, static int get_dirty_bitmaps(int sock, struct vfio_user_dma_region *dma_regions, - int nr_dma_regions) + UNUSED int nr_dma_regions) { struct vfio_iommu_type1_dirty_bitmap dirty_bitmap = {0}; struct vfio_iommu_type1_dirty_bitmap_get bitmaps[2]; @@ -566,7 +566,8 @@ get_dirty_bitmaps(int sock, struct vfio_user_dma_region *dma_regions, char data[ARRAY_SIZE(bitmaps)]; assert(dma_regions != NULL); - assert(nr_dma_regions >= (int)ARRAY_SIZE(bitmaps)); + //FIXME: Is below assert correct? + //assert(nr_dma_regions >= (int)ARRAY_SIZE(bitmaps)); for (i = 0; i < ARRAY_SIZE(bitmaps); i++) { bitmaps[i].iova = dma_regions[i].addr; diff --git a/samples/gpio-pci-idio-16.c b/samples/gpio-pci-idio-16.c index 9a79d0c..d9bfa0e 100644 --- a/samples/gpio-pci-idio-16.c +++ b/samples/gpio-pci-idio-16.c @@ -114,9 +114,6 @@ int main(int argc, char *argv[]) lm_ctx = lm_ctx_create(&dev_info); if (lm_ctx == NULL) { - if (errno == EINTR) { - goto out; - } fprintf(stderr, "failed to initialize device emulation: %m\n"); return -1; } @@ -126,7 +123,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "failed to realize device emulation: %m\n"); } } -out: + lm_ctx_destroy(lm_ctx); return ret; } diff --git a/samples/server.c b/samples/server.c index 01978f3..5e3c89e 100644 --- a/samples/server.c +++ b/samples/server.c @@ -96,6 +96,8 @@ bar1_access(UNUSED void *pvt, UNUSED char * const buf, UNUSED size_t count, UNUSED loff_t offset, UNUSED const bool is_write) { assert(false); + + return -ENOTSUP; } bool irq_triggered = false; @@ -207,6 +209,8 @@ unsigned long map_area(UNUSED void *pvt, UNUSED unsigned long off, UNUSED unsigned long len) { assert(false); + + return 0; } static int device_reset(UNUSED void *pvt) @@ -264,7 +268,9 @@ migration_read_data(void *pvt, UNUSED void *buf, __u64 size, { struct server_data *server_data = pvt; - assert(server_data->migration.data_size >= size); + if (server_data->migration.data_size < size) { + assert(false); + } return 0; } @@ -273,6 +279,8 @@ static size_t migration_write_data(UNUSED void *pvt, UNUSED void *data, UNUSED __u64 size) { assert(false); + + return 0; } int main(int argc, char *argv[]){ @@ -283,7 +291,6 @@ int main(int argc, char *argv[]){ struct server_data server_data = {0}; int nr_sparse_areas = 2, size = 1024, i; struct lm_sparse_mmap_areas *sparse_areas; - lm_ctx_t *lm_ctx; while ((opt = getopt(argc, argv, "v")) != -1) { @@ -310,7 +317,8 @@ int main(int argc, char *argv[]){ sparse_areas = calloc(1, sizeof(*sparse_areas) + (nr_sparse_areas * sizeof(struct lm_mmap_area))); if (sparse_areas == NULL) { - err(EXIT_FAILURE, "MMAP sparse areas ENOMEM"); + ret = -ENOMEM; + fprintf(stderr, "MMAP sparse areas ENOMEM\n"); goto out; } sparse_areas->nr_mmap_areas = nr_sparse_areas; @@ -359,15 +367,16 @@ int main(int argc, char *argv[]){ sigemptyset(&act.sa_mask); if (sigaction(SIGUSR1, &act, NULL) == -1) { - err(EXIT_FAILURE, "failed to register signal handler"); + fprintf(stderr, "failed to register signal handler\n"); + ret = -EFAULT; + goto out; } lm_ctx = lm_ctx_create(&dev_info); if (lm_ctx == NULL) { - if (errno == EINTR) { - goto out; - } - err(EXIT_FAILURE, "failed to initialize device emulation"); + fprintf(stderr, "failed to initialize device emulation\n"); + ret = -1; + goto out; } do { @@ -394,8 +403,9 @@ int main(int argc, char *argv[]){ fprintf(stderr, "failed to realize device emulation: %s\n", strerror(-ret)); } -out: lm_ctx_destroy(lm_ctx); + +out: free(server_data.bar1); free(sparse_areas); return ret; diff --git a/samples/test_dma_map.c b/samples/test_dma_map.c deleted file mode 100644 index e797b57..0000000 --- a/samples/test_dma_map.c +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Userspace mediated device sample application - * - * Copyright (c) 2019, Nutanix Inc. All rights reserved. - * Author: Thanos Makatos <thanos@nutanix.com> - * Swapnil Ingle <swapnil.ingle@nutanix.com> - * Felipe Franciosi <felipe@nutanix.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Nutanix nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <stdbool.h> -#include <string.h> -#include <linux/vfio.h> -#include <limits.h> -#include <assert.h> -#include <sys/ioctl.h> -#include <inttypes.h> -#include <err.h> -#include "../lib/muser_priv.h" - -#define ARRAY_SIZE(array) (sizeof(array) / sizeof(*array)) - -#define VFIO_PATH "/dev/vfio/" -#define VFIO_CTR_PATH VFIO_PATH "vfio" -#define SYSFS_PCI_DEV_PATH "/sys/bus/pci/devices/" -#define SYSFS_IOMMU_GROUP "/iommu_group" - -static int -pci_group_id(const char *bdf) -{ - char *dev_path; - char group_path[PATH_MAX]; - int group_id; - - assert(bdf); - - asprintf(&dev_path, SYSFS_PCI_DEV_PATH "%s" SYSFS_IOMMU_GROUP, bdf); - memset(group_path, 0, sizeof(group_path)); - readlink(dev_path, group_path, sizeof(group_path)); - free(dev_path); - sscanf(basename(group_path), "%d", &group_id); - return group_id; -} - -static void* -test_map_dma(const int fd, void *vaddr, unsigned long size, unsigned long iova) -{ - int err; - struct vfio_iommu_type1_dma_map dma_map = { - .argsz = sizeof(dma_map), - .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, - .vaddr = (unsigned long long)vaddr, - .iova = iova, - .size = size, - }; - fprintf(stderr, "attempting to MAP_DMA IOVA=%llx\n", dma_map.iova); - - err = ioctl(fd, VFIO_IOMMU_MAP_DMA, &dma_map); - if (err) { - fprintf(stderr, "failed to MAP_DMA: %d (%s)\n", err, - strerror(errno)); - return NULL; - } - - return (void*)dma_map.vaddr; -} - -static void -test_unmap_dma(const int fd, unsigned long size, unsigned long long iova) -{ - int err; - struct vfio_iommu_type1_dma_unmap dma_unmap = { - .argsz = sizeof dma_unmap, - .size = size, - .iova = iova, - .flags = 0 - }; - - err = ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &dma_unmap); - if (err) { - perror("UNMAP_DMA\n"); - return; - } - printf("unmapped IOVA=%llx\n", dma_unmap.iova); -} - -static int -get_container_fd(const char *path) -{ - int err, vfio_ctr_fd, vfio_grp_fd, vfio_dev_fd; - char *grp_path; - - vfio_ctr_fd = open(VFIO_CTR_PATH, O_RDWR); - assert(vfio_ctr_fd >= 0); - - // Open the VFIO entry for this device's IOMMU GROUP. - err = asprintf(&grp_path, VFIO_PATH "%d", pci_group_id(path)); - assert(err > 0); - vfio_grp_fd = open(grp_path, O_RDWR); - assert(vfio_grp_fd >= 0); - free(grp_path); - - // Add the group to the container. - err = ioctl(vfio_grp_fd, VFIO_GROUP_SET_CONTAINER, &vfio_ctr_fd); - assert(!err); - - // Enable IOMMU type 1 on container. - err = ioctl(vfio_ctr_fd, VFIO_SET_IOMMU, VFIO_TYPE1v2_IOMMU); - assert(!err); - - // Get a device fd from VFIO. - vfio_dev_fd = ioctl(vfio_grp_fd, VFIO_GROUP_GET_DEVICE_FD, path); - assert(vfio_dev_fd >= 0); - - return vfio_ctr_fd; -} - -int main(int argc, char * argv[]) -{ - int vfio_ctr_fd; - void *dma_map_addr; - struct iovec dma_regions[] = { - {.iov_base = (void*)0x0, .iov_len = 1 << 21}, - {.iov_base = (void*)(1 << 21), .iov_len = 1 << 21}, - }; - size_t i; - bool huge = true; - int fd; - int flags = MAP_SHARED; - void *vaddr; - size_t size = 1 << 23; /* FIXME */ - int ret; - - if (argc != 2) { - fprintf(stderr, "usage: %s <MUSER device UUID>\n", argv[0]); - return EXIT_FAILURE; - } - - vfio_ctr_fd = get_container_fd(argv[1]); - - if (huge) { - char template[] = "/dev/hugepages/XXXXXX"; - fd = mkstemp(template); - assert(fd != -1); - } - - ret = lseek(fd, size, SEEK_END); - if (ret == -1) { - err(EXIT_FAILURE, "failed to seek at %lu", size); - } - - /* - * Allocate some space and setup a DMA mapping. - * It *must* be MAP_SHARED. - */ - vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0); - if (vaddr == MAP_FAILED) { - err(EXIT_FAILURE, "failed to mmap"); - } - - for (i = 0; i < ARRAY_SIZE(dma_regions); i++) { - if ((unsigned long long)dma_regions[i].iov_base + dma_regions[i].iov_len > size - || (huge && (dma_regions[i].iov_len < (1 << 21)))) { - err(EXIT_FAILURE, "bad IOVA %#lx-%#lx\n", - (unsigned long)dma_regions[i].iov_base, - (unsigned long)dma_regions[i].iov_base + dma_regions[i].iov_len); - } - dma_map_addr = test_map_dma(vfio_ctr_fd, vaddr, - dma_regions[i].iov_len, - (unsigned long)dma_regions[i].iov_base); - if (!dma_map_addr) - exit(EXIT_FAILURE); - } - - printf("press enter to continue\n"); - getchar(); - - for (i = 0; i < ARRAY_SIZE(dma_regions); i++) { - test_unmap_dma(vfio_ctr_fd, - (unsigned long long)dma_regions[i].iov_len, - (unsigned long long)dma_regions[i].iov_base); - } - return 0; -} diff --git a/samples/test_mmap.c b/samples/test_mmap.c deleted file mode 100644 index 02c32f1..0000000 --- a/samples/test_mmap.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Userspace mediated device sample application - * - * Copyright (c) 2019, Nutanix Inc. All rights reserved. - * Author: Thanos Makatos <thanos@nutanix.com> - * Swapnil Ingle <swapnil.ingle@nutanix.com> - * Felipe Franciosi <felipe@nutanix.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Nutanix nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <stdbool.h> -#include <string.h> -#include <linux/vfio.h> -#include <limits.h> -#include <assert.h> -#include <sys/ioctl.h> -#include <inttypes.h> - -#define VFIO_PATH "/dev/vfio/" -#define VFIO_CTR_PATH VFIO_PATH "vfio" -#define SYSFS_PCI_DEV_PATH "/sys/bus/pci/devices/" -#define SYSFS_IOMMU_GROUP "/iommu_group" - -static int -pci_group_id(const char *bdf) -{ - char *dev_path; - char group_path[PATH_MAX]; - int group_id; - - assert(bdf); - - asprintf(&dev_path, SYSFS_PCI_DEV_PATH "%s" SYSFS_IOMMU_GROUP, bdf); - memset(group_path, 0, sizeof(group_path)); - readlink(dev_path, group_path, sizeof(group_path)); - free(dev_path); - sscanf(basename(group_path), "%d", &group_id); - return group_id; -} - -static inline void* -test_map_dma(const int fd, const unsigned long size, const unsigned long iova) -{ - int err; - struct vfio_iommu_type1_dma_map dma_map = { - .argsz = sizeof(dma_map), - .size = size, - .iova = iova, - .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, - }; - - /* Allocate some space and setup a DMA mapping */ - /* FIXME it *must* be MAP_SHARED */ - dma_map.vaddr = (unsigned long long)mmap(0, size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, 0, 0); - if (dma_map.vaddr == (unsigned long)MAP_FAILED) { - perror("failed to map DMA"); - return NULL; - } - printf("%llx\n", dma_map.vaddr); - strcpy((char*)dma_map.vaddr, "foo"); - - fprintf(stderr, "attempting to MAP_DMA IOVA=%llx\n", dma_map.iova); - - err = ioctl(fd, VFIO_IOMMU_MAP_DMA, &dma_map); - if (err) { - fprintf(stderr, "failed to MAP_DMA: %d (errno=%d)", err, errno); - return NULL; - } - printf("[%s]\n", (char*)dma_map.vaddr); - - return (void*)dma_map.vaddr; -} - -static inline void -test_unmap_dma(const int fd, const unsigned long size, const unsigned long iova) -{ - int err; - struct vfio_iommu_type1_dma_unmap dma_unmap = { - .argsz = sizeof dma_unmap, - .size = size, - .iova = iova, - .flags = 0 - }; - - err = ioctl(fd, VFIO_IOMMU_UNMAP_DMA, &dma_unmap); - if (err) { - perror("UNMAP_DMA\n"); - return; - } - printf("unmapped IOVA=%llx\n", dma_unmap.iova); -} - -int main(int argc, char * argv[]) -{ - int err, vfio_ctr_fd, vfio_grp_fd, vfio_dev_fd; - char *grp_path; -#ifdef DEBUG - struct vfio_group_status grp_status; -#endif - struct vfio_iommu_type1_info iommu_info; - void *dma_map_addr = NULL; - - if (argc != 2) { - printf("Usage: %s <device bdf in full>\n", argv[0]); - printf(" ex: %s 0000:82:00.0\n", argv[0]); - return EXIT_FAILURE; - } - - vfio_ctr_fd = open(VFIO_CTR_PATH, O_RDWR); - assert(vfio_ctr_fd >= 0); - -#ifdef DEBUG - err = ioctl(vfio_ctr_fd, VFIO_GET_API_VERSION); - assert(err == VFIO_API_VERSION); - err = ioctl(vfio_ctr_fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU); - assert(err == 1); -#endif - - // Open the VFIO entry for this device's IOMMU GROUP. - err = asprintf(&grp_path, VFIO_PATH "%d", pci_group_id(argv[1])); - assert(err > 0); - vfio_grp_fd = open(grp_path, O_RDWR); - assert(vfio_grp_fd >= 0); - free(grp_path); - -#ifdef DEBUG - // Ensure group is viable. - memset(&grp_status, 0, sizeof(grp_status)); - grp_status.argsz = sizeof(grp_status); - err = ioctl(vfio_grp_fd, VFIO_GROUP_GET_STATUS, &grp_status); - assert(!err); - assert((grp_status.flags & VFIO_GROUP_FLAGS_VIABLE) == 1); -#endif - - // Add the group to the container. - err = ioctl(vfio_grp_fd, VFIO_GROUP_SET_CONTAINER, &vfio_ctr_fd); - assert(!err); - - // Enable IOMMU type 1 on container. - err = ioctl(vfio_ctr_fd, VFIO_SET_IOMMU, VFIO_TYPE1v2_IOMMU); - assert(!err); - - // Fetch IOMMU information from VFIO. - memset(&iommu_info, 0, sizeof(iommu_info)); - iommu_info.argsz = sizeof(iommu_info); - err = ioctl(vfio_ctr_fd, VFIO_IOMMU_GET_INFO, &iommu_info); - assert(!err); - - // Get a device fd from VFIO. - vfio_dev_fd = ioctl(vfio_grp_fd, VFIO_GROUP_GET_DEVICE_FD, argv[1]); - assert(vfio_dev_fd >= 0); - - void *p; - p = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, - MAP_SHARED, vfio_dev_fd, 0); - assert(p != MAP_FAILED); - printf("%p\n", p); - printf("%s\n", (char*)p); - - dma_map_addr = test_map_dma(vfio_ctr_fd, 4096, 0xdeadbeef000); - if (!dma_map_addr) - exit(EXIT_FAILURE); - test_unmap_dma(vfio_ctr_fd, 4096, 0xdeadbeef000); - - return 0; -} diff --git a/samples/test_read.c b/samples/test_read.c deleted file mode 100644 index d8798c3..0000000 --- a/samples/test_read.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Userspace mediated device sample application - * - * Copyright (c) 2019, Nutanix Inc. All rights reserved. - * Author: Thanos Makatos <thanos@nutanix.com> - * Swapnil Ingle <swapnil.ingle@nutanix.com> - * Felipe Franciosi <felipe@nutanix.com> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Nutanix nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <stdbool.h> -#include <string.h> -#include <linux/vfio.h> -#include <limits.h> -#include <assert.h> -#include <sys/ioctl.h> -#include <inttypes.h> - -#define VFIO_PATH "/dev/vfio/" -#define VFIO_CTR_PATH VFIO_PATH "vfio" -#define SYSFS_MUSER_DEV_PATH "/sys/class/muser/muser/" -#define SYSFS_IOMMU_GROUP "/iommu_group" - -static int -test_read(int vfio_dev_fd, off_t offset) -{ - size_t bytes, i; - char buf[256]; - - memset(buf, 0, sizeof(buf)); - printf("* Reading %zd bytes at %#zx\n", sizeof(buf), offset); - bytes = pread(vfio_dev_fd, buf, sizeof(buf), offset); - printf("** bytes = %zd\n", bytes); - assert(bytes == sizeof(buf)); - printf("** Read %zd bytes\n", bytes); - - for (i = 0; i < sizeof(buf); i++) { - if (i % 16 == 0) { - printf("%04lX:", i); - } - printf(" %02hhX", buf[i]); - if (i % 16 == 15) { - printf("\n"); - } - } - if (i % 16 != 0) { - printf("\n"); - } - - return 0; -} - -static int -pci_group_id(const char *uuid) -{ - char *dev_path; - char group_path[PATH_MAX]; - int group_id; - - assert(uuid != NULL); - - asprintf(&dev_path, SYSFS_MUSER_DEV_PATH "%s" SYSFS_IOMMU_GROUP, uuid); - memset(group_path, 0, sizeof(group_path)); - readlink(dev_path, group_path, sizeof(group_path)); - free(dev_path); - sscanf(basename(group_path), "%d", &group_id); - return group_id; -} - -void print_sparse_mmap_info(struct vfio_region_info *reg) -{ - struct vfio_region_info_cap_sparse_mmap *sparse; - - printf("argsz %u, cap_off %u\n", reg->argsz, reg->cap_offset); - if (reg->cap_offset) { - sparse = (struct vfio_region_info_cap_sparse_mmap *) - ((void *)reg + reg->cap_offset); - printf("cap_hdr: id %u version %u\n", sparse->header.id, - sparse->header.version); - printf("sparse: nr_areas %u, off 0x%llx size 0x%llx\n", sparse->nr_areas, - sparse->areas[0].offset, sparse->areas[0].size); - } -} - -int -main(int argc, char * argv[]) -{ - int vfio_ctr_fd, vfio_grp_fd, vfio_dev_fd; - char *grp_path; - size_t size = 0; - int i; - int err; - - if (argc != 2) { - printf("Usage: %s <muser_dev_uuid>\n", argv[0]); - return EXIT_FAILURE; - } - - // Create a new VFIO container. - printf("* Creating new VFIO container...\n"); - vfio_ctr_fd = open(VFIO_CTR_PATH, O_RDWR); - assert(vfio_ctr_fd >= 0); - printf("** vfio_ctr_fd = %d\n", vfio_ctr_fd); - - // Ensure kernel VFIO is compatible. - printf("* Fetching VFIO API version...\n"); - err = ioctl(vfio_ctr_fd, VFIO_GET_API_VERSION); - assert(err == VFIO_API_VERSION); - - // Ensure VFIO supports TYPE1 IOMMU. - printf("* Checking for IOMMU TYPE1 extension in VFIO...\n"); - err = ioctl(vfio_ctr_fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU); - assert(err == 1); - - // Open the VFIO entry for this device's IOMMU GROUP. - err = asprintf(&grp_path, VFIO_PATH "%d", pci_group_id(argv[1])); - assert(err > 0); - printf("* Opening the VFIO group (%s)...\n", grp_path); - vfio_grp_fd = open(grp_path, O_RDWR); - assert(vfio_grp_fd >= 0); - printf("** vfio_grp_fd = %d\n", vfio_grp_fd); - free(grp_path); - - // Ensure group is viable. - struct vfio_group_status grp_status; - printf("* Ensuring all devices in this group are bound to VFIO...\n"); - memset(&grp_status, 0, sizeof(grp_status)); - grp_status.argsz = sizeof(grp_status); - err = ioctl(vfio_grp_fd, VFIO_GROUP_GET_STATUS, &grp_status); - assert(!err); - assert((grp_status.flags & VFIO_GROUP_FLAGS_VIABLE) == 1); - - // Add the group to the container. - printf("* Adding group to container...\n"); - err = ioctl(vfio_grp_fd, VFIO_GROUP_SET_CONTAINER, &vfio_ctr_fd); - assert(!err); - - // Enable IOMMU type 1 on container. - printf("* Setting IOMMU Type 1 on container...\n"); - err = ioctl(vfio_ctr_fd, VFIO_SET_IOMMU, VFIO_TYPE1v2_IOMMU); - assert(!err); - - // Fetch IOMMU information from VFIO. - struct vfio_iommu_type1_info iommu_info; - printf("* Fetching IOMMU information...\n"); - memset(&iommu_info, 0, sizeof(iommu_info)); - iommu_info.argsz = sizeof(iommu_info); - err = ioctl(vfio_ctr_fd, VFIO_IOMMU_GET_INFO, &iommu_info); - assert(!err); - - // Get a device fd from VFIO. - printf("* Getting a device (%s) fd from group...\n", argv[1]); - vfio_dev_fd = ioctl(vfio_grp_fd, VFIO_GROUP_GET_DEVICE_FD, argv[1]); - assert(vfio_dev_fd >= 0); - printf("** vfio_dev_fd = %d\n", vfio_dev_fd); - - // Fetch device information. - printf("* Fetching device information...\n"); - struct vfio_device_info dev_info; - memset(&dev_info, 0, sizeof(dev_info)); - dev_info.argsz = sizeof(dev_info); - err = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_INFO, &dev_info); - assert(err == 0); - assert(dev_info.num_regions <= VFIO_PCI_NUM_REGIONS); - - // Fetch region information for this device. - struct vfio_region_info *reg_info[VFIO_PCI_NUM_REGIONS] = {0}; - struct vfio_region_info *reg; - printf("* Fetching information for %u regions\n", dev_info.num_regions); - for (i = 0; i < (int)dev_info.num_regions; i++) { - size = sizeof(struct vfio_region_info); - reg = calloc(1, size); - assert(reg != NULL); - reg->argsz = size; - reg->index = i; -retry: - err = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, reg); - if (err != 0) { - // This region doesn't exist or isn't accessible. - printf("** %d: Region info unavailable\n", i); - memset(reg, 0, size); - } else { - printf("** %d: argsz=0x%X, flags=0x%X, index=0x%X, " - "size=0x%llX, offset=0x%llX\n", - i, - reg->argsz, - reg->flags, - reg->index, - reg->size, - reg->offset); - if (reg->argsz > size) { - size = reg->argsz; - reg = realloc(reg, reg->argsz); - goto retry; - } - print_sparse_mmap_info(reg); - } - reg_info[i] = reg; - } - - // Fetch irq information for this device. - struct vfio_irq_info irq_info[VFIO_PCI_NUM_IRQS]; - printf("* Fetching information for %u irqs\n", dev_info.num_irqs); - for (i = 0; i < (int)dev_info.num_irqs; i++) { - memset(&irq_info[i], 0, sizeof(irq_info[i])); - irq_info[i].argsz = sizeof(irq_info[i]); - irq_info[i].index = i; - err = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, irq_info[i]); - if (err != 0) { - // This irq doesn't exist or isn't accessible. - printf("** %d: Irq info unavailable\n", i); - memset(&irq_info[i], 0, sizeof(irq_info[i])); - } else { - printf("** %d: argsz=0x%X, flags=0x%X, index=0x%X, count=%u\n", - i, - irq_info[i].argsz, - irq_info[i].flags, - irq_info[i].index, - irq_info[i].count); - } - } - - // Test. - err = test_read(vfio_dev_fd, reg_info[VFIO_PCI_CONFIG_REGION_INDEX]->offset); - assert(!err); - for (i = 0; i < (int)dev_info.num_regions; i++) { - free(reg_info[i]); - } - - return 0; -} |