xref: /openbmc/qemu/hw/virtio/vhost-backend.c (revision 12a6c15e)
1 /*
2  * vhost-backend
3  *
4  * Copyright (c) 2013 Virtual Open Systems Sarl.
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  *
9  */
10 
11 #include "qemu/osdep.h"
12 #include <linux/vhost.h>
13 #include <sys/ioctl.h>
14 #include "hw/virtio/vhost.h"
15 #include "hw/virtio/vhost-backend.h"
16 #include "qemu/error-report.h"
17 
18 static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
19                              void *arg)
20 {
21     int fd = (uintptr_t) dev->opaque;
22 
23     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
24 
25     return ioctl(fd, request, arg);
26 }
27 
28 static int vhost_kernel_init(struct vhost_dev *dev, void *opaque)
29 {
30     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
31 
32     dev->opaque = opaque;
33 
34     return 0;
35 }
36 
37 static int vhost_kernel_cleanup(struct vhost_dev *dev)
38 {
39     int fd = (uintptr_t) dev->opaque;
40 
41     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
42 
43     return close(fd);
44 }
45 
46 static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
47 {
48     int limit = 64;
49     char *s;
50 
51     if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions",
52                             &s, NULL, NULL)) {
53         uint64_t val = g_ascii_strtoull(s, NULL, 10);
54         if (!((val == G_MAXUINT64 || !val) && errno)) {
55             g_free(s);
56             return val;
57         }
58         error_report("ignoring invalid max_mem_regions value in vhost module:"
59                      " %s", s);
60     }
61     g_free(s);
62     return limit;
63 }
64 
65 static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
66                                         struct vhost_vring_file *file)
67 {
68     return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
69 }
70 
71 static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
72                                           struct vhost_scsi_target *target)
73 {
74     return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
75 }
76 
77 static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
78                                             struct vhost_scsi_target *target)
79 {
80     return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
81 }
82 
83 static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
84 {
85     return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
86 }
87 
88 static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
89                                      struct vhost_log *log)
90 {
91     return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
92 }
93 
94 static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
95                                       struct vhost_memory *mem)
96 {
97     return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
98 }
99 
100 static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
101                                        struct vhost_vring_addr *addr)
102 {
103     return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
104 }
105 
106 static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
107                                          struct vhost_vring_state *ring)
108 {
109     return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
110 }
111 
112 static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
113                                       struct vhost_vring_state *ring)
114 {
115     return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
116 }
117 
118 static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
119                                        struct vhost_vring_state *ring)
120 {
121     return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
122 }
123 
124 static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
125                                        struct vhost_vring_state *ring)
126 {
127     return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
128 }
129 
130 static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
131                                        struct vhost_vring_file *file)
132 {
133     return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
134 }
135 
136 static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
137                                        struct vhost_vring_file *file)
138 {
139     return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
140 }
141 
142 static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev,
143                                                    struct vhost_vring_state *s)
144 {
145     return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s);
146 }
147 
148 static int vhost_kernel_set_features(struct vhost_dev *dev,
149                                      uint64_t features)
150 {
151     return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
152 }
153 
154 static int vhost_kernel_get_features(struct vhost_dev *dev,
155                                      uint64_t *features)
156 {
157     return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
158 }
159 
160 static int vhost_kernel_set_owner(struct vhost_dev *dev)
161 {
162     return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
163 }
164 
165 static int vhost_kernel_reset_device(struct vhost_dev *dev)
166 {
167     return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
168 }
169 
170 static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
171 {
172     assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
173 
174     return idx - dev->vq_index;
175 }
176 
177 #ifdef CONFIG_VHOST_VSOCK
178 static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev,
179                                             uint64_t guest_cid)
180 {
181     return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid);
182 }
183 
184 static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start)
185 {
186     return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start);
187 }
188 #endif /* CONFIG_VHOST_VSOCK */
189 
190 static void vhost_kernel_iotlb_read(void *opaque)
191 {
192     struct vhost_dev *dev = opaque;
193     struct vhost_msg msg;
194     ssize_t len;
195 
196     while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) {
197         if (len < sizeof msg) {
198             error_report("Wrong vhost message len: %d", (int)len);
199             break;
200         }
201         if (msg.type != VHOST_IOTLB_MSG) {
202             error_report("Unknown vhost iotlb message type");
203             break;
204         }
205 
206         vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
207     }
208 }
209 
210 static int vhost_kernel_send_device_iotlb_msg(struct vhost_dev *dev,
211                                               struct vhost_iotlb_msg *imsg)
212 {
213     struct vhost_msg msg;
214 
215     msg.type = VHOST_IOTLB_MSG;
216     msg.iotlb = *imsg;
217 
218     if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
219         error_report("Fail to update device iotlb");
220         return -EFAULT;
221     }
222 
223     return 0;
224 }
225 
226 static void vhost_kernel_set_iotlb_callback(struct vhost_dev *dev,
227                                            int enabled)
228 {
229     if (enabled)
230         qemu_set_fd_handler((uintptr_t)dev->opaque,
231                             vhost_kernel_iotlb_read, NULL, dev);
232     else
233         qemu_set_fd_handler((uintptr_t)dev->opaque, NULL, NULL, NULL);
234 }
235 
236 static const VhostOps kernel_ops = {
237         .backend_type = VHOST_BACKEND_TYPE_KERNEL,
238         .vhost_backend_init = vhost_kernel_init,
239         .vhost_backend_cleanup = vhost_kernel_cleanup,
240         .vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
241         .vhost_net_set_backend = vhost_kernel_net_set_backend,
242         .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
243         .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
244         .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
245         .vhost_set_log_base = vhost_kernel_set_log_base,
246         .vhost_set_mem_table = vhost_kernel_set_mem_table,
247         .vhost_set_vring_addr = vhost_kernel_set_vring_addr,
248         .vhost_set_vring_endian = vhost_kernel_set_vring_endian,
249         .vhost_set_vring_num = vhost_kernel_set_vring_num,
250         .vhost_set_vring_base = vhost_kernel_set_vring_base,
251         .vhost_get_vring_base = vhost_kernel_get_vring_base,
252         .vhost_set_vring_kick = vhost_kernel_set_vring_kick,
253         .vhost_set_vring_call = vhost_kernel_set_vring_call,
254         .vhost_set_vring_busyloop_timeout =
255                                 vhost_kernel_set_vring_busyloop_timeout,
256         .vhost_set_features = vhost_kernel_set_features,
257         .vhost_get_features = vhost_kernel_get_features,
258         .vhost_set_owner = vhost_kernel_set_owner,
259         .vhost_reset_device = vhost_kernel_reset_device,
260         .vhost_get_vq_index = vhost_kernel_get_vq_index,
261 #ifdef CONFIG_VHOST_VSOCK
262         .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
263         .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
264 #endif /* CONFIG_VHOST_VSOCK */
265         .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
266         .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
267 };
268 
269 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
270 {
271     int r = 0;
272 
273     switch (backend_type) {
274     case VHOST_BACKEND_TYPE_KERNEL:
275         dev->vhost_ops = &kernel_ops;
276         break;
277     case VHOST_BACKEND_TYPE_USER:
278         dev->vhost_ops = &user_ops;
279         break;
280     default:
281         error_report("Unknown vhost backend type");
282         r = -1;
283     }
284 
285     return r;
286 }
287 
288 int vhost_backend_update_device_iotlb(struct vhost_dev *dev,
289                                              uint64_t iova, uint64_t uaddr,
290                                              uint64_t len,
291                                              IOMMUAccessFlags perm)
292 {
293     struct vhost_iotlb_msg imsg;
294 
295     imsg.iova =  iova;
296     imsg.uaddr = uaddr;
297     imsg.size = len;
298     imsg.type = VHOST_IOTLB_UPDATE;
299 
300     switch (perm) {
301     case IOMMU_RO:
302         imsg.perm = VHOST_ACCESS_RO;
303         break;
304     case IOMMU_WO:
305         imsg.perm = VHOST_ACCESS_WO;
306         break;
307     case IOMMU_RW:
308         imsg.perm = VHOST_ACCESS_RW;
309         break;
310     default:
311         return -EINVAL;
312     }
313 
314     if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg)
315         return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
316 
317     return -ENODEV;
318 }
319 
320 int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev,
321                                                  uint64_t iova, uint64_t len)
322 {
323     struct vhost_iotlb_msg imsg;
324 
325     imsg.iova = iova;
326     imsg.size = len;
327     imsg.type = VHOST_IOTLB_INVALIDATE;
328 
329     if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg)
330         return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
331 
332     return -ENODEV;
333 }
334 
335 int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev,
336                                           struct vhost_iotlb_msg *imsg)
337 {
338     int ret = 0;
339 
340     switch (imsg->type) {
341     case VHOST_IOTLB_MISS:
342         ret = vhost_device_iotlb_miss(dev, imsg->iova,
343                                       imsg->perm != VHOST_ACCESS_RO);
344         break;
345     case VHOST_IOTLB_ACCESS_FAIL:
346         /* FIXME: report device iotlb error */
347         error_report("Access failure IOTLB message type not supported");
348         ret = -ENOTSUP;
349         break;
350     case VHOST_IOTLB_UPDATE:
351     case VHOST_IOTLB_INVALIDATE:
352     default:
353         error_report("Unexpected IOTLB message type");
354         ret = -EINVAL;
355         break;
356     }
357 
358     return ret;
359 }
360