1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 /* 7 * vfio-user client socket messages. 8 */ 9 10 #include "spdk/stdinc.h" 11 #include "spdk/queue.h" 12 #include "spdk/util.h" 13 #include "spdk/log.h" 14 #include "spdk/vfio_user_spec.h" 15 16 #include "vfio_user_internal.h" 17 18 struct vfio_user_request { 19 struct vfio_user_header hdr; 20 #define VFIO_USER_MAX_PAYLOAD_SIZE (4096) 21 uint8_t payload[VFIO_USER_MAX_PAYLOAD_SIZE]; 22 int fds[VFIO_MAXIMUM_SPARSE_MMAP_REGIONS]; 23 int fd_num; 24 }; 25 26 #ifdef DEBUG 27 static const char *vfio_user_message_str[VFIO_USER_MAX] = { 28 [VFIO_USER_VERSION] = "VFIO_USER_VERSION", 29 [VFIO_USER_DMA_MAP] = "VFIO_USER_DMA_MAP", 30 [VFIO_USER_DMA_UNMAP] = "VFIO_USER_DMA_UNMAP", 31 [VFIO_USER_DEVICE_GET_INFO] = "VFIO_USER_DEVICE_GET_INFO", 32 [VFIO_USER_DEVICE_GET_REGION_INFO] = "VFIO_USER_DEVICE_GET_REGION_INFO", 33 [VFIO_USER_DEVICE_GET_IRQ_INFO] = "VFIO_USER_DEVICE_GET_IRQ_INFO", 34 [VFIO_USER_DEVICE_SET_IRQS] = "VFIO_USER_DEVICE_SET_IRQS", 35 [VFIO_USER_REGION_READ] = "VFIO_USER_REGION_READ", 36 [VFIO_USER_REGION_WRITE] = "VFIO_USER_REGION_WRITE", 37 [VFIO_USER_DMA_READ] = "VFIO_USER_DMA_READ", 38 [VFIO_USER_DMA_WRITE] = "VFIO_USER_DMA_WRITE", 39 [VFIO_USER_DEVICE_RESET] = "VFIO_USER_DEVICE_RESET", 40 }; 41 #endif 42 43 static int 44 vfio_user_write(int fd, void *buf, int len, int *fds, int num_fds) 45 { 46 int r; 47 struct msghdr msgh; 48 struct iovec iov; 49 size_t fd_size = num_fds * sizeof(int); 50 char control[CMSG_SPACE(VFIO_MAXIMUM_SPARSE_MMAP_REGIONS * sizeof(int))]; 51 struct cmsghdr *cmsg; 52 53 memset(&msgh, 0, sizeof(msgh)); 54 memset(control, 0, sizeof(control)); 55 56 iov.iov_base = (uint8_t *)buf; 57 iov.iov_len = len; 58 59 msgh.msg_iov = &iov; 60 msgh.msg_iovlen = 1; 61 62 assert(num_fds <= VFIO_MAXIMUM_SPARSE_MMAP_REGIONS); 63 64 if (fds && num_fds) { 65 msgh.msg_control = control; 66 msgh.msg_controllen = CMSG_SPACE(fd_size); 67 cmsg = CMSG_FIRSTHDR(&msgh); 68 assert(cmsg != NULL); 69 cmsg->cmsg_len = CMSG_LEN(fd_size); 70 cmsg->cmsg_level = SOL_SOCKET; 71 cmsg->cmsg_type = SCM_RIGHTS; 72 memcpy(CMSG_DATA(cmsg), fds, fd_size); 73 } else { 74 msgh.msg_control = NULL; 75 msgh.msg_controllen = 0; 76 } 77 78 do { 79 r = sendmsg(fd, &msgh, MSG_NOSIGNAL); 80 } while (r < 0 && errno == EINTR); 81 82 if (r == -1) { 83 return -errno; 84 } 85 86 return 0; 87 } 88 89 static int 90 read_fd_message(int sockfd, char *buf, int buflen, int *fds, int *fd_num) 91 { 92 struct iovec iov; 93 struct msghdr msgh; 94 char control[CMSG_SPACE(VFIO_MAXIMUM_SPARSE_MMAP_REGIONS * sizeof(int))]; 95 struct cmsghdr *cmsg; 96 int got_fds = 0; 97 int ret; 98 99 memset(&msgh, 0, sizeof(msgh)); 100 iov.iov_base = buf; 101 iov.iov_len = buflen; 102 103 msgh.msg_iov = &iov; 104 msgh.msg_iovlen = 1; 105 msgh.msg_control = control; 106 msgh.msg_controllen = sizeof(control); 107 108 ret = recvmsg(sockfd, &msgh, 0); 109 if (ret <= 0) { 110 return ret; 111 } 112 113 if (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) { 114 return -ENOTSUP; 115 } 116 117 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; 118 cmsg = CMSG_NXTHDR(&msgh, cmsg)) { 119 if ((cmsg->cmsg_level == SOL_SOCKET) && 120 (cmsg->cmsg_type == SCM_RIGHTS)) { 121 got_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); 122 *fd_num = got_fds; 123 assert(got_fds <= VFIO_MAXIMUM_SPARSE_MMAP_REGIONS); 124 memcpy(fds, CMSG_DATA(cmsg), got_fds * sizeof(int)); 125 break; 126 } 127 } 128 129 return ret; 130 } 131 132 static int 133 vfio_user_read(int fd, struct vfio_user_request *req) 134 { 135 int ret; 136 size_t sz_payload; 137 138 ret = read_fd_message(fd, (char *)req, sizeof(struct vfio_user_header), req->fds, &req->fd_num); 139 if (ret <= 0) { 140 return ret; 141 } 142 143 if (req->hdr.flags.error) { 144 SPDK_ERRLOG("Command %u return failure\n", req->hdr.cmd); 145 errno = req->hdr.error_no; 146 return -EFAULT; 147 } 148 149 if (req->hdr.msg_size > sizeof(struct vfio_user_header)) { 150 sz_payload = req->hdr.msg_size - sizeof(struct vfio_user_header); 151 ret = read(fd, req->payload, sz_payload); 152 if (ret <= 0) { 153 return ret; 154 } 155 } 156 157 return 0; 158 } 159 160 int 161 vfio_user_dev_send_request(struct vfio_device *dev, enum vfio_user_command command, 162 void *arg, size_t arg_len, size_t buf_len, int *fds, int max_fds) 163 { 164 struct vfio_user_request req = {}; 165 size_t sz_payload; 166 int ret; 167 bool fds_write = false; 168 169 if (arg_len > VFIO_USER_MAX_PAYLOAD_SIZE) { 170 SPDK_ERRLOG("Oversized argument length, command %u\n", command); 171 return -EINVAL; 172 } 173 174 req.hdr.cmd = command; 175 req.hdr.msg_size = sizeof(struct vfio_user_header) + arg_len; 176 memcpy(req.payload, arg, arg_len); 177 178 if (command == VFIO_USER_DMA_MAP || command == VFIO_USER_DMA_UNMAP) { 179 fds_write = true; 180 } 181 182 SPDK_DEBUGLOG(vfio_user, "[I] Command %s, msg size %u, fds %p, max_fds %d\n", 183 vfio_user_message_str[command], req.hdr.msg_size, fds, max_fds); 184 185 if (fds_write && fds) { 186 ret = vfio_user_write(dev->fd, (void *)&req, req.hdr.msg_size, fds, max_fds); 187 } else { 188 ret = vfio_user_write(dev->fd, (void *)&req, req.hdr.msg_size, NULL, 0); 189 } 190 191 if (ret) { 192 return ret; 193 } 194 195 /* a reply is mandatory */ 196 memset(&req, 0, sizeof(req)); 197 ret = vfio_user_read(dev->fd, &req); 198 if (ret) { 199 return ret; 200 } 201 202 SPDK_DEBUGLOG(vfio_user, "[I] Command %s response, msg size %u\n", 203 vfio_user_message_str[req.hdr.cmd], req.hdr.msg_size); 204 205 assert(req.hdr.flags.type == VFIO_USER_MESSAGE_REPLY); 206 sz_payload = req.hdr.msg_size - sizeof(struct vfio_user_header); 207 if (!sz_payload) { 208 return 0; 209 } 210 211 if (!fds_write) { 212 if (sz_payload > buf_len) { 213 SPDK_ERRLOG("Payload size error sz %zd, buf_len %zd\n", sz_payload, buf_len); 214 return -EIO; 215 } 216 memcpy(arg, req.payload, sz_payload); 217 /* VFIO_USER_DEVICE_GET_REGION_INFO may contains BAR fd */ 218 if (fds && req.fd_num) { 219 assert(req.fd_num < max_fds); 220 memcpy(fds, req.fds, sizeof(int) * req.fd_num); 221 } 222 } 223 224 return 0; 225 } 226 227 static int 228 vfio_user_check_version(struct vfio_device *dev) 229 { 230 int ret; 231 struct vfio_user_request req = {}; 232 struct vfio_user_version *version = (struct vfio_user_version *)req.payload; 233 234 version->major = VFIO_USER_MAJOR_VER; 235 version->minor = VFIO_USER_MINOR_VER; 236 237 ret = vfio_user_dev_send_request(dev, VFIO_USER_VERSION, req.payload, 238 sizeof(struct vfio_user_version), sizeof(req.payload), NULL, 0); 239 if (ret < 0) { 240 return ret; 241 } 242 243 SPDK_DEBUGLOG(vfio_user, "%s Negotiate version %u.%u\n", vfio_user_message_str[VFIO_USER_VERSION], 244 version->major, version->minor); 245 246 return 0; 247 } 248 249 int 250 vfio_user_get_dev_region_info(struct vfio_device *dev, struct vfio_region_info *region_info, 251 size_t buf_len, int *fds, int num_fds) 252 { 253 assert(buf_len > sizeof(struct vfio_region_info)); 254 region_info->argsz = buf_len - sizeof(struct vfio_region_info); 255 return vfio_user_dev_send_request(dev, VFIO_USER_DEVICE_GET_REGION_INFO, 256 region_info, region_info->argsz, buf_len, fds, num_fds); 257 } 258 259 int 260 vfio_user_get_dev_info(struct vfio_device *dev, struct vfio_user_device_info *dev_info, 261 size_t buf_len) 262 { 263 dev_info->argsz = sizeof(struct vfio_user_device_info); 264 return vfio_user_dev_send_request(dev, VFIO_USER_DEVICE_GET_INFO, 265 dev_info, dev_info->argsz, buf_len, NULL, 0); 266 } 267 268 int 269 vfio_user_dev_dma_map_unmap(struct vfio_device *dev, struct vfio_memory_region *mr, bool map) 270 { 271 struct vfio_user_dma_map dma_map = { 0 }; 272 struct vfio_user_dma_unmap dma_unmap = { 0 }; 273 274 if (map) { 275 dma_map.argsz = sizeof(struct vfio_user_dma_map); 276 dma_map.addr = mr->iova; 277 dma_map.size = mr->size; 278 dma_map.offset = mr->offset; 279 dma_map.flags = VFIO_USER_F_DMA_REGION_READ | VFIO_USER_F_DMA_REGION_WRITE; 280 281 return vfio_user_dev_send_request(dev, VFIO_USER_DMA_MAP, 282 &dma_map, sizeof(dma_map), sizeof(dma_map), &mr->fd, 1); 283 } else { 284 dma_unmap.argsz = sizeof(struct vfio_user_dma_unmap); 285 dma_unmap.addr = mr->iova; 286 dma_unmap.size = mr->size; 287 return vfio_user_dev_send_request(dev, VFIO_USER_DMA_UNMAP, 288 &dma_unmap, sizeof(dma_unmap), sizeof(dma_unmap), &mr->fd, 1); 289 } 290 } 291 292 int 293 vfio_user_dev_mmio_access(struct vfio_device *dev, uint32_t index, uint64_t offset, 294 size_t len, void *buf, bool is_write) 295 { 296 struct vfio_user_region_access *access; 297 size_t arg_len; 298 int ret; 299 300 arg_len = sizeof(*access) + len; 301 access = calloc(1, arg_len); 302 if (!access) { 303 return -ENOMEM; 304 } 305 306 access->offset = offset; 307 access->region = index; 308 access->count = len; 309 if (is_write) { 310 memcpy(access->data, buf, len); 311 ret = vfio_user_dev_send_request(dev, VFIO_USER_REGION_WRITE, 312 access, arg_len, arg_len, NULL, 0); 313 } else { 314 ret = vfio_user_dev_send_request(dev, VFIO_USER_REGION_READ, 315 access, sizeof(*access), arg_len, NULL, 0); 316 } 317 318 if (ret) { 319 free(access); 320 return ret; 321 } 322 323 if (!is_write) { 324 memcpy(buf, (void *)access->data, len); 325 } 326 327 free(access); 328 return 0; 329 } 330 331 int 332 vfio_user_dev_setup(struct vfio_device *dev) 333 { 334 int fd; 335 int flag; 336 struct sockaddr_un un; 337 ssize_t rc; 338 339 fd = socket(AF_UNIX, SOCK_STREAM, 0); 340 if (fd < 0) { 341 SPDK_ERRLOG("socket() error\n"); 342 return -errno; 343 } 344 345 flag = fcntl(fd, F_GETFD); 346 if (fcntl(fd, F_SETFD, flag | FD_CLOEXEC) < 0) { 347 SPDK_ERRLOG("fcntl failed\n"); 348 } 349 350 memset(&un, 0, sizeof(un)); 351 un.sun_family = AF_UNIX; 352 rc = snprintf(un.sun_path, sizeof(un.sun_path), "%s", dev->path); 353 if (rc < 0 || (size_t)rc >= sizeof(un.sun_path)) { 354 SPDK_ERRLOG("socket path too long\n"); 355 close(fd); 356 if (rc < 0) { 357 return -errno; 358 } else { 359 return -EINVAL; 360 } 361 } 362 if (connect(fd, (struct sockaddr *)&un, sizeof(un)) < 0) { 363 SPDK_ERRLOG("connect error\n"); 364 close(fd); 365 return -errno; 366 } 367 368 dev->fd = fd; 369 370 if (vfio_user_check_version(dev)) { 371 SPDK_ERRLOG("Check VFIO_USER_VERSION message failed\n"); 372 close(fd); 373 return -EFAULT; 374 } 375 376 return 0; 377 } 378 379 SPDK_LOG_REGISTER_COMPONENT(vfio_user) 380