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