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