1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * vfio-user client socket messages. 36 */ 37 38 #include "spdk/stdinc.h" 39 #include "spdk/queue.h" 40 #include "spdk/util.h" 41 #include "spdk/log.h" 42 #include "spdk/vfio_user_spec.h" 43 44 #include "vfio_user_internal.h" 45 46 struct vfio_user_request { 47 struct vfio_user_header hdr; 48 #define VFIO_USER_MAX_PAYLOAD_SIZE (4096) 49 uint8_t payload[VFIO_USER_MAX_PAYLOAD_SIZE]; 50 int fds[VFIO_MAXIMUM_SPARSE_MMAP_REGIONS]; 51 int fd_num; 52 }; 53 54 #ifdef DEBUG 55 static const char *vfio_user_message_str[VFIO_USER_MAX] = { 56 [VFIO_USER_VERSION] = "VFIO_USER_VERSION", 57 [VFIO_USER_DMA_MAP] = "VFIO_USER_DMA_MAP", 58 [VFIO_USER_DMA_UNMAP] = "VFIO_USER_DMA_UNMAP", 59 [VFIO_USER_DEVICE_GET_INFO] = "VFIO_USER_DEVICE_GET_INFO", 60 [VFIO_USER_DEVICE_GET_REGION_INFO] = "VFIO_USER_DEVICE_GET_REGION_INFO", 61 [VFIO_USER_DEVICE_GET_IRQ_INFO] = "VFIO_USER_DEVICE_GET_IRQ_INFO", 62 [VFIO_USER_DEVICE_SET_IRQS] = "VFIO_USER_DEVICE_SET_IRQS", 63 [VFIO_USER_REGION_READ] = "VFIO_USER_REGION_READ", 64 [VFIO_USER_REGION_WRITE] = "VFIO_USER_REGION_WRITE", 65 [VFIO_USER_DMA_READ] = "VFIO_USER_DMA_READ", 66 [VFIO_USER_DMA_WRITE] = "VFIO_USER_DMA_WRITE", 67 [VFIO_USER_DEVICE_RESET] = "VFIO_USER_DEVICE_RESET", 68 }; 69 #endif 70 71 static int 72 vfio_user_write(int fd, void *buf, int len, int *fds, int num_fds) 73 { 74 int r; 75 struct msghdr msgh; 76 struct iovec iov; 77 size_t fd_size = num_fds * sizeof(int); 78 char control[CMSG_SPACE(VFIO_MAXIMUM_SPARSE_MMAP_REGIONS * sizeof(int))]; 79 struct cmsghdr *cmsg; 80 81 memset(&msgh, 0, sizeof(msgh)); 82 memset(control, 0, sizeof(control)); 83 84 iov.iov_base = (uint8_t *)buf; 85 iov.iov_len = len; 86 87 msgh.msg_iov = &iov; 88 msgh.msg_iovlen = 1; 89 90 assert(num_fds <= VFIO_MAXIMUM_SPARSE_MMAP_REGIONS); 91 92 if (fds && num_fds) { 93 msgh.msg_control = control; 94 msgh.msg_controllen = CMSG_SPACE(fd_size); 95 cmsg = CMSG_FIRSTHDR(&msgh); 96 assert(cmsg != NULL); 97 cmsg->cmsg_len = CMSG_LEN(fd_size); 98 cmsg->cmsg_level = SOL_SOCKET; 99 cmsg->cmsg_type = SCM_RIGHTS; 100 memcpy(CMSG_DATA(cmsg), fds, fd_size); 101 } else { 102 msgh.msg_control = NULL; 103 msgh.msg_controllen = 0; 104 } 105 106 do { 107 r = sendmsg(fd, &msgh, MSG_NOSIGNAL); 108 } while (r < 0 && errno == EINTR); 109 110 if (r == -1) { 111 return -errno; 112 } 113 114 return 0; 115 } 116 117 static int 118 read_fd_message(int sockfd, char *buf, int buflen, int *fds, int *fd_num) 119 { 120 struct iovec iov; 121 struct msghdr msgh; 122 char control[CMSG_SPACE(VFIO_MAXIMUM_SPARSE_MMAP_REGIONS * sizeof(int))]; 123 struct cmsghdr *cmsg; 124 int got_fds = 0; 125 int ret; 126 127 memset(&msgh, 0, sizeof(msgh)); 128 iov.iov_base = buf; 129 iov.iov_len = buflen; 130 131 msgh.msg_iov = &iov; 132 msgh.msg_iovlen = 1; 133 msgh.msg_control = control; 134 msgh.msg_controllen = sizeof(control); 135 136 ret = recvmsg(sockfd, &msgh, 0); 137 if (ret <= 0) { 138 return ret; 139 } 140 141 if (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { 142 return -ENOTSUP; 143 } 144 145 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; 146 cmsg = CMSG_NXTHDR(&msgh, cmsg)) { 147 if ((cmsg->cmsg_level == SOL_SOCKET) && 148 (cmsg->cmsg_type == SCM_RIGHTS)) { 149 got_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); 150 *fd_num = got_fds; 151 assert(got_fds <= VFIO_MAXIMUM_SPARSE_MMAP_REGIONS); 152 memcpy(fds, CMSG_DATA(cmsg), got_fds * sizeof(int)); 153 break; 154 } 155 } 156 157 return ret; 158 } 159 160 static int 161 vfio_user_read(int fd, struct vfio_user_request *req) 162 { 163 int ret; 164 size_t sz_payload; 165 166 ret = read_fd_message(fd, (char *)req, sizeof(struct vfio_user_header), req->fds, &req->fd_num); 167 if (ret <= 0) { 168 return ret; 169 } 170 171 if (req->hdr.flags.error) { 172 SPDK_ERRLOG("Command %u return failure\n", req->hdr.cmd); 173 errno = req->hdr.error_no; 174 return -EFAULT; 175 } 176 177 if (req->hdr.msg_size > sizeof(struct vfio_user_header)) { 178 sz_payload = req->hdr.msg_size - sizeof(struct vfio_user_header); 179 ret = read(fd, req->payload, sz_payload); 180 if (ret <= 0) { 181 return ret; 182 } 183 } 184 185 return 0; 186 } 187 188 static int 189 vfio_user_dev_send_request(struct vfio_device *dev, enum vfio_user_command command, 190 void *arg, size_t arg_len, size_t buf_len, int *fds, int max_fds) 191 { 192 struct vfio_user_request req = {}; 193 size_t sz_payload; 194 int ret; 195 bool fds_write = false; 196 197 if (arg_len > VFIO_USER_MAX_PAYLOAD_SIZE) { 198 SPDK_ERRLOG("Oversized argument length, command %u\n", command); 199 return -EINVAL; 200 } 201 202 req.hdr.cmd = command; 203 req.hdr.msg_size = sizeof(struct vfio_user_header) + arg_len; 204 memcpy(req.payload, arg, arg_len); 205 206 if (command == VFIO_USER_DMA_MAP || command == VFIO_USER_DMA_UNMAP) { 207 fds_write = true; 208 } 209 210 SPDK_DEBUGLOG(vfio_user, "[I] Command %s, msg size %u, fds %p, max_fds %d\n", 211 vfio_user_message_str[command], req.hdr.msg_size, fds, max_fds); 212 213 if (fds_write && fds) { 214 ret = vfio_user_write(dev->fd, (void *)&req, req.hdr.msg_size, fds, max_fds); 215 } else { 216 ret = vfio_user_write(dev->fd, (void *)&req, req.hdr.msg_size, NULL, 0); 217 } 218 219 if (ret) { 220 return ret; 221 } 222 223 /* a reply is mandatory */ 224 memset(&req, 0, sizeof(req)); 225 ret = vfio_user_read(dev->fd, &req); 226 if (ret) { 227 return ret; 228 } 229 230 SPDK_DEBUGLOG(vfio_user, "[I] Command %s response, msg size %u\n", 231 vfio_user_message_str[req.hdr.cmd], req.hdr.msg_size); 232 233 assert(req.hdr.flags.type == VFIO_USER_MESSAGE_REPLY); 234 sz_payload = req.hdr.msg_size - sizeof(struct vfio_user_header); 235 if (!sz_payload) { 236 return 0; 237 } 238 239 if (!fds_write) { 240 if (sz_payload > buf_len) { 241 SPDK_ERRLOG("Payload size error sz %zd, buf_len %zd\n", sz_payload, buf_len); 242 return -EIO; 243 } 244 memcpy(arg, req.payload, sz_payload); 245 /* VFIO_USER_DEVICE_GET_REGION_INFO may contains BAR fd */ 246 if (fds && req.fd_num) { 247 assert(req.fd_num < max_fds); 248 memcpy(fds, req.fds, sizeof(int) * req.fd_num); 249 } 250 } 251 252 return 0; 253 } 254 255 static int 256 vfio_user_check_version(struct vfio_device *dev) 257 { 258 int ret; 259 struct vfio_user_request req = {}; 260 struct vfio_user_version *version = (struct vfio_user_version *)req.payload; 261 262 version->major = VFIO_USER_MAJOR_VER; 263 version->minor = VFIO_USER_MINOR_VER; 264 265 ret = vfio_user_dev_send_request(dev, VFIO_USER_VERSION, req.payload, 266 sizeof(struct vfio_user_version), sizeof(req.payload), NULL, 0); 267 if (ret < 0) { 268 return ret; 269 } 270 271 SPDK_DEBUGLOG(vfio_user, "%s Negotiate version %u.%u\n", vfio_user_message_str[VFIO_USER_VERSION], 272 version->major, version->minor); 273 274 return 0; 275 } 276 277 int 278 vfio_user_get_dev_region_info(struct vfio_device *dev, struct vfio_region_info *region_info, 279 size_t buf_len, int *fds, int num_fds) 280 { 281 assert(buf_len > sizeof(struct vfio_region_info)); 282 region_info->argsz = buf_len - sizeof(struct vfio_region_info); 283 return vfio_user_dev_send_request(dev, VFIO_USER_DEVICE_GET_REGION_INFO, 284 region_info, region_info->argsz, buf_len, fds, num_fds); 285 } 286 287 int 288 vfio_user_get_dev_info(struct vfio_device *dev, struct vfio_user_device_info *dev_info, 289 size_t buf_len) 290 { 291 dev_info->argsz = sizeof(struct vfio_user_device_info); 292 return vfio_user_dev_send_request(dev, VFIO_USER_DEVICE_GET_INFO, 293 dev_info, dev_info->argsz, buf_len, NULL, 0); 294 } 295 296 int 297 vfio_user_dev_dma_map_unmap(struct vfio_device *dev, struct vfio_memory_region *mr, bool map) 298 { 299 struct vfio_user_dma_map dma_map = { 0 }; 300 struct vfio_user_dma_unmap dma_unmap = { 0 }; 301 302 if (map) { 303 dma_map.argsz = sizeof(struct vfio_user_dma_map); 304 dma_map.addr = mr->iova; 305 dma_map.size = mr->size; 306 dma_map.offset = mr->offset; 307 dma_map.flags = VFIO_USER_F_DMA_REGION_READ | VFIO_USER_F_DMA_REGION_WRITE; 308 309 return vfio_user_dev_send_request(dev, VFIO_USER_DMA_MAP, 310 &dma_map, sizeof(dma_map), sizeof(dma_map), &mr->fd, 1); 311 } else { 312 dma_unmap.argsz = sizeof(struct vfio_user_dma_unmap); 313 dma_unmap.addr = mr->iova; 314 dma_unmap.size = mr->size; 315 return vfio_user_dev_send_request(dev, VFIO_USER_DMA_UNMAP, 316 &dma_unmap, sizeof(dma_unmap), sizeof(dma_unmap), &mr->fd, 1); 317 } 318 } 319 320 int 321 vfio_user_dev_mmio_access(struct vfio_device *dev, uint32_t index, uint64_t offset, 322 size_t len, void *buf, bool is_write) 323 { 324 struct vfio_user_region_access *access; 325 size_t arg_len; 326 int ret; 327 328 arg_len = sizeof(*access) + len; 329 access = calloc(1, arg_len); 330 if (!access) { 331 return -ENOMEM; 332 } 333 334 access->offset = offset; 335 access->region = index; 336 access->count = len; 337 if (is_write) { 338 memcpy(access->data, buf, len); 339 ret = vfio_user_dev_send_request(dev, VFIO_USER_REGION_WRITE, 340 access, arg_len, arg_len, NULL, 0); 341 } else { 342 ret = vfio_user_dev_send_request(dev, VFIO_USER_REGION_READ, 343 access, sizeof(*access), arg_len, NULL, 0); 344 } 345 346 if (ret) { 347 free(access); 348 return ret; 349 } 350 351 if (!is_write) { 352 memcpy(buf, (void *)access->data, len); 353 } 354 355 free(access); 356 return 0; 357 } 358 359 int 360 vfio_user_dev_setup(struct vfio_device *dev) 361 { 362 int fd; 363 int flag; 364 struct sockaddr_un un; 365 ssize_t rc; 366 367 fd = socket(AF_UNIX, SOCK_STREAM, 0); 368 if (fd < 0) { 369 SPDK_ERRLOG("socket() error\n"); 370 return -errno; 371 } 372 373 flag = fcntl(fd, F_GETFD); 374 if (fcntl(fd, F_SETFD, flag | FD_CLOEXEC) < 0) { 375 SPDK_ERRLOG("fcntl failed\n"); 376 } 377 378 memset(&un, 0, sizeof(un)); 379 un.sun_family = AF_UNIX; 380 rc = snprintf(un.sun_path, sizeof(un.sun_path), "%s", dev->path); 381 if (rc < 0 || (size_t)rc >= sizeof(un.sun_path)) { 382 SPDK_ERRLOG("socket path too long\n"); 383 close(fd); 384 if (rc < 0) { 385 return -errno; 386 } else { 387 return -EINVAL; 388 } 389 } 390 if (connect(fd, (struct sockaddr *)&un, sizeof(un)) < 0) { 391 SPDK_ERRLOG("connect error\n"); 392 close(fd); 393 return -errno; 394 } 395 396 dev->fd = fd; 397 398 if (vfio_user_check_version(dev)) { 399 SPDK_ERRLOG("Check VFIO_USER_VERSION message failed\n"); 400 close(fd); 401 return -EFAULT; 402 } 403 404 return 0; 405 } 406 407 SPDK_LOG_REGISTER_COMPONENT(vfio_user) 408