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 /* 63 * Groups can use the same or different IOMMU domains. If the same then 64 * adding a new group may change the coherency of groups we've previously 65 * been told about. We don't want to care about any of that so we retest 66 * each group and bail as soon as we find one that's noncoherent. This 67 * means we only ever [un]register_noncoherent_dma once for the whole device. 68 */ 69 static void kvm_vfio_update_coherency(struct kvm_device *dev) 70 { 71 struct kvm_vfio *kv = dev->private; 72 bool noncoherent = false; 73 struct kvm_vfio_group *kvg; 74 75 mutex_lock(&kv->lock); 76 77 list_for_each_entry(kvg, &kv->group_list, node) { 78 /* 79 * TODO: We need an interface to check the coherency of 80 * the IOMMU domain this group is using. For now, assume 81 * it's always noncoherent. 82 */ 83 noncoherent = true; 84 break; 85 } 86 87 if (noncoherent != kv->noncoherent) { 88 kv->noncoherent = noncoherent; 89 90 if (kv->noncoherent) 91 kvm_arch_register_noncoherent_dma(dev->kvm); 92 else 93 kvm_arch_unregister_noncoherent_dma(dev->kvm); 94 } 95 96 mutex_unlock(&kv->lock); 97 } 98 99 static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg) 100 { 101 struct kvm_vfio *kv = dev->private; 102 struct vfio_group *vfio_group; 103 struct kvm_vfio_group *kvg; 104 void __user *argp = (void __user *)arg; 105 struct fd f; 106 int32_t fd; 107 int ret; 108 109 switch (attr) { 110 case KVM_DEV_VFIO_GROUP_ADD: 111 if (get_user(fd, (int32_t __user *)argp)) 112 return -EFAULT; 113 114 f = fdget(fd); 115 if (!f.file) 116 return -EBADF; 117 118 vfio_group = kvm_vfio_group_get_external_user(f.file); 119 fdput(f); 120 121 if (IS_ERR(vfio_group)) 122 return PTR_ERR(vfio_group); 123 124 mutex_lock(&kv->lock); 125 126 list_for_each_entry(kvg, &kv->group_list, node) { 127 if (kvg->vfio_group == vfio_group) { 128 mutex_unlock(&kv->lock); 129 kvm_vfio_group_put_external_user(vfio_group); 130 return -EEXIST; 131 } 132 } 133 134 kvg = kzalloc(sizeof(*kvg), GFP_KERNEL); 135 if (!kvg) { 136 mutex_unlock(&kv->lock); 137 kvm_vfio_group_put_external_user(vfio_group); 138 return -ENOMEM; 139 } 140 141 list_add_tail(&kvg->node, &kv->group_list); 142 kvg->vfio_group = vfio_group; 143 144 mutex_unlock(&kv->lock); 145 146 kvm_vfio_update_coherency(dev); 147 148 return 0; 149 150 case KVM_DEV_VFIO_GROUP_DEL: 151 if (get_user(fd, (int32_t __user *)argp)) 152 return -EFAULT; 153 154 f = fdget(fd); 155 if (!f.file) 156 return -EBADF; 157 158 vfio_group = kvm_vfio_group_get_external_user(f.file); 159 fdput(f); 160 161 if (IS_ERR(vfio_group)) 162 return PTR_ERR(vfio_group); 163 164 ret = -ENOENT; 165 166 mutex_lock(&kv->lock); 167 168 list_for_each_entry(kvg, &kv->group_list, node) { 169 if (kvg->vfio_group != vfio_group) 170 continue; 171 172 list_del(&kvg->node); 173 kvm_vfio_group_put_external_user(kvg->vfio_group); 174 kfree(kvg); 175 ret = 0; 176 break; 177 } 178 179 mutex_unlock(&kv->lock); 180 181 kvm_vfio_group_put_external_user(vfio_group); 182 183 kvm_vfio_update_coherency(dev); 184 185 return ret; 186 } 187 188 return -ENXIO; 189 } 190 191 static int kvm_vfio_set_attr(struct kvm_device *dev, 192 struct kvm_device_attr *attr) 193 { 194 switch (attr->group) { 195 case KVM_DEV_VFIO_GROUP: 196 return kvm_vfio_set_group(dev, attr->attr, attr->addr); 197 } 198 199 return -ENXIO; 200 } 201 202 static int kvm_vfio_has_attr(struct kvm_device *dev, 203 struct kvm_device_attr *attr) 204 { 205 switch (attr->group) { 206 case KVM_DEV_VFIO_GROUP: 207 switch (attr->attr) { 208 case KVM_DEV_VFIO_GROUP_ADD: 209 case KVM_DEV_VFIO_GROUP_DEL: 210 return 0; 211 } 212 213 break; 214 } 215 216 return -ENXIO; 217 } 218 219 static void kvm_vfio_destroy(struct kvm_device *dev) 220 { 221 struct kvm_vfio *kv = dev->private; 222 struct kvm_vfio_group *kvg, *tmp; 223 224 list_for_each_entry_safe(kvg, tmp, &kv->group_list, node) { 225 kvm_vfio_group_put_external_user(kvg->vfio_group); 226 list_del(&kvg->node); 227 kfree(kvg); 228 } 229 230 kvm_vfio_update_coherency(dev); 231 232 kfree(kv); 233 kfree(dev); /* alloc by kvm_ioctl_create_device, free by .destroy */ 234 } 235 236 static int kvm_vfio_create(struct kvm_device *dev, u32 type) 237 { 238 struct kvm_device *tmp; 239 struct kvm_vfio *kv; 240 241 /* Only one VFIO "device" per VM */ 242 list_for_each_entry(tmp, &dev->kvm->devices, vm_node) 243 if (tmp->ops == &kvm_vfio_ops) 244 return -EBUSY; 245 246 kv = kzalloc(sizeof(*kv), GFP_KERNEL); 247 if (!kv) 248 return -ENOMEM; 249 250 INIT_LIST_HEAD(&kv->group_list); 251 mutex_init(&kv->lock); 252 253 dev->private = kv; 254 255 return 0; 256 } 257 258 struct kvm_device_ops kvm_vfio_ops = { 259 .name = "kvm-vfio", 260 .create = kvm_vfio_create, 261 .destroy = kvm_vfio_destroy, 262 .set_attr = kvm_vfio_set_attr, 263 .has_attr = kvm_vfio_has_attr, 264 }; 265