13bdb738bSJohn Levon /* 23bdb738bSJohn Levon * vfio protocol over a UNIX socket device handling. 33bdb738bSJohn Levon * 43bdb738bSJohn Levon * Copyright © 2018, 2021 Oracle and/or its affiliates. 53bdb738bSJohn Levon * 63bdb738bSJohn Levon * SPDX-License-Identifier: GPL-2.0-or-later 73bdb738bSJohn Levon */ 83bdb738bSJohn Levon 93bdb738bSJohn Levon #include "qemu/osdep.h" 103bdb738bSJohn Levon #include "qapi/error.h" 113bdb738bSJohn Levon #include "qemu/error-report.h" 12*1a0c32a9SJohn Levon #include "qemu/lockable.h" 13*1a0c32a9SJohn Levon #include "qemu/thread.h" 143bdb738bSJohn Levon 153bdb738bSJohn Levon #include "hw/vfio-user/device.h" 163bdb738bSJohn Levon #include "hw/vfio-user/trace.h" 173bdb738bSJohn Levon 183bdb738bSJohn Levon /* 193bdb738bSJohn Levon * These are to defend against a malign server trying 203bdb738bSJohn Levon * to force us to run out of memory. 213bdb738bSJohn Levon */ 223bdb738bSJohn Levon #define VFIO_USER_MAX_REGIONS 100 233bdb738bSJohn Levon #define VFIO_USER_MAX_IRQS 50 243bdb738bSJohn Levon 253bdb738bSJohn Levon bool vfio_user_get_device_info(VFIOUserProxy *proxy, 263bdb738bSJohn Levon struct vfio_device_info *info, Error **errp) 273bdb738bSJohn Levon { 283bdb738bSJohn Levon VFIOUserDeviceInfo msg; 293bdb738bSJohn Levon uint32_t argsz = sizeof(msg) - sizeof(msg.hdr); 303bdb738bSJohn Levon 313bdb738bSJohn Levon memset(&msg, 0, sizeof(msg)); 323bdb738bSJohn Levon vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_INFO, sizeof(msg), 0); 333bdb738bSJohn Levon msg.argsz = argsz; 343bdb738bSJohn Levon 353bdb738bSJohn Levon if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, errp)) { 363bdb738bSJohn Levon return false; 373bdb738bSJohn Levon } 383bdb738bSJohn Levon 393bdb738bSJohn Levon if (msg.hdr.flags & VFIO_USER_ERROR) { 403bdb738bSJohn Levon error_setg_errno(errp, -msg.hdr.error_reply, 413bdb738bSJohn Levon "VFIO_USER_DEVICE_GET_INFO failed"); 423bdb738bSJohn Levon return false; 433bdb738bSJohn Levon } 443bdb738bSJohn Levon 453bdb738bSJohn Levon trace_vfio_user_get_info(msg.num_regions, msg.num_irqs); 463bdb738bSJohn Levon 473bdb738bSJohn Levon memcpy(info, &msg.argsz, argsz); 483bdb738bSJohn Levon 493bdb738bSJohn Levon /* defend against a malicious server */ 503bdb738bSJohn Levon if (info->num_regions > VFIO_USER_MAX_REGIONS || 513bdb738bSJohn Levon info->num_irqs > VFIO_USER_MAX_IRQS) { 523bdb738bSJohn Levon error_setg_errno(errp, EINVAL, "invalid reply"); 533bdb738bSJohn Levon return false; 543bdb738bSJohn Levon } 553bdb738bSJohn Levon 563bdb738bSJohn Levon return true; 573bdb738bSJohn Levon } 58667866d6SJohn Levon 5901923235SJohn Levon void vfio_user_device_reset(VFIOUserProxy *proxy) 6001923235SJohn Levon { 6101923235SJohn Levon Error *local_err = NULL; 6201923235SJohn Levon VFIOUserHdr hdr; 6301923235SJohn Levon 6401923235SJohn Levon vfio_user_request_msg(&hdr, VFIO_USER_DEVICE_RESET, sizeof(hdr), 0); 6501923235SJohn Levon 6601923235SJohn Levon if (!vfio_user_send_wait(proxy, &hdr, NULL, 0, &local_err)) { 6701923235SJohn Levon error_prepend(&local_err, "%s: ", __func__); 6801923235SJohn Levon error_report_err(local_err); 6901923235SJohn Levon return; 7001923235SJohn Levon } 7101923235SJohn Levon 7201923235SJohn Levon if (hdr.flags & VFIO_USER_ERROR) { 7301923235SJohn Levon error_printf("reset reply error %d\n", hdr.error_reply); 7401923235SJohn Levon } 7501923235SJohn Levon } 7601923235SJohn Levon 77667866d6SJohn Levon static int vfio_user_get_region_info(VFIOUserProxy *proxy, 78667866d6SJohn Levon struct vfio_region_info *info, 79667866d6SJohn Levon VFIOUserFDs *fds) 80667866d6SJohn Levon { 81667866d6SJohn Levon g_autofree VFIOUserRegionInfo *msgp = NULL; 82667866d6SJohn Levon Error *local_err = NULL; 83667866d6SJohn Levon uint32_t size; 84667866d6SJohn Levon 85667866d6SJohn Levon /* data returned can be larger than vfio_region_info */ 86667866d6SJohn Levon if (info->argsz < sizeof(*info)) { 87667866d6SJohn Levon error_printf("vfio_user_get_region_info argsz too small\n"); 88667866d6SJohn Levon return -E2BIG; 89667866d6SJohn Levon } 90667866d6SJohn Levon if (fds != NULL && fds->send_fds != 0) { 91667866d6SJohn Levon error_printf("vfio_user_get_region_info can't send FDs\n"); 92667866d6SJohn Levon return -EINVAL; 93667866d6SJohn Levon } 94667866d6SJohn Levon 95667866d6SJohn Levon size = info->argsz + sizeof(VFIOUserHdr); 96667866d6SJohn Levon msgp = g_malloc0(size); 97667866d6SJohn Levon 98667866d6SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_GET_REGION_INFO, 99667866d6SJohn Levon sizeof(*msgp), 0); 100667866d6SJohn Levon msgp->argsz = info->argsz; 101667866d6SJohn Levon msgp->index = info->index; 102667866d6SJohn Levon 103667866d6SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, fds, size, &local_err)) { 104667866d6SJohn Levon error_prepend(&local_err, "%s: ", __func__); 105667866d6SJohn Levon error_report_err(local_err); 106667866d6SJohn Levon return -EFAULT; 107667866d6SJohn Levon } 108667866d6SJohn Levon 109667866d6SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 110667866d6SJohn Levon return -msgp->hdr.error_reply; 111667866d6SJohn Levon } 112667866d6SJohn Levon trace_vfio_user_get_region_info(msgp->index, msgp->flags, msgp->size); 113667866d6SJohn Levon 114667866d6SJohn Levon memcpy(info, &msgp->argsz, info->argsz); 11598a906d9SJohn Levon 11698a906d9SJohn Levon /* 11798a906d9SJohn Levon * If at least one region is directly mapped into the VM, then we can no 11898a906d9SJohn Levon * longer rely on the sequential nature of vfio-user request handling to 11998a906d9SJohn Levon * ensure that posted writes are completed before a subsequent read. In this 12098a906d9SJohn Levon * case, disable posted write support. This is a per-device property, not 12198a906d9SJohn Levon * per-region. 12298a906d9SJohn Levon */ 12398a906d9SJohn Levon if (info->flags & VFIO_REGION_INFO_FLAG_MMAP) { 12498a906d9SJohn Levon vfio_user_disable_posted_writes(proxy); 125667866d6SJohn Levon } 126667866d6SJohn Levon 12798a906d9SJohn Levon return 0; 12898a906d9SJohn Levon } 129667866d6SJohn Levon 130667866d6SJohn Levon static int vfio_user_device_io_get_region_info(VFIODevice *vbasedev, 131667866d6SJohn Levon struct vfio_region_info *info, 132667866d6SJohn Levon int *fd) 133667866d6SJohn Levon { 134667866d6SJohn Levon VFIOUserFDs fds = { 0, 1, fd}; 135667866d6SJohn Levon int ret; 136667866d6SJohn Levon 137667866d6SJohn Levon if (info->index > vbasedev->num_regions) { 138667866d6SJohn Levon return -EINVAL; 139667866d6SJohn Levon } 140667866d6SJohn Levon 141667866d6SJohn Levon ret = vfio_user_get_region_info(vbasedev->proxy, info, &fds); 142667866d6SJohn Levon if (ret) { 143667866d6SJohn Levon return ret; 144667866d6SJohn Levon } 145667866d6SJohn Levon 146667866d6SJohn Levon /* cap_offset in valid area */ 147667866d6SJohn Levon if ((info->flags & VFIO_REGION_INFO_FLAG_CAPS) && 148667866d6SJohn Levon (info->cap_offset < sizeof(*info) || info->cap_offset > info->argsz)) { 149667866d6SJohn Levon return -EINVAL; 150667866d6SJohn Levon } 151667866d6SJohn Levon 152667866d6SJohn Levon return 0; 153667866d6SJohn Levon } 154667866d6SJohn Levon 155ca1add16SJohn Levon static int vfio_user_device_io_get_irq_info(VFIODevice *vbasedev, 156ca1add16SJohn Levon struct vfio_irq_info *info) 157ca1add16SJohn Levon { 158ca1add16SJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 159ca1add16SJohn Levon Error *local_err = NULL; 160ca1add16SJohn Levon VFIOUserIRQInfo msg; 161ca1add16SJohn Levon 162ca1add16SJohn Levon memset(&msg, 0, sizeof(msg)); 163ca1add16SJohn Levon vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_IRQ_INFO, 164ca1add16SJohn Levon sizeof(msg), 0); 165ca1add16SJohn Levon msg.argsz = info->argsz; 166ca1add16SJohn Levon msg.index = info->index; 167ca1add16SJohn Levon 168ca1add16SJohn Levon if (!vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, &local_err)) { 169ca1add16SJohn Levon error_prepend(&local_err, "%s: ", __func__); 170ca1add16SJohn Levon error_report_err(local_err); 171ca1add16SJohn Levon return -EFAULT; 172ca1add16SJohn Levon } 173ca1add16SJohn Levon 174ca1add16SJohn Levon if (msg.hdr.flags & VFIO_USER_ERROR) { 175ca1add16SJohn Levon return -msg.hdr.error_reply; 176ca1add16SJohn Levon } 177ca1add16SJohn Levon trace_vfio_user_get_irq_info(msg.index, msg.flags, msg.count); 178ca1add16SJohn Levon 179ca1add16SJohn Levon memcpy(info, &msg.argsz, sizeof(*info)); 180ca1add16SJohn Levon return 0; 181ca1add16SJohn Levon } 182ca1add16SJohn Levon 183ca1add16SJohn Levon static int irq_howmany(int *fdp, uint32_t cur, uint32_t max) 184ca1add16SJohn Levon { 185ca1add16SJohn Levon int n = 0; 186ca1add16SJohn Levon 187ca1add16SJohn Levon if (fdp[cur] != -1) { 188ca1add16SJohn Levon do { 189ca1add16SJohn Levon n++; 190ca1add16SJohn Levon } while (n < max && fdp[cur + n] != -1); 191ca1add16SJohn Levon } else { 192ca1add16SJohn Levon do { 193ca1add16SJohn Levon n++; 194ca1add16SJohn Levon } while (n < max && fdp[cur + n] == -1); 195ca1add16SJohn Levon } 196ca1add16SJohn Levon 197ca1add16SJohn Levon return n; 198ca1add16SJohn Levon } 199ca1add16SJohn Levon 200ca1add16SJohn Levon static int vfio_user_device_io_set_irqs(VFIODevice *vbasedev, 201ca1add16SJohn Levon struct vfio_irq_set *irq) 202ca1add16SJohn Levon { 203ca1add16SJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 204ca1add16SJohn Levon g_autofree VFIOUserIRQSet *msgp = NULL; 205ca1add16SJohn Levon uint32_t size, nfds, send_fds, sent_fds, max; 206ca1add16SJohn Levon Error *local_err = NULL; 207ca1add16SJohn Levon 208ca1add16SJohn Levon if (irq->argsz < sizeof(*irq)) { 209ca1add16SJohn Levon error_printf("vfio_user_set_irqs argsz too small\n"); 210ca1add16SJohn Levon return -EINVAL; 211ca1add16SJohn Levon } 212ca1add16SJohn Levon 213ca1add16SJohn Levon /* 214ca1add16SJohn Levon * Handle simple case 215ca1add16SJohn Levon */ 216ca1add16SJohn Levon if ((irq->flags & VFIO_IRQ_SET_DATA_EVENTFD) == 0) { 217ca1add16SJohn Levon size = sizeof(VFIOUserHdr) + irq->argsz; 218ca1add16SJohn Levon msgp = g_malloc0(size); 219ca1add16SJohn Levon 220ca1add16SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, size, 0); 221ca1add16SJohn Levon msgp->argsz = irq->argsz; 222ca1add16SJohn Levon msgp->flags = irq->flags; 223ca1add16SJohn Levon msgp->index = irq->index; 224ca1add16SJohn Levon msgp->start = irq->start; 225ca1add16SJohn Levon msgp->count = irq->count; 226ca1add16SJohn Levon trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count, 227ca1add16SJohn Levon msgp->flags); 228ca1add16SJohn Levon 229ca1add16SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) { 230ca1add16SJohn Levon error_prepend(&local_err, "%s: ", __func__); 231ca1add16SJohn Levon error_report_err(local_err); 232ca1add16SJohn Levon return -EFAULT; 233ca1add16SJohn Levon } 234ca1add16SJohn Levon 235ca1add16SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 236ca1add16SJohn Levon return -msgp->hdr.error_reply; 237ca1add16SJohn Levon } 238ca1add16SJohn Levon 239ca1add16SJohn Levon return 0; 240ca1add16SJohn Levon } 241ca1add16SJohn Levon 242ca1add16SJohn Levon /* 243ca1add16SJohn Levon * Calculate the number of FDs to send 244ca1add16SJohn Levon * and adjust argsz 245ca1add16SJohn Levon */ 246ca1add16SJohn Levon nfds = (irq->argsz - sizeof(*irq)) / sizeof(int); 247ca1add16SJohn Levon irq->argsz = sizeof(*irq); 248ca1add16SJohn Levon msgp = g_malloc0(sizeof(*msgp)); 249ca1add16SJohn Levon /* 250ca1add16SJohn Levon * Send in chunks if over max_send_fds 251ca1add16SJohn Levon */ 252ca1add16SJohn Levon for (sent_fds = 0; nfds > sent_fds; sent_fds += send_fds) { 253ca1add16SJohn Levon VFIOUserFDs *arg_fds, loop_fds; 254ca1add16SJohn Levon 255ca1add16SJohn Levon /* must send all valid FDs or all invalid FDs in single msg */ 256ca1add16SJohn Levon max = nfds - sent_fds; 257ca1add16SJohn Levon if (max > proxy->max_send_fds) { 258ca1add16SJohn Levon max = proxy->max_send_fds; 259ca1add16SJohn Levon } 260ca1add16SJohn Levon send_fds = irq_howmany((int *)irq->data, sent_fds, max); 261ca1add16SJohn Levon 262ca1add16SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_DEVICE_SET_IRQS, 263ca1add16SJohn Levon sizeof(*msgp), 0); 264ca1add16SJohn Levon msgp->argsz = irq->argsz; 265ca1add16SJohn Levon msgp->flags = irq->flags; 266ca1add16SJohn Levon msgp->index = irq->index; 267ca1add16SJohn Levon msgp->start = irq->start + sent_fds; 268ca1add16SJohn Levon msgp->count = send_fds; 269ca1add16SJohn Levon trace_vfio_user_set_irqs(msgp->index, msgp->start, msgp->count, 270ca1add16SJohn Levon msgp->flags); 271ca1add16SJohn Levon 272ca1add16SJohn Levon loop_fds.send_fds = send_fds; 273ca1add16SJohn Levon loop_fds.recv_fds = 0; 274ca1add16SJohn Levon loop_fds.fds = (int *)irq->data + sent_fds; 275ca1add16SJohn Levon arg_fds = loop_fds.fds[0] != -1 ? &loop_fds : NULL; 276ca1add16SJohn Levon 277ca1add16SJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, arg_fds, 0, &local_err)) { 278ca1add16SJohn Levon error_prepend(&local_err, "%s: ", __func__); 279ca1add16SJohn Levon error_report_err(local_err); 280ca1add16SJohn Levon return -EFAULT; 281ca1add16SJohn Levon } 282ca1add16SJohn Levon 283ca1add16SJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 284ca1add16SJohn Levon return -msgp->hdr.error_reply; 285ca1add16SJohn Levon } 286ca1add16SJohn Levon } 287ca1add16SJohn Levon 288ca1add16SJohn Levon return 0; 289ca1add16SJohn Levon } 290ca1add16SJohn Levon 2911ed50fcbSJohn Levon static int vfio_user_device_io_region_read(VFIODevice *vbasedev, uint8_t index, 2921ed50fcbSJohn Levon off_t off, uint32_t count, 2931ed50fcbSJohn Levon void *data) 2941ed50fcbSJohn Levon { 2951ed50fcbSJohn Levon g_autofree VFIOUserRegionRW *msgp = NULL; 2961ed50fcbSJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 2971ed50fcbSJohn Levon int size = sizeof(*msgp) + count; 2981ed50fcbSJohn Levon Error *local_err = NULL; 2991ed50fcbSJohn Levon 3001ed50fcbSJohn Levon if (count > proxy->max_xfer_size) { 3011ed50fcbSJohn Levon return -EINVAL; 3021ed50fcbSJohn Levon } 3031ed50fcbSJohn Levon 3041ed50fcbSJohn Levon msgp = g_malloc0(size); 3051ed50fcbSJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_READ, sizeof(*msgp), 0); 3061ed50fcbSJohn Levon msgp->offset = off; 3071ed50fcbSJohn Levon msgp->region = index; 3081ed50fcbSJohn Levon msgp->count = count; 3091ed50fcbSJohn Levon trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count); 3101ed50fcbSJohn Levon 3111ed50fcbSJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, size, &local_err)) { 3121ed50fcbSJohn Levon error_prepend(&local_err, "%s: ", __func__); 3131ed50fcbSJohn Levon error_report_err(local_err); 3141ed50fcbSJohn Levon return -EFAULT; 3151ed50fcbSJohn Levon } 3161ed50fcbSJohn Levon 3171ed50fcbSJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 3181ed50fcbSJohn Levon return -msgp->hdr.error_reply; 3191ed50fcbSJohn Levon } else if (msgp->count > count) { 3201ed50fcbSJohn Levon return -E2BIG; 3211ed50fcbSJohn Levon } else { 3221ed50fcbSJohn Levon memcpy(data, &msgp->data, msgp->count); 3231ed50fcbSJohn Levon } 3241ed50fcbSJohn Levon 3251ed50fcbSJohn Levon return msgp->count; 3261ed50fcbSJohn Levon } 3271ed50fcbSJohn Levon 32898a906d9SJohn Levon /* 32998a906d9SJohn Levon * If this is a posted write, and VFIO_PROXY_NO_POST is not set, then we are OK 33098a906d9SJohn Levon * to send the write to the socket without waiting for the server's reply: 33198a906d9SJohn Levon * a subsequent read (of any region) will not pass the posted write, as all 33298a906d9SJohn Levon * messages are handled sequentially. 33398a906d9SJohn Levon */ 3341ed50fcbSJohn Levon static int vfio_user_device_io_region_write(VFIODevice *vbasedev, uint8_t index, 3351ed50fcbSJohn Levon off_t off, unsigned count, 3361ed50fcbSJohn Levon void *data, bool post) 3371ed50fcbSJohn Levon { 33898a906d9SJohn Levon VFIOUserRegionRW *msgp = NULL; 3391ed50fcbSJohn Levon VFIOUserProxy *proxy = vbasedev->proxy; 3401ed50fcbSJohn Levon int size = sizeof(*msgp) + count; 3411ed50fcbSJohn Levon Error *local_err = NULL; 342*1a0c32a9SJohn Levon bool can_multi; 34398a906d9SJohn Levon int flags = 0; 3441ed50fcbSJohn Levon int ret; 3451ed50fcbSJohn Levon 3461ed50fcbSJohn Levon if (count > proxy->max_xfer_size) { 3471ed50fcbSJohn Levon return -EINVAL; 3481ed50fcbSJohn Levon } 3491ed50fcbSJohn Levon 35098a906d9SJohn Levon if (proxy->flags & VFIO_PROXY_NO_POST) { 35198a906d9SJohn Levon post = false; 35298a906d9SJohn Levon } 35398a906d9SJohn Levon 35498a906d9SJohn Levon if (post) { 35598a906d9SJohn Levon flags |= VFIO_USER_NO_REPLY; 35698a906d9SJohn Levon } 35798a906d9SJohn Levon 358*1a0c32a9SJohn Levon /* write eligible to be in a WRITE_MULTI msg ? */ 359*1a0c32a9SJohn Levon can_multi = (proxy->flags & VFIO_PROXY_USE_MULTI) && post && 360*1a0c32a9SJohn Levon count <= VFIO_USER_MULTI_DATA; 361*1a0c32a9SJohn Levon 362*1a0c32a9SJohn Levon /* 363*1a0c32a9SJohn Levon * This should be a rare case, so first check without the lock, 364*1a0c32a9SJohn Levon * if we're wrong, vfio_send_queued() will flush any posted writes 365*1a0c32a9SJohn Levon * we missed here 366*1a0c32a9SJohn Levon */ 367*1a0c32a9SJohn Levon if (proxy->wr_multi != NULL || 368*1a0c32a9SJohn Levon (proxy->num_outgoing > VFIO_USER_OUT_HIGH && can_multi)) { 369*1a0c32a9SJohn Levon 370*1a0c32a9SJohn Levon /* 371*1a0c32a9SJohn Levon * re-check with lock 372*1a0c32a9SJohn Levon * 373*1a0c32a9SJohn Levon * if already building a WRITE_MULTI msg, 374*1a0c32a9SJohn Levon * add this one if possible else flush pending before 375*1a0c32a9SJohn Levon * sending the current one 376*1a0c32a9SJohn Levon * 377*1a0c32a9SJohn Levon * else if outgoing queue is over the highwater, 378*1a0c32a9SJohn Levon * start a new WRITE_MULTI message 379*1a0c32a9SJohn Levon */ 380*1a0c32a9SJohn Levon WITH_QEMU_LOCK_GUARD(&proxy->lock) { 381*1a0c32a9SJohn Levon if (proxy->wr_multi != NULL) { 382*1a0c32a9SJohn Levon if (can_multi) { 383*1a0c32a9SJohn Levon vfio_user_add_multi(proxy, index, off, count, data); 384*1a0c32a9SJohn Levon return count; 385*1a0c32a9SJohn Levon } 386*1a0c32a9SJohn Levon vfio_user_flush_multi(proxy); 387*1a0c32a9SJohn Levon } else if (proxy->num_outgoing > VFIO_USER_OUT_HIGH && can_multi) { 388*1a0c32a9SJohn Levon vfio_user_create_multi(proxy); 389*1a0c32a9SJohn Levon vfio_user_add_multi(proxy, index, off, count, data); 390*1a0c32a9SJohn Levon return count; 391*1a0c32a9SJohn Levon } 392*1a0c32a9SJohn Levon } 393*1a0c32a9SJohn Levon } 394*1a0c32a9SJohn Levon 3951ed50fcbSJohn Levon msgp = g_malloc0(size); 39698a906d9SJohn Levon vfio_user_request_msg(&msgp->hdr, VFIO_USER_REGION_WRITE, size, flags); 3971ed50fcbSJohn Levon msgp->offset = off; 3981ed50fcbSJohn Levon msgp->region = index; 3991ed50fcbSJohn Levon msgp->count = count; 4001ed50fcbSJohn Levon memcpy(&msgp->data, data, count); 4011ed50fcbSJohn Levon trace_vfio_user_region_rw(msgp->region, msgp->offset, msgp->count); 4021ed50fcbSJohn Levon 40398a906d9SJohn Levon /* async send will free msg after it's sent */ 40498a906d9SJohn Levon if (post) { 40598a906d9SJohn Levon if (!vfio_user_send_async(proxy, &msgp->hdr, NULL, &local_err)) { 40698a906d9SJohn Levon error_prepend(&local_err, "%s: ", __func__); 40798a906d9SJohn Levon error_report_err(local_err); 40898a906d9SJohn Levon return -EFAULT; 40998a906d9SJohn Levon } 41098a906d9SJohn Levon 41198a906d9SJohn Levon return count; 41298a906d9SJohn Levon } 4131ed50fcbSJohn Levon 4141ed50fcbSJohn Levon if (!vfio_user_send_wait(proxy, &msgp->hdr, NULL, 0, &local_err)) { 4151ed50fcbSJohn Levon error_prepend(&local_err, "%s: ", __func__); 4161ed50fcbSJohn Levon error_report_err(local_err); 41798a906d9SJohn Levon g_free(msgp); 4181ed50fcbSJohn Levon return -EFAULT; 4191ed50fcbSJohn Levon } 4201ed50fcbSJohn Levon 4211ed50fcbSJohn Levon if (msgp->hdr.flags & VFIO_USER_ERROR) { 4221ed50fcbSJohn Levon ret = -msgp->hdr.error_reply; 4231ed50fcbSJohn Levon } else { 4241ed50fcbSJohn Levon ret = count; 4251ed50fcbSJohn Levon } 4261ed50fcbSJohn Levon 42798a906d9SJohn Levon g_free(msgp); 4281ed50fcbSJohn Levon return ret; 4291ed50fcbSJohn Levon } 4301ed50fcbSJohn Levon 431667866d6SJohn Levon /* 432667866d6SJohn Levon * Socket-based io_ops 433667866d6SJohn Levon */ 434667866d6SJohn Levon VFIODeviceIOOps vfio_user_device_io_ops_sock = { 435667866d6SJohn Levon .get_region_info = vfio_user_device_io_get_region_info, 436ca1add16SJohn Levon .get_irq_info = vfio_user_device_io_get_irq_info, 437ca1add16SJohn Levon .set_irqs = vfio_user_device_io_set_irqs, 4381ed50fcbSJohn Levon .region_read = vfio_user_device_io_region_read, 4391ed50fcbSJohn Levon .region_write = vfio_user_device_io_region_write, 4401ed50fcbSJohn Levon 441667866d6SJohn Levon }; 442