vfio-iommu-map-unmap

https://github.com/awilliam/tests/blob/master/vfio-iommu-map-unmap.c

#include <errno.h>
#include <libgen.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <linux/ioctl.h>
#include <linux/vfio.h>

#define MAP_SIZE (1UL * 1024 * 1024 * 1024)
#define MAP_CHUNK (4 * 1024)
#define REALLOC_INTERVAL 30

void usage(char *name)
{
    printf("usage: %s ssss:bb:dd.f\n", name);
    printf("\tssss: PCI segment, ex. 0000\n");
    printf("\tbb:   PCI bus, ex. 01\n");
    printf("\tdd:   PCI device, ex. 06\n");
    printf("\tf:    PCI function, ex. 0\n");
}

int main(int argc, char **argv)
{
    int seg, bus, slot, func;
    int ret, container, group, groupid;
    char path[50], iommu_group_path[50], *group_name;
    struct stat st;
    ssize_t len;
    unsigned long i, count;
    void *vaddr;
    void **maps;
    struct vfio_group_status group_status = {
        .argsz = sizeof(group_status)
    };
    struct vfio_iommu_type1_dma_map dma_map = {
        .argsz = sizeof(dma_map)
    };
    struct vfio_iommu_type1_dma_unmap dma_unmap = {
        .argsz = sizeof(dma_unmap)
    };

    if (argc != 2) {
        usage(argv[0]);
        return -1;
    }

    /* Boilerplate vfio setup */
    ret = sscanf(argv[1], "%04x:%02x:%02x.%d", &seg, &bus, &slot, &func);
    if (ret != 4) {
        usage(argv[0]);
        return -1;
    }

    container = open("/dev/vfio/vfio", O_RDWR);
    if (container < 0) {
        printf("Failed to open /dev/vfio/vfio, %d (%s)\n",
               container, strerror(errno));
        return container;
    }

    snprintf(path, sizeof(path),
         "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
         seg, bus, slot, func);

    ret = stat(path, &st);
    if (ret < 0) {
        printf("No such device\n");
        return  ret;
    }

    strncat(path, "iommu_group", sizeof(path) - strlen(path) - 1);

    len = readlink(path, iommu_group_path, sizeof(iommu_group_path));
    if (len <= 0) {
        printf("No iommu_group for device\n");
        return -1;
    }

    iommu_group_path[len] = 0;
    group_name = basename(iommu_group_path);

    if (sscanf(group_name, "%d", &groupid) != 1) {
        printf("Unknown group\n");
        return -1;
    }

    snprintf(path, sizeof(path), "/dev/vfio/%d", groupid);
    group = open(path, O_RDWR);
    if (group < 0) {
        printf("Failed to open %s, %d (%s)\n",
               path, group, strerror(errno));
        return group;
    }

    ret = ioctl(group, VFIO_GROUP_GET_STATUS, &group_status);
    if (ret) {
        printf("ioctl(VFIO_GROUP_GET_STATUS) failed\n");
        return ret;
    }

    if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) {
        printf("Group not viable, are all devices attached to vfio?\n");
        return -1;
    }

    ret = ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
    if (ret) {
        printf("Failed to set group container\n");
        return ret;
    }

    ret = ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
    if (ret) {
        printf("Failed to set IOMMU\n");
        return ret;
    }

    /* Test code */
    dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
    dma_map.size = MAP_CHUNK;
    dma_unmap.size = MAP_SIZE;
    dma_unmap.iova = 0;

    /* Track our mmaps for re-use */
    maps = malloc(sizeof(void *) * (MAP_SIZE/dma_map.size));
    if (!maps) {
        printf("Failed to allocate map (%s)\n", strerror(errno));
        return -1;
    }

    memset(maps, 0, sizeof(void *) * (MAP_SIZE/dma_map.size));

    for (count = 0;; count++) {

        /* Every REALLOC_INTERVAL, dump our mappings to give THP something to collapse */
        if (count % REALLOC_INTERVAL == 0) {
            for (i = 0; i < MAP_SIZE/dma_map.size; i++) {
                if (maps[i]) {
                    munmap(maps[i], dma_map.size);
                    maps[i] = NULL;
                }
            }
            if (count) {
                printf("\t%ld\n", count);
                //return 0;
            }
            printf("|");
            fflush(stdout);
        }

        /* Map MAP_CHUNK at a time, each chunk is pinned on map, so THP can't do anything until unmap */
        for (i = dma_map.iova = 0; i < MAP_SIZE/dma_map.size; i++, dma_map.iova += dma_map.size) {
            if (!maps[i]) {
                maps[i] = mmap(NULL, dma_map.size,
                        PROT_READ | PROT_WRITE,
                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
                if (maps[i] == MAP_FAILED) {
                    printf("Failed to mmap memory (%s)\n", strerror(errno));
                    return -1;
                }
            }

            ret = madvise(maps[i], dma_map.size, MADV_HUGEPAGE);
            if (ret) {
                printf("Madvise failed (%s)\n", strerror(errno));
            }

            dma_map.vaddr = (unsigned long)maps[i];

            ret = ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);
            if (ret) {
                printf("Failed to map memory (%s)\n",
                    strerror(errno));
                return ret;
            }
        }

        printf("+");
        fflush(stdout);

        /* Unmap everything at once */
        ret = ioctl(container, VFIO_IOMMU_UNMAP_DMA, &dma_unmap);
        if (ret) {
            printf("Failed to unmap memory (%s)\n", strerror(errno));
            return ret;
        }

        printf("-");
        fflush(stdout);
    }

    return 0;
}

 

posted on 2020-10-17 20:03  tycoon3  阅读(216)  评论(0编辑  收藏  举报

导航