4 * Copyright (c) 2013 Virtual Open Systems Sarl.
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.
11 #include "hw/virtio/vhost.h"
12 #include "hw/virtio/vhost-backend.h"
13 #include "sysemu/char.h"
14 #include "sysemu/kvm.h"
15 #include "qemu/error-report.h"
16 #include "qemu/sockets.h"
17 #include "exec/ram_addr.h"
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
24 #include <linux/vhost.h>
26 #define VHOST_MEMORY_MAX_NREGIONS 8
27 #define VHOST_USER_F_PROTOCOL_FEATURES 30
28 #define VHOST_USER_PROTOCOL_FEATURE_MASK 0x0ULL
30 typedef enum VhostUserRequest
{
32 VHOST_USER_GET_FEATURES
= 1,
33 VHOST_USER_SET_FEATURES
= 2,
34 VHOST_USER_SET_OWNER
= 3,
35 VHOST_USER_RESET_OWNER
= 4,
36 VHOST_USER_SET_MEM_TABLE
= 5,
37 VHOST_USER_SET_LOG_BASE
= 6,
38 VHOST_USER_SET_LOG_FD
= 7,
39 VHOST_USER_SET_VRING_NUM
= 8,
40 VHOST_USER_SET_VRING_ADDR
= 9,
41 VHOST_USER_SET_VRING_BASE
= 10,
42 VHOST_USER_GET_VRING_BASE
= 11,
43 VHOST_USER_SET_VRING_KICK
= 12,
44 VHOST_USER_SET_VRING_CALL
= 13,
45 VHOST_USER_SET_VRING_ERR
= 14,
46 VHOST_USER_GET_PROTOCOL_FEATURES
= 15,
47 VHOST_USER_SET_PROTOCOL_FEATURES
= 16,
51 typedef struct VhostUserMemoryRegion
{
52 uint64_t guest_phys_addr
;
54 uint64_t userspace_addr
;
56 } VhostUserMemoryRegion
;
58 typedef struct VhostUserMemory
{
61 VhostUserMemoryRegion regions
[VHOST_MEMORY_MAX_NREGIONS
];
64 typedef struct VhostUserMsg
{
65 VhostUserRequest request
;
67 #define VHOST_USER_VERSION_MASK (0x3)
68 #define VHOST_USER_REPLY_MASK (0x1<<2)
70 uint32_t size
; /* the following payload size */
72 #define VHOST_USER_VRING_IDX_MASK (0xff)
73 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
75 struct vhost_vring_state state
;
76 struct vhost_vring_addr addr
;
77 VhostUserMemory memory
;
79 } QEMU_PACKED VhostUserMsg
;
81 static VhostUserMsg m
__attribute__ ((unused
));
82 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
86 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
88 /* The version of the protocol we support */
89 #define VHOST_USER_VERSION (0x1)
91 static bool ioeventfd_enabled(void)
93 return kvm_enabled() && kvm_eventfds_enabled();
96 static unsigned long int ioctl_to_vhost_user_request
[VHOST_USER_MAX
] = {
97 -1, /* VHOST_USER_NONE */
98 VHOST_GET_FEATURES
, /* VHOST_USER_GET_FEATURES */
99 VHOST_SET_FEATURES
, /* VHOST_USER_SET_FEATURES */
100 VHOST_SET_OWNER
, /* VHOST_USER_SET_OWNER */
101 VHOST_RESET_OWNER
, /* VHOST_USER_RESET_OWNER */
102 VHOST_SET_MEM_TABLE
, /* VHOST_USER_SET_MEM_TABLE */
103 VHOST_SET_LOG_BASE
, /* VHOST_USER_SET_LOG_BASE */
104 VHOST_SET_LOG_FD
, /* VHOST_USER_SET_LOG_FD */
105 VHOST_SET_VRING_NUM
, /* VHOST_USER_SET_VRING_NUM */
106 VHOST_SET_VRING_ADDR
, /* VHOST_USER_SET_VRING_ADDR */
107 VHOST_SET_VRING_BASE
, /* VHOST_USER_SET_VRING_BASE */
108 VHOST_GET_VRING_BASE
, /* VHOST_USER_GET_VRING_BASE */
109 VHOST_SET_VRING_KICK
, /* VHOST_USER_SET_VRING_KICK */
110 VHOST_SET_VRING_CALL
, /* VHOST_USER_SET_VRING_CALL */
111 VHOST_SET_VRING_ERR
/* VHOST_USER_SET_VRING_ERR */
114 static VhostUserRequest
vhost_user_request_translate(unsigned long int request
)
116 VhostUserRequest idx
;
118 for (idx
= 0; idx
< VHOST_USER_MAX
; idx
++) {
119 if (ioctl_to_vhost_user_request
[idx
] == request
) {
124 return (idx
== VHOST_USER_MAX
) ? VHOST_USER_NONE
: idx
;
127 static int vhost_user_read(struct vhost_dev
*dev
, VhostUserMsg
*msg
)
129 CharDriverState
*chr
= dev
->opaque
;
130 uint8_t *p
= (uint8_t *) msg
;
131 int r
, size
= VHOST_USER_HDR_SIZE
;
133 r
= qemu_chr_fe_read_all(chr
, p
, size
);
135 error_report("Failed to read msg header. Read %d instead of %d.", r
,
140 /* validate received flags */
141 if (msg
->flags
!= (VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
)) {
142 error_report("Failed to read msg header."
143 " Flags 0x%x instead of 0x%x.", msg
->flags
,
144 VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
);
148 /* validate message size is sane */
149 if (msg
->size
> VHOST_USER_PAYLOAD_SIZE
) {
150 error_report("Failed to read msg header."
151 " Size %d exceeds the maximum %zu.", msg
->size
,
152 VHOST_USER_PAYLOAD_SIZE
);
157 p
+= VHOST_USER_HDR_SIZE
;
159 r
= qemu_chr_fe_read_all(chr
, p
, size
);
161 error_report("Failed to read msg payload."
162 " Read %d instead of %d.", r
, msg
->size
);
173 static int vhost_user_write(struct vhost_dev
*dev
, VhostUserMsg
*msg
,
174 int *fds
, int fd_num
)
176 CharDriverState
*chr
= dev
->opaque
;
177 int size
= VHOST_USER_HDR_SIZE
+ msg
->size
;
180 qemu_chr_fe_set_msgfds(chr
, fds
, fd_num
);
183 return qemu_chr_fe_write_all(chr
, (const uint8_t *) msg
, size
) == size
?
187 static int vhost_user_call(struct vhost_dev
*dev
, unsigned long int request
,
191 VhostUserRequest msg_request
;
192 struct vhost_vring_file
*file
= 0;
194 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
198 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
200 /* only translate vhost ioctl requests */
201 if (request
> VHOST_USER_MAX
) {
202 msg_request
= vhost_user_request_translate(request
);
204 msg_request
= request
;
207 msg
.request
= msg_request
;
208 msg
.flags
= VHOST_USER_VERSION
;
211 switch (msg_request
) {
212 case VHOST_USER_GET_FEATURES
:
213 case VHOST_USER_GET_PROTOCOL_FEATURES
:
217 case VHOST_USER_SET_FEATURES
:
218 case VHOST_USER_SET_LOG_BASE
:
219 case VHOST_USER_SET_PROTOCOL_FEATURES
:
220 msg
.u64
= *((__u64
*) arg
);
221 msg
.size
= sizeof(m
.u64
);
224 case VHOST_USER_SET_OWNER
:
225 case VHOST_USER_RESET_OWNER
:
228 case VHOST_USER_SET_MEM_TABLE
:
229 for (i
= 0; i
< dev
->mem
->nregions
; ++i
) {
230 struct vhost_memory_region
*reg
= dev
->mem
->regions
+ i
;
233 assert((uintptr_t)reg
->userspace_addr
== reg
->userspace_addr
);
234 qemu_ram_addr_from_host((void *)(uintptr_t)reg
->userspace_addr
, &ram_addr
);
235 fd
= qemu_get_ram_fd(ram_addr
);
237 msg
.memory
.regions
[fd_num
].userspace_addr
= reg
->userspace_addr
;
238 msg
.memory
.regions
[fd_num
].memory_size
= reg
->memory_size
;
239 msg
.memory
.regions
[fd_num
].guest_phys_addr
= reg
->guest_phys_addr
;
240 msg
.memory
.regions
[fd_num
].mmap_offset
= reg
->userspace_addr
-
241 (uintptr_t) qemu_get_ram_block_host_ptr(ram_addr
);
242 assert(fd_num
< VHOST_MEMORY_MAX_NREGIONS
);
247 msg
.memory
.nregions
= fd_num
;
250 error_report("Failed initializing vhost-user memory map, "
251 "consider using -object memory-backend-file share=on");
255 msg
.size
= sizeof(m
.memory
.nregions
);
256 msg
.size
+= sizeof(m
.memory
.padding
);
257 msg
.size
+= fd_num
* sizeof(VhostUserMemoryRegion
);
261 case VHOST_USER_SET_LOG_FD
:
262 fds
[fd_num
++] = *((int *) arg
);
265 case VHOST_USER_SET_VRING_NUM
:
266 case VHOST_USER_SET_VRING_BASE
:
267 memcpy(&msg
.state
, arg
, sizeof(struct vhost_vring_state
));
268 msg
.size
= sizeof(m
.state
);
271 case VHOST_USER_GET_VRING_BASE
:
272 memcpy(&msg
.state
, arg
, sizeof(struct vhost_vring_state
));
273 msg
.size
= sizeof(m
.state
);
277 case VHOST_USER_SET_VRING_ADDR
:
278 memcpy(&msg
.addr
, arg
, sizeof(struct vhost_vring_addr
));
279 msg
.size
= sizeof(m
.addr
);
282 case VHOST_USER_SET_VRING_KICK
:
283 case VHOST_USER_SET_VRING_CALL
:
284 case VHOST_USER_SET_VRING_ERR
:
286 msg
.u64
= file
->index
& VHOST_USER_VRING_IDX_MASK
;
287 msg
.size
= sizeof(m
.u64
);
288 if (ioeventfd_enabled() && file
->fd
> 0) {
289 fds
[fd_num
++] = file
->fd
;
291 msg
.u64
|= VHOST_USER_VRING_NOFD_MASK
;
295 error_report("vhost-user trying to send unhandled ioctl");
300 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
305 if (vhost_user_read(dev
, &msg
) < 0) {
309 if (msg_request
!= msg
.request
) {
310 error_report("Received unexpected msg type."
311 " Expected %d received %d", msg_request
, msg
.request
);
315 switch (msg_request
) {
316 case VHOST_USER_GET_FEATURES
:
317 case VHOST_USER_GET_PROTOCOL_FEATURES
:
318 if (msg
.size
!= sizeof(m
.u64
)) {
319 error_report("Received bad msg size.");
322 *((__u64
*) arg
) = msg
.u64
;
324 case VHOST_USER_GET_VRING_BASE
:
325 if (msg
.size
!= sizeof(m
.state
)) {
326 error_report("Received bad msg size.");
329 memcpy(arg
, &msg
.state
, sizeof(struct vhost_vring_state
));
332 error_report("Received unexpected msg type.");
341 static int vhost_user_init(struct vhost_dev
*dev
, void *opaque
)
343 unsigned long long features
;
346 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
348 dev
->opaque
= opaque
;
350 err
= vhost_user_call(dev
, VHOST_USER_GET_FEATURES
, &features
);
355 if (virtio_has_feature(features
, VHOST_USER_F_PROTOCOL_FEATURES
)) {
356 dev
->backend_features
|= 1ULL << VHOST_USER_F_PROTOCOL_FEATURES
;
358 err
= vhost_user_call(dev
, VHOST_USER_GET_PROTOCOL_FEATURES
, &features
);
363 dev
->protocol_features
= features
& VHOST_USER_PROTOCOL_FEATURE_MASK
;
364 err
= vhost_user_call(dev
, VHOST_USER_SET_PROTOCOL_FEATURES
,
365 &dev
->protocol_features
);
374 static int vhost_user_cleanup(struct vhost_dev
*dev
)
376 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
383 const VhostOps user_ops
= {
384 .backend_type
= VHOST_BACKEND_TYPE_USER
,
385 .vhost_call
= vhost_user_call
,
386 .vhost_backend_init
= vhost_user_init
,
387 .vhost_backend_cleanup
= vhost_user_cleanup