xref: /qemu/hw/vfio-user/device.c (revision 019232358124e4f4b929e40fa23253de60eec73e)
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 void vfio_user_device_reset(VFIOUserProxy *proxy)
58 {
59     Error *local_err = NULL;
60     VFIOUserHdr hdr;
61 
62     vfio_user_request_msg(&hdr, VFIO_USER_DEVICE_RESET, sizeof(hdr), 0);
63 
64     if (!vfio_user_send_wait(proxy, &hdr, NULL, 0, &local_err)) {
65         error_prepend(&local_err, "%s: ", __func__);
66         error_report_err(local_err);
67         return;
68     }
69 
70     if (hdr.flags & VFIO_USER_ERROR) {
71         error_printf("reset reply error %d\n", hdr.error_reply);
72     }
73 }
74 
75 static int vfio_user_get_region_info(VFIOUserProxy *proxy,
76                                      struct vfio_region_info *info,
77                                      VFIOUserFDs *fds)
78 {
79     g_autofree VFIOUserRegionInfo *msgp = NULL;
80     Error *local_err = NULL;
81     uint32_t size;
82 
83     /* data returned can be larger than vfio_region_info */
84     if (info->argsz < sizeof(*info)) {
85         error_printf("vfio_user_get_region_info argsz too small\n");
86         return -E2BIG;
87     }
88     if (fds != NULL && fds->send_fds != 0) {
89         error_printf("vfio_user_get_region_info can't send FDs\n");
90         return -EINVAL;
91     }
92 
93     size = info->argsz + sizeof(VFIOUserHdr);
94     msgp = g_malloc0(size);
95 
96     vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_INFO,
97                           sizeof(*msgp), 0);
98     msgp->argsz = info->argsz;
99     msgp->index = info->index;
100 
101     if (!vfio_user_send_wait(proxy, &msgp->hdr, fds, size, &local_err)) {
102         error_prepend(&local_err, "%s: ", __func__);
103         error_report_err(local_err);
104         return -EFAULT;
105     }
106 
107     if (msgp->hdr.flags & VFIO_USER_ERROR) {
108         return -msgp->hdr.error_reply;
109     }
110     trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size);
111 
112     memcpy(info, &msgp->argsz, info->argsz);
113     return 0;
114 }
115 
116 
117 static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev,
118                                                struct vfio_region_info *info,
119                                                int *fd)
120 {
121     VFIOUserFDs fds = { 0, 1, fd};
122     int ret;
123 
124     if (info->index > vbasedev->num_regions) {
125         return -EINVAL;
126     }
127 
128     ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds);
129     if (ret) {
130         return ret;
131     }
132 
133     /* cap_offset in valid area */
134     if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) &&
135         (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) {
136         return -EINVAL;
137     }
138 
139     return 0;
140 }
141 
142 static int vfio_user_device_io_get_irq_info(VFIODevice *vbasedev,
143                                             struct vfio_irq_info *info)
144 {
145     VFIOUserProxy *proxy = vbasedev->proxy;
146     Error *local_err = NULL;
147     VFIOUserIRQInfo msg;
148 
149     memset(&msg, 0, sizeof(msg));
150     vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_IRQ_INFO,
151                           sizeof(msg), 0);
152     msg.argsz = info->argsz;
153     msg.index = info->index;
154 
155     if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, &local_err)) {
156         error_prepend(&local_err, "%s: ", __func__);
157         error_report_err(local_err);
158         return -EFAULT;
159     }
160 
161     if (msg.hdr.flags & VFIO_USER_ERROR) {
162         return -msg.hdr.error_reply;
163     }
164     trace_vfio_user_get_irq_info(msg.index, msg.flags, msg.count);
165 
166     memcpy(info, &msg.argsz, sizeof(*info));
167     return 0;
168 }
169 
170 static int irq_howmany(int *fdp, uint32_t cur, uint32_t max)
171 {
172     int n = 0;
173 
174     if (fdp[cur] != -1) {
175         do {
176             n++;
177         } while (n < max && fdp[cur + n] != -1);
178     } else {
179         do {
180             n++;
181         } while (n < max && fdp[cur + n] == -1);
182     }
183 
184     return n;
185 }
186 
187 static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev,
188                                         struct vfio_irq_set *irq)
189 {
190     VFIOUserProxy *proxy = vbasedev->proxy;
191     g_autofree VFIOUserIRQSet *msgp = NULL;
192     uint32_t size, nfds, send_fds, sent_fds, max;
193     Error *local_err = NULL;
194 
195     if (irq->argsz < sizeof(*irq)) {
196         error_printf("vfio_user_set_irqs argsz too small\n");
197         return -EINVAL;
198     }
199 
200     /*
201      * Handle simple case
202      */
203     if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) {
204         size = sizeof(VFIOUserHdr) + irq->argsz;
205         msgp = g_malloc0(size);
206 
207         vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0);
208         msgp->argsz = irq->argsz;
209         msgp->flags = irq->flags;
210         msgp->index = irq->index;
211         msgp->start = irq->start;
212         msgp->count = irq->count;
213         trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
214                                  msgp->flags);
215 
216         if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
217             error_prepend(&local_err, "%s: ", __func__);
218             error_report_err(local_err);
219             return -EFAULT;
220         }
221 
222         if (msgp->hdr.flags & VFIO_USER_ERROR) {
223             return -msgp->hdr.error_reply;
224         }
225 
226         return 0;
227     }
228 
229     /*
230      * Calculate the number of FDs to send
231      * and adjust argsz
232      */
233     nfds = (irq->argsz - sizeof(*irq)) / sizeof(int);
234     irq->argsz = sizeof(*irq);
235     msgp = g_malloc0(sizeof(*msgp));
236     /*
237      * Send in chunks if over max_send_fds
238      */
239     for (sent_fds = 0; nfds > sent_fds; sent_fds += send_fds) {
240         VFIOUserFDs *arg_fds, loop_fds;
241 
242         /* must send all valid FDs or all invalid FDs in single msg */
243         max = nfds - sent_fds;
244         if (max > proxy->max_send_fds) {
245             max = proxy->max_send_fds;
246         }
247         send_fds = irq_howmany((int *)irq->data, sent_fds, max);
248 
249         vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS,
250                               sizeof(*msgp), 0);
251         msgp->argsz = irq->argsz;
252         msgp->flags = irq->flags;
253         msgp->index = irq->index;
254         msgp->start = irq->start + sent_fds;
255         msgp->count = send_fds;
256         trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
257                                  msgp->flags);
258 
259         loop_fds.send_fds = send_fds;
260         loop_fds.recv_fds = 0;
261         loop_fds.fds = (int *)irq->data + sent_fds;
262         arg_fds = loop_fds.fds[0] != -1 ? &loop_fds : NULL;
263 
264         if (!vfio_user_send_wait(proxy, &msgp->hdr, arg_fds, 0, &local_err)) {
265             error_prepend(&local_err, "%s: ", __func__);
266             error_report_err(local_err);
267             return -EFAULT;
268         }
269 
270         if (msgp->hdr.flags & VFIO_USER_ERROR) {
271             return -msgp->hdr.error_reply;
272         }
273     }
274 
275     return 0;
276 }
277 
278 static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index,
279                                            off_t off, uint32_t count,
280                                            void *data)
281 {
282     g_autofree VFIOUserRegionRW *msgp = NULL;
283     VFIOUserProxy *proxy = vbasedev->proxy;
284     int size = sizeof(*msgp) + count;
285     Error *local_err = NULL;
286 
287     if (count > proxy->max_xfer_size) {
288         return -EINVAL;
289     }
290 
291     msgp = g_malloc0(size);
292     vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0);
293     msgp->offset = off;
294     msgp->region = index;
295     msgp->count = count;
296     trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
297 
298     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) {
299         error_prepend(&local_err, "%s: ", __func__);
300         error_report_err(local_err);
301         return -EFAULT;
302     }
303 
304     if (msgp->hdr.flags & VFIO_USER_ERROR) {
305         return -msgp->hdr.error_reply;
306     } else if (msgp->count > count) {
307         return -E2BIG;
308     } else {
309         memcpy(data, &msgp->data, msgp->count);
310     }
311 
312     return msgp->count;
313 }
314 
315 static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index,
316                                             off_t off, unsigned count,
317                                             void *data, bool post)
318 {
319     g_autofree VFIOUserRegionRW *msgp = NULL;
320     VFIOUserProxy *proxy = vbasedev->proxy;
321     int size = sizeof(*msgp) + count;
322     Error *local_err = NULL;
323     int ret;
324 
325     if (count > proxy->max_xfer_size) {
326         return -EINVAL;
327     }
328 
329     msgp = g_malloc0(size);
330     vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, 0);
331     msgp->offset = off;
332     msgp->region = index;
333     msgp->count = count;
334     memcpy(&msgp->data, data, count);
335     trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
336 
337     /* Ignore post: all writes are synchronous/non-posted. */
338 
339     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
340         error_prepend(&local_err, "%s: ", __func__);
341         error_report_err(local_err);
342         return -EFAULT;
343     }
344 
345     if (msgp->hdr.flags & VFIO_USER_ERROR) {
346         ret = -msgp->hdr.error_reply;
347     } else {
348         ret = count;
349     }
350 
351     return ret;
352 }
353 
354 /*
355  * Socket-based io_ops
356  */
357 VFIODeviceIOOps vfio_user_device_io_ops_sock = {
358     .get_region_info = vfio_user_device_io_get_region_info,
359     .get_irq_info = vfio_user_device_io_get_irq_info,
360     .set_irqs = vfio_user_device_io_set_irqs,
361     .region_read = vfio_user_device_io_region_read,
362     .region_write = vfio_user_device_io_region_write,
363 
364 };
365