1 /* 2 * vhost-user 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 "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 18 #include <fcntl.h> 19 #include <unistd.h> 20 #include <sys/ioctl.h> 21 #include <sys/socket.h> 22 #include <sys/un.h> 23 #include <linux/vhost.h> 24 25 #define VHOST_MEMORY_MAX_NREGIONS 8 26 27 typedef enum VhostUserRequest { 28 VHOST_USER_NONE = 0, 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, 43 VHOST_USER_MAX 44 } VhostUserRequest; 45 46 typedef struct VhostUserMemoryRegion { 47 uint64_t guest_phys_addr; 48 uint64_t memory_size; 49 uint64_t userspace_addr; 50 } VhostUserMemoryRegion; 51 52 typedef struct VhostUserMemory { 53 uint32_t nregions; 54 uint32_t padding; 55 VhostUserMemoryRegion regions[VHOST_MEMORY_MAX_NREGIONS]; 56 } VhostUserMemory; 57 58 typedef struct VhostUserMsg { 59 VhostUserRequest request; 60 61 #define VHOST_USER_VERSION_MASK (0x3) 62 #define VHOST_USER_REPLY_MASK (0x1<<2) 63 uint32_t flags; 64 uint32_t size; /* the following payload size */ 65 union { 66 #define VHOST_USER_VRING_IDX_MASK (0xff) 67 #define VHOST_USER_VRING_NOFD_MASK (0x1<<8) 68 uint64_t u64; 69 struct vhost_vring_state state; 70 struct vhost_vring_addr addr; 71 VhostUserMemory memory; 72 }; 73 } QEMU_PACKED VhostUserMsg; 74 75 static VhostUserMsg m __attribute__ ((unused)); 76 #define VHOST_USER_HDR_SIZE (sizeof(m.request) \ 77 + sizeof(m.flags) \ 78 + sizeof(m.size)) 79 80 #define VHOST_USER_PAYLOAD_SIZE (sizeof(m) - VHOST_USER_HDR_SIZE) 81 82 /* The version of the protocol we support */ 83 #define VHOST_USER_VERSION (0x1) 84 85 static bool ioeventfd_enabled(void) 86 { 87 return kvm_enabled() && kvm_eventfds_enabled(); 88 } 89 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 */ 106 }; 107 108 static VhostUserRequest vhost_user_request_translate(unsigned long int request) 109 { 110 VhostUserRequest idx; 111 112 for (idx = 0; idx < VHOST_USER_MAX; idx++) { 113 if (ioctl_to_vhost_user_request[idx] == request) { 114 break; 115 } 116 } 117 118 return (idx == VHOST_USER_MAX) ? VHOST_USER_NONE : idx; 119 } 120 121 static int vhost_user_read(struct vhost_dev *dev, VhostUserMsg *msg) 122 { 123 CharDriverState *chr = dev->opaque; 124 uint8_t *p = (uint8_t *) msg; 125 int r, size = VHOST_USER_HDR_SIZE; 126 127 r = qemu_chr_fe_read_all(chr, p, size); 128 if (r != size) { 129 error_report("Failed to read msg header. Read %d instead of %d.\n", r, 130 size); 131 goto fail; 132 } 133 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); 139 goto fail; 140 } 141 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); 147 goto fail; 148 } 149 150 if (msg->size) { 151 p += VHOST_USER_HDR_SIZE; 152 size = msg->size; 153 r = qemu_chr_fe_read_all(chr, p, size); 154 if (r != size) { 155 error_report("Failed to read msg payload." 156 " Read %d instead of %d.\n", r, msg->size); 157 goto fail; 158 } 159 } 160 161 return 0; 162 163 fail: 164 return -1; 165 } 166 167 static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg, 168 int *fds, int fd_num) 169 { 170 CharDriverState *chr = dev->opaque; 171 int size = VHOST_USER_HDR_SIZE + msg->size; 172 173 if (fd_num) { 174 qemu_chr_fe_set_msgfds(chr, fds, fd_num); 175 } 176 177 return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ? 178 0 : -1; 179 } 180 181 static int vhost_user_call(struct vhost_dev *dev, unsigned long int request, 182 void *arg) 183 { 184 VhostUserMsg msg; 185 VhostUserRequest msg_request; 186 RAMBlock *block = 0; 187 struct vhost_vring_file *file = 0; 188 int need_reply = 0; 189 int fds[VHOST_MEMORY_MAX_NREGIONS]; 190 size_t fd_num = 0; 191 192 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 193 194 msg_request = vhost_user_request_translate(request); 195 msg.request = msg_request; 196 msg.flags = VHOST_USER_VERSION; 197 msg.size = 0; 198 199 switch (request) { 200 case VHOST_GET_FEATURES: 201 need_reply = 1; 202 break; 203 204 case VHOST_SET_FEATURES: 205 case VHOST_SET_LOG_BASE: 206 msg.u64 = *((__u64 *) arg); 207 msg.size = sizeof(m.u64); 208 break; 209 210 case VHOST_SET_OWNER: 211 case VHOST_RESET_OWNER: 212 break; 213 214 case VHOST_SET_MEM_TABLE: 215 QTAILQ_FOREACH(block, &ram_list.blocks, next) 216 { 217 if (block->fd > 0) { 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; 223 } 224 } 225 226 msg.memory.nregions = fd_num; 227 228 if (!fd_num) { 229 error_report("Failed initializing vhost-user memory map\n" 230 "consider using -object memory-backend-file share=on\n"); 231 return -1; 232 } 233 234 msg.size = sizeof(m.memory.nregions); 235 msg.size += sizeof(m.memory.padding); 236 msg.size += fd_num * sizeof(VhostUserMemoryRegion); 237 238 break; 239 240 case VHOST_SET_LOG_FD: 241 fds[fd_num++] = *((int *) arg); 242 break; 243 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); 248 break; 249 250 case VHOST_GET_VRING_BASE: 251 memcpy(&msg.state, arg, sizeof(struct vhost_vring_state)); 252 msg.size = sizeof(m.state); 253 need_reply = 1; 254 break; 255 256 case VHOST_SET_VRING_ADDR: 257 memcpy(&msg.addr, arg, sizeof(struct vhost_vring_addr)); 258 msg.size = sizeof(m.addr); 259 break; 260 261 case VHOST_SET_VRING_KICK: 262 case VHOST_SET_VRING_CALL: 263 case VHOST_SET_VRING_ERR: 264 file = arg; 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; 269 } else { 270 msg.u64 |= VHOST_USER_VRING_NOFD_MASK; 271 } 272 break; 273 default: 274 error_report("vhost-user trying to send unhandled ioctl\n"); 275 return -1; 276 break; 277 } 278 279 if (vhost_user_write(dev, &msg, fds, fd_num) < 0) { 280 return 0; 281 } 282 283 if (need_reply) { 284 if (vhost_user_read(dev, &msg) < 0) { 285 return 0; 286 } 287 288 if (msg_request != msg.request) { 289 error_report("Received unexpected msg type." 290 " Expected %d received %d\n", msg_request, msg.request); 291 return -1; 292 } 293 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"); 298 return -1; 299 } 300 *((__u64 *) arg) = msg.u64; 301 break; 302 case VHOST_USER_GET_VRING_BASE: 303 if (msg.size != sizeof(m.state)) { 304 error_report("Received bad msg size.\n"); 305 return -1; 306 } 307 memcpy(arg, &msg.state, sizeof(struct vhost_vring_state)); 308 break; 309 default: 310 error_report("Received unexpected msg type.\n"); 311 return -1; 312 break; 313 } 314 } 315 316 return 0; 317 } 318 319 static int vhost_user_init(struct vhost_dev *dev, void *opaque) 320 { 321 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 322 323 dev->opaque = opaque; 324 325 return 0; 326 } 327 328 static int vhost_user_cleanup(struct vhost_dev *dev) 329 { 330 assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER); 331 332 dev->opaque = 0; 333 334 return 0; 335 } 336 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 342 }; 343