master
c 394 lines 12.3 KB
Raw
1 /*
2 * vhost-kernel
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_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_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_init = vhost_kernel_init,
362 .vhost_cleanup = vhost_kernel_cleanup,
363 .vhost_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