1*6078a454SJean-Philippe Brucker #include "kvm/kvm.h" 2*6078a454SJean-Philippe Brucker #include "kvm/vfio.h" 3*6078a454SJean-Philippe Brucker 4*6078a454SJean-Philippe Brucker #include <linux/list.h> 5*6078a454SJean-Philippe Brucker 6*6078a454SJean-Philippe Brucker #define VFIO_DEV_DIR "/dev/vfio" 7*6078a454SJean-Philippe Brucker #define VFIO_DEV_NODE VFIO_DEV_DIR "/vfio" 8*6078a454SJean-Philippe Brucker #define IOMMU_GROUP_DIR "/sys/kernel/iommu_groups" 9*6078a454SJean-Philippe Brucker 10*6078a454SJean-Philippe Brucker static int vfio_container; 11*6078a454SJean-Philippe Brucker static LIST_HEAD(vfio_groups); 12*6078a454SJean-Philippe Brucker static struct vfio_device *vfio_devices; 13*6078a454SJean-Philippe Brucker 14*6078a454SJean-Philippe Brucker static int vfio_device_pci_parser(const struct option *opt, char *arg, 15*6078a454SJean-Philippe Brucker struct vfio_device_params *dev) 16*6078a454SJean-Philippe Brucker { 17*6078a454SJean-Philippe Brucker unsigned int domain, bus, devnr, fn; 18*6078a454SJean-Philippe Brucker 19*6078a454SJean-Philippe Brucker int nr = sscanf(arg, "%4x:%2x:%2x.%1x", &domain, &bus, &devnr, &fn); 20*6078a454SJean-Philippe Brucker if (nr < 4) { 21*6078a454SJean-Philippe Brucker domain = 0; 22*6078a454SJean-Philippe Brucker nr = sscanf(arg, "%2x:%2x.%1x", &bus, &devnr, &fn); 23*6078a454SJean-Philippe Brucker if (nr < 3) { 24*6078a454SJean-Philippe Brucker pr_err("Invalid device identifier %s", arg); 25*6078a454SJean-Philippe Brucker return -EINVAL; 26*6078a454SJean-Philippe Brucker } 27*6078a454SJean-Philippe Brucker } 28*6078a454SJean-Philippe Brucker 29*6078a454SJean-Philippe Brucker dev->type = VFIO_DEVICE_PCI; 30*6078a454SJean-Philippe Brucker dev->bus = "pci"; 31*6078a454SJean-Philippe Brucker dev->name = malloc(13); 32*6078a454SJean-Philippe Brucker if (!dev->name) 33*6078a454SJean-Philippe Brucker return -ENOMEM; 34*6078a454SJean-Philippe Brucker 35*6078a454SJean-Philippe Brucker snprintf(dev->name, 13, "%04x:%02x:%02x.%x", domain, bus, devnr, fn); 36*6078a454SJean-Philippe Brucker 37*6078a454SJean-Philippe Brucker return 0; 38*6078a454SJean-Philippe Brucker } 39*6078a454SJean-Philippe Brucker 40*6078a454SJean-Philippe Brucker int vfio_device_parser(const struct option *opt, const char *arg, int unset) 41*6078a454SJean-Philippe Brucker { 42*6078a454SJean-Philippe Brucker int ret = -EINVAL; 43*6078a454SJean-Philippe Brucker static int idx = 0; 44*6078a454SJean-Philippe Brucker struct kvm *kvm = opt->ptr; 45*6078a454SJean-Philippe Brucker struct vfio_device_params *dev, *devs; 46*6078a454SJean-Philippe Brucker char *cur, *buf = strdup(arg); 47*6078a454SJean-Philippe Brucker 48*6078a454SJean-Philippe Brucker if (!buf) 49*6078a454SJean-Philippe Brucker return -ENOMEM; 50*6078a454SJean-Philippe Brucker 51*6078a454SJean-Philippe Brucker if (idx >= MAX_VFIO_DEVICES) { 52*6078a454SJean-Philippe Brucker pr_warning("Too many VFIO devices"); 53*6078a454SJean-Philippe Brucker goto out_free_buf; 54*6078a454SJean-Philippe Brucker } 55*6078a454SJean-Philippe Brucker 56*6078a454SJean-Philippe Brucker devs = realloc(kvm->cfg.vfio_devices, sizeof(*dev) * (idx + 1)); 57*6078a454SJean-Philippe Brucker if (!devs) { 58*6078a454SJean-Philippe Brucker ret = -ENOMEM; 59*6078a454SJean-Philippe Brucker goto out_free_buf; 60*6078a454SJean-Philippe Brucker } 61*6078a454SJean-Philippe Brucker 62*6078a454SJean-Philippe Brucker kvm->cfg.vfio_devices = devs; 63*6078a454SJean-Philippe Brucker dev = &devs[idx]; 64*6078a454SJean-Philippe Brucker 65*6078a454SJean-Philippe Brucker cur = strtok(buf, ","); 66*6078a454SJean-Philippe Brucker if (!cur) 67*6078a454SJean-Philippe Brucker goto out_free_buf; 68*6078a454SJean-Philippe Brucker 69*6078a454SJean-Philippe Brucker if (!strcmp(opt->long_name, "vfio-pci")) 70*6078a454SJean-Philippe Brucker ret = vfio_device_pci_parser(opt, cur, dev); 71*6078a454SJean-Philippe Brucker else 72*6078a454SJean-Philippe Brucker ret = -EINVAL; 73*6078a454SJean-Philippe Brucker 74*6078a454SJean-Philippe Brucker if (!ret) 75*6078a454SJean-Philippe Brucker kvm->cfg.num_vfio_devices = ++idx; 76*6078a454SJean-Philippe Brucker 77*6078a454SJean-Philippe Brucker out_free_buf: 78*6078a454SJean-Philippe Brucker free(buf); 79*6078a454SJean-Philippe Brucker 80*6078a454SJean-Philippe Brucker return ret; 81*6078a454SJean-Philippe Brucker } 82*6078a454SJean-Philippe Brucker 83*6078a454SJean-Philippe Brucker int vfio_map_region(struct kvm *kvm, struct vfio_device *vdev, 84*6078a454SJean-Philippe Brucker struct vfio_region *region) 85*6078a454SJean-Philippe Brucker { 86*6078a454SJean-Philippe Brucker void *base; 87*6078a454SJean-Philippe Brucker int ret, prot = 0; 88*6078a454SJean-Philippe Brucker /* KVM needs page-aligned regions */ 89*6078a454SJean-Philippe Brucker u64 map_size = ALIGN(region->info.size, PAGE_SIZE); 90*6078a454SJean-Philippe Brucker 91*6078a454SJean-Philippe Brucker /* 92*6078a454SJean-Philippe Brucker * We don't want to mess about trapping config accesses, so require that 93*6078a454SJean-Philippe Brucker * they can be mmap'd. Note that for PCI, this precludes the use of I/O 94*6078a454SJean-Philippe Brucker * BARs in the guest (we will hide them from Configuration Space, which 95*6078a454SJean-Philippe Brucker * is trapped). 96*6078a454SJean-Philippe Brucker */ 97*6078a454SJean-Philippe Brucker if (!(region->info.flags & VFIO_REGION_INFO_FLAG_MMAP)) { 98*6078a454SJean-Philippe Brucker vfio_dev_info(vdev, "ignoring region %u, as it can't be mmap'd", 99*6078a454SJean-Philippe Brucker region->info.index); 100*6078a454SJean-Philippe Brucker return 0; 101*6078a454SJean-Philippe Brucker } 102*6078a454SJean-Philippe Brucker 103*6078a454SJean-Philippe Brucker if (region->info.flags & VFIO_REGION_INFO_FLAG_READ) 104*6078a454SJean-Philippe Brucker prot |= PROT_READ; 105*6078a454SJean-Philippe Brucker if (region->info.flags & VFIO_REGION_INFO_FLAG_WRITE) 106*6078a454SJean-Philippe Brucker prot |= PROT_WRITE; 107*6078a454SJean-Philippe Brucker 108*6078a454SJean-Philippe Brucker base = mmap(NULL, region->info.size, prot, MAP_SHARED, vdev->fd, 109*6078a454SJean-Philippe Brucker region->info.offset); 110*6078a454SJean-Philippe Brucker if (base == MAP_FAILED) { 111*6078a454SJean-Philippe Brucker ret = -errno; 112*6078a454SJean-Philippe Brucker vfio_dev_err(vdev, "failed to mmap region %u (0x%llx bytes)", 113*6078a454SJean-Philippe Brucker region->info.index, region->info.size); 114*6078a454SJean-Philippe Brucker return ret; 115*6078a454SJean-Philippe Brucker } 116*6078a454SJean-Philippe Brucker region->host_addr = base; 117*6078a454SJean-Philippe Brucker 118*6078a454SJean-Philippe Brucker ret = kvm__register_dev_mem(kvm, region->guest_phys_addr, map_size, 119*6078a454SJean-Philippe Brucker region->host_addr); 120*6078a454SJean-Philippe Brucker if (ret) { 121*6078a454SJean-Philippe Brucker vfio_dev_err(vdev, "failed to register region with KVM"); 122*6078a454SJean-Philippe Brucker return ret; 123*6078a454SJean-Philippe Brucker } 124*6078a454SJean-Philippe Brucker 125*6078a454SJean-Philippe Brucker return 0; 126*6078a454SJean-Philippe Brucker } 127*6078a454SJean-Philippe Brucker 128*6078a454SJean-Philippe Brucker void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region) 129*6078a454SJean-Philippe Brucker { 130*6078a454SJean-Philippe Brucker munmap(region->host_addr, region->info.size); 131*6078a454SJean-Philippe Brucker } 132*6078a454SJean-Philippe Brucker 133*6078a454SJean-Philippe Brucker static int vfio_configure_device(struct kvm *kvm, struct vfio_device *vdev) 134*6078a454SJean-Philippe Brucker { 135*6078a454SJean-Philippe Brucker int ret; 136*6078a454SJean-Philippe Brucker struct vfio_group *group = vdev->group; 137*6078a454SJean-Philippe Brucker 138*6078a454SJean-Philippe Brucker vdev->fd = ioctl(group->fd, VFIO_GROUP_GET_DEVICE_FD, 139*6078a454SJean-Philippe Brucker vdev->params->name); 140*6078a454SJean-Philippe Brucker if (vdev->fd < 0) { 141*6078a454SJean-Philippe Brucker vfio_dev_warn(vdev, "failed to get fd"); 142*6078a454SJean-Philippe Brucker 143*6078a454SJean-Philippe Brucker /* The device might be a bridge without an fd */ 144*6078a454SJean-Philippe Brucker return 0; 145*6078a454SJean-Philippe Brucker } 146*6078a454SJean-Philippe Brucker 147*6078a454SJean-Philippe Brucker vdev->info.argsz = sizeof(vdev->info); 148*6078a454SJean-Philippe Brucker if (ioctl(vdev->fd, VFIO_DEVICE_GET_INFO, &vdev->info)) { 149*6078a454SJean-Philippe Brucker ret = -errno; 150*6078a454SJean-Philippe Brucker vfio_dev_err(vdev, "failed to get info"); 151*6078a454SJean-Philippe Brucker goto err_close_device; 152*6078a454SJean-Philippe Brucker } 153*6078a454SJean-Philippe Brucker 154*6078a454SJean-Philippe Brucker if (vdev->info.flags & VFIO_DEVICE_FLAGS_RESET && 155*6078a454SJean-Philippe Brucker ioctl(vdev->fd, VFIO_DEVICE_RESET) < 0) 156*6078a454SJean-Philippe Brucker vfio_dev_warn(vdev, "failed to reset device"); 157*6078a454SJean-Philippe Brucker 158*6078a454SJean-Philippe Brucker vdev->regions = calloc(vdev->info.num_regions, sizeof(*vdev->regions)); 159*6078a454SJean-Philippe Brucker if (!vdev->regions) { 160*6078a454SJean-Philippe Brucker ret = -ENOMEM; 161*6078a454SJean-Philippe Brucker goto err_close_device; 162*6078a454SJean-Philippe Brucker } 163*6078a454SJean-Philippe Brucker 164*6078a454SJean-Philippe Brucker /* Now for the bus-specific initialization... */ 165*6078a454SJean-Philippe Brucker switch (vdev->params->type) { 166*6078a454SJean-Philippe Brucker case VFIO_DEVICE_PCI: 167*6078a454SJean-Philippe Brucker BUG_ON(!(vdev->info.flags & VFIO_DEVICE_FLAGS_PCI)); 168*6078a454SJean-Philippe Brucker ret = vfio_pci_setup_device(kvm, vdev); 169*6078a454SJean-Philippe Brucker break; 170*6078a454SJean-Philippe Brucker default: 171*6078a454SJean-Philippe Brucker BUG_ON(1); 172*6078a454SJean-Philippe Brucker ret = -EINVAL; 173*6078a454SJean-Philippe Brucker } 174*6078a454SJean-Philippe Brucker 175*6078a454SJean-Philippe Brucker if (ret) 176*6078a454SJean-Philippe Brucker goto err_free_regions; 177*6078a454SJean-Philippe Brucker 178*6078a454SJean-Philippe Brucker vfio_dev_info(vdev, "assigned to device number 0x%x in group %lu", 179*6078a454SJean-Philippe Brucker vdev->dev_hdr.dev_num, group->id); 180*6078a454SJean-Philippe Brucker 181*6078a454SJean-Philippe Brucker return 0; 182*6078a454SJean-Philippe Brucker 183*6078a454SJean-Philippe Brucker err_free_regions: 184*6078a454SJean-Philippe Brucker free(vdev->regions); 185*6078a454SJean-Philippe Brucker err_close_device: 186*6078a454SJean-Philippe Brucker close(vdev->fd); 187*6078a454SJean-Philippe Brucker 188*6078a454SJean-Philippe Brucker return ret; 189*6078a454SJean-Philippe Brucker } 190*6078a454SJean-Philippe Brucker 191*6078a454SJean-Philippe Brucker static int vfio_configure_devices(struct kvm *kvm) 192*6078a454SJean-Philippe Brucker { 193*6078a454SJean-Philippe Brucker int i, ret; 194*6078a454SJean-Philippe Brucker 195*6078a454SJean-Philippe Brucker for (i = 0; i < kvm->cfg.num_vfio_devices; ++i) { 196*6078a454SJean-Philippe Brucker ret = vfio_configure_device(kvm, &vfio_devices[i]); 197*6078a454SJean-Philippe Brucker if (ret) 198*6078a454SJean-Philippe Brucker return ret; 199*6078a454SJean-Philippe Brucker } 200*6078a454SJean-Philippe Brucker 201*6078a454SJean-Philippe Brucker return 0; 202*6078a454SJean-Philippe Brucker } 203*6078a454SJean-Philippe Brucker 204*6078a454SJean-Philippe Brucker static int vfio_get_iommu_type(void) 205*6078a454SJean-Philippe Brucker { 206*6078a454SJean-Philippe Brucker if (ioctl(vfio_container, VFIO_CHECK_EXTENSION, VFIO_TYPE1v2_IOMMU)) 207*6078a454SJean-Philippe Brucker return VFIO_TYPE1v2_IOMMU; 208*6078a454SJean-Philippe Brucker 209*6078a454SJean-Philippe Brucker if (ioctl(vfio_container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU)) 210*6078a454SJean-Philippe Brucker return VFIO_TYPE1_IOMMU; 211*6078a454SJean-Philippe Brucker 212*6078a454SJean-Philippe Brucker return -ENODEV; 213*6078a454SJean-Philippe Brucker } 214*6078a454SJean-Philippe Brucker 215*6078a454SJean-Philippe Brucker static int vfio_map_mem_bank(struct kvm *kvm, struct kvm_mem_bank *bank, void *data) 216*6078a454SJean-Philippe Brucker { 217*6078a454SJean-Philippe Brucker int ret = 0; 218*6078a454SJean-Philippe Brucker struct vfio_iommu_type1_dma_map dma_map = { 219*6078a454SJean-Philippe Brucker .argsz = sizeof(dma_map), 220*6078a454SJean-Philippe Brucker .flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE, 221*6078a454SJean-Philippe Brucker .vaddr = (unsigned long)bank->host_addr, 222*6078a454SJean-Philippe Brucker .iova = (u64)bank->guest_phys_addr, 223*6078a454SJean-Philippe Brucker .size = bank->size, 224*6078a454SJean-Philippe Brucker }; 225*6078a454SJean-Philippe Brucker 226*6078a454SJean-Philippe Brucker /* Map the guest memory for DMA (i.e. provide isolation) */ 227*6078a454SJean-Philippe Brucker if (ioctl(vfio_container, VFIO_IOMMU_MAP_DMA, &dma_map)) { 228*6078a454SJean-Philippe Brucker ret = -errno; 229*6078a454SJean-Philippe Brucker pr_err("Failed to map 0x%llx -> 0x%llx (%llu) for DMA", 230*6078a454SJean-Philippe Brucker dma_map.iova, dma_map.vaddr, dma_map.size); 231*6078a454SJean-Philippe Brucker } 232*6078a454SJean-Philippe Brucker 233*6078a454SJean-Philippe Brucker return ret; 234*6078a454SJean-Philippe Brucker } 235*6078a454SJean-Philippe Brucker 236*6078a454SJean-Philippe Brucker static int vfio_unmap_mem_bank(struct kvm *kvm, struct kvm_mem_bank *bank, void *data) 237*6078a454SJean-Philippe Brucker { 238*6078a454SJean-Philippe Brucker struct vfio_iommu_type1_dma_unmap dma_unmap = { 239*6078a454SJean-Philippe Brucker .argsz = sizeof(dma_unmap), 240*6078a454SJean-Philippe Brucker .size = bank->size, 241*6078a454SJean-Philippe Brucker .iova = bank->guest_phys_addr, 242*6078a454SJean-Philippe Brucker }; 243*6078a454SJean-Philippe Brucker 244*6078a454SJean-Philippe Brucker ioctl(vfio_container, VFIO_IOMMU_UNMAP_DMA, &dma_unmap); 245*6078a454SJean-Philippe Brucker 246*6078a454SJean-Philippe Brucker return 0; 247*6078a454SJean-Philippe Brucker } 248*6078a454SJean-Philippe Brucker 249*6078a454SJean-Philippe Brucker static struct vfio_group *vfio_group_create(struct kvm *kvm, unsigned long id) 250*6078a454SJean-Philippe Brucker { 251*6078a454SJean-Philippe Brucker int ret; 252*6078a454SJean-Philippe Brucker struct vfio_group *group; 253*6078a454SJean-Philippe Brucker char group_node[PATH_MAX]; 254*6078a454SJean-Philippe Brucker struct vfio_group_status group_status = { 255*6078a454SJean-Philippe Brucker .argsz = sizeof(group_status), 256*6078a454SJean-Philippe Brucker }; 257*6078a454SJean-Philippe Brucker 258*6078a454SJean-Philippe Brucker group = calloc(1, sizeof(*group)); 259*6078a454SJean-Philippe Brucker if (!group) 260*6078a454SJean-Philippe Brucker return NULL; 261*6078a454SJean-Philippe Brucker 262*6078a454SJean-Philippe Brucker group->id = id; 263*6078a454SJean-Philippe Brucker group->refs = 1; 264*6078a454SJean-Philippe Brucker 265*6078a454SJean-Philippe Brucker ret = snprintf(group_node, PATH_MAX, VFIO_DEV_DIR "/%lu", id); 266*6078a454SJean-Philippe Brucker if (ret < 0 || ret == PATH_MAX) 267*6078a454SJean-Philippe Brucker return NULL; 268*6078a454SJean-Philippe Brucker 269*6078a454SJean-Philippe Brucker group->fd = open(group_node, O_RDWR); 270*6078a454SJean-Philippe Brucker if (group->fd < 0) { 271*6078a454SJean-Philippe Brucker pr_err("Failed to open IOMMU group %s", group_node); 272*6078a454SJean-Philippe Brucker goto err_free_group; 273*6078a454SJean-Philippe Brucker } 274*6078a454SJean-Philippe Brucker 275*6078a454SJean-Philippe Brucker if (ioctl(group->fd, VFIO_GROUP_GET_STATUS, &group_status)) { 276*6078a454SJean-Philippe Brucker pr_err("Failed to determine status of IOMMU group %lu", id); 277*6078a454SJean-Philippe Brucker goto err_close_group; 278*6078a454SJean-Philippe Brucker } 279*6078a454SJean-Philippe Brucker 280*6078a454SJean-Philippe Brucker if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)) { 281*6078a454SJean-Philippe Brucker pr_err("IOMMU group %lu is not viable", id); 282*6078a454SJean-Philippe Brucker goto err_close_group; 283*6078a454SJean-Philippe Brucker } 284*6078a454SJean-Philippe Brucker 285*6078a454SJean-Philippe Brucker if (ioctl(group->fd, VFIO_GROUP_SET_CONTAINER, &vfio_container)) { 286*6078a454SJean-Philippe Brucker pr_err("Failed to add IOMMU group %lu to VFIO container", id); 287*6078a454SJean-Philippe Brucker goto err_close_group; 288*6078a454SJean-Philippe Brucker } 289*6078a454SJean-Philippe Brucker 290*6078a454SJean-Philippe Brucker list_add(&group->list, &vfio_groups); 291*6078a454SJean-Philippe Brucker 292*6078a454SJean-Philippe Brucker return group; 293*6078a454SJean-Philippe Brucker 294*6078a454SJean-Philippe Brucker err_close_group: 295*6078a454SJean-Philippe Brucker close(group->fd); 296*6078a454SJean-Philippe Brucker err_free_group: 297*6078a454SJean-Philippe Brucker free(group); 298*6078a454SJean-Philippe Brucker 299*6078a454SJean-Philippe Brucker return NULL; 300*6078a454SJean-Philippe Brucker } 301*6078a454SJean-Philippe Brucker 302*6078a454SJean-Philippe Brucker static void vfio_group_exit(struct kvm *kvm, struct vfio_group *group) 303*6078a454SJean-Philippe Brucker { 304*6078a454SJean-Philippe Brucker if (--group->refs != 0) 305*6078a454SJean-Philippe Brucker return; 306*6078a454SJean-Philippe Brucker 307*6078a454SJean-Philippe Brucker ioctl(group->fd, VFIO_GROUP_UNSET_CONTAINER); 308*6078a454SJean-Philippe Brucker 309*6078a454SJean-Philippe Brucker list_del(&group->list); 310*6078a454SJean-Philippe Brucker close(group->fd); 311*6078a454SJean-Philippe Brucker free(group); 312*6078a454SJean-Philippe Brucker } 313*6078a454SJean-Philippe Brucker 314*6078a454SJean-Philippe Brucker static struct vfio_group * 315*6078a454SJean-Philippe Brucker vfio_group_get_for_dev(struct kvm *kvm, struct vfio_device *vdev) 316*6078a454SJean-Philippe Brucker { 317*6078a454SJean-Philippe Brucker int dirfd; 318*6078a454SJean-Philippe Brucker ssize_t ret; 319*6078a454SJean-Philippe Brucker char *group_name; 320*6078a454SJean-Philippe Brucker unsigned long group_id; 321*6078a454SJean-Philippe Brucker char group_path[PATH_MAX]; 322*6078a454SJean-Philippe Brucker struct vfio_group *group = NULL; 323*6078a454SJean-Philippe Brucker 324*6078a454SJean-Philippe Brucker /* Find IOMMU group for this device */ 325*6078a454SJean-Philippe Brucker dirfd = open(vdev->sysfs_path, O_DIRECTORY | O_PATH | O_RDONLY); 326*6078a454SJean-Philippe Brucker if (dirfd < 0) { 327*6078a454SJean-Philippe Brucker vfio_dev_err(vdev, "failed to open '%s'", vdev->sysfs_path); 328*6078a454SJean-Philippe Brucker return NULL; 329*6078a454SJean-Philippe Brucker } 330*6078a454SJean-Philippe Brucker 331*6078a454SJean-Philippe Brucker ret = readlinkat(dirfd, "iommu_group", group_path, PATH_MAX); 332*6078a454SJean-Philippe Brucker if (ret < 0) { 333*6078a454SJean-Philippe Brucker vfio_dev_err(vdev, "no iommu_group"); 334*6078a454SJean-Philippe Brucker goto out_close; 335*6078a454SJean-Philippe Brucker } 336*6078a454SJean-Philippe Brucker if (ret == PATH_MAX) 337*6078a454SJean-Philippe Brucker goto out_close; 338*6078a454SJean-Philippe Brucker 339*6078a454SJean-Philippe Brucker group_path[ret] = '\0'; 340*6078a454SJean-Philippe Brucker 341*6078a454SJean-Philippe Brucker group_name = basename(group_path); 342*6078a454SJean-Philippe Brucker errno = 0; 343*6078a454SJean-Philippe Brucker group_id = strtoul(group_name, NULL, 10); 344*6078a454SJean-Philippe Brucker if (errno) 345*6078a454SJean-Philippe Brucker goto out_close; 346*6078a454SJean-Philippe Brucker 347*6078a454SJean-Philippe Brucker list_for_each_entry(group, &vfio_groups, list) { 348*6078a454SJean-Philippe Brucker if (group->id == group_id) { 349*6078a454SJean-Philippe Brucker group->refs++; 350*6078a454SJean-Philippe Brucker return group; 351*6078a454SJean-Philippe Brucker } 352*6078a454SJean-Philippe Brucker } 353*6078a454SJean-Philippe Brucker 354*6078a454SJean-Philippe Brucker group = vfio_group_create(kvm, group_id); 355*6078a454SJean-Philippe Brucker 356*6078a454SJean-Philippe Brucker out_close: 357*6078a454SJean-Philippe Brucker close(dirfd); 358*6078a454SJean-Philippe Brucker return group; 359*6078a454SJean-Philippe Brucker } 360*6078a454SJean-Philippe Brucker 361*6078a454SJean-Philippe Brucker static int vfio_device_init(struct kvm *kvm, struct vfio_device *vdev) 362*6078a454SJean-Philippe Brucker { 363*6078a454SJean-Philippe Brucker int ret; 364*6078a454SJean-Philippe Brucker char dev_path[PATH_MAX]; 365*6078a454SJean-Philippe Brucker struct vfio_group *group; 366*6078a454SJean-Philippe Brucker 367*6078a454SJean-Philippe Brucker ret = snprintf(dev_path, PATH_MAX, "/sys/bus/%s/devices/%s", 368*6078a454SJean-Philippe Brucker vdev->params->bus, vdev->params->name); 369*6078a454SJean-Philippe Brucker if (ret < 0 || ret == PATH_MAX) 370*6078a454SJean-Philippe Brucker return -EINVAL; 371*6078a454SJean-Philippe Brucker 372*6078a454SJean-Philippe Brucker vdev->sysfs_path = strndup(dev_path, PATH_MAX); 373*6078a454SJean-Philippe Brucker if (!vdev->sysfs_path) 374*6078a454SJean-Philippe Brucker return -errno; 375*6078a454SJean-Philippe Brucker 376*6078a454SJean-Philippe Brucker group = vfio_group_get_for_dev(kvm, vdev); 377*6078a454SJean-Philippe Brucker if (!group) { 378*6078a454SJean-Philippe Brucker free(vdev->sysfs_path); 379*6078a454SJean-Philippe Brucker return -EINVAL; 380*6078a454SJean-Philippe Brucker } 381*6078a454SJean-Philippe Brucker 382*6078a454SJean-Philippe Brucker vdev->group = group; 383*6078a454SJean-Philippe Brucker 384*6078a454SJean-Philippe Brucker return 0; 385*6078a454SJean-Philippe Brucker } 386*6078a454SJean-Philippe Brucker 387*6078a454SJean-Philippe Brucker static void vfio_device_exit(struct kvm *kvm, struct vfio_device *vdev) 388*6078a454SJean-Philippe Brucker { 389*6078a454SJean-Philippe Brucker vfio_group_exit(kvm, vdev->group); 390*6078a454SJean-Philippe Brucker 391*6078a454SJean-Philippe Brucker switch (vdev->params->type) { 392*6078a454SJean-Philippe Brucker case VFIO_DEVICE_PCI: 393*6078a454SJean-Philippe Brucker vfio_pci_teardown_device(kvm, vdev); 394*6078a454SJean-Philippe Brucker break; 395*6078a454SJean-Philippe Brucker default: 396*6078a454SJean-Philippe Brucker vfio_dev_warn(vdev, "no teardown function for device"); 397*6078a454SJean-Philippe Brucker } 398*6078a454SJean-Philippe Brucker 399*6078a454SJean-Philippe Brucker close(vdev->fd); 400*6078a454SJean-Philippe Brucker 401*6078a454SJean-Philippe Brucker free(vdev->regions); 402*6078a454SJean-Philippe Brucker free(vdev->sysfs_path); 403*6078a454SJean-Philippe Brucker } 404*6078a454SJean-Philippe Brucker 405*6078a454SJean-Philippe Brucker static int vfio_container_init(struct kvm *kvm) 406*6078a454SJean-Philippe Brucker { 407*6078a454SJean-Philippe Brucker int api, i, ret, iommu_type;; 408*6078a454SJean-Philippe Brucker 409*6078a454SJean-Philippe Brucker /* Create a container for our IOMMU groups */ 410*6078a454SJean-Philippe Brucker vfio_container = open(VFIO_DEV_NODE, O_RDWR); 411*6078a454SJean-Philippe Brucker if (vfio_container == -1) { 412*6078a454SJean-Philippe Brucker ret = errno; 413*6078a454SJean-Philippe Brucker pr_err("Failed to open %s", VFIO_DEV_NODE); 414*6078a454SJean-Philippe Brucker return ret; 415*6078a454SJean-Philippe Brucker } 416*6078a454SJean-Philippe Brucker 417*6078a454SJean-Philippe Brucker api = ioctl(vfio_container, VFIO_GET_API_VERSION); 418*6078a454SJean-Philippe Brucker if (api != VFIO_API_VERSION) { 419*6078a454SJean-Philippe Brucker pr_err("Unknown VFIO API version %d", api); 420*6078a454SJean-Philippe Brucker return -ENODEV; 421*6078a454SJean-Philippe Brucker } 422*6078a454SJean-Philippe Brucker 423*6078a454SJean-Philippe Brucker iommu_type = vfio_get_iommu_type(); 424*6078a454SJean-Philippe Brucker if (iommu_type < 0) { 425*6078a454SJean-Philippe Brucker pr_err("VFIO type-1 IOMMU not supported on this platform"); 426*6078a454SJean-Philippe Brucker return iommu_type; 427*6078a454SJean-Philippe Brucker } 428*6078a454SJean-Philippe Brucker 429*6078a454SJean-Philippe Brucker /* Create groups for our devices and add them to the container */ 430*6078a454SJean-Philippe Brucker for (i = 0; i < kvm->cfg.num_vfio_devices; ++i) { 431*6078a454SJean-Philippe Brucker vfio_devices[i].params = &kvm->cfg.vfio_devices[i]; 432*6078a454SJean-Philippe Brucker 433*6078a454SJean-Philippe Brucker ret = vfio_device_init(kvm, &vfio_devices[i]); 434*6078a454SJean-Philippe Brucker if (ret) 435*6078a454SJean-Philippe Brucker return ret; 436*6078a454SJean-Philippe Brucker } 437*6078a454SJean-Philippe Brucker 438*6078a454SJean-Philippe Brucker /* Finalise the container */ 439*6078a454SJean-Philippe Brucker if (ioctl(vfio_container, VFIO_SET_IOMMU, iommu_type)) { 440*6078a454SJean-Philippe Brucker ret = -errno; 441*6078a454SJean-Philippe Brucker pr_err("Failed to set IOMMU type %d for VFIO container", 442*6078a454SJean-Philippe Brucker iommu_type); 443*6078a454SJean-Philippe Brucker return ret; 444*6078a454SJean-Philippe Brucker } else { 445*6078a454SJean-Philippe Brucker pr_info("Using IOMMU type %d for VFIO container", iommu_type); 446*6078a454SJean-Philippe Brucker } 447*6078a454SJean-Philippe Brucker 448*6078a454SJean-Philippe Brucker return kvm__for_each_mem_bank(kvm, KVM_MEM_TYPE_RAM, vfio_map_mem_bank, 449*6078a454SJean-Philippe Brucker NULL); 450*6078a454SJean-Philippe Brucker } 451*6078a454SJean-Philippe Brucker 452*6078a454SJean-Philippe Brucker static int vfio__init(struct kvm *kvm) 453*6078a454SJean-Philippe Brucker { 454*6078a454SJean-Philippe Brucker int ret; 455*6078a454SJean-Philippe Brucker 456*6078a454SJean-Philippe Brucker if (!kvm->cfg.num_vfio_devices) 457*6078a454SJean-Philippe Brucker return 0; 458*6078a454SJean-Philippe Brucker 459*6078a454SJean-Philippe Brucker vfio_devices = calloc(kvm->cfg.num_vfio_devices, sizeof(*vfio_devices)); 460*6078a454SJean-Philippe Brucker if (!vfio_devices) 461*6078a454SJean-Philippe Brucker return -ENOMEM; 462*6078a454SJean-Philippe Brucker 463*6078a454SJean-Philippe Brucker ret = vfio_container_init(kvm); 464*6078a454SJean-Philippe Brucker if (ret) 465*6078a454SJean-Philippe Brucker return ret; 466*6078a454SJean-Philippe Brucker 467*6078a454SJean-Philippe Brucker ret = vfio_configure_devices(kvm); 468*6078a454SJean-Philippe Brucker if (ret) 469*6078a454SJean-Philippe Brucker return ret; 470*6078a454SJean-Philippe Brucker 471*6078a454SJean-Philippe Brucker return 0; 472*6078a454SJean-Philippe Brucker } 473*6078a454SJean-Philippe Brucker dev_base_init(vfio__init); 474*6078a454SJean-Philippe Brucker 475*6078a454SJean-Philippe Brucker static int vfio__exit(struct kvm *kvm) 476*6078a454SJean-Philippe Brucker { 477*6078a454SJean-Philippe Brucker int i; 478*6078a454SJean-Philippe Brucker 479*6078a454SJean-Philippe Brucker if (!kvm->cfg.num_vfio_devices) 480*6078a454SJean-Philippe Brucker return 0; 481*6078a454SJean-Philippe Brucker 482*6078a454SJean-Philippe Brucker for (i = 0; i < kvm->cfg.num_vfio_devices; i++) 483*6078a454SJean-Philippe Brucker vfio_device_exit(kvm, &vfio_devices[i]); 484*6078a454SJean-Philippe Brucker 485*6078a454SJean-Philippe Brucker free(vfio_devices); 486*6078a454SJean-Philippe Brucker 487*6078a454SJean-Philippe Brucker kvm__for_each_mem_bank(kvm, KVM_MEM_TYPE_RAM, vfio_unmap_mem_bank, NULL); 488*6078a454SJean-Philippe Brucker close(vfio_container); 489*6078a454SJean-Philippe Brucker 490*6078a454SJean-Philippe Brucker free(kvm->cfg.vfio_devices); 491*6078a454SJean-Philippe Brucker 492*6078a454SJean-Philippe Brucker return 0; 493*6078a454SJean-Philippe Brucker } 494*6078a454SJean-Philippe Brucker dev_base_exit(vfio__exit); 495