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"
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
23 #include <linux/vhost.h>
25 #define VHOST_MEMORY_MAX_NREGIONS 8
27 typedef enum VhostUserRequest
{
29 VHOST_USER_GET_FEATURES
= 1,
30 VHOST_USER_SET_FEATURES
= 2,
31 VHOST_USER_SET_OWNER
= 3,
32 VHOST_USER_RESET_OWNER
= 4,
33 VHOST_USER_SET_MEM_TABLE
= 5,
34 VHOST_USER_SET_LOG_BASE
= 6,
35 VHOST_USER_SET_LOG_FD
= 7,
36 VHOST_USER_SET_VRING_NUM
= 8,
37 VHOST_USER_SET_VRING_ADDR
= 9,
38 VHOST_USER_SET_VRING_BASE
= 10,
39 VHOST_USER_GET_VRING_BASE
= 11,
40 VHOST_USER_SET_VRING_KICK
= 12,
41 VHOST_USER_SET_VRING_CALL
= 13,
42 VHOST_USER_SET_VRING_ERR
= 14,
46 typedef struct VhostUserMemoryRegion
{
47 uint64_t guest_phys_addr
;
49 uint64_t userspace_addr
;
50 } VhostUserMemoryRegion
;
52 typedef struct VhostUserMemory
{
55 VhostUserMemoryRegion regions
[VHOST_MEMORY_MAX_NREGIONS
];
58 typedef struct VhostUserMsg
{
59 VhostUserRequest request
;
61 #define VHOST_USER_VERSION_MASK (0x3)
62 #define VHOST_USER_REPLY_MASK (0x1<<2)
64 uint32_t size
; /* the following payload size */
66 #define VHOST_USER_VRING_IDX_MASK (0xff)
67 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8)
69 struct vhost_vring_state state
;
70 struct vhost_vring_addr addr
;
71 VhostUserMemory memory
;
73 } QEMU_PACKED VhostUserMsg
;
75 static VhostUserMsg m
__attribute__ ((unused
));
76 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \
80 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE)
82 /* The version of the protocol we support */
83 #define VHOST_USER_VERSION (0x1)
85 static bool ioeventfd_enabled(void)
87 return kvm_enabled() && kvm_eventfds_enabled();
90 static unsigned long int ioctl_to_vhost_user_request
[VHOST_USER_MAX
] = {
91 -1, /* VHOST_USER_NONE */
92 VHOST_GET_FEATURES
, /* VHOST_USER_GET_FEATURES */
93 VHOST_SET_FEATURES
, /* VHOST_USER_SET_FEATURES */
94 VHOST_SET_OWNER
, /* VHOST_USER_SET_OWNER */
95 VHOST_RESET_OWNER
, /* VHOST_USER_RESET_OWNER */
96 VHOST_SET_MEM_TABLE
, /* VHOST_USER_SET_MEM_TABLE */
97 VHOST_SET_LOG_BASE
, /* VHOST_USER_SET_LOG_BASE */
98 VHOST_SET_LOG_FD
, /* VHOST_USER_SET_LOG_FD */
99 VHOST_SET_VRING_NUM
, /* VHOST_USER_SET_VRING_NUM */
100 VHOST_SET_VRING_ADDR
, /* VHOST_USER_SET_VRING_ADDR */
101 VHOST_SET_VRING_BASE
, /* VHOST_USER_SET_VRING_BASE */
102 VHOST_GET_VRING_BASE
, /* VHOST_USER_GET_VRING_BASE */
103 VHOST_SET_VRING_KICK
, /* VHOST_USER_SET_VRING_KICK */
104 VHOST_SET_VRING_CALL
, /* VHOST_USER_SET_VRING_CALL */
105 VHOST_SET_VRING_ERR
/* VHOST_USER_SET_VRING_ERR */
108 static VhostUserRequest
vhost_user_request_translate(unsigned long int request
)
110 VhostUserRequest idx
;
112 for (idx
= 0; idx
< VHOST_USER_MAX
; idx
++) {
113 if (ioctl_to_vhost_user_request
[idx
] == request
) {
118 return (idx
== VHOST_USER_MAX
) ? VHOST_USER_NONE
: idx
;
121 static int vhost_user_read(struct vhost_dev
*dev
, VhostUserMsg
*msg
)
123 CharDriverState
*chr
= dev
->opaque
;
124 uint8_t *p
= (uint8_t *) msg
;
125 int r
, size
= VHOST_USER_HDR_SIZE
;
127 r
= qemu_chr_fe_read_all(chr
, p
, size
);
129 error_report("Failed to read msg header. Read %d instead of %d.\n", r
,
134 /* validate received flags */
135 if (msg
->flags
!= (VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
)) {
136 error_report("Failed to read msg header."
137 " Flags 0x%x instead of 0x%x.\n", msg
->flags
,
138 VHOST_USER_REPLY_MASK
| VHOST_USER_VERSION
);
142 /* validate message size is sane */
143 if (msg
->size
> VHOST_USER_PAYLOAD_SIZE
) {
144 error_report("Failed to read msg header."
145 " Size %d exceeds the maximum %zu.\n", msg
->size
,
146 VHOST_USER_PAYLOAD_SIZE
);
151 p
+= VHOST_USER_HDR_SIZE
;
153 r
= qemu_chr_fe_read_all(chr
, p
, size
);
155 error_report("Failed to read msg payload."
156 " Read %d instead of %d.\n", r
, msg
->size
);
167 static int vhost_user_write(struct vhost_dev
*dev
, VhostUserMsg
*msg
,
168 int *fds
, int fd_num
)
170 CharDriverState
*chr
= dev
->opaque
;
171 int size
= VHOST_USER_HDR_SIZE
+ msg
->size
;
174 qemu_chr_fe_set_msgfds(chr
, fds
, fd_num
);
177 return qemu_chr_fe_write_all(chr
, (const uint8_t *) msg
, size
) == size
?
181 static int vhost_user_call(struct vhost_dev
*dev
, unsigned long int request
,
185 VhostUserRequest msg_request
;
187 struct vhost_vring_file
*file
= 0;
189 int fds
[VHOST_MEMORY_MAX_NREGIONS
];
192 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
194 msg_request
= vhost_user_request_translate(request
);
195 msg
.request
= msg_request
;
196 msg
.flags
= VHOST_USER_VERSION
;
200 case VHOST_GET_FEATURES
:
204 case VHOST_SET_FEATURES
:
205 case VHOST_SET_LOG_BASE
:
206 msg
.u64
= *((__u64
*) arg
);
207 msg
.size
= sizeof(m
.u64
);
210 case VHOST_SET_OWNER
:
211 case VHOST_RESET_OWNER
:
214 case VHOST_SET_MEM_TABLE
:
215 QTAILQ_FOREACH(block
, &ram_list
.blocks
, next
)
218 msg
.memory
.regions
[fd_num
].userspace_addr
=
219 (uintptr_t) block
->host
;
220 msg
.memory
.regions
[fd_num
].memory_size
= block
->length
;
221 msg
.memory
.regions
[fd_num
].guest_phys_addr
= block
->offset
;
222 fds
[fd_num
++] = block
->fd
;
226 msg
.memory
.nregions
= fd_num
;
229 error_report("Failed initializing vhost-user memory map\n"
230 "consider using -object memory-backend-file share=on\n");
234 msg
.size
= sizeof(m
.memory
.nregions
);
235 msg
.size
+= sizeof(m
.memory
.padding
);
236 msg
.size
+= fd_num
* sizeof(VhostUserMemoryRegion
);
240 case VHOST_SET_LOG_FD
:
241 fds
[fd_num
++] = *((int *) arg
);
244 case VHOST_SET_VRING_NUM
:
245 case VHOST_SET_VRING_BASE
:
246 memcpy(&msg
.state
, arg
, sizeof(struct vhost_vring_state
));
247 msg
.size
= sizeof(m
.state
);
250 case VHOST_GET_VRING_BASE
:
251 memcpy(&msg
.state
, arg
, sizeof(struct vhost_vring_state
));
252 msg
.size
= sizeof(m
.state
);
256 case VHOST_SET_VRING_ADDR
:
257 memcpy(&msg
.addr
, arg
, sizeof(struct vhost_vring_addr
));
258 msg
.size
= sizeof(m
.addr
);
261 case VHOST_SET_VRING_KICK
:
262 case VHOST_SET_VRING_CALL
:
263 case VHOST_SET_VRING_ERR
:
265 msg
.u64
= file
->index
& VHOST_USER_VRING_IDX_MASK
;
266 msg
.size
= sizeof(m
.u64
);
267 if (ioeventfd_enabled() && file
->fd
> 0) {
268 fds
[fd_num
++] = file
->fd
;
270 msg
.u64
|= VHOST_USER_VRING_NOFD_MASK
;
274 error_report("vhost-user trying to send unhandled ioctl\n");
279 if (vhost_user_write(dev
, &msg
, fds
, fd_num
) < 0) {
284 if (vhost_user_read(dev
, &msg
) < 0) {
288 if (msg_request
!= msg
.request
) {
289 error_report("Received unexpected msg type."
290 " Expected %d received %d\n", msg_request
, msg
.request
);
294 switch (msg_request
) {
295 case VHOST_USER_GET_FEATURES
:
296 if (msg
.size
!= sizeof(m
.u64
)) {
297 error_report("Received bad msg size.\n");
300 *((__u64
*) arg
) = msg
.u64
;
302 case VHOST_USER_GET_VRING_BASE
:
303 if (msg
.size
!= sizeof(m
.state
)) {
304 error_report("Received bad msg size.\n");
307 memcpy(arg
, &msg
.state
, sizeof(struct vhost_vring_state
));
310 error_report("Received unexpected msg type.\n");
319 static int vhost_user_init(struct vhost_dev
*dev
, void *opaque
)
321 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
323 dev
->opaque
= opaque
;
328 static int vhost_user_cleanup(struct vhost_dev
*dev
)
330 assert(dev
->vhost_ops
->backend_type
== VHOST_BACKEND_TYPE_USER
);
337 const VhostOps user_ops
= {
338 .backend_type
= VHOST_BACKEND_TYPE_USER
,
339 .vhost_call
= vhost_user_call
,
340 .vhost_backend_init
= vhost_user_init
,
341 .vhost_backend_cleanup
= vhost_user_cleanup