xref: /openbmc/qemu/hw/virtio/vhost-backend.c (revision 92a0dcbd751d771512b9dedd97e00553181b7699)
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 "hw/virtio/vhost.h"
13 #include "hw/virtio/vhost-backend.h"
14 #include "qemu/error-report.h"
15 #include "qemu/main-loop.h"
16 #include "standard-headers/linux/vhost_types.h"
17 
18 #include "hw/virtio/vhost-vdpa.h"
19 #ifdef CONFIG_VHOST_KERNEL
20 #include <linux/vhost.h>
21 #include <sys/ioctl.h>
22 
23 struct vhost_features {
24     uint64_t count;
25     uint64_t features[VIRTIO_FEATURES_NU64S];
26 };
27 
28 static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
29                              void *arg)
30 {
31     int fd = (uintptr_t) dev->opaque;
32     int ret;
33 
34     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
35 
36     ret = ioctl(fd, request, arg);
37     return ret < 0 ? -errno : ret;
38 }
39 
40 static int vhost_kernel_init(struct vhost_dev *dev, void *opaque, Error **errp)
41 {
42     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
43 
44     dev->opaque = opaque;
45 
46     return 0;
47 }
48 
49 static int vhost_kernel_cleanup(struct vhost_dev *dev)
50 {
51     int fd = (uintptr_t) dev->opaque;
52 
53     assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_KERNEL);
54 
55     return close(fd) < 0 ? -errno : 0;
56 }
57 
58 static int vhost_kernel_memslots_limit(struct vhost_dev *dev)
59 {
60     int limit = 64;
61     char *s;
62 
63     if (g_file_get_contents("/sys/module/vhost/parameters/max_mem_regions",
64                             &s, NULL, NULL)) {
65         uint64_t val = g_ascii_strtoull(s, NULL, 10);
66         if (val < INT_MAX && val > 0) {
67             g_free(s);
68             return val;
69         }
70         error_report("ignoring invalid max_mem_regions value in vhost module:"
71                      " %s", s);
72     }
73     g_free(s);
74     return limit;
75 }
76 
77 static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
78                                         struct vhost_vring_file *file)
79 {
80     return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
81 }
82 
83 static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
84                                           struct vhost_scsi_target *target)
85 {
86     return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
87 }
88 
89 static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
90                                             struct vhost_scsi_target *target)
91 {
92     return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
93 }
94 
95 static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
96 {
97     return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
98 }
99 
100 static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
101                                      struct vhost_log *log)
102 {
103     return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
104 }
105 
106 static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
107                                       struct vhost_memory *mem)
108 {
109     return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
110 }
111 
112 static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
113                                        struct vhost_vring_addr *addr)
114 {
115     return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
116 }
117 
118 static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
119                                          struct vhost_vring_state *ring)
120 {
121     return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
122 }
123 
124 static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
125                                       struct vhost_vring_state *ring)
126 {
127     return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
128 }
129 
130 static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
131                                        struct vhost_vring_state *ring)
132 {
133     return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
134 }
135 
136 static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
137                                        struct vhost_vring_state *ring)
138 {
139     return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
140 }
141 
142 static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
143                                        struct vhost_vring_file *file)
144 {
145     return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
146 }
147 
148 static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
149                                        struct vhost_vring_file *file)
150 {
151     return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
152 }
153 
154 static int vhost_kernel_set_vring_err(struct vhost_dev *dev,
155                                       struct vhost_vring_file *file)
156 {
157     return vhost_kernel_call(dev, VHOST_SET_VRING_ERR, file);
158 }
159 
160 static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev,
161                                                    struct vhost_vring_state *s)
162 {
163     return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s);
164 }
165 
166 static int vhost_kernel_new_worker(struct vhost_dev *dev,
167                                    struct vhost_worker_state *worker)
168 {
169     return vhost_kernel_call(dev, VHOST_NEW_WORKER, worker);
170 }
171 
172 static int vhost_kernel_free_worker(struct vhost_dev *dev,
173                                     struct vhost_worker_state *worker)
174 {
175     return vhost_kernel_call(dev, VHOST_FREE_WORKER, worker);
176 }
177 
178 static int vhost_kernel_attach_vring_worker(struct vhost_dev *dev,
179                                             struct vhost_vring_worker *worker)
180 {
181     return vhost_kernel_call(dev, VHOST_ATTACH_VRING_WORKER, worker);
182 }
183 
184 static int vhost_kernel_get_vring_worker(struct vhost_dev *dev,
185                                          struct vhost_vring_worker *worker)
186 {
187     return vhost_kernel_call(dev, VHOST_GET_VRING_WORKER, worker);
188 }
189 
190 static int vhost_kernel_set_backend_cap(struct vhost_dev *dev)
191 {
192     uint64_t features;
193     uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2;
194     int r;
195 
196     if (vhost_kernel_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) {
197         return 0;
198     }
199 
200     features &= f;
201     r = vhost_kernel_call(dev, VHOST_SET_BACKEND_FEATURES,
202                               &features);
203     if (r) {
204         return 0;
205     }
206 
207     dev->backend_cap = features;
208 
209     return 0;
210 }
211 
212 static int vhost_kernel_set_features(struct vhost_dev *dev,
213                                      const uint64_t *features)
214 {
215     struct vhost_features farray;
216     bool extended_in_use;
217     int r;
218 
219     farray.count = VIRTIO_FEATURES_NU64S;
220     virtio_features_copy(farray.features, features);
221     extended_in_use = virtio_features_use_ex(farray.features);
222 
223     /*
224      * Can't check for ENOTTY: for unknown ioctls the kernel interprets
225      * the argument as a virtio queue id and most likely errors out validating
226      * such id, instead of reporting an unknown operation.
227      */
228     r = vhost_kernel_call(dev, VHOST_SET_FEATURES_ARRAY, &farray);
229     if (!r) {
230         return 0;
231     }
232 
233     if (extended_in_use) {
234         error_report("Trying to set extended features without kernel support");
235         return -EINVAL;
236     }
237     return vhost_kernel_call(dev, VHOST_SET_FEATURES, &farray.features[0]);
238 }
239 
240 static int vhost_kernel_get_features(struct vhost_dev *dev, uint64_t *features)
241 {
242     struct vhost_features farray;
243     int r;
244 
245     farray.count = VIRTIO_FEATURES_NU64S;
246     r = vhost_kernel_call(dev, VHOST_GET_FEATURES_ARRAY, &farray);
247     if (r) {
248         memset(&farray, 0, sizeof(farray));
249         r = vhost_kernel_call(dev, VHOST_GET_FEATURES, &farray.features[0]);
250     }
251     if (r) {
252         return r;
253     }
254 
255     virtio_features_copy(features, farray.features);
256     return 0;
257 }
258 
259 static int vhost_kernel_set_owner(struct vhost_dev *dev)
260 {
261     return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
262 }
263 
264 static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
265 {
266     assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
267 
268     return idx - dev->vq_index;
269 }
270 
271 static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev,
272                                             uint64_t guest_cid)
273 {
274     return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid);
275 }
276 
277 static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start)
278 {
279     return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start);
280 }
281 
282 static void vhost_kernel_iotlb_read(void *opaque)
283 {
284     struct vhost_dev *dev = opaque;
285     ssize_t len;
286 
287     if (dev->backend_cap &
288         (0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) {
289         struct vhost_msg_v2 msg;
290 
291         while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) {
292             if (len < sizeof msg) {
293                 error_report("Wrong vhost message len: %d", (int)len);
294                 break;
295             }
296             if (msg.type != VHOST_IOTLB_MSG_V2) {
297                 error_report("Unknown vhost iotlb message type");
298                 break;
299             }
300 
301             vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
302         }
303     } else {
304         struct vhost_msg msg;
305 
306         while ((len = read((uintptr_t)dev->opaque, &msg, sizeof msg)) > 0) {
307             if (len < sizeof msg) {
308                 error_report("Wrong vhost message len: %d", (int)len);
309                 break;
310             }
311             if (msg.type != VHOST_IOTLB_MSG) {
312                 error_report("Unknown vhost iotlb message type");
313                 break;
314             }
315 
316             vhost_backend_handle_iotlb_msg(dev, &msg.iotlb);
317         }
318     }
319 }
320 
321 static int vhost_kernel_send_device_iotlb_msg(struct vhost_dev *dev,
322                                               struct vhost_iotlb_msg *imsg)
323 {
324     if (dev->backend_cap & (1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2)) {
325         struct vhost_msg_v2 msg = {};
326 
327         msg.type = VHOST_IOTLB_MSG_V2;
328         msg.iotlb = *imsg;
329 
330         if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
331             error_report("Fail to update device iotlb");
332             return -EFAULT;
333         }
334     } else {
335         struct vhost_msg msg = {};
336 
337         msg.type = VHOST_IOTLB_MSG;
338         msg.iotlb = *imsg;
339 
340         if (write((uintptr_t)dev->opaque, &msg, sizeof msg) != sizeof msg) {
341             error_report("Fail to update device iotlb");
342             return -EFAULT;
343         }
344     }
345 
346     return 0;
347 }
348 
349 static void vhost_kernel_set_iotlb_callback(struct vhost_dev *dev,
350                                            int enabled)
351 {
352     if (enabled)
353         qemu_set_fd_handler((uintptr_t)dev->opaque,
354                             vhost_kernel_iotlb_read, NULL, dev);
355     else
356         qemu_set_fd_handler((uintptr_t)dev->opaque, NULL, NULL, NULL);
357 }
358 
359 const VhostOps kernel_ops = {
360         .backend_type = VHOST_BACKEND_TYPE_KERNEL,
361         .vhost_backend_init = vhost_kernel_init,
362         .vhost_backend_cleanup = vhost_kernel_cleanup,
363         .vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
364         .vhost_net_set_backend = vhost_kernel_net_set_backend,
365         .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
366         .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
367         .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
368         .vhost_set_log_base = vhost_kernel_set_log_base,
369         .vhost_set_mem_table = vhost_kernel_set_mem_table,
370         .vhost_set_vring_addr = vhost_kernel_set_vring_addr,
371         .vhost_set_vring_endian = vhost_kernel_set_vring_endian,
372         .vhost_set_vring_num = vhost_kernel_set_vring_num,
373         .vhost_set_vring_base = vhost_kernel_set_vring_base,
374         .vhost_get_vring_base = vhost_kernel_get_vring_base,
375         .vhost_set_vring_kick = vhost_kernel_set_vring_kick,
376         .vhost_set_vring_call = vhost_kernel_set_vring_call,
377         .vhost_set_vring_err = vhost_kernel_set_vring_err,
378         .vhost_set_vring_busyloop_timeout =
379                                 vhost_kernel_set_vring_busyloop_timeout,
380         .vhost_get_vring_worker = vhost_kernel_get_vring_worker,
381         .vhost_attach_vring_worker = vhost_kernel_attach_vring_worker,
382         .vhost_new_worker = vhost_kernel_new_worker,
383         .vhost_free_worker = vhost_kernel_free_worker,
384         .vhost_set_features_ex = vhost_kernel_set_features,
385         .vhost_get_features_ex = vhost_kernel_get_features,
386         .vhost_set_backend_cap = vhost_kernel_set_backend_cap,
387         .vhost_set_owner = vhost_kernel_set_owner,
388         .vhost_get_vq_index = vhost_kernel_get_vq_index,
389         .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
390         .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
391         .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
392         .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
393 };
394 #endif
395 
396 int vhost_backend_update_device_iotlb(struct vhost_dev *dev,
397                                              uint64_t iova, uint64_t uaddr,
398                                              uint64_t len,
399                                              IOMMUAccessFlags perm)
400 {
401     struct vhost_iotlb_msg imsg;
402 
403     imsg.iova =  iova;
404     imsg.uaddr = uaddr;
405     imsg.size = len;
406     imsg.type = VHOST_IOTLB_UPDATE;
407 
408     switch (perm) {
409     case IOMMU_RO:
410         imsg.perm = VHOST_ACCESS_RO;
411         break;
412     case IOMMU_WO:
413         imsg.perm = VHOST_ACCESS_WO;
414         break;
415     case IOMMU_RW:
416         imsg.perm = VHOST_ACCESS_RW;
417         break;
418     default:
419         return -EINVAL;
420     }
421 
422     if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg)
423         return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
424 
425     return -ENODEV;
426 }
427 
428 int vhost_backend_invalidate_device_iotlb(struct vhost_dev *dev,
429                                                  uint64_t iova, uint64_t len)
430 {
431     struct vhost_iotlb_msg imsg;
432 
433     imsg.iova = iova;
434     imsg.size = len;
435     imsg.type = VHOST_IOTLB_INVALIDATE;
436 
437     if (dev->vhost_ops && dev->vhost_ops->vhost_send_device_iotlb_msg)
438         return dev->vhost_ops->vhost_send_device_iotlb_msg(dev, &imsg);
439 
440     return -ENODEV;
441 }
442 
443 int vhost_backend_handle_iotlb_msg(struct vhost_dev *dev,
444                                           struct vhost_iotlb_msg *imsg)
445 {
446     int ret = 0;
447 
448     if (unlikely(!dev->vdev)) {
449         error_report("Unexpected IOTLB message when virtio device is stopped");
450         return -EINVAL;
451     }
452 
453     switch (imsg->type) {
454     case VHOST_IOTLB_MISS:
455         ret = vhost_device_iotlb_miss(dev, imsg->iova,
456                                       imsg->perm != VHOST_ACCESS_RO);
457         break;
458     case VHOST_IOTLB_ACCESS_FAIL:
459         /* FIXME: report device iotlb error */
460         error_report("Access failure IOTLB message type not supported");
461         ret = -ENOTSUP;
462         break;
463     case VHOST_IOTLB_UPDATE:
464     case VHOST_IOTLB_INVALIDATE:
465     default:
466         error_report("Unexpected IOTLB message type");
467         ret = -EINVAL;
468         break;
469     }
470 
471     return ret;
472 }
473