1438d863fSJohn Levon /*
2438d863fSJohn Levon * vfio protocol over a UNIX socket.
3438d863fSJohn Levon *
4438d863fSJohn Levon * Copyright © 2018, 2021 Oracle and/or its affiliates.
5438d863fSJohn Levon *
6438d863fSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later
7438d863fSJohn Levon */
8438d863fSJohn Levon
9438d863fSJohn Levon #include "qemu/osdep.h"
10438d863fSJohn Levon #include <sys/ioctl.h>
11438d863fSJohn Levon
12438d863fSJohn Levon #include "hw/vfio/vfio-device.h"
13438d863fSJohn Levon #include "hw/vfio-user/proxy.h"
140b3d881aSJohn Levon #include "hw/vfio-user/trace.h"
15438d863fSJohn Levon #include "qapi/error.h"
16*1a0c32a9SJohn Levon #include "qobject/qbool.h"
1736227628SJohn Levon #include "qobject/qdict.h"
1836227628SJohn Levon #include "qobject/qjson.h"
1936227628SJohn Levon #include "qobject/qnum.h"
20438d863fSJohn Levon #include "qemu/error-report.h"
21438d863fSJohn Levon #include "qemu/lockable.h"
220b3d881aSJohn Levon #include "qemu/main-loop.h"
23*1a0c32a9SJohn Levon #include "qemu/thread.h"
24438d863fSJohn Levon #include "system/iothread.h"
25438d863fSJohn Levon
26438d863fSJohn Levon static IOThread *vfio_user_iothread;
27438d863fSJohn Levon
28438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy);
290b3d881aSJohn Levon static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
300b3d881aSJohn Levon VFIOUserFDs *fds);
310b3d881aSJohn Levon static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg);
32438d863fSJohn Levon
330b3d881aSJohn Levon static void vfio_user_recv(void *opaque);
3436227628SJohn Levon static void vfio_user_send(void *opaque);
350b3d881aSJohn Levon static void vfio_user_cb(void *opaque);
360b3d881aSJohn Levon
370b3d881aSJohn Levon static void vfio_user_request(void *opaque);
380b3d881aSJohn Levon
vfio_user_set_error(VFIOUserHdr * hdr,uint32_t err)390b3d881aSJohn Levon static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err)
400b3d881aSJohn Levon {
410b3d881aSJohn Levon hdr->flags |= VFIO_USER_ERROR;
420b3d881aSJohn Levon hdr->error_reply = err;
430b3d881aSJohn Levon }
44438d863fSJohn Levon
45438d863fSJohn Levon /*
46438d863fSJohn Levon * Functions called by main, CPU, or iothread threads
47438d863fSJohn Levon */
48438d863fSJohn Levon
vfio_user_shutdown(VFIOUserProxy * proxy)49438d863fSJohn Levon static void vfio_user_shutdown(VFIOUserProxy *proxy)
50438d863fSJohn Levon {
51438d863fSJohn Levon qio_channel_shutdown(proxy->ioc, QIO_CHANNEL_SHUTDOWN_READ, NULL);
52438d863fSJohn Levon qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx, NULL,
53438d863fSJohn Levon proxy->ctx, NULL, NULL);
54438d863fSJohn Levon }
55438d863fSJohn Levon
5636227628SJohn Levon /*
5736227628SJohn Levon * Same return values as qio_channel_writev_full():
5836227628SJohn Levon *
5936227628SJohn Levon * QIO_CHANNEL_ERR_BLOCK: *errp not set
6036227628SJohn Levon * -1: *errp will be populated
6136227628SJohn Levon * otherwise: bytes written
6236227628SJohn Levon */
vfio_user_send_qio(VFIOUserProxy * proxy,VFIOUserMsg * msg,Error ** errp)6336227628SJohn Levon static ssize_t vfio_user_send_qio(VFIOUserProxy *proxy, VFIOUserMsg *msg,
6436227628SJohn Levon Error **errp)
6536227628SJohn Levon {
6636227628SJohn Levon VFIOUserFDs *fds = msg->fds;
6736227628SJohn Levon struct iovec iov = {
6836227628SJohn Levon .iov_base = msg->hdr,
6936227628SJohn Levon .iov_len = msg->hdr->size,
7036227628SJohn Levon };
7136227628SJohn Levon size_t numfds = 0;
7236227628SJohn Levon int *fdp = NULL;
7336227628SJohn Levon ssize_t ret;
7436227628SJohn Levon
7536227628SJohn Levon if (fds != NULL && fds->send_fds != 0) {
7636227628SJohn Levon numfds = fds->send_fds;
7736227628SJohn Levon fdp = fds->fds;
7836227628SJohn Levon }
7936227628SJohn Levon
8036227628SJohn Levon ret = qio_channel_writev_full(proxy->ioc, &iov, 1, fdp, numfds, 0, errp);
8136227628SJohn Levon
8236227628SJohn Levon if (ret == -1) {
8336227628SJohn Levon vfio_user_set_error(msg->hdr, EIO);
8436227628SJohn Levon vfio_user_shutdown(proxy);
8536227628SJohn Levon }
8636227628SJohn Levon trace_vfio_user_send_write(msg->hdr->id, ret);
8736227628SJohn Levon
8836227628SJohn Levon return ret;
8936227628SJohn Levon }
9036227628SJohn Levon
vfio_user_getmsg(VFIOUserProxy * proxy,VFIOUserHdr * hdr,VFIOUserFDs * fds)910b3d881aSJohn Levon static VFIOUserMsg *vfio_user_getmsg(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
920b3d881aSJohn Levon VFIOUserFDs *fds)
930b3d881aSJohn Levon {
940b3d881aSJohn Levon VFIOUserMsg *msg;
950b3d881aSJohn Levon
960b3d881aSJohn Levon msg = QTAILQ_FIRST(&proxy->free);
970b3d881aSJohn Levon if (msg != NULL) {
980b3d881aSJohn Levon QTAILQ_REMOVE(&proxy->free, msg, next);
990b3d881aSJohn Levon } else {
1000b3d881aSJohn Levon msg = g_malloc0(sizeof(*msg));
1010b3d881aSJohn Levon qemu_cond_init(&msg->cv);
1020b3d881aSJohn Levon }
1030b3d881aSJohn Levon
1040b3d881aSJohn Levon msg->hdr = hdr;
1050b3d881aSJohn Levon msg->fds = fds;
1060b3d881aSJohn Levon return msg;
1070b3d881aSJohn Levon }
1080b3d881aSJohn Levon
1090b3d881aSJohn Levon /*
1100b3d881aSJohn Levon * Recycle a message list entry to the free list.
1110b3d881aSJohn Levon */
vfio_user_recycle(VFIOUserProxy * proxy,VFIOUserMsg * msg)1120b3d881aSJohn Levon static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg)
1130b3d881aSJohn Levon {
1140b3d881aSJohn Levon if (msg->type == VFIO_MSG_NONE) {
1150b3d881aSJohn Levon error_printf("vfio_user_recycle - freeing free msg\n");
1160b3d881aSJohn Levon return;
1170b3d881aSJohn Levon }
1180b3d881aSJohn Levon
1190b3d881aSJohn Levon /* free msg buffer if no one is waiting to consume the reply */
1200b3d881aSJohn Levon if (msg->type == VFIO_MSG_NOWAIT || msg->type == VFIO_MSG_ASYNC) {
1210b3d881aSJohn Levon g_free(msg->hdr);
1220b3d881aSJohn Levon if (msg->fds != NULL) {
1230b3d881aSJohn Levon g_free(msg->fds);
1240b3d881aSJohn Levon }
1250b3d881aSJohn Levon }
1260b3d881aSJohn Levon
1270b3d881aSJohn Levon msg->type = VFIO_MSG_NONE;
1280b3d881aSJohn Levon msg->hdr = NULL;
1290b3d881aSJohn Levon msg->fds = NULL;
1300b3d881aSJohn Levon msg->complete = false;
13136227628SJohn Levon msg->pending = false;
1320b3d881aSJohn Levon QTAILQ_INSERT_HEAD(&proxy->free, msg, next);
1330b3d881aSJohn Levon }
1340b3d881aSJohn Levon
vfio_user_getfds(int numfds)13518e899e6SJohn Levon VFIOUserFDs *vfio_user_getfds(int numfds)
1360b3d881aSJohn Levon {
1370b3d881aSJohn Levon VFIOUserFDs *fds = g_malloc0(sizeof(*fds) + (numfds * sizeof(int)));
1380b3d881aSJohn Levon
1390b3d881aSJohn Levon fds->fds = (int *)((char *)fds + sizeof(*fds));
1400b3d881aSJohn Levon
1410b3d881aSJohn Levon return fds;
1420b3d881aSJohn Levon }
1430b3d881aSJohn Levon
144438d863fSJohn Levon /*
145438d863fSJohn Levon * Functions only called by iothread
146438d863fSJohn Levon */
147438d863fSJohn Levon
1480b3d881aSJohn Levon /*
1490b3d881aSJohn Levon * Process a received message.
1500b3d881aSJohn Levon */
vfio_user_process(VFIOUserProxy * proxy,VFIOUserMsg * msg,bool isreply)1510b3d881aSJohn Levon static void vfio_user_process(VFIOUserProxy *proxy, VFIOUserMsg *msg,
1520b3d881aSJohn Levon bool isreply)
1530b3d881aSJohn Levon {
1540b3d881aSJohn Levon
1550b3d881aSJohn Levon /*
1560b3d881aSJohn Levon * Replies signal a waiter, if none just check for errors
1570b3d881aSJohn Levon * and free the message buffer.
1580b3d881aSJohn Levon *
1590b3d881aSJohn Levon * Requests get queued for the BH.
1600b3d881aSJohn Levon */
1610b3d881aSJohn Levon if (isreply) {
1620b3d881aSJohn Levon msg->complete = true;
1630b3d881aSJohn Levon if (msg->type == VFIO_MSG_WAIT) {
1640b3d881aSJohn Levon qemu_cond_signal(&msg->cv);
1650b3d881aSJohn Levon } else {
1660b3d881aSJohn Levon if (msg->hdr->flags & VFIO_USER_ERROR) {
1670b3d881aSJohn Levon error_printf("vfio_user_process: error reply on async ");
1680b3d881aSJohn Levon error_printf("request command %x error %s\n",
1690b3d881aSJohn Levon msg->hdr->command,
1700b3d881aSJohn Levon strerror(msg->hdr->error_reply));
1710b3d881aSJohn Levon }
1720b3d881aSJohn Levon /* youngest nowait msg has been ack'd */
1730b3d881aSJohn Levon if (proxy->last_nowait == msg) {
1740b3d881aSJohn Levon proxy->last_nowait = NULL;
1750b3d881aSJohn Levon }
1760b3d881aSJohn Levon vfio_user_recycle(proxy, msg);
1770b3d881aSJohn Levon }
1780b3d881aSJohn Levon } else {
1790b3d881aSJohn Levon QTAILQ_INSERT_TAIL(&proxy->incoming, msg, next);
1800b3d881aSJohn Levon qemu_bh_schedule(proxy->req_bh);
1810b3d881aSJohn Levon }
1820b3d881aSJohn Levon }
1830b3d881aSJohn Levon
1840b3d881aSJohn Levon /*
1850b3d881aSJohn Levon * Complete a partial message read
1860b3d881aSJohn Levon */
vfio_user_complete(VFIOUserProxy * proxy,Error ** errp)1870b3d881aSJohn Levon static int vfio_user_complete(VFIOUserProxy *proxy, Error **errp)
1880b3d881aSJohn Levon {
1890b3d881aSJohn Levon VFIOUserMsg *msg = proxy->part_recv;
1900b3d881aSJohn Levon size_t msgleft = proxy->recv_left;
1910b3d881aSJohn Levon bool isreply;
1920b3d881aSJohn Levon char *data;
1930b3d881aSJohn Levon int ret;
1940b3d881aSJohn Levon
1950b3d881aSJohn Levon data = (char *)msg->hdr + (msg->hdr->size - msgleft);
1960b3d881aSJohn Levon while (msgleft > 0) {
1970b3d881aSJohn Levon ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
1980b3d881aSJohn Levon
1990b3d881aSJohn Levon /* error or would block */
2000b3d881aSJohn Levon if (ret <= 0) {
2010b3d881aSJohn Levon /* try for rest on next iternation */
2020b3d881aSJohn Levon if (ret == QIO_CHANNEL_ERR_BLOCK) {
2030b3d881aSJohn Levon proxy->recv_left = msgleft;
2040b3d881aSJohn Levon }
2050b3d881aSJohn Levon return ret;
2060b3d881aSJohn Levon }
2070b3d881aSJohn Levon trace_vfio_user_recv_read(msg->hdr->id, ret);
2080b3d881aSJohn Levon
2090b3d881aSJohn Levon msgleft -= ret;
2100b3d881aSJohn Levon data += ret;
2110b3d881aSJohn Levon }
2120b3d881aSJohn Levon
2130b3d881aSJohn Levon /*
2140b3d881aSJohn Levon * Read complete message, process it.
2150b3d881aSJohn Levon */
2160b3d881aSJohn Levon proxy->part_recv = NULL;
2170b3d881aSJohn Levon proxy->recv_left = 0;
2180b3d881aSJohn Levon isreply = (msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REPLY;
2190b3d881aSJohn Levon vfio_user_process(proxy, msg, isreply);
2200b3d881aSJohn Levon
2210b3d881aSJohn Levon /* return positive value */
2220b3d881aSJohn Levon return 1;
2230b3d881aSJohn Levon }
2240b3d881aSJohn Levon
2250b3d881aSJohn Levon /*
2260b3d881aSJohn Levon * Receive and process one incoming message.
2270b3d881aSJohn Levon *
2280b3d881aSJohn Levon * For replies, find matching outgoing request and wake any waiters.
2290b3d881aSJohn Levon * For requests, queue in incoming list and run request BH.
2300b3d881aSJohn Levon */
vfio_user_recv_one(VFIOUserProxy * proxy,Error ** errp)2310b3d881aSJohn Levon static int vfio_user_recv_one(VFIOUserProxy *proxy, Error **errp)
2320b3d881aSJohn Levon {
2330b3d881aSJohn Levon VFIOUserMsg *msg = NULL;
2340b3d881aSJohn Levon g_autofree int *fdp = NULL;
2350b3d881aSJohn Levon VFIOUserFDs *reqfds;
2360b3d881aSJohn Levon VFIOUserHdr hdr;
2370b3d881aSJohn Levon struct iovec iov = {
2380b3d881aSJohn Levon .iov_base = &hdr,
2390b3d881aSJohn Levon .iov_len = sizeof(hdr),
2400b3d881aSJohn Levon };
2410b3d881aSJohn Levon bool isreply = false;
2420b3d881aSJohn Levon int i, ret;
2430b3d881aSJohn Levon size_t msgleft, numfds = 0;
2440b3d881aSJohn Levon char *data = NULL;
2450b3d881aSJohn Levon char *buf = NULL;
2460b3d881aSJohn Levon
2470b3d881aSJohn Levon /*
2480b3d881aSJohn Levon * Complete any partial reads
2490b3d881aSJohn Levon */
2500b3d881aSJohn Levon if (proxy->part_recv != NULL) {
2510b3d881aSJohn Levon ret = vfio_user_complete(proxy, errp);
2520b3d881aSJohn Levon
2530b3d881aSJohn Levon /* still not complete, try later */
2540b3d881aSJohn Levon if (ret == QIO_CHANNEL_ERR_BLOCK) {
2550b3d881aSJohn Levon return ret;
2560b3d881aSJohn Levon }
2570b3d881aSJohn Levon
2580b3d881aSJohn Levon if (ret <= 0) {
2590b3d881aSJohn Levon goto fatal;
2600b3d881aSJohn Levon }
2610b3d881aSJohn Levon /* else fall into reading another msg */
2620b3d881aSJohn Levon }
2630b3d881aSJohn Levon
2640b3d881aSJohn Levon /*
2650b3d881aSJohn Levon * Read header
2660b3d881aSJohn Levon */
2670b3d881aSJohn Levon ret = qio_channel_readv_full(proxy->ioc, &iov, 1, &fdp, &numfds, 0,
2680b3d881aSJohn Levon errp);
2690b3d881aSJohn Levon if (ret == QIO_CHANNEL_ERR_BLOCK) {
2700b3d881aSJohn Levon return ret;
2710b3d881aSJohn Levon }
2720b3d881aSJohn Levon
2730b3d881aSJohn Levon /* read error or other side closed connection */
2740b3d881aSJohn Levon if (ret <= 0) {
2750b3d881aSJohn Levon goto fatal;
2760b3d881aSJohn Levon }
2770b3d881aSJohn Levon
2780b3d881aSJohn Levon if (ret < sizeof(hdr)) {
2790b3d881aSJohn Levon error_setg(errp, "short read of header");
2800b3d881aSJohn Levon goto fatal;
2810b3d881aSJohn Levon }
2820b3d881aSJohn Levon
2830b3d881aSJohn Levon /*
2840b3d881aSJohn Levon * Validate header
2850b3d881aSJohn Levon */
2860b3d881aSJohn Levon if (hdr.size < sizeof(VFIOUserHdr)) {
2870b3d881aSJohn Levon error_setg(errp, "bad header size");
2880b3d881aSJohn Levon goto fatal;
2890b3d881aSJohn Levon }
2900b3d881aSJohn Levon switch (hdr.flags & VFIO_USER_TYPE) {
2910b3d881aSJohn Levon case VFIO_USER_REQUEST:
2920b3d881aSJohn Levon isreply = false;
2930b3d881aSJohn Levon break;
2940b3d881aSJohn Levon case VFIO_USER_REPLY:
2950b3d881aSJohn Levon isreply = true;
2960b3d881aSJohn Levon break;
2970b3d881aSJohn Levon default:
2980b3d881aSJohn Levon error_setg(errp, "unknown message type");
2990b3d881aSJohn Levon goto fatal;
3000b3d881aSJohn Levon }
3010b3d881aSJohn Levon trace_vfio_user_recv_hdr(proxy->sockname, hdr.id, hdr.command, hdr.size,
3020b3d881aSJohn Levon hdr.flags);
3030b3d881aSJohn Levon
3040b3d881aSJohn Levon /*
3050b3d881aSJohn Levon * For replies, find the matching pending request.
3060b3d881aSJohn Levon * For requests, reap incoming FDs.
3070b3d881aSJohn Levon */
3080b3d881aSJohn Levon if (isreply) {
3090b3d881aSJohn Levon QTAILQ_FOREACH(msg, &proxy->pending, next) {
3100b3d881aSJohn Levon if (hdr.id == msg->id) {
3110b3d881aSJohn Levon break;
3120b3d881aSJohn Levon }
3130b3d881aSJohn Levon }
3140b3d881aSJohn Levon if (msg == NULL) {
3150b3d881aSJohn Levon error_setg(errp, "unexpected reply");
3160b3d881aSJohn Levon goto err;
3170b3d881aSJohn Levon }
3180b3d881aSJohn Levon QTAILQ_REMOVE(&proxy->pending, msg, next);
3190b3d881aSJohn Levon
3200b3d881aSJohn Levon /*
3210b3d881aSJohn Levon * Process any received FDs
3220b3d881aSJohn Levon */
3230b3d881aSJohn Levon if (numfds != 0) {
3240b3d881aSJohn Levon if (msg->fds == NULL || msg->fds->recv_fds < numfds) {
3250b3d881aSJohn Levon error_setg(errp, "unexpected FDs");
3260b3d881aSJohn Levon goto err;
3270b3d881aSJohn Levon }
3280b3d881aSJohn Levon msg->fds->recv_fds = numfds;
3290b3d881aSJohn Levon memcpy(msg->fds->fds, fdp, numfds * sizeof(int));
3300b3d881aSJohn Levon }
3310b3d881aSJohn Levon } else {
3320b3d881aSJohn Levon if (numfds != 0) {
3330b3d881aSJohn Levon reqfds = vfio_user_getfds(numfds);
3340b3d881aSJohn Levon memcpy(reqfds->fds, fdp, numfds * sizeof(int));
3350b3d881aSJohn Levon } else {
3360b3d881aSJohn Levon reqfds = NULL;
3370b3d881aSJohn Levon }
3380b3d881aSJohn Levon }
3390b3d881aSJohn Levon
3400b3d881aSJohn Levon /*
3410b3d881aSJohn Levon * Put the whole message into a single buffer.
3420b3d881aSJohn Levon */
3430b3d881aSJohn Levon if (isreply) {
3440b3d881aSJohn Levon if (hdr.size > msg->rsize) {
3450b3d881aSJohn Levon error_setg(errp, "reply larger than recv buffer");
3460b3d881aSJohn Levon goto err;
3470b3d881aSJohn Levon }
3480b3d881aSJohn Levon *msg->hdr = hdr;
3490b3d881aSJohn Levon data = (char *)msg->hdr + sizeof(hdr);
3500b3d881aSJohn Levon } else {
351c6ac52a4SJohn Levon if (hdr.size > proxy->max_xfer_size + sizeof(VFIOUserDMARW)) {
352c6ac52a4SJohn Levon error_setg(errp, "vfio_user_recv request larger than max");
353c6ac52a4SJohn Levon goto err;
354c6ac52a4SJohn Levon }
3550b3d881aSJohn Levon buf = g_malloc0(hdr.size);
3560b3d881aSJohn Levon memcpy(buf, &hdr, sizeof(hdr));
3570b3d881aSJohn Levon data = buf + sizeof(hdr);
3580b3d881aSJohn Levon msg = vfio_user_getmsg(proxy, (VFIOUserHdr *)buf, reqfds);
3590b3d881aSJohn Levon msg->type = VFIO_MSG_REQ;
3600b3d881aSJohn Levon }
3610b3d881aSJohn Levon
3620b3d881aSJohn Levon /*
3630b3d881aSJohn Levon * Read rest of message.
3640b3d881aSJohn Levon */
3650b3d881aSJohn Levon msgleft = hdr.size - sizeof(hdr);
3660b3d881aSJohn Levon while (msgleft > 0) {
3670b3d881aSJohn Levon ret = qio_channel_read(proxy->ioc, data, msgleft, errp);
3680b3d881aSJohn Levon
3690b3d881aSJohn Levon /* prepare to complete read on next iternation */
3700b3d881aSJohn Levon if (ret == QIO_CHANNEL_ERR_BLOCK) {
3710b3d881aSJohn Levon proxy->part_recv = msg;
3720b3d881aSJohn Levon proxy->recv_left = msgleft;
3730b3d881aSJohn Levon return ret;
3740b3d881aSJohn Levon }
3750b3d881aSJohn Levon
3760b3d881aSJohn Levon if (ret <= 0) {
3770b3d881aSJohn Levon goto fatal;
3780b3d881aSJohn Levon }
3790b3d881aSJohn Levon trace_vfio_user_recv_read(hdr.id, ret);
3800b3d881aSJohn Levon
3810b3d881aSJohn Levon msgleft -= ret;
3820b3d881aSJohn Levon data += ret;
3830b3d881aSJohn Levon }
3840b3d881aSJohn Levon
3850b3d881aSJohn Levon vfio_user_process(proxy, msg, isreply);
3860b3d881aSJohn Levon return 0;
3870b3d881aSJohn Levon
3880b3d881aSJohn Levon /*
3890b3d881aSJohn Levon * fatal means the other side closed or we don't trust the stream
3900b3d881aSJohn Levon * err means this message is corrupt
3910b3d881aSJohn Levon */
3920b3d881aSJohn Levon fatal:
3930b3d881aSJohn Levon vfio_user_shutdown(proxy);
3940b3d881aSJohn Levon proxy->state = VFIO_PROXY_ERROR;
3950b3d881aSJohn Levon
3960b3d881aSJohn Levon /* set error if server side closed */
3970b3d881aSJohn Levon if (ret == 0) {
3980b3d881aSJohn Levon error_setg(errp, "server closed socket");
3990b3d881aSJohn Levon }
4000b3d881aSJohn Levon
4010b3d881aSJohn Levon err:
4020b3d881aSJohn Levon for (i = 0; i < numfds; i++) {
4030b3d881aSJohn Levon close(fdp[i]);
4040b3d881aSJohn Levon }
4050b3d881aSJohn Levon if (isreply && msg != NULL) {
4060b3d881aSJohn Levon /* force an error to keep sending thread from hanging */
4070b3d881aSJohn Levon vfio_user_set_error(msg->hdr, EINVAL);
4080b3d881aSJohn Levon msg->complete = true;
4090b3d881aSJohn Levon qemu_cond_signal(&msg->cv);
4100b3d881aSJohn Levon }
4110b3d881aSJohn Levon return -1;
4120b3d881aSJohn Levon }
4130b3d881aSJohn Levon
vfio_user_recv(void * opaque)4140b3d881aSJohn Levon static void vfio_user_recv(void *opaque)
4150b3d881aSJohn Levon {
4160b3d881aSJohn Levon VFIOUserProxy *proxy = opaque;
4170b3d881aSJohn Levon
4180b3d881aSJohn Levon QEMU_LOCK_GUARD(&proxy->lock);
4190b3d881aSJohn Levon
4200b3d881aSJohn Levon if (proxy->state == VFIO_PROXY_CONNECTED) {
4210b3d881aSJohn Levon Error *local_err = NULL;
4220b3d881aSJohn Levon
4230b3d881aSJohn Levon while (vfio_user_recv_one(proxy, &local_err) == 0) {
4240b3d881aSJohn Levon ;
4250b3d881aSJohn Levon }
4260b3d881aSJohn Levon
4270b3d881aSJohn Levon if (local_err != NULL) {
4280b3d881aSJohn Levon error_report_err(local_err);
4290b3d881aSJohn Levon }
4300b3d881aSJohn Levon }
4310b3d881aSJohn Levon }
4320b3d881aSJohn Levon
43336227628SJohn Levon /*
43436227628SJohn Levon * Send a single message, same return semantics as vfio_user_send_qio().
43536227628SJohn Levon *
43636227628SJohn Levon * Sent async messages are freed, others are moved to pending queue.
43736227628SJohn Levon */
vfio_user_send_one(VFIOUserProxy * proxy,Error ** errp)43836227628SJohn Levon static ssize_t vfio_user_send_one(VFIOUserProxy *proxy, Error **errp)
43936227628SJohn Levon {
44036227628SJohn Levon VFIOUserMsg *msg;
44136227628SJohn Levon ssize_t ret;
44236227628SJohn Levon
44336227628SJohn Levon msg = QTAILQ_FIRST(&proxy->outgoing);
44436227628SJohn Levon ret = vfio_user_send_qio(proxy, msg, errp);
44536227628SJohn Levon if (ret < 0) {
44636227628SJohn Levon return ret;
44736227628SJohn Levon }
44836227628SJohn Levon
44936227628SJohn Levon QTAILQ_REMOVE(&proxy->outgoing, msg, next);
450*1a0c32a9SJohn Levon proxy->num_outgoing--;
45136227628SJohn Levon if (msg->type == VFIO_MSG_ASYNC) {
45236227628SJohn Levon vfio_user_recycle(proxy, msg);
45336227628SJohn Levon } else {
45436227628SJohn Levon QTAILQ_INSERT_TAIL(&proxy->pending, msg, next);
45536227628SJohn Levon msg->pending = true;
45636227628SJohn Levon }
45736227628SJohn Levon
45836227628SJohn Levon return ret;
45936227628SJohn Levon }
46036227628SJohn Levon
46136227628SJohn Levon /*
46236227628SJohn Levon * Send messages from outgoing queue when the socket buffer has space.
46336227628SJohn Levon * If we deplete 'outgoing', remove ourselves from the poll list.
46436227628SJohn Levon */
vfio_user_send(void * opaque)46536227628SJohn Levon static void vfio_user_send(void *opaque)
46636227628SJohn Levon {
46736227628SJohn Levon VFIOUserProxy *proxy = opaque;
46836227628SJohn Levon
46936227628SJohn Levon QEMU_LOCK_GUARD(&proxy->lock);
47036227628SJohn Levon
47136227628SJohn Levon if (proxy->state == VFIO_PROXY_CONNECTED) {
47236227628SJohn Levon while (!QTAILQ_EMPTY(&proxy->outgoing)) {
47336227628SJohn Levon Error *local_err = NULL;
47436227628SJohn Levon int ret;
47536227628SJohn Levon
47636227628SJohn Levon ret = vfio_user_send_one(proxy, &local_err);
47736227628SJohn Levon
47836227628SJohn Levon if (ret == QIO_CHANNEL_ERR_BLOCK) {
47936227628SJohn Levon return;
48036227628SJohn Levon } else if (ret == -1) {
48136227628SJohn Levon error_report_err(local_err);
48236227628SJohn Levon return;
48336227628SJohn Levon }
48436227628SJohn Levon }
48536227628SJohn Levon qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
48636227628SJohn Levon vfio_user_recv, NULL, NULL, proxy);
487*1a0c32a9SJohn Levon
488*1a0c32a9SJohn Levon /* queue empty - send any pending multi write msgs */
489*1a0c32a9SJohn Levon if (proxy->wr_multi != NULL) {
490*1a0c32a9SJohn Levon vfio_user_flush_multi(proxy);
491*1a0c32a9SJohn Levon }
49236227628SJohn Levon }
49336227628SJohn Levon }
49436227628SJohn Levon
vfio_user_cb(void * opaque)495438d863fSJohn Levon static void vfio_user_cb(void *opaque)
496438d863fSJohn Levon {
497438d863fSJohn Levon VFIOUserProxy *proxy = opaque;
498438d863fSJohn Levon
499438d863fSJohn Levon QEMU_LOCK_GUARD(&proxy->lock);
500438d863fSJohn Levon
501438d863fSJohn Levon proxy->state = VFIO_PROXY_CLOSED;
502438d863fSJohn Levon qemu_cond_signal(&proxy->close_cv);
503438d863fSJohn Levon }
504438d863fSJohn Levon
505438d863fSJohn Levon
506438d863fSJohn Levon /*
507438d863fSJohn Levon * Functions called by main or CPU threads
508438d863fSJohn Levon */
509438d863fSJohn Levon
5100b3d881aSJohn Levon /*
5110b3d881aSJohn Levon * Process incoming requests.
5120b3d881aSJohn Levon *
5130b3d881aSJohn Levon * The bus-specific callback has the form:
5140b3d881aSJohn Levon * request(opaque, msg)
5150b3d881aSJohn Levon * where 'opaque' was specified in vfio_user_set_handler
5160b3d881aSJohn Levon * and 'msg' is the inbound message.
5170b3d881aSJohn Levon *
5180b3d881aSJohn Levon * The callback is responsible for disposing of the message buffer,
5190b3d881aSJohn Levon * usually by re-using it when calling vfio_send_reply or vfio_send_error,
5200b3d881aSJohn Levon * both of which free their message buffer when the reply is sent.
5210b3d881aSJohn Levon *
5220b3d881aSJohn Levon * If the callback uses a new buffer, it needs to free the old one.
5230b3d881aSJohn Levon */
vfio_user_request(void * opaque)5240b3d881aSJohn Levon static void vfio_user_request(void *opaque)
5250b3d881aSJohn Levon {
5260b3d881aSJohn Levon VFIOUserProxy *proxy = opaque;
5270b3d881aSJohn Levon VFIOUserMsgQ new, free;
5280b3d881aSJohn Levon VFIOUserMsg *msg, *m1;
5290b3d881aSJohn Levon
5300b3d881aSJohn Levon /* reap all incoming */
5310b3d881aSJohn Levon QTAILQ_INIT(&new);
5320b3d881aSJohn Levon WITH_QEMU_LOCK_GUARD(&proxy->lock) {
5330b3d881aSJohn Levon QTAILQ_FOREACH_SAFE(msg, &proxy->incoming, next, m1) {
5340b3d881aSJohn Levon QTAILQ_REMOVE(&proxy->incoming, msg, next);
5350b3d881aSJohn Levon QTAILQ_INSERT_TAIL(&new, msg, next);
5360b3d881aSJohn Levon }
5370b3d881aSJohn Levon }
5380b3d881aSJohn Levon
5390b3d881aSJohn Levon /* process list */
5400b3d881aSJohn Levon QTAILQ_INIT(&free);
5410b3d881aSJohn Levon QTAILQ_FOREACH_SAFE(msg, &new, next, m1) {
5420b3d881aSJohn Levon QTAILQ_REMOVE(&new, msg, next);
5430b3d881aSJohn Levon trace_vfio_user_recv_request(msg->hdr->command);
5440b3d881aSJohn Levon proxy->request(proxy->req_arg, msg);
5450b3d881aSJohn Levon QTAILQ_INSERT_HEAD(&free, msg, next);
5460b3d881aSJohn Levon }
5470b3d881aSJohn Levon
5480b3d881aSJohn Levon /* free list */
5490b3d881aSJohn Levon WITH_QEMU_LOCK_GUARD(&proxy->lock) {
5500b3d881aSJohn Levon QTAILQ_FOREACH_SAFE(msg, &free, next, m1) {
5510b3d881aSJohn Levon vfio_user_recycle(proxy, msg);
5520b3d881aSJohn Levon }
5530b3d881aSJohn Levon }
5540b3d881aSJohn Levon }
5550b3d881aSJohn Levon
55636227628SJohn Levon /*
55736227628SJohn Levon * Messages are queued onto the proxy's outgoing list.
55836227628SJohn Levon *
55936227628SJohn Levon * It handles 3 types of messages:
56036227628SJohn Levon *
56136227628SJohn Levon * async messages - replies and posted writes
56236227628SJohn Levon *
56336227628SJohn Levon * There will be no reply from the server, so message
56436227628SJohn Levon * buffers are freed after they're sent.
56536227628SJohn Levon *
56636227628SJohn Levon * nowait messages - map/unmap during address space transactions
56736227628SJohn Levon *
56836227628SJohn Levon * These are also sent async, but a reply is expected so that
56936227628SJohn Levon * vfio_wait_reqs() can wait for the youngest nowait request.
57036227628SJohn Levon * They transition from the outgoing list to the pending list
57136227628SJohn Levon * when sent, and are freed when the reply is received.
57236227628SJohn Levon *
57336227628SJohn Levon * wait messages - all other requests
57436227628SJohn Levon *
57536227628SJohn Levon * The reply to these messages is waited for by their caller.
57636227628SJohn Levon * They also transition from outgoing to pending when sent, but
57736227628SJohn Levon * the message buffer is returned to the caller with the reply
57836227628SJohn Levon * contents. The caller is responsible for freeing these messages.
57936227628SJohn Levon *
58036227628SJohn Levon * As an optimization, if the outgoing list and the socket send
58136227628SJohn Levon * buffer are empty, the message is sent inline instead of being
58236227628SJohn Levon * added to the outgoing list. The rest of the transitions are
58336227628SJohn Levon * unchanged.
58436227628SJohn Levon */
vfio_user_send_queued(VFIOUserProxy * proxy,VFIOUserMsg * msg,Error ** errp)58536227628SJohn Levon static bool vfio_user_send_queued(VFIOUserProxy *proxy, VFIOUserMsg *msg,
58636227628SJohn Levon Error **errp)
58736227628SJohn Levon {
58836227628SJohn Levon int ret;
58936227628SJohn Levon
590*1a0c32a9SJohn Levon /* older coalesced writes go first */
591*1a0c32a9SJohn Levon if (proxy->wr_multi != NULL &&
592*1a0c32a9SJohn Levon ((msg->hdr->flags & VFIO_USER_TYPE) == VFIO_USER_REQUEST)) {
593*1a0c32a9SJohn Levon vfio_user_flush_multi(proxy);
594*1a0c32a9SJohn Levon }
595*1a0c32a9SJohn Levon
59636227628SJohn Levon /*
59736227628SJohn Levon * Unsent outgoing msgs - add to tail
59836227628SJohn Levon */
59936227628SJohn Levon if (!QTAILQ_EMPTY(&proxy->outgoing)) {
60036227628SJohn Levon QTAILQ_INSERT_TAIL(&proxy->outgoing, msg, next);
601*1a0c32a9SJohn Levon proxy->num_outgoing++;
60236227628SJohn Levon return true;
60336227628SJohn Levon }
60436227628SJohn Levon
60536227628SJohn Levon /*
60636227628SJohn Levon * Try inline - if blocked, queue it and kick send poller
60736227628SJohn Levon */
60836227628SJohn Levon if (proxy->flags & VFIO_PROXY_FORCE_QUEUED) {
60936227628SJohn Levon ret = QIO_CHANNEL_ERR_BLOCK;
61036227628SJohn Levon } else {
61136227628SJohn Levon ret = vfio_user_send_qio(proxy, msg, errp);
61236227628SJohn Levon }
61336227628SJohn Levon
61436227628SJohn Levon if (ret == QIO_CHANNEL_ERR_BLOCK) {
61536227628SJohn Levon QTAILQ_INSERT_HEAD(&proxy->outgoing, msg, next);
616*1a0c32a9SJohn Levon proxy->num_outgoing = 1;
61736227628SJohn Levon qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
61836227628SJohn Levon vfio_user_recv, proxy->ctx,
61936227628SJohn Levon vfio_user_send, proxy);
62036227628SJohn Levon return true;
62136227628SJohn Levon }
62236227628SJohn Levon if (ret == -1) {
62336227628SJohn Levon return false;
62436227628SJohn Levon }
62536227628SJohn Levon
62636227628SJohn Levon /*
62736227628SJohn Levon * Sent - free async, add others to pending
62836227628SJohn Levon */
62936227628SJohn Levon if (msg->type == VFIO_MSG_ASYNC) {
63036227628SJohn Levon vfio_user_recycle(proxy, msg);
63136227628SJohn Levon } else {
63236227628SJohn Levon QTAILQ_INSERT_TAIL(&proxy->pending, msg, next);
63336227628SJohn Levon msg->pending = true;
63436227628SJohn Levon }
63536227628SJohn Levon
63636227628SJohn Levon return true;
63736227628SJohn Levon }
63836227628SJohn Levon
63936227628SJohn Levon /*
64018e899e6SJohn Levon * nowait send - vfio_wait_reqs() can wait for it later
64118e899e6SJohn Levon *
64218e899e6SJohn Levon * Returns false if we did not successfully receive a reply message, in which
64318e899e6SJohn Levon * case @errp will be populated.
64418e899e6SJohn Levon *
64518e899e6SJohn Levon * In either case, ownership of @hdr and @fds is taken, and the caller must
64618e899e6SJohn Levon * *not* free them itself.
64718e899e6SJohn Levon */
vfio_user_send_nowait(VFIOUserProxy * proxy,VFIOUserHdr * hdr,VFIOUserFDs * fds,int rsize,Error ** errp)64818e899e6SJohn Levon bool vfio_user_send_nowait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
64918e899e6SJohn Levon VFIOUserFDs *fds, int rsize, Error **errp)
65018e899e6SJohn Levon {
65118e899e6SJohn Levon VFIOUserMsg *msg;
65218e899e6SJohn Levon
65318e899e6SJohn Levon QEMU_LOCK_GUARD(&proxy->lock);
65418e899e6SJohn Levon
65518e899e6SJohn Levon msg = vfio_user_getmsg(proxy, hdr, fds);
65618e899e6SJohn Levon msg->id = hdr->id;
65718e899e6SJohn Levon msg->rsize = rsize ? rsize : hdr->size;
65818e899e6SJohn Levon msg->type = VFIO_MSG_NOWAIT;
65918e899e6SJohn Levon
66018e899e6SJohn Levon if (hdr->flags & VFIO_USER_NO_REPLY) {
66118e899e6SJohn Levon error_setg_errno(errp, EINVAL, "%s on NO_REPLY message", __func__);
66218e899e6SJohn Levon vfio_user_recycle(proxy, msg);
66318e899e6SJohn Levon return false;
66418e899e6SJohn Levon }
66518e899e6SJohn Levon
66618e899e6SJohn Levon if (!vfio_user_send_queued(proxy, msg, errp)) {
66718e899e6SJohn Levon vfio_user_recycle(proxy, msg);
66818e899e6SJohn Levon return false;
66918e899e6SJohn Levon }
67018e899e6SJohn Levon
67118e899e6SJohn Levon proxy->last_nowait = msg;
67218e899e6SJohn Levon
67318e899e6SJohn Levon return true;
67418e899e6SJohn Levon }
67518e899e6SJohn Levon
67618e899e6SJohn Levon /*
67736227628SJohn Levon * Returns false if we did not successfully receive a reply message, in which
67836227628SJohn Levon * case @errp will be populated.
67936227628SJohn Levon *
68036227628SJohn Levon * In either case, the caller must free @hdr and @fds if needed.
68136227628SJohn Levon */
vfio_user_send_wait(VFIOUserProxy * proxy,VFIOUserHdr * hdr,VFIOUserFDs * fds,int rsize,Error ** errp)6823bdb738bSJohn Levon bool vfio_user_send_wait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
68336227628SJohn Levon VFIOUserFDs *fds, int rsize, Error **errp)
68436227628SJohn Levon {
68536227628SJohn Levon VFIOUserMsg *msg;
68636227628SJohn Levon bool ok = false;
68736227628SJohn Levon
68836227628SJohn Levon if (hdr->flags & VFIO_USER_NO_REPLY) {
68936227628SJohn Levon error_setg_errno(errp, EINVAL, "%s on NO_REPLY message", __func__);
69036227628SJohn Levon return false;
69136227628SJohn Levon }
69236227628SJohn Levon
69336227628SJohn Levon qemu_mutex_lock(&proxy->lock);
69436227628SJohn Levon
69536227628SJohn Levon msg = vfio_user_getmsg(proxy, hdr, fds);
69636227628SJohn Levon msg->id = hdr->id;
69736227628SJohn Levon msg->rsize = rsize ? rsize : hdr->size;
69836227628SJohn Levon msg->type = VFIO_MSG_WAIT;
69936227628SJohn Levon
70036227628SJohn Levon ok = vfio_user_send_queued(proxy, msg, errp);
70136227628SJohn Levon
70236227628SJohn Levon if (ok) {
70336227628SJohn Levon while (!msg->complete) {
7043358d926SJohn Levon if (!qemu_cond_timedwait(&msg->cv, &proxy->lock,
7053358d926SJohn Levon proxy->wait_time)) {
70636227628SJohn Levon VFIOUserMsgQ *list;
70736227628SJohn Levon
70836227628SJohn Levon list = msg->pending ? &proxy->pending : &proxy->outgoing;
70936227628SJohn Levon QTAILQ_REMOVE(list, msg, next);
71036227628SJohn Levon error_setg_errno(errp, ETIMEDOUT,
71136227628SJohn Levon "timed out waiting for reply");
71236227628SJohn Levon ok = false;
71336227628SJohn Levon break;
71436227628SJohn Levon }
71536227628SJohn Levon }
71636227628SJohn Levon }
71736227628SJohn Levon
71836227628SJohn Levon vfio_user_recycle(proxy, msg);
71936227628SJohn Levon
72036227628SJohn Levon qemu_mutex_unlock(&proxy->lock);
72136227628SJohn Levon
72236227628SJohn Levon return ok;
72336227628SJohn Levon }
7240b3d881aSJohn Levon
725c6ac52a4SJohn Levon /*
726c6ac52a4SJohn Levon * async send - msg can be queued, but will be freed when sent
727c6ac52a4SJohn Levon *
728c6ac52a4SJohn Levon * Returns false on failure, in which case @errp will be populated.
729c6ac52a4SJohn Levon *
730c6ac52a4SJohn Levon * In either case, ownership of @hdr and @fds is taken, and the caller must
731c6ac52a4SJohn Levon * *not* free them itself.
732c6ac52a4SJohn Levon */
vfio_user_send_async(VFIOUserProxy * proxy,VFIOUserHdr * hdr,VFIOUserFDs * fds,Error ** errp)73398a906d9SJohn Levon bool vfio_user_send_async(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
734c6ac52a4SJohn Levon VFIOUserFDs *fds, Error **errp)
735c6ac52a4SJohn Levon {
736c6ac52a4SJohn Levon VFIOUserMsg *msg;
737c6ac52a4SJohn Levon
738c6ac52a4SJohn Levon QEMU_LOCK_GUARD(&proxy->lock);
739c6ac52a4SJohn Levon
740c6ac52a4SJohn Levon msg = vfio_user_getmsg(proxy, hdr, fds);
741c6ac52a4SJohn Levon msg->id = hdr->id;
742c6ac52a4SJohn Levon msg->rsize = 0;
743c6ac52a4SJohn Levon msg->type = VFIO_MSG_ASYNC;
744c6ac52a4SJohn Levon
745c6ac52a4SJohn Levon if (!(hdr->flags & (VFIO_USER_NO_REPLY | VFIO_USER_REPLY))) {
746c6ac52a4SJohn Levon error_setg_errno(errp, EINVAL, "%s on sync message", __func__);
747c6ac52a4SJohn Levon vfio_user_recycle(proxy, msg);
748c6ac52a4SJohn Levon return false;
749c6ac52a4SJohn Levon }
750c6ac52a4SJohn Levon
751c6ac52a4SJohn Levon if (!vfio_user_send_queued(proxy, msg, errp)) {
752c6ac52a4SJohn Levon vfio_user_recycle(proxy, msg);
753c6ac52a4SJohn Levon return false;
754c6ac52a4SJohn Levon }
755c6ac52a4SJohn Levon
756c6ac52a4SJohn Levon return true;
757c6ac52a4SJohn Levon }
758c6ac52a4SJohn Levon
vfio_user_wait_reqs(VFIOUserProxy * proxy)75918e899e6SJohn Levon void vfio_user_wait_reqs(VFIOUserProxy *proxy)
76018e899e6SJohn Levon {
76118e899e6SJohn Levon VFIOUserMsg *msg;
76218e899e6SJohn Levon
76318e899e6SJohn Levon /*
76418e899e6SJohn Levon * Any DMA map/unmap requests sent in the middle
76518e899e6SJohn Levon * of a memory region transaction were sent nowait.
76618e899e6SJohn Levon * Wait for them here.
76718e899e6SJohn Levon */
76818e899e6SJohn Levon qemu_mutex_lock(&proxy->lock);
76918e899e6SJohn Levon if (proxy->last_nowait != NULL) {
77018e899e6SJohn Levon /*
77118e899e6SJohn Levon * Change type to WAIT to wait for reply
77218e899e6SJohn Levon */
77318e899e6SJohn Levon msg = proxy->last_nowait;
77418e899e6SJohn Levon msg->type = VFIO_MSG_WAIT;
77518e899e6SJohn Levon proxy->last_nowait = NULL;
77618e899e6SJohn Levon while (!msg->complete) {
7773358d926SJohn Levon if (!qemu_cond_timedwait(&msg->cv, &proxy->lock,
7783358d926SJohn Levon proxy->wait_time)) {
77918e899e6SJohn Levon VFIOUserMsgQ *list;
78018e899e6SJohn Levon
78118e899e6SJohn Levon list = msg->pending ? &proxy->pending : &proxy->outgoing;
78218e899e6SJohn Levon QTAILQ_REMOVE(list, msg, next);
78318e899e6SJohn Levon error_printf("vfio_wait_reqs - timed out\n");
78418e899e6SJohn Levon break;
78518e899e6SJohn Levon }
78618e899e6SJohn Levon }
78718e899e6SJohn Levon
78818e899e6SJohn Levon if (msg->hdr->flags & VFIO_USER_ERROR) {
78918e899e6SJohn Levon error_printf("vfio_user_wait_reqs - error reply on async ");
79018e899e6SJohn Levon error_printf("request: command %x error %s\n", msg->hdr->command,
79118e899e6SJohn Levon strerror(msg->hdr->error_reply));
79218e899e6SJohn Levon }
79318e899e6SJohn Levon
79418e899e6SJohn Levon /*
79518e899e6SJohn Levon * Change type back to NOWAIT to free
79618e899e6SJohn Levon */
79718e899e6SJohn Levon msg->type = VFIO_MSG_NOWAIT;
79818e899e6SJohn Levon vfio_user_recycle(proxy, msg);
79918e899e6SJohn Levon }
80018e899e6SJohn Levon
80118e899e6SJohn Levon qemu_mutex_unlock(&proxy->lock);
80218e899e6SJohn Levon }
80318e899e6SJohn Levon
804c6ac52a4SJohn Levon /*
805c6ac52a4SJohn Levon * Reply to an incoming request.
806c6ac52a4SJohn Levon */
vfio_user_send_reply(VFIOUserProxy * proxy,VFIOUserHdr * hdr,int size)807c6ac52a4SJohn Levon void vfio_user_send_reply(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int size)
808c6ac52a4SJohn Levon {
809c6ac52a4SJohn Levon Error *local_err = NULL;
810c6ac52a4SJohn Levon
811c6ac52a4SJohn Levon if (size < sizeof(VFIOUserHdr)) {
812c6ac52a4SJohn Levon error_printf("%s: size too small", __func__);
813c6ac52a4SJohn Levon g_free(hdr);
814c6ac52a4SJohn Levon return;
815c6ac52a4SJohn Levon }
816c6ac52a4SJohn Levon
817c6ac52a4SJohn Levon /*
818c6ac52a4SJohn Levon * convert header to associated reply
819c6ac52a4SJohn Levon */
820c6ac52a4SJohn Levon hdr->flags = VFIO_USER_REPLY;
821c6ac52a4SJohn Levon hdr->size = size;
822c6ac52a4SJohn Levon
823c6ac52a4SJohn Levon if (!vfio_user_send_async(proxy, hdr, NULL, &local_err)) {
824c6ac52a4SJohn Levon error_report_err(local_err);
825c6ac52a4SJohn Levon }
826c6ac52a4SJohn Levon }
827c6ac52a4SJohn Levon
828c6ac52a4SJohn Levon /*
829c6ac52a4SJohn Levon * Send an error reply to an incoming request.
830c6ac52a4SJohn Levon */
vfio_user_send_error(VFIOUserProxy * proxy,VFIOUserHdr * hdr,int error)831c6ac52a4SJohn Levon void vfio_user_send_error(VFIOUserProxy *proxy, VFIOUserHdr *hdr, int error)
832c6ac52a4SJohn Levon {
833c6ac52a4SJohn Levon Error *local_err = NULL;
834c6ac52a4SJohn Levon
835c6ac52a4SJohn Levon /*
836c6ac52a4SJohn Levon * convert header to associated reply
837c6ac52a4SJohn Levon */
838c6ac52a4SJohn Levon hdr->flags = VFIO_USER_REPLY;
839c6ac52a4SJohn Levon hdr->flags |= VFIO_USER_ERROR;
840c6ac52a4SJohn Levon hdr->error_reply = error;
841c6ac52a4SJohn Levon hdr->size = sizeof(*hdr);
842c6ac52a4SJohn Levon
843c6ac52a4SJohn Levon if (!vfio_user_send_async(proxy, hdr, NULL, &local_err)) {
844c6ac52a4SJohn Levon error_report_err(local_err);
845c6ac52a4SJohn Levon }
846c6ac52a4SJohn Levon }
847c6ac52a4SJohn Levon
848c6ac52a4SJohn Levon /*
849c6ac52a4SJohn Levon * Close FDs erroneously received in an incoming request.
850c6ac52a4SJohn Levon */
vfio_user_putfds(VFIOUserMsg * msg)851c6ac52a4SJohn Levon void vfio_user_putfds(VFIOUserMsg *msg)
852c6ac52a4SJohn Levon {
853c6ac52a4SJohn Levon VFIOUserFDs *fds = msg->fds;
854c6ac52a4SJohn Levon int i;
855c6ac52a4SJohn Levon
856c6ac52a4SJohn Levon for (i = 0; i < fds->recv_fds; i++) {
857c6ac52a4SJohn Levon close(fds->fds[i]);
858c6ac52a4SJohn Levon }
859c6ac52a4SJohn Levon g_free(fds);
860c6ac52a4SJohn Levon msg->fds = NULL;
861c6ac52a4SJohn Levon }
862c6ac52a4SJohn Levon
86398a906d9SJohn Levon void
vfio_user_disable_posted_writes(VFIOUserProxy * proxy)86498a906d9SJohn Levon vfio_user_disable_posted_writes(VFIOUserProxy *proxy)
86598a906d9SJohn Levon {
86698a906d9SJohn Levon WITH_QEMU_LOCK_GUARD(&proxy->lock) {
86798a906d9SJohn Levon proxy->flags |= VFIO_PROXY_NO_POST;
86898a906d9SJohn Levon }
86998a906d9SJohn Levon }
87098a906d9SJohn Levon
871438d863fSJohn Levon static QLIST_HEAD(, VFIOUserProxy) vfio_user_sockets =
872438d863fSJohn Levon QLIST_HEAD_INITIALIZER(vfio_user_sockets);
873438d863fSJohn Levon
vfio_user_connect_dev(SocketAddress * addr,Error ** errp)874438d863fSJohn Levon VFIOUserProxy *vfio_user_connect_dev(SocketAddress *addr, Error **errp)
875438d863fSJohn Levon {
876438d863fSJohn Levon VFIOUserProxy *proxy;
877438d863fSJohn Levon QIOChannelSocket *sioc;
878438d863fSJohn Levon QIOChannel *ioc;
879438d863fSJohn Levon char *sockname;
880438d863fSJohn Levon
881438d863fSJohn Levon if (addr->type != SOCKET_ADDRESS_TYPE_UNIX) {
882438d863fSJohn Levon error_setg(errp, "vfio_user_connect - bad address family");
883438d863fSJohn Levon return NULL;
884438d863fSJohn Levon }
885438d863fSJohn Levon sockname = addr->u.q_unix.path;
886438d863fSJohn Levon
887438d863fSJohn Levon sioc = qio_channel_socket_new();
888438d863fSJohn Levon ioc = QIO_CHANNEL(sioc);
889438d863fSJohn Levon if (qio_channel_socket_connect_sync(sioc, addr, errp)) {
890438d863fSJohn Levon object_unref(OBJECT(ioc));
891438d863fSJohn Levon return NULL;
892438d863fSJohn Levon }
893438d863fSJohn Levon qio_channel_set_blocking(ioc, false, NULL);
894438d863fSJohn Levon
895438d863fSJohn Levon proxy = g_malloc0(sizeof(VFIOUserProxy));
896438d863fSJohn Levon proxy->sockname = g_strdup_printf("unix:%s", sockname);
897438d863fSJohn Levon proxy->ioc = ioc;
89836227628SJohn Levon
89936227628SJohn Levon /* init defaults */
90036227628SJohn Levon proxy->max_xfer_size = VFIO_USER_DEF_MAX_XFER;
90136227628SJohn Levon proxy->max_send_fds = VFIO_USER_DEF_MAX_FDS;
90236227628SJohn Levon proxy->max_dma = VFIO_USER_DEF_MAP_MAX;
90336227628SJohn Levon proxy->dma_pgsizes = VFIO_USER_DEF_PGSIZE;
90436227628SJohn Levon proxy->max_bitmap = VFIO_USER_DEF_MAX_BITMAP;
90536227628SJohn Levon proxy->migr_pgsize = VFIO_USER_DEF_PGSIZE;
90636227628SJohn Levon
907438d863fSJohn Levon proxy->flags = VFIO_PROXY_CLIENT;
908438d863fSJohn Levon proxy->state = VFIO_PROXY_CONNECTED;
909438d863fSJohn Levon
910438d863fSJohn Levon qemu_mutex_init(&proxy->lock);
911438d863fSJohn Levon qemu_cond_init(&proxy->close_cv);
912438d863fSJohn Levon
913438d863fSJohn Levon if (vfio_user_iothread == NULL) {
914438d863fSJohn Levon vfio_user_iothread = iothread_create("VFIO user", errp);
915438d863fSJohn Levon }
916438d863fSJohn Levon
917438d863fSJohn Levon proxy->ctx = iothread_get_aio_context(vfio_user_iothread);
9180b3d881aSJohn Levon proxy->req_bh = qemu_bh_new(vfio_user_request, proxy);
919438d863fSJohn Levon
920438d863fSJohn Levon QTAILQ_INIT(&proxy->outgoing);
921438d863fSJohn Levon QTAILQ_INIT(&proxy->incoming);
922438d863fSJohn Levon QTAILQ_INIT(&proxy->free);
923438d863fSJohn Levon QTAILQ_INIT(&proxy->pending);
924438d863fSJohn Levon QLIST_INSERT_HEAD(&vfio_user_sockets, proxy, next);
925438d863fSJohn Levon
926438d863fSJohn Levon return proxy;
927438d863fSJohn Levon }
928438d863fSJohn Levon
vfio_user_set_handler(VFIODevice * vbasedev,void (* handler)(void * opaque,VFIOUserMsg * msg),void * req_arg)9290b3d881aSJohn Levon void vfio_user_set_handler(VFIODevice *vbasedev,
9300b3d881aSJohn Levon void (*handler)(void *opaque, VFIOUserMsg *msg),
9310b3d881aSJohn Levon void *req_arg)
9320b3d881aSJohn Levon {
9330b3d881aSJohn Levon VFIOUserProxy *proxy = vbasedev->proxy;
9340b3d881aSJohn Levon
9350b3d881aSJohn Levon proxy->request = handler;
9360b3d881aSJohn Levon proxy->req_arg = req_arg;
9370b3d881aSJohn Levon qio_channel_set_aio_fd_handler(proxy->ioc, proxy->ctx,
9380b3d881aSJohn Levon vfio_user_recv, NULL, NULL, proxy);
9390b3d881aSJohn Levon }
9400b3d881aSJohn Levon
vfio_user_disconnect(VFIOUserProxy * proxy)941438d863fSJohn Levon void vfio_user_disconnect(VFIOUserProxy *proxy)
942438d863fSJohn Levon {
943438d863fSJohn Levon VFIOUserMsg *r1, *r2;
944438d863fSJohn Levon
945438d863fSJohn Levon qemu_mutex_lock(&proxy->lock);
946438d863fSJohn Levon
947438d863fSJohn Levon /* our side is quitting */
948438d863fSJohn Levon if (proxy->state == VFIO_PROXY_CONNECTED) {
949438d863fSJohn Levon vfio_user_shutdown(proxy);
950438d863fSJohn Levon if (!QTAILQ_EMPTY(&proxy->pending)) {
951438d863fSJohn Levon error_printf("vfio_user_disconnect: outstanding requests\n");
952438d863fSJohn Levon }
953438d863fSJohn Levon }
954438d863fSJohn Levon object_unref(OBJECT(proxy->ioc));
955438d863fSJohn Levon proxy->ioc = NULL;
9560b3d881aSJohn Levon qemu_bh_delete(proxy->req_bh);
9570b3d881aSJohn Levon proxy->req_bh = NULL;
958438d863fSJohn Levon
959438d863fSJohn Levon proxy->state = VFIO_PROXY_CLOSING;
960438d863fSJohn Levon QTAILQ_FOREACH_SAFE(r1, &proxy->outgoing, next, r2) {
961438d863fSJohn Levon qemu_cond_destroy(&r1->cv);
962438d863fSJohn Levon QTAILQ_REMOVE(&proxy->outgoing, r1, next);
963438d863fSJohn Levon g_free(r1);
964438d863fSJohn Levon }
965438d863fSJohn Levon QTAILQ_FOREACH_SAFE(r1, &proxy->incoming, next, r2) {
966438d863fSJohn Levon qemu_cond_destroy(&r1->cv);
967438d863fSJohn Levon QTAILQ_REMOVE(&proxy->incoming, r1, next);
968438d863fSJohn Levon g_free(r1);
969438d863fSJohn Levon }
970438d863fSJohn Levon QTAILQ_FOREACH_SAFE(r1, &proxy->pending, next, r2) {
971438d863fSJohn Levon qemu_cond_destroy(&r1->cv);
972438d863fSJohn Levon QTAILQ_REMOVE(&proxy->pending, r1, next);
973438d863fSJohn Levon g_free(r1);
974438d863fSJohn Levon }
975438d863fSJohn Levon QTAILQ_FOREACH_SAFE(r1, &proxy->free, next, r2) {
976438d863fSJohn Levon qemu_cond_destroy(&r1->cv);
977438d863fSJohn Levon QTAILQ_REMOVE(&proxy->free, r1, next);
978438d863fSJohn Levon g_free(r1);
979438d863fSJohn Levon }
980438d863fSJohn Levon
981438d863fSJohn Levon /*
982438d863fSJohn Levon * Make sure the iothread isn't blocking anywhere
983438d863fSJohn Levon * with a ref to this proxy by waiting for a BH
984438d863fSJohn Levon * handler to run after the proxy fd handlers were
985438d863fSJohn Levon * deleted above.
986438d863fSJohn Levon */
987438d863fSJohn Levon aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
988438d863fSJohn Levon qemu_cond_wait(&proxy->close_cv, &proxy->lock);
989438d863fSJohn Levon
990438d863fSJohn Levon /* we now hold the only ref to proxy */
991438d863fSJohn Levon qemu_mutex_unlock(&proxy->lock);
992438d863fSJohn Levon qemu_cond_destroy(&proxy->close_cv);
993438d863fSJohn Levon qemu_mutex_destroy(&proxy->lock);
994438d863fSJohn Levon
995438d863fSJohn Levon QLIST_REMOVE(proxy, next);
996438d863fSJohn Levon if (QLIST_EMPTY(&vfio_user_sockets)) {
997438d863fSJohn Levon iothread_destroy(vfio_user_iothread);
998438d863fSJohn Levon vfio_user_iothread = NULL;
999438d863fSJohn Levon }
1000438d863fSJohn Levon
1001438d863fSJohn Levon g_free(proxy->sockname);
1002438d863fSJohn Levon g_free(proxy);
1003438d863fSJohn Levon }
100436227628SJohn Levon
vfio_user_request_msg(VFIOUserHdr * hdr,uint16_t cmd,uint32_t size,uint32_t flags)10053bdb738bSJohn Levon void vfio_user_request_msg(VFIOUserHdr *hdr, uint16_t cmd,
100636227628SJohn Levon uint32_t size, uint32_t flags)
100736227628SJohn Levon {
100836227628SJohn Levon static uint16_t next_id;
100936227628SJohn Levon
101036227628SJohn Levon hdr->id = qatomic_fetch_inc(&next_id);
101136227628SJohn Levon hdr->command = cmd;
101236227628SJohn Levon hdr->size = size;
101336227628SJohn Levon hdr->flags = (flags & ~VFIO_USER_TYPE) | VFIO_USER_REQUEST;
101436227628SJohn Levon hdr->error_reply = 0;
101536227628SJohn Levon }
101636227628SJohn Levon
101736227628SJohn Levon struct cap_entry {
101836227628SJohn Levon const char *name;
101936227628SJohn Levon bool (*check)(VFIOUserProxy *proxy, QObject *qobj, Error **errp);
102036227628SJohn Levon };
102136227628SJohn Levon
caps_parse(VFIOUserProxy * proxy,QDict * qdict,struct cap_entry caps[],Error ** errp)102236227628SJohn Levon static bool caps_parse(VFIOUserProxy *proxy, QDict *qdict,
102336227628SJohn Levon struct cap_entry caps[], Error **errp)
102436227628SJohn Levon {
102536227628SJohn Levon QObject *qobj;
102636227628SJohn Levon struct cap_entry *p;
102736227628SJohn Levon
102836227628SJohn Levon for (p = caps; p->name != NULL; p++) {
102936227628SJohn Levon qobj = qdict_get(qdict, p->name);
103036227628SJohn Levon if (qobj != NULL) {
103136227628SJohn Levon if (!p->check(proxy, qobj, errp)) {
103236227628SJohn Levon return false;
103336227628SJohn Levon }
103436227628SJohn Levon qdict_del(qdict, p->name);
103536227628SJohn Levon }
103636227628SJohn Levon }
103736227628SJohn Levon
103836227628SJohn Levon /* warning, for now */
103936227628SJohn Levon if (qdict_size(qdict) != 0) {
104036227628SJohn Levon warn_report("spurious capabilities");
104136227628SJohn Levon }
104236227628SJohn Levon return true;
104336227628SJohn Levon }
104436227628SJohn Levon
check_migr_pgsize(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)104536227628SJohn Levon static bool check_migr_pgsize(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
104636227628SJohn Levon {
104736227628SJohn Levon QNum *qn = qobject_to(QNum, qobj);
104836227628SJohn Levon uint64_t pgsize;
104936227628SJohn Levon
105036227628SJohn Levon if (qn == NULL || !qnum_get_try_uint(qn, &pgsize)) {
105136227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_PGSIZE);
105236227628SJohn Levon return false;
105336227628SJohn Levon }
105436227628SJohn Levon
105536227628SJohn Levon /* must be larger than default */
105636227628SJohn Levon if (pgsize & (VFIO_USER_DEF_PGSIZE - 1)) {
105736227628SJohn Levon error_setg(errp, "pgsize 0x%"PRIx64" too small", pgsize);
105836227628SJohn Levon return false;
105936227628SJohn Levon }
106036227628SJohn Levon
106136227628SJohn Levon proxy->migr_pgsize = pgsize;
106236227628SJohn Levon return true;
106336227628SJohn Levon }
106436227628SJohn Levon
check_bitmap(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)106536227628SJohn Levon static bool check_bitmap(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
106636227628SJohn Levon {
106736227628SJohn Levon QNum *qn = qobject_to(QNum, qobj);
106836227628SJohn Levon uint64_t bitmap_size;
106936227628SJohn Levon
107036227628SJohn Levon if (qn == NULL || !qnum_get_try_uint(qn, &bitmap_size)) {
107136227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_BITMAP);
107236227628SJohn Levon return false;
107336227628SJohn Levon }
107436227628SJohn Levon
107536227628SJohn Levon /* can only lower it */
107636227628SJohn Levon if (bitmap_size > VFIO_USER_DEF_MAX_BITMAP) {
107736227628SJohn Levon error_setg(errp, "%s too large", VFIO_USER_CAP_MAX_BITMAP);
107836227628SJohn Levon return false;
107936227628SJohn Levon }
108036227628SJohn Levon
108136227628SJohn Levon proxy->max_bitmap = bitmap_size;
108236227628SJohn Levon return true;
108336227628SJohn Levon }
108436227628SJohn Levon
108536227628SJohn Levon static struct cap_entry caps_migr[] = {
108636227628SJohn Levon { VFIO_USER_CAP_PGSIZE, check_migr_pgsize },
108736227628SJohn Levon { VFIO_USER_CAP_MAX_BITMAP, check_bitmap },
108836227628SJohn Levon { NULL }
108936227628SJohn Levon };
109036227628SJohn Levon
check_max_fds(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)109136227628SJohn Levon static bool check_max_fds(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
109236227628SJohn Levon {
109336227628SJohn Levon QNum *qn = qobject_to(QNum, qobj);
109436227628SJohn Levon uint64_t max_send_fds;
109536227628SJohn Levon
109636227628SJohn Levon if (qn == NULL || !qnum_get_try_uint(qn, &max_send_fds) ||
109736227628SJohn Levon max_send_fds > VFIO_USER_MAX_MAX_FDS) {
109836227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_FDS);
109936227628SJohn Levon return false;
110036227628SJohn Levon }
110136227628SJohn Levon proxy->max_send_fds = max_send_fds;
110236227628SJohn Levon return true;
110336227628SJohn Levon }
110436227628SJohn Levon
check_max_xfer(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)110536227628SJohn Levon static bool check_max_xfer(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
110636227628SJohn Levon {
110736227628SJohn Levon QNum *qn = qobject_to(QNum, qobj);
110836227628SJohn Levon uint64_t max_xfer_size;
110936227628SJohn Levon
111036227628SJohn Levon if (qn == NULL || !qnum_get_try_uint(qn, &max_xfer_size) ||
111136227628SJohn Levon max_xfer_size > VFIO_USER_MAX_MAX_XFER) {
111236227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_XFER);
111336227628SJohn Levon return false;
111436227628SJohn Levon }
111536227628SJohn Levon proxy->max_xfer_size = max_xfer_size;
111636227628SJohn Levon return true;
111736227628SJohn Levon }
111836227628SJohn Levon
check_pgsizes(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)111936227628SJohn Levon static bool check_pgsizes(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
112036227628SJohn Levon {
112136227628SJohn Levon QNum *qn = qobject_to(QNum, qobj);
112236227628SJohn Levon uint64_t pgsizes;
112336227628SJohn Levon
112436227628SJohn Levon if (qn == NULL || !qnum_get_try_uint(qn, &pgsizes)) {
112536227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_PGSIZES);
112636227628SJohn Levon return false;
112736227628SJohn Levon }
112836227628SJohn Levon
112936227628SJohn Levon /* must be larger than default */
113036227628SJohn Levon if (pgsizes & (VFIO_USER_DEF_PGSIZE - 1)) {
113136227628SJohn Levon error_setg(errp, "pgsize 0x%"PRIx64" too small", pgsizes);
113236227628SJohn Levon return false;
113336227628SJohn Levon }
113436227628SJohn Levon
113536227628SJohn Levon proxy->dma_pgsizes = pgsizes;
113636227628SJohn Levon return true;
113736227628SJohn Levon }
113836227628SJohn Levon
check_max_dma(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)113936227628SJohn Levon static bool check_max_dma(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
114036227628SJohn Levon {
114136227628SJohn Levon QNum *qn = qobject_to(QNum, qobj);
114236227628SJohn Levon uint64_t max_dma;
114336227628SJohn Levon
114436227628SJohn Levon if (qn == NULL || !qnum_get_try_uint(qn, &max_dma)) {
114536227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_MAP_MAX);
114636227628SJohn Levon return false;
114736227628SJohn Levon }
114836227628SJohn Levon
114936227628SJohn Levon /* can only lower it */
115036227628SJohn Levon if (max_dma > VFIO_USER_DEF_MAP_MAX) {
115136227628SJohn Levon error_setg(errp, "%s too large", VFIO_USER_CAP_MAP_MAX);
115236227628SJohn Levon return false;
115336227628SJohn Levon }
115436227628SJohn Levon
115536227628SJohn Levon proxy->max_dma = max_dma;
115636227628SJohn Levon return true;
115736227628SJohn Levon }
115836227628SJohn Levon
check_migr(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)115936227628SJohn Levon static bool check_migr(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
116036227628SJohn Levon {
116136227628SJohn Levon QDict *qdict = qobject_to(QDict, qobj);
116236227628SJohn Levon
116336227628SJohn Levon if (qdict == NULL) {
116436227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_MAX_FDS);
116536227628SJohn Levon return true;
116636227628SJohn Levon }
116736227628SJohn Levon return caps_parse(proxy, qdict, caps_migr, errp);
116836227628SJohn Levon }
116936227628SJohn Levon
check_multi(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)1170*1a0c32a9SJohn Levon static bool check_multi(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
1171*1a0c32a9SJohn Levon {
1172*1a0c32a9SJohn Levon QBool *qb = qobject_to(QBool, qobj);
1173*1a0c32a9SJohn Levon
1174*1a0c32a9SJohn Levon if (qb == NULL) {
1175*1a0c32a9SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP_MULTI);
1176*1a0c32a9SJohn Levon return false;
1177*1a0c32a9SJohn Levon }
1178*1a0c32a9SJohn Levon if (qbool_get_bool(qb)) {
1179*1a0c32a9SJohn Levon proxy->flags |= VFIO_PROXY_USE_MULTI;
1180*1a0c32a9SJohn Levon }
1181*1a0c32a9SJohn Levon return true;
1182*1a0c32a9SJohn Levon }
1183*1a0c32a9SJohn Levon
118436227628SJohn Levon static struct cap_entry caps_cap[] = {
118536227628SJohn Levon { VFIO_USER_CAP_MAX_FDS, check_max_fds },
118636227628SJohn Levon { VFIO_USER_CAP_MAX_XFER, check_max_xfer },
118736227628SJohn Levon { VFIO_USER_CAP_PGSIZES, check_pgsizes },
118836227628SJohn Levon { VFIO_USER_CAP_MAP_MAX, check_max_dma },
118936227628SJohn Levon { VFIO_USER_CAP_MIGR, check_migr },
1190*1a0c32a9SJohn Levon { VFIO_USER_CAP_MULTI, check_multi },
119136227628SJohn Levon { NULL }
119236227628SJohn Levon };
119336227628SJohn Levon
check_cap(VFIOUserProxy * proxy,QObject * qobj,Error ** errp)119436227628SJohn Levon static bool check_cap(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
119536227628SJohn Levon {
119636227628SJohn Levon QDict *qdict = qobject_to(QDict, qobj);
119736227628SJohn Levon
119836227628SJohn Levon if (qdict == NULL) {
119936227628SJohn Levon error_setg(errp, "malformed %s", VFIO_USER_CAP);
120036227628SJohn Levon return false;
120136227628SJohn Levon }
120236227628SJohn Levon return caps_parse(proxy, qdict, caps_cap, errp);
120336227628SJohn Levon }
120436227628SJohn Levon
120536227628SJohn Levon static struct cap_entry ver_0_0[] = {
120636227628SJohn Levon { VFIO_USER_CAP, check_cap },
120736227628SJohn Levon { NULL }
120836227628SJohn Levon };
120936227628SJohn Levon
caps_check(VFIOUserProxy * proxy,int minor,const char * caps,Error ** errp)121036227628SJohn Levon static bool caps_check(VFIOUserProxy *proxy, int minor, const char *caps,
121136227628SJohn Levon Error **errp)
121236227628SJohn Levon {
121336227628SJohn Levon QObject *qobj;
121436227628SJohn Levon QDict *qdict;
121536227628SJohn Levon bool ret;
121636227628SJohn Levon
121736227628SJohn Levon qobj = qobject_from_json(caps, NULL);
121836227628SJohn Levon if (qobj == NULL) {
121936227628SJohn Levon error_setg(errp, "malformed capabilities %s", caps);
122036227628SJohn Levon return false;
122136227628SJohn Levon }
122236227628SJohn Levon qdict = qobject_to(QDict, qobj);
122336227628SJohn Levon if (qdict == NULL) {
122436227628SJohn Levon error_setg(errp, "capabilities %s not an object", caps);
122536227628SJohn Levon qobject_unref(qobj);
122636227628SJohn Levon return false;
122736227628SJohn Levon }
122836227628SJohn Levon ret = caps_parse(proxy, qdict, ver_0_0, errp);
122936227628SJohn Levon
123036227628SJohn Levon qobject_unref(qobj);
123136227628SJohn Levon return ret;
123236227628SJohn Levon }
123336227628SJohn Levon
caps_json(void)123436227628SJohn Levon static GString *caps_json(void)
123536227628SJohn Levon {
123636227628SJohn Levon QDict *dict = qdict_new();
123736227628SJohn Levon QDict *capdict = qdict_new();
123836227628SJohn Levon QDict *migdict = qdict_new();
123936227628SJohn Levon GString *str;
124036227628SJohn Levon
124136227628SJohn Levon qdict_put_int(migdict, VFIO_USER_CAP_PGSIZE, VFIO_USER_DEF_PGSIZE);
124236227628SJohn Levon qdict_put_int(migdict, VFIO_USER_CAP_MAX_BITMAP, VFIO_USER_DEF_MAX_BITMAP);
124336227628SJohn Levon qdict_put_obj(capdict, VFIO_USER_CAP_MIGR, QOBJECT(migdict));
124436227628SJohn Levon
124536227628SJohn Levon qdict_put_int(capdict, VFIO_USER_CAP_MAX_FDS, VFIO_USER_MAX_MAX_FDS);
124636227628SJohn Levon qdict_put_int(capdict, VFIO_USER_CAP_MAX_XFER, VFIO_USER_DEF_MAX_XFER);
124736227628SJohn Levon qdict_put_int(capdict, VFIO_USER_CAP_PGSIZES, VFIO_USER_DEF_PGSIZE);
124836227628SJohn Levon qdict_put_int(capdict, VFIO_USER_CAP_MAP_MAX, VFIO_USER_DEF_MAP_MAX);
1249*1a0c32a9SJohn Levon qdict_put_bool(capdict, VFIO_USER_CAP_MULTI, true);
125036227628SJohn Levon
125136227628SJohn Levon qdict_put_obj(dict, VFIO_USER_CAP, QOBJECT(capdict));
125236227628SJohn Levon
125336227628SJohn Levon str = qobject_to_json(QOBJECT(dict));
125436227628SJohn Levon qobject_unref(dict);
125536227628SJohn Levon return str;
125636227628SJohn Levon }
125736227628SJohn Levon
vfio_user_validate_version(VFIOUserProxy * proxy,Error ** errp)125836227628SJohn Levon bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
125936227628SJohn Levon {
126036227628SJohn Levon g_autofree VFIOUserVersion *msgp = NULL;
126136227628SJohn Levon GString *caps;
126236227628SJohn Levon char *reply;
126336227628SJohn Levon int size, caplen;
126436227628SJohn Levon
126536227628SJohn Levon caps = caps_json();
126636227628SJohn Levon caplen = caps->len + 1;
126736227628SJohn Levon size = sizeof(*msgp) + caplen;
126836227628SJohn Levon msgp = g_malloc0(size);
126936227628SJohn Levon
127036227628SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_VERSION, size, 0);
127136227628SJohn Levon msgp->major = VFIO_USER_MAJOR_VER;
127236227628SJohn Levon msgp->minor = VFIO_USER_MINOR_VER;
127336227628SJohn Levon memcpy(&msgp->capabilities, caps->str, caplen);
127436227628SJohn Levon g_string_free(caps, true);
127536227628SJohn Levon trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
127636227628SJohn Levon
127736227628SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, errp)) {
127836227628SJohn Levon return false;
127936227628SJohn Levon }
128036227628SJohn Levon
128136227628SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) {
128236227628SJohn Levon error_setg_errno(errp, msgp->hdr.error_reply, "version reply");
128336227628SJohn Levon return false;
128436227628SJohn Levon }
128536227628SJohn Levon
128636227628SJohn Levon if (msgp->major != VFIO_USER_MAJOR_VER ||
128736227628SJohn Levon msgp->minor > VFIO_USER_MINOR_VER) {
128836227628SJohn Levon error_setg(errp, "incompatible server version");
128936227628SJohn Levon return false;
129036227628SJohn Levon }
129136227628SJohn Levon
129236227628SJohn Levon reply = msgp->capabilities;
129336227628SJohn Levon if (reply[msgp->hdr.size - sizeof(*msgp) - 1] != '\0') {
129436227628SJohn Levon error_setg(errp, "corrupt version reply");
129536227628SJohn Levon return false;
129636227628SJohn Levon }
129736227628SJohn Levon
129836227628SJohn Levon if (!caps_check(proxy, msgp->minor, reply, errp)) {
129936227628SJohn Levon return false;
130036227628SJohn Levon }
130136227628SJohn Levon
130236227628SJohn Levon trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
130336227628SJohn Levon return true;
130436227628SJohn Levon }
1305*1a0c32a9SJohn Levon
vfio_user_flush_multi(VFIOUserProxy * proxy)1306*1a0c32a9SJohn Levon void vfio_user_flush_multi(VFIOUserProxy *proxy)
1307*1a0c32a9SJohn Levon {
1308*1a0c32a9SJohn Levon VFIOUserMsg *msg;
1309*1a0c32a9SJohn Levon VFIOUserWRMulti *wm = proxy->wr_multi;
1310*1a0c32a9SJohn Levon Error *local_err = NULL;
1311*1a0c32a9SJohn Levon
1312*1a0c32a9SJohn Levon proxy->wr_multi = NULL;
1313*1a0c32a9SJohn Levon
1314*1a0c32a9SJohn Levon /* adjust size for actual # of writes */
1315*1a0c32a9SJohn Levon wm->hdr.size -= (VFIO_USER_MULTI_MAX - wm->wr_cnt) * sizeof(VFIOUserWROne);
1316*1a0c32a9SJohn Levon
1317*1a0c32a9SJohn Levon msg = vfio_user_getmsg(proxy, &wm->hdr, NULL);
1318*1a0c32a9SJohn Levon msg->id = wm->hdr.id;
1319*1a0c32a9SJohn Levon msg->rsize = 0;
1320*1a0c32a9SJohn Levon msg->type = VFIO_MSG_ASYNC;
1321*1a0c32a9SJohn Levon trace_vfio_user_wrmulti("flush", wm->wr_cnt);
1322*1a0c32a9SJohn Levon
1323*1a0c32a9SJohn Levon if (!vfio_user_send_queued(proxy, msg, &local_err)) {
1324*1a0c32a9SJohn Levon error_report_err(local_err);
1325*1a0c32a9SJohn Levon vfio_user_recycle(proxy, msg);
1326*1a0c32a9SJohn Levon }
1327*1a0c32a9SJohn Levon }
1328*1a0c32a9SJohn Levon
vfio_user_create_multi(VFIOUserProxy * proxy)1329*1a0c32a9SJohn Levon void vfio_user_create_multi(VFIOUserProxy *proxy)
1330*1a0c32a9SJohn Levon {
1331*1a0c32a9SJohn Levon VFIOUserWRMulti *wm;
1332*1a0c32a9SJohn Levon
1333*1a0c32a9SJohn Levon wm = g_malloc0(sizeof(*wm));
1334*1a0c32a9SJohn Levon vfio_user_request_msg(&wm->hdr, VFIO_USER_REGION_WRITE_MULTI,
1335*1a0c32a9SJohn Levon sizeof(*wm), VFIO_USER_NO_REPLY);
1336*1a0c32a9SJohn Levon proxy->wr_multi = wm;
1337*1a0c32a9SJohn Levon }
1338*1a0c32a9SJohn Levon
vfio_user_add_multi(VFIOUserProxy * proxy,uint8_t index,off_t offset,uint32_t count,void * data)1339*1a0c32a9SJohn Levon void vfio_user_add_multi(VFIOUserProxy *proxy, uint8_t index,
1340*1a0c32a9SJohn Levon off_t offset, uint32_t count, void *data)
1341*1a0c32a9SJohn Levon {
1342*1a0c32a9SJohn Levon VFIOUserWRMulti *wm = proxy->wr_multi;
1343*1a0c32a9SJohn Levon VFIOUserWROne *w1 = &wm->wrs[wm->wr_cnt];
1344*1a0c32a9SJohn Levon
1345*1a0c32a9SJohn Levon w1->offset = offset;
1346*1a0c32a9SJohn Levon w1->region = index;
1347*1a0c32a9SJohn Levon w1->count = count;
1348*1a0c32a9SJohn Levon memcpy(&w1->data, data, count);
1349*1a0c32a9SJohn Levon
1350*1a0c32a9SJohn Levon wm->wr_cnt++;
1351*1a0c32a9SJohn Levon trace_vfio_user_wrmulti("add", wm->wr_cnt);
1352*1a0c32a9SJohn Levon if (wm->wr_cnt == VFIO_USER_MULTI_MAX ||
1353*1a0c32a9SJohn Levon proxy->num_outgoing < VFIO_USER_OUT_LOW) {
1354*1a0c32a9SJohn Levon vfio_user_flush_multi(proxy);
1355*1a0c32a9SJohn Levon }
1356*1a0c32a9SJohn Levon }
1357