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
vfio_user_write(int fd,void * buf,int len,int * fds,int num_fds)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
read_fd_message(int sockfd,char * buf,int buflen,int * fds,int * fd_num)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
vfio_user_read(int fd,struct vfio_user_request * req)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
vfio_user_dev_send_request(struct vfio_device * dev,enum vfio_user_command command,void * arg,size_t arg_len,size_t buf_len,int * fds,int max_fds)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
vfio_user_check_version(struct vfio_device * dev)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
vfio_user_get_dev_region_info(struct vfio_device * dev,struct vfio_region_info * region_info,size_t buf_len,int * fds,int num_fds)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
vfio_user_get_dev_info(struct vfio_device * dev,struct vfio_user_device_info * dev_info,size_t buf_len)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
vfio_user_dev_dma_map_unmap(struct vfio_device * dev,struct vfio_memory_region * mr,bool map)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
vfio_user_dev_mmio_access(struct vfio_device * dev,uint32_t index,uint64_t offset,size_t len,void * buf,bool is_write)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
vfio_user_dev_setup(struct vfio_device * dev)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