1 /* 2 * VFIO-KVM bridge pseudo device 3 * 4 * Copyright (C) 2013 Red Hat, Inc. All rights reserved. 5 * Author: Alex Williamson <alex.williamson@redhat.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/errno.h> 13 #include <linux/file.h> 14 #include <linux/kvm_host.h> 15 #include <linux/list.h> 16 #include <linux/module.h> 17 #include <linux/mutex.h> 18 #include <linux/slab.h> 19 #include <linux/uaccess.h> 20 #include <linux/vfio.h> 21 22 struct kvm_vfio_group { 23 struct list_head node; 24 struct vfio_group *vfio_group; 25 }; 26 27 struct kvm_vfio { 28 struct list_head group_list; 29 struct mutex lock; 30 bool noncoherent; 31 }; 32 33 static struct vfio_group *kvm_vfio_group_get_external_user(struct file *filep) 34 { 35 struct vfio_group *vfio_group; 36 struct vfio_group *(*fn)(struct file *); 37 38 fn = symbol_get(vfio_group_get_external_user); 39 if (!fn) 40 return ERR_PTR(-EINVAL); 41 42 vfio_group = fn(filep); 43 44 symbol_put(vfio_group_get_external_user); 45 46 return vfio_group; 47 } 48 49 static void kvm_vfio_group_put_external_user(struct vfio_group *vfio_group) 50 { 51 void (*fn)(struct vfio_group *); 52 53 fn = symbol_get(vfio_group_put_external_user); 54 if (!fn) 55 return; 56 57 fn(vfio_group); 58 59 symbol_put(vfio_group_put_external_user); 60 } 61 62 static bool kvm_vfio_group_is_coherent(struct vfio_group *vfio_group) 63 { 64 long (*fn)(struct vfio_group *, unsigned long); 65 long ret; 66 67 fn = symbol_get(vfio_external_check_extension); 68 if (!fn) 69 return false; 70 71 ret = fn(vfio_group, VFIO_DMA_CC_IOMMU); 72 73 symbol_put(vfio_external_check_extension); 74 75 return ret > 0; 76 } 77 78 /* 79 * Groups can use the same or different IOMMU domains. If the same then 80 * adding a new group may change the coherency of groups we've previously 81 * been told about. We don't want to care about any of that so we retest 82 * each group and bail as soon as we find one that's noncoherent. This 83 * means we only ever [un]register_noncoherent_dma once for the whole device. 84 */ 85 static void kvm_vfio_update_coherency(struct kvm_device *dev) 86 { 87 struct kvm_vfio *kv = dev->private; 88 bool noncoherent = false; 89 struct kvm_vfio_group *kvg; 90 91 mutex_lock(&kv->lock); 92 93 list_for_each_entry(kvg, &kv->group_list, node) { 94 if (!kvm_vfio_group_is_coherent(kvg->vfio_group)) { 95 noncoherent = true; 96 break; 97 } 98 } 99 100 if (noncoherent != kv->noncoherent) { 101 kv->noncoherent = noncoherent; 102 103 if (kv->noncoherent) 104 kvm_arch_register_noncoherent_dma(dev->kvm); 105 else 106 kvm_arch_unregister_noncoherent_dma(dev->kvm); 107 } 108 109 mutex_unlock(&kv->lock); 110 } 111 112 static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg) 113 { 114 struct kvm_vfio *kv = dev->private; 115 struct vfio_group *vfio_group; 116 struct kvm_vfio_group *kvg; 117 int32_t __user *argp = (int32_t __user *)(unsigned long)arg; 118 struct fd f; 119 int32_t fd; 120 int ret; 121 122 switch (attr) { 123 case KVM_DEV_VFIO_GROUP_ADD: 124 if (get_user(fd, argp)) 125 return -EFAULT; 126 127 f = fdget(fd); 128 if (!f.file) 129 return -EBADF; 130 131 vfio_group = kvm_vfio_group_get_external_user(f.file); 132 fdput(f); 133 134 if (IS_ERR(vfio_group)) 135 return PTR_ERR(vfio_group); 136 137 mutex_lock(&kv->lock); 138 139 list_for_each_entry(kvg, &kv->group_list, node) { 140 if (kvg->vfio_group == vfio_group) { 141 mutex_unlock(&kv->lock); 142 kvm_vfio_group_put_external_user(vfio_group); 143 return -EEXIST; 144 } 145 } 146 147 kvg = kzalloc(sizeof(*kvg), GFP_KERNEL); 148 if (!kvg) { 149 mutex_unlock(&kv->lock); 150 kvm_vfio_group_put_external_user(vfio_group); 151 return -ENOMEM; 152 } 153 154 list_add_tail(&kvg->node, &kv->group_list); 155 kvg->vfio_group = vfio_group; 156 157 mutex_unlock(&kv->lock); 158 159 kvm_vfio_update_coherency(dev); 160 161 return 0; 162 163 case KVM_DEV_VFIO_GROUP_DEL: 164 if (get_user(fd, argp)) 165 return -EFAULT; 166 167 f = fdget(fd); 168 if (!f.file) 169 return -EBADF; 170 171 vfio_group = kvm_vfio_group_get_external_user(f.file); 172 fdput(f); 173 174 if (IS_ERR(vfio_group)) 175 return PTR_ERR(vfio_group); 176 177 ret = -ENOENT; 178 179 mutex_lock(&kv->lock); 180 181 list_for_each_entry(kvg, &kv->group_list, node) { 182 if (kvg->vfio_group != vfio_group) 183 continue; 184 185 list_del(&kvg->node); 186 kvm_vfio_group_put_external_user(kvg->vfio_group); 187 kfree(kvg); 188 ret = 0; 189 break; 190 } 191 192 mutex_unlock(&kv->lock); 193 194 kvm_vfio_group_put_external_user(vfio_group); 195 196 kvm_vfio_update_coherency(dev); 197 198 return ret; 199 } 200 201 return -ENXIO; 202 } 203 204 static int kvm_vfio_set_attr(struct kvm_device *dev, 205 struct kvm_device_attr *attr) 206 { 207 switch (attr->group) { 208 case KVM_DEV_VFIO_GROUP: 209 return kvm_vfio_set_group(dev, attr->attr, attr->addr); 210 } 211 212 return -ENXIO; 213 } 214 215 static int kvm_vfio_has_attr(struct kvm_device *dev, 216 struct kvm_device_attr *attr) 217 { 218 switch (attr->group) { 219 case KVM_DEV_VFIO_GROUP: 220 switch (attr->attr) { 221 case KVM_DEV_VFIO_GROUP_ADD: 222 case KVM_DEV_VFIO_GROUP_DEL: 223 return 0; 224 } 225 226 break; 227 } 228 229 return -ENXIO; 230 } 231 232 static void kvm_vfio_destroy(struct kvm_device *dev) 233 { 234 struct kvm_vfio *kv = dev->private; 235 struct kvm_vfio_group *kvg, *tmp; 236 237 list_for_each_entry_safe(kvg, tmp, &kv->group_list, node) { 238 kvm_vfio_group_put_external_user(kvg->vfio_group); 239 list_del(&kvg->node); 240 kfree(kvg); 241 } 242 243 kvm_vfio_update_coherency(dev); 244 245 kfree(kv); 246 kfree(dev); /* alloc by kvm_ioctl_create_device, free by .destroy */ 247 } 248 249 static int kvm_vfio_create(struct kvm_device *dev, u32 type) 250 { 251 struct kvm_device *tmp; 252 struct kvm_vfio *kv; 253 254 /* Only one VFIO "device" per VM */ 255 list_for_each_entry(tmp, &dev->kvm->devices, vm_node) 256 if (tmp->ops == &kvm_vfio_ops) 257 return -EBUSY; 258 259 kv = kzalloc(sizeof(*kv), GFP_KERNEL); 260 if (!kv) 261 return -ENOMEM; 262 263 INIT_LIST_HEAD(&kv->group_list); 264 mutex_init(&kv->lock); 265 266 dev->private = kv; 267 268 return 0; 269 } 270 271 struct kvm_device_ops kvm_vfio_ops = { 272 .name = "kvm-vfio", 273 .create = kvm_vfio_create, 274 .destroy = kvm_vfio_destroy, 275 .set_attr = kvm_vfio_set_attr, 276 .has_attr = kvm_vfio_has_attr, 277 }; 278