xref: /qemu/hw/vfio-user/device.c (revision 98a906d9e5827b18c51d7d7485be2f21f8900cc7)
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 
114     /*
115      * If at least one region is directly mapped into the VM, then we can no
116      * longer rely on the sequential nature of vfio-user request handling to
117      * ensure that posted writes are completed before a subsequent read. In this
118      * case, disable posted write support. This is a per-device property, not
119      * per-region.
120      */
121     if (info->flags & VFIO_REGION_INFO_FLAG_MMAP) {
122         vfio_user_disable_posted_writes(proxy);
123     }
124 
125     return 0;
126 }
127 
128 static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev,
129                                                struct vfio_region_info *info,
130                                                int *fd)
131 {
132     VFIOUserFDs fds = { 0, 1, fd};
133     int ret;
134 
135     if (info->index > vbasedev->num_regions) {
136         return -EINVAL;
137     }
138 
139     ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds);
140     if (ret) {
141         return ret;
142     }
143 
144     /* cap_offset in valid area */
145     if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) &&
146         (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) {
147         return -EINVAL;
148     }
149 
150     return 0;
151 }
152 
153 static int vfio_user_device_io_get_irq_info(VFIODevice *vbasedev,
154                                             struct vfio_irq_info *info)
155 {
156     VFIOUserProxy *proxy = vbasedev->proxy;
157     Error *local_err = NULL;
158     VFIOUserIRQInfo msg;
159 
160     memset(&msg, 0, sizeof(msg));
161     vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_IRQ_INFO,
162                           sizeof(msg), 0);
163     msg.argsz = info->argsz;
164     msg.index = info->index;
165 
166     if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, &local_err)) {
167         error_prepend(&local_err, "%s: ", __func__);
168         error_report_err(local_err);
169         return -EFAULT;
170     }
171 
172     if (msg.hdr.flags & VFIO_USER_ERROR) {
173         return -msg.hdr.error_reply;
174     }
175     trace_vfio_user_get_irq_info(msg.index, msg.flags, msg.count);
176 
177     memcpy(info, &msg.argsz, sizeof(*info));
178     return 0;
179 }
180 
181 static int irq_howmany(int *fdp, uint32_t cur, uint32_t max)
182 {
183     int n = 0;
184 
185     if (fdp[cur] != -1) {
186         do {
187             n++;
188         } while (n < max && fdp[cur + n] != -1);
189     } else {
190         do {
191             n++;
192         } while (n < max && fdp[cur + n] == -1);
193     }
194 
195     return n;
196 }
197 
198 static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev,
199                                         struct vfio_irq_set *irq)
200 {
201     VFIOUserProxy *proxy = vbasedev->proxy;
202     g_autofree VFIOUserIRQSet *msgp = NULL;
203     uint32_t size, nfds, send_fds, sent_fds, max;
204     Error *local_err = NULL;
205 
206     if (irq->argsz < sizeof(*irq)) {
207         error_printf("vfio_user_set_irqs argsz too small\n");
208         return -EINVAL;
209     }
210 
211     /*
212      * Handle simple case
213      */
214     if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) {
215         size = sizeof(VFIOUserHdr) + irq->argsz;
216         msgp = g_malloc0(size);
217 
218         vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0);
219         msgp->argsz = irq->argsz;
220         msgp->flags = irq->flags;
221         msgp->index = irq->index;
222         msgp->start = irq->start;
223         msgp->count = irq->count;
224         trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
225                                  msgp->flags);
226 
227         if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
228             error_prepend(&local_err, "%s: ", __func__);
229             error_report_err(local_err);
230             return -EFAULT;
231         }
232 
233         if (msgp->hdr.flags & VFIO_USER_ERROR) {
234             return -msgp->hdr.error_reply;
235         }
236 
237         return 0;
238     }
239 
240     /*
241      * Calculate the number of FDs to send
242      * and adjust argsz
243      */
244     nfds = (irq->argsz - sizeof(*irq)) / sizeof(int);
245     irq->argsz = sizeof(*irq);
246     msgp = g_malloc0(sizeof(*msgp));
247     /*
248      * Send in chunks if over max_send_fds
249      */
250     for (sent_fds = 0; nfds > sent_fds; sent_fds += send_fds) {
251         VFIOUserFDs *arg_fds, loop_fds;
252 
253         /* must send all valid FDs or all invalid FDs in single msg */
254         max = nfds - sent_fds;
255         if (max > proxy->max_send_fds) {
256             max = proxy->max_send_fds;
257         }
258         send_fds = irq_howmany((int *)irq->data, sent_fds, max);
259 
260         vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS,
261                               sizeof(*msgp), 0);
262         msgp->argsz = irq->argsz;
263         msgp->flags = irq->flags;
264         msgp->index = irq->index;
265         msgp->start = irq->start + sent_fds;
266         msgp->count = send_fds;
267         trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count,
268                                  msgp->flags);
269 
270         loop_fds.send_fds = send_fds;
271         loop_fds.recv_fds = 0;
272         loop_fds.fds = (int *)irq->data + sent_fds;
273         arg_fds = loop_fds.fds[0] != -1 ? &loop_fds : NULL;
274 
275         if (!vfio_user_send_wait(proxy, &msgp->hdr, arg_fds, 0, &local_err)) {
276             error_prepend(&local_err, "%s: ", __func__);
277             error_report_err(local_err);
278             return -EFAULT;
279         }
280 
281         if (msgp->hdr.flags & VFIO_USER_ERROR) {
282             return -msgp->hdr.error_reply;
283         }
284     }
285 
286     return 0;
287 }
288 
289 static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index,
290                                            off_t off, uint32_t count,
291                                            void *data)
292 {
293     g_autofree VFIOUserRegionRW *msgp = NULL;
294     VFIOUserProxy *proxy = vbasedev->proxy;
295     int size = sizeof(*msgp) + count;
296     Error *local_err = NULL;
297 
298     if (count > proxy->max_xfer_size) {
299         return -EINVAL;
300     }
301 
302     msgp = g_malloc0(size);
303     vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0);
304     msgp->offset = off;
305     msgp->region = index;
306     msgp->count = count;
307     trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
308 
309     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) {
310         error_prepend(&local_err, "%s: ", __func__);
311         error_report_err(local_err);
312         return -EFAULT;
313     }
314 
315     if (msgp->hdr.flags & VFIO_USER_ERROR) {
316         return -msgp->hdr.error_reply;
317     } else if (msgp->count > count) {
318         return -E2BIG;
319     } else {
320         memcpy(data, &msgp->data, msgp->count);
321     }
322 
323     return msgp->count;
324 }
325 
326 /*
327  * If this is a posted write, and VFIO_PROXY_NO_POST is not set, then we are OK
328  * to send the write to the socket without waiting for the server's reply:
329  * a subsequent read (of any region) will not pass the posted write, as all
330  * messages are handled sequentially.
331  */
332 static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index,
333                                             off_t off, unsigned count,
334                                             void *data, bool post)
335 {
336     VFIOUserRegionRW *msgp = NULL;
337     VFIOUserProxy *proxy = vbasedev->proxy;
338     int size = sizeof(*msgp) + count;
339     Error *local_err = NULL;
340     int flags = 0;
341     int ret;
342 
343     if (count > proxy->max_xfer_size) {
344         return -EINVAL;
345     }
346 
347     if (proxy->flags & VFIO_PROXY_NO_POST) {
348         post = false;
349     }
350 
351     if (post) {
352         flags |= VFIO_USER_NO_REPLY;
353     }
354 
355     msgp = g_malloc0(size);
356     vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, flags);
357     msgp->offset = off;
358     msgp->region = index;
359     msgp->count = count;
360     memcpy(&msgp->data, data, count);
361     trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count);
362 
363     /* async send will free msg after it's sent */
364     if (post) {
365         if (!vfio_user_send_async(proxy, &msgp->hdr, NULL, &local_err)) {
366             error_prepend(&local_err, "%s: ", __func__);
367             error_report_err(local_err);
368             return -EFAULT;
369         }
370 
371         return count;
372     }
373 
374     if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) {
375         error_prepend(&local_err, "%s: ", __func__);
376         error_report_err(local_err);
377         g_free(msgp);
378         return -EFAULT;
379     }
380 
381     if (msgp->hdr.flags & VFIO_USER_ERROR) {
382         ret = -msgp->hdr.error_reply;
383     } else {
384         ret = count;
385     }
386 
387     g_free(msgp);
388     return ret;
389 }
390 
391 /*
392  * Socket-based io_ops
393  */
394 VFIODeviceIOOps vfio_user_device_io_ops_sock = {
395     .get_region_info = vfio_user_device_io_get_region_info,
396     .get_irq_info = vfio_user_device_io_get_irq_info,
397     .set_irqs = vfio_user_device_io_set_irqs,
398     .region_read = vfio_user_device_io_region_read,
399     .region_write = vfio_user_device_io_region_write,
400 
401 };
402