1
2
3
4
5
6
7
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
18static 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
28static 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
37static 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
46static 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
65static 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
71static 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
77static 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
83static 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
88static 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
94static 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
100static 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
106static 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
112static 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
118static 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
124static 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
130static 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
136static 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
142static 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
148static 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
154static 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
160static int vhost_kernel_set_owner(struct vhost_dev *dev)
161{
162 return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
163}
164
165static int vhost_kernel_reset_device(struct vhost_dev *dev)
166{
167 return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
168}
169
170static 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
178static 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
184static 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
189
190static 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
210static 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
226static 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
236static 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
265 .vhost_set_iotlb_callback = vhost_kernel_set_iotlb_callback,
266 .vhost_send_device_iotlb_msg = vhost_kernel_send_device_iotlb_msg,
267};
268
269int 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
288int 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
320int 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
335int 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
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