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 return val;
56 }
57 error_report("ignoring invalid max_mem_regions value in vhost module:"
58 " %s", s);
59 }
60 return limit;
61}
62
63static int vhost_kernel_net_set_backend(struct vhost_dev *dev,
64 struct vhost_vring_file *file)
65{
66 return vhost_kernel_call(dev, VHOST_NET_SET_BACKEND, file);
67}
68
69static int vhost_kernel_scsi_set_endpoint(struct vhost_dev *dev,
70 struct vhost_scsi_target *target)
71{
72 return vhost_kernel_call(dev, VHOST_SCSI_SET_ENDPOINT, target);
73}
74
75static int vhost_kernel_scsi_clear_endpoint(struct vhost_dev *dev,
76 struct vhost_scsi_target *target)
77{
78 return vhost_kernel_call(dev, VHOST_SCSI_CLEAR_ENDPOINT, target);
79}
80
81static int vhost_kernel_scsi_get_abi_version(struct vhost_dev *dev, int *version)
82{
83 return vhost_kernel_call(dev, VHOST_SCSI_GET_ABI_VERSION, version);
84}
85
86static int vhost_kernel_set_log_base(struct vhost_dev *dev, uint64_t base,
87 struct vhost_log *log)
88{
89 return vhost_kernel_call(dev, VHOST_SET_LOG_BASE, &base);
90}
91
92static int vhost_kernel_set_mem_table(struct vhost_dev *dev,
93 struct vhost_memory *mem)
94{
95 return vhost_kernel_call(dev, VHOST_SET_MEM_TABLE, mem);
96}
97
98static int vhost_kernel_set_vring_addr(struct vhost_dev *dev,
99 struct vhost_vring_addr *addr)
100{
101 return vhost_kernel_call(dev, VHOST_SET_VRING_ADDR, addr);
102}
103
104static int vhost_kernel_set_vring_endian(struct vhost_dev *dev,
105 struct vhost_vring_state *ring)
106{
107 return vhost_kernel_call(dev, VHOST_SET_VRING_ENDIAN, ring);
108}
109
110static int vhost_kernel_set_vring_num(struct vhost_dev *dev,
111 struct vhost_vring_state *ring)
112{
113 return vhost_kernel_call(dev, VHOST_SET_VRING_NUM, ring);
114}
115
116static int vhost_kernel_set_vring_base(struct vhost_dev *dev,
117 struct vhost_vring_state *ring)
118{
119 return vhost_kernel_call(dev, VHOST_SET_VRING_BASE, ring);
120}
121
122static int vhost_kernel_get_vring_base(struct vhost_dev *dev,
123 struct vhost_vring_state *ring)
124{
125 return vhost_kernel_call(dev, VHOST_GET_VRING_BASE, ring);
126}
127
128static int vhost_kernel_set_vring_kick(struct vhost_dev *dev,
129 struct vhost_vring_file *file)
130{
131 return vhost_kernel_call(dev, VHOST_SET_VRING_KICK, file);
132}
133
134static int vhost_kernel_set_vring_call(struct vhost_dev *dev,
135 struct vhost_vring_file *file)
136{
137 return vhost_kernel_call(dev, VHOST_SET_VRING_CALL, file);
138}
139
140static int vhost_kernel_set_vring_busyloop_timeout(struct vhost_dev *dev,
141 struct vhost_vring_state *s)
142{
143 return vhost_kernel_call(dev, VHOST_SET_VRING_BUSYLOOP_TIMEOUT, s);
144}
145
146static int vhost_kernel_set_features(struct vhost_dev *dev,
147 uint64_t features)
148{
149 return vhost_kernel_call(dev, VHOST_SET_FEATURES, &features);
150}
151
152static int vhost_kernel_get_features(struct vhost_dev *dev,
153 uint64_t *features)
154{
155 return vhost_kernel_call(dev, VHOST_GET_FEATURES, features);
156}
157
158static int vhost_kernel_set_owner(struct vhost_dev *dev)
159{
160 return vhost_kernel_call(dev, VHOST_SET_OWNER, NULL);
161}
162
163static int vhost_kernel_reset_device(struct vhost_dev *dev)
164{
165 return vhost_kernel_call(dev, VHOST_RESET_OWNER, NULL);
166}
167
168static int vhost_kernel_get_vq_index(struct vhost_dev *dev, int idx)
169{
170 assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
171
172 return idx - dev->vq_index;
173}
174
175#ifdef CONFIG_VHOST_VSOCK
176static int vhost_kernel_vsock_set_guest_cid(struct vhost_dev *dev,
177 uint64_t guest_cid)
178{
179 return vhost_kernel_call(dev, VHOST_VSOCK_SET_GUEST_CID, &guest_cid);
180}
181
182static int vhost_kernel_vsock_set_running(struct vhost_dev *dev, int start)
183{
184 return vhost_kernel_call(dev, VHOST_VSOCK_SET_RUNNING, &start);
185}
186#endif
187
188static const VhostOps kernel_ops = {
189 .backend_type = VHOST_BACKEND_TYPE_KERNEL,
190 .vhost_backend_init = vhost_kernel_init,
191 .vhost_backend_cleanup = vhost_kernel_cleanup,
192 .vhost_backend_memslots_limit = vhost_kernel_memslots_limit,
193 .vhost_net_set_backend = vhost_kernel_net_set_backend,
194 .vhost_scsi_set_endpoint = vhost_kernel_scsi_set_endpoint,
195 .vhost_scsi_clear_endpoint = vhost_kernel_scsi_clear_endpoint,
196 .vhost_scsi_get_abi_version = vhost_kernel_scsi_get_abi_version,
197 .vhost_set_log_base = vhost_kernel_set_log_base,
198 .vhost_set_mem_table = vhost_kernel_set_mem_table,
199 .vhost_set_vring_addr = vhost_kernel_set_vring_addr,
200 .vhost_set_vring_endian = vhost_kernel_set_vring_endian,
201 .vhost_set_vring_num = vhost_kernel_set_vring_num,
202 .vhost_set_vring_base = vhost_kernel_set_vring_base,
203 .vhost_get_vring_base = vhost_kernel_get_vring_base,
204 .vhost_set_vring_kick = vhost_kernel_set_vring_kick,
205 .vhost_set_vring_call = vhost_kernel_set_vring_call,
206 .vhost_set_vring_busyloop_timeout =
207 vhost_kernel_set_vring_busyloop_timeout,
208 .vhost_set_features = vhost_kernel_set_features,
209 .vhost_get_features = vhost_kernel_get_features,
210 .vhost_set_owner = vhost_kernel_set_owner,
211 .vhost_reset_device = vhost_kernel_reset_device,
212 .vhost_get_vq_index = vhost_kernel_get_vq_index,
213#ifdef CONFIG_VHOST_VSOCK
214 .vhost_vsock_set_guest_cid = vhost_kernel_vsock_set_guest_cid,
215 .vhost_vsock_set_running = vhost_kernel_vsock_set_running,
216#endif
217};
218
219int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type)
220{
221 int r = 0;
222
223 switch (backend_type) {
224 case VHOST_BACKEND_TYPE_KERNEL:
225 dev->vhost_ops = &kernel_ops;
226 break;
227 case VHOST_BACKEND_TYPE_USER:
228 dev->vhost_ops = &user_ops;
229 break;
230 default:
231 error_report("Unknown vhost backend type");
232 r = -1;
233 }
234
235 return r;
236}
237