Merge branch 'linux-3.10.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable...
[firefly-linux-kernel-4.4.55.git] / virt / kvm / vfio.c
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 };
31
32 static struct vfio_group *kvm_vfio_group_get_external_user(struct file *filep)
33 {
34         struct vfio_group *vfio_group;
35         struct vfio_group *(*fn)(struct file *);
36
37         fn = symbol_get(vfio_group_get_external_user);
38         if (!fn)
39                 return ERR_PTR(-EINVAL);
40
41         vfio_group = fn(filep);
42
43         symbol_put(vfio_group_get_external_user);
44
45         return vfio_group;
46 }
47
48 static void kvm_vfio_group_put_external_user(struct vfio_group *vfio_group)
49 {
50         void (*fn)(struct vfio_group *);
51
52         fn = symbol_get(vfio_group_put_external_user);
53         if (!fn)
54                 return;
55
56         fn(vfio_group);
57
58         symbol_put(vfio_group_put_external_user);
59 }
60
61 static int kvm_vfio_set_group(struct kvm_device *dev, long attr, u64 arg)
62 {
63         struct kvm_vfio *kv = dev->private;
64         struct vfio_group *vfio_group;
65         struct kvm_vfio_group *kvg;
66         void __user *argp = (void __user *)arg;
67         struct fd f;
68         int32_t fd;
69         int ret;
70
71         switch (attr) {
72         case KVM_DEV_VFIO_GROUP_ADD:
73                 if (get_user(fd, (int32_t __user *)argp))
74                         return -EFAULT;
75
76                 f = fdget(fd);
77                 if (!f.file)
78                         return -EBADF;
79
80                 vfio_group = kvm_vfio_group_get_external_user(f.file);
81                 fdput(f);
82
83                 if (IS_ERR(vfio_group))
84                         return PTR_ERR(vfio_group);
85
86                 mutex_lock(&kv->lock);
87
88                 list_for_each_entry(kvg, &kv->group_list, node) {
89                         if (kvg->vfio_group == vfio_group) {
90                                 mutex_unlock(&kv->lock);
91                                 kvm_vfio_group_put_external_user(vfio_group);
92                                 return -EEXIST;
93                         }
94                 }
95
96                 kvg = kzalloc(sizeof(*kvg), GFP_KERNEL);
97                 if (!kvg) {
98                         mutex_unlock(&kv->lock);
99                         kvm_vfio_group_put_external_user(vfio_group);
100                         return -ENOMEM;
101                 }
102
103                 list_add_tail(&kvg->node, &kv->group_list);
104                 kvg->vfio_group = vfio_group;
105
106                 mutex_unlock(&kv->lock);
107
108                 return 0;
109
110         case KVM_DEV_VFIO_GROUP_DEL:
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                 ret = -ENOENT;
125
126                 mutex_lock(&kv->lock);
127
128                 list_for_each_entry(kvg, &kv->group_list, node) {
129                         if (kvg->vfio_group != vfio_group)
130                                 continue;
131
132                         list_del(&kvg->node);
133                         kvm_vfio_group_put_external_user(kvg->vfio_group);
134                         kfree(kvg);
135                         ret = 0;
136                         break;
137                 }
138
139                 mutex_unlock(&kv->lock);
140
141                 kvm_vfio_group_put_external_user(vfio_group);
142
143                 return ret;
144         }
145
146         return -ENXIO;
147 }
148
149 static int kvm_vfio_set_attr(struct kvm_device *dev,
150                              struct kvm_device_attr *attr)
151 {
152         switch (attr->group) {
153         case KVM_DEV_VFIO_GROUP:
154                 return kvm_vfio_set_group(dev, attr->attr, attr->addr);
155         }
156
157         return -ENXIO;
158 }
159
160 static int kvm_vfio_has_attr(struct kvm_device *dev,
161                              struct kvm_device_attr *attr)
162 {
163         switch (attr->group) {
164         case KVM_DEV_VFIO_GROUP:
165                 switch (attr->attr) {
166                 case KVM_DEV_VFIO_GROUP_ADD:
167                 case KVM_DEV_VFIO_GROUP_DEL:
168                         return 0;
169                 }
170
171                 break;
172         }
173
174         return -ENXIO;
175 }
176
177 static void kvm_vfio_destroy(struct kvm_device *dev)
178 {
179         struct kvm_vfio *kv = dev->private;
180         struct kvm_vfio_group *kvg, *tmp;
181
182         list_for_each_entry_safe(kvg, tmp, &kv->group_list, node) {
183                 kvm_vfio_group_put_external_user(kvg->vfio_group);
184                 list_del(&kvg->node);
185                 kfree(kvg);
186         }
187
188         kfree(kv);
189         kfree(dev); /* alloc by kvm_ioctl_create_device, free by .destroy */
190 }
191
192 static int kvm_vfio_create(struct kvm_device *dev, u32 type);
193
194 static struct kvm_device_ops kvm_vfio_ops = {
195         .name = "kvm-vfio",
196         .create = kvm_vfio_create,
197         .destroy = kvm_vfio_destroy,
198         .set_attr = kvm_vfio_set_attr,
199         .has_attr = kvm_vfio_has_attr,
200 };
201
202 static int kvm_vfio_create(struct kvm_device *dev, u32 type)
203 {
204         struct kvm_device *tmp;
205         struct kvm_vfio *kv;
206
207         /* Only one VFIO "device" per VM */
208         list_for_each_entry(tmp, &dev->kvm->devices, vm_node)
209                 if (tmp->ops == &kvm_vfio_ops)
210                         return -EBUSY;
211
212         kv = kzalloc(sizeof(*kv), GFP_KERNEL);
213         if (!kv)
214                 return -ENOMEM;
215
216         INIT_LIST_HEAD(&kv->group_list);
217         mutex_init(&kv->lock);
218
219         dev->private = kv;
220
221         return 0;
222 }
223
224 static int __init kvm_vfio_ops_init(void)
225 {
226         return kvm_register_device_ops(&kvm_vfio_ops, KVM_DEV_TYPE_VFIO);
227 }
228 module_init(kvm_vfio_ops_init);