LCOV - code coverage report
Current view: top level - spdk/lib/vfio_user/host - vfio_user.c (source / functions) Hit Total Coverage
Test: Combined Lines: 152 185 82.2 %
Date: 2024-07-12 14:09:53 Functions: 11 11 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 81 138 58.7 %

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

Generated by: LCOV version 1.14