xref: /qemu/hw/vfio-user/device.c (revision ca1add1696dd53f905c2a17f36159d54e9b6f527)
1 /*
2  * vfio protocol over a UNIX socket device handling.
3  *
4  * Copyright © 2018, 2021 Oracle and/or its affiliates.
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "qemu/osdep.h"
10 #include "qapi/error.h"
11 #include "qemu/error-report.h"
12 
13 #include "hw/vfio-user/device.h"
14 #include "hw/vfio-user/trace.h"
15 
16 /*
17  * These are to defend against a malign server trying
18  * to force us to run out of memory.
19  */
20 #define VFIO_USER_MAX_REGIONS   100
21 #define VFIO_USER_MAX_IRQS      50
22 
23 bool vfio_user_get_device_info(VFIOUserProxy *proxy,
24                                struct vfio_device_info *info, Error **errp)
25 {
26     VFIOUserDeviceInfo msg;
27     uint32_t argsz = sizeof(msg) - sizeof(msg.hdr);
28 
29     memset(&msg, 0, sizeof(msg));
30     vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_INFO, sizeof(msg), 0);
31     msg.argsz = argsz;
32 
33     if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, errp)) {
34         return false;
35     }
36 
37     if (msg.hdr.flags & VFIO_USER_ERROR) {
38         error_setg_errno(errp, -msg.hdr.error_reply,
39                          "VFIO_USER_DEVICE_GET_INFO failed");
40         return false;
41     }
42 
43     trace_vfio_user_get_info(msg.num_regions, msg.num_irqs);
44 
45     memcpy(info, &msg.argsz, argsz);
46 
47     /* defend against a malicious server */
48     if (info->num_regions > VFIO_USER_MAX_REGIONS ||
49         info->num_irqs > VFIO_USER_MAX_IRQS) {
50         error_setg_errno(errp, EINVAL, "invalid reply");
51         return false;
52     }
53 
54     return true;
55 }
56 
57 static int vfio_user_get_region_info(VFIOUserProxy *proxy,
58                                      struct vfio_region_info *info,
59                                      VFIOUserFDs *fds)
60 {
61     g_autofree VFIOUserRegionInfo *msgp = NULL;
62     Error *local_err = NULL;
63     uint32_t size;
64 
65     /* data returned can be larger than vfio_region_info */
66     if (info->argsz < sizeof(*info)) {
67         error_printf("vfio_user_get_region_info argsz too small\n");
68         return -E2BIG;
69     }
70     if (fds != NULL && fds->send_fds != 0) {
71         error_printf("vfio_user_get_region_info can't send FDs\n");
72         return -EINVAL;
73     }
74 
75     size = info->argsz + sizeof(VFIOUserHdr);
76     msgp = g_malloc0(size);
77 
78     vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_INFO,
79                           sizeof(*msgp), 0);
80     msgp->argsz = info->argsz;
81     msgp->index = info->index;
82 
83     if (!vfio_user_send_wait(proxy, &msgp->hdr, fds, size, &local_err)) {
84         error_prepend(&local_err, "%s: ", __func__);
85         error_report_err(local_err);
86         return -EFAULT;
87     }
88 
89     if (msgp->hdr.flags & VFIO_USER_ERROR) {
90         return -msgp->hdr.error_reply;
91     }
92     trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size);
93 
94     memcpy(info, &msgp->argsz, info->argsz);
95     return 0;
96 }
97 
98 
99 static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev,
100                                                struct vfio_region_info *info,
101                                                int *fd)
102 {
103     VFIOUserFDs fds = { 0, 1, fd};
104     int ret;
105 
106     if (info->index > vbasedev->num_regions) {
107         return -EINVAL;
108     }
109 
110     ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds);
111     if (ret) {
112         return ret;
113     }
114 
115     /* cap_offset in valid area */
116     if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) &&
117         (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) {
118         return -EINVAL;
119     }
120 
121     return 0;
122 }
123 
124 static int vfio_user_device_io_get_irq_info(VFIODevice *vbasedev,
125                                             struct vfio_irq_info *info)
126 {
127     VFIOUserProxy *proxy = vbasedev->proxy;
128     Error *local_err = NULL;
129     VFIOUserIRQInfo msg;
130 
131     memset(&msg, 0, sizeof(msg));
132     vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_IRQ_INFO,
133                           sizeof(msg), 0);
134     msg.argsz = info->argsz;
135     msg.index = info->index;
136 
137     if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, &local_err)) {
138         error_prepend(&local_err, "%s: ", __func__);
139         error_report_err(local_err);
140         return -EFAULT;
141     }
142 
143     if (msg.hdr.flags & VFIO_USER_ERROR) {
144         return -msg.hdr.error_reply;
145     }
146     trace_vfio_user_get_irq_info(msg.index, msg.flags, msg.count);
147 
148     memcpy(info, &msg.argsz, sizeof(*info));
149     return 0;
150 }
151 
152 static int irq_howmany(int *fdp, uint32_t cur, uint32_t max)
153 {
154     int n = 0;
155 
156     if (fdp[cur] != -1) {
157         do {
158             n++;
159         } while (n < max && fdp[cur + n] != -1);
160     } else {
161         do {
162             n++;
163         } while (n < max && fdp[cur + n] == -1);
164     }
165 
166     return n;
167 }
168 
169 static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev,
170                                         struct vfio_irq_set *irq)
171 {
172     VFIOUserProxy *proxy = vbasedev->proxy;
173     g_autofree VFIOUserIRQSet *msgp = NULL;
174     uint32_t size, nfds, send_fds, sent_fds, max;
175     Error *local_err = NULL;
176 
177     if (irq->argsz < sizeof(*irq)) {
178         error_printf("vfio_user_set_irqs argsz too small\n");
179         return -EINVAL;
180     }
181 
182     /*
183      * Handle simple case
184      */
185     if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) {
186         size = sizeof(VFIOUserHdr) + irq->argsz;
187         msgp = g_malloc0(size);
188 
189         vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0);
190         msgp->argsz = irq->argsz;
191         msgp->flags = irq->flags;
192         msgp->index = irq->index;
193         msgp->start = irq->start;
194         msgp->count = irq->count;
195         trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
196                                  msgp->flags);
197 
198         if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
199             error_prepend(&local_err, "%s: ", __func__);
200             error_report_err(local_err);
201             return -EFAULT;
202         }
203 
204         if (msgp->hdr.flags & VFIO_USER_ERROR) {
205             return -msgp->hdr.error_reply;
206         }
207 
208         return 0;
209     }
210 
211     /*
212      * Calculate the number of FDs to send
213      * and adjust argsz
214      */
215     nfds = (irq->argsz - sizeof(*irq)) / sizeof(int);
216     irq->argsz = sizeof(*irq);
217     msgp = g_malloc0(sizeof(*msgp));
218     /*
219      * Send in chunks if over max_send_fds
220      */
221     for (sent_fds = 0; nfds > sent_fds; sent_fds += send_fds) {
222         VFIOUserFDs *arg_fds, loop_fds;
223 
224         /* must send all valid FDs or all invalid FDs in single msg */
225         max = nfds - sent_fds;
226         if (max > proxy->max_send_fds) {
227             max = proxy->max_send_fds;
228         }
229         send_fds = irq_howmany((int *)irq->data, sent_fds, max);
230 
231         vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS,
232                               sizeof(*msgp), 0);
233         msgp->argsz = irq->argsz;
234         msgp->flags = irq->flags;
235         msgp->index = irq->index;
236         msgp->start = irq->start + sent_fds;
237         msgp->count = send_fds;
238         trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
239                                  msgp->flags);
240 
241         loop_fds.send_fds = send_fds;
242         loop_fds.recv_fds = 0;
243         loop_fds.fds = (int *)irq->data + sent_fds;
244         arg_fds = loop_fds.fds[0] != -1 ? &loop_fds : NULL;
245 
246         if (!vfio_user_send_wait(proxy, &msgp->hdr, arg_fds, 0, &local_err)) {
247             error_prepend(&local_err, "%s: ", __func__);
248             error_report_err(local_err);
249             return -EFAULT;
250         }
251 
252         if (msgp->hdr.flags & VFIO_USER_ERROR) {
253             return -msgp->hdr.error_reply;
254         }
255     }
256 
257     return 0;
258 }
259 
260 static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index,
261                                            off_t off, uint32_t count,
262                                            void *data)
263 {
264     g_autofree VFIOUserRegionRW *msgp = NULL;
265     VFIOUserProxy *proxy = vbasedev->proxy;
266     int size = sizeof(*msgp) + count;
267     Error *local_err = NULL;
268 
269     if (count > proxy->max_xfer_size) {
270         return -EINVAL;
271     }
272 
273     msgp = g_malloc0(size);
274     vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0);
275     msgp->offset = off;
276     msgp->region = index;
277     msgp->count = count;
278     trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
279 
280     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) {
281         error_prepend(&local_err, "%s: ", __func__);
282         error_report_err(local_err);
283         return -EFAULT;
284     }
285 
286     if (msgp->hdr.flags & VFIO_USER_ERROR) {
287         return -msgp->hdr.error_reply;
288     } else if (msgp->count > count) {
289         return -E2BIG;
290     } else {
291         memcpy(data, &msgp->data, msgp->count);
292     }
293 
294     return msgp->count;
295 }
296 
297 static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index,
298                                             off_t off, unsigned count,
299                                             void *data, bool post)
300 {
301     g_autofree VFIOUserRegionRW *msgp = NULL;
302     VFIOUserProxy *proxy = vbasedev->proxy;
303     int size = sizeof(*msgp) + count;
304     Error *local_err = NULL;
305     int ret;
306 
307     if (count > proxy->max_xfer_size) {
308         return -EINVAL;
309     }
310 
311     msgp = g_malloc0(size);
312     vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, 0);
313     msgp->offset = off;
314     msgp->region = index;
315     msgp->count = count;
316     memcpy(&msgp->data, data, count);
317     trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
318 
319     /* Ignore post: all writes are synchronous/non-posted. */
320 
321     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
322         error_prepend(&local_err, "%s: ", __func__);
323         error_report_err(local_err);
324         return -EFAULT;
325     }
326 
327     if (msgp->hdr.flags & VFIO_USER_ERROR) {
328         ret = -msgp->hdr.error_reply;
329     } else {
330         ret = count;
331     }
332 
333     return ret;
334 }
335 
336 /*
337  * Socket-based io_ops
338  */
339 VFIODeviceIOOps vfio_user_device_io_ops_sock = {
340     .get_region_info = vfio_user_device_io_get_region_info,
341     .get_irq_info = vfio_user_device_io_get_irq_info,
342     .set_irqs = vfio_user_device_io_set_irqs,
343     .region_read = vfio_user_device_io_region_read,
344     .region_write = vfio_user_device_io_region_write,
345 
346 };
347