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