qemu/hw/remote/mpqemu-link.c
<<
>>
Prefs
   1/*
   2 * Communication channel between QEMU and remote device process
   3 *
   4 * Copyright © 2018, 2021 Oracle and/or its affiliates.
   5 *
   6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   7 * See the COPYING file in the top-level directory.
   8 *
   9 */
  10
  11#include "qemu/osdep.h"
  12#include "qemu-common.h"
  13
  14#include "qemu/module.h"
  15#include "hw/remote/mpqemu-link.h"
  16#include "qapi/error.h"
  17#include "qemu/iov.h"
  18#include "qemu/error-report.h"
  19#include "qemu/main-loop.h"
  20#include "io/channel.h"
  21#include "sysemu/iothread.h"
  22#include "trace.h"
  23
  24/*
  25 * Send message over the ioc QIOChannel.
  26 * This function is safe to call from:
  27 * - main loop in co-routine context. Will block the main loop if not in
  28 *   co-routine context;
  29 * - vCPU thread with no co-routine context and if the channel is not part
  30 *   of the main loop handling;
  31 * - IOThread within co-routine context, outside of co-routine context
  32 *   will block IOThread;
  33 * Returns true if no errors were encountered, false otherwise.
  34 */
  35bool mpqemu_msg_send(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
  36{
  37    ERRP_GUARD();
  38    bool iolock = qemu_mutex_iothread_locked();
  39    bool iothread = qemu_in_iothread();
  40    struct iovec send[2] = {};
  41    int *fds = NULL;
  42    size_t nfds = 0;
  43    bool ret = false;
  44
  45    send[0].iov_base = msg;
  46    send[0].iov_len = MPQEMU_MSG_HDR_SIZE;
  47
  48    send[1].iov_base = (void *)&msg->data;
  49    send[1].iov_len = msg->size;
  50
  51    if (msg->num_fds) {
  52        nfds = msg->num_fds;
  53        fds = msg->fds;
  54    }
  55
  56    /*
  57     * Dont use in IOThread out of co-routine context as
  58     * it will block IOThread.
  59     */
  60    assert(qemu_in_coroutine() || !iothread);
  61
  62    /*
  63     * Skip unlocking/locking iothread lock when the IOThread is running
  64     * in co-routine context. Co-routine context is asserted above
  65     * for IOThread case.
  66     * Also skip lock handling while in a co-routine in the main context.
  67     */
  68    if (iolock && !iothread && !qemu_in_coroutine()) {
  69        qemu_mutex_unlock_iothread();
  70    }
  71
  72    if (!qio_channel_writev_full_all(ioc, send, G_N_ELEMENTS(send),
  73                                    fds, nfds, errp)) {
  74        ret = true;
  75    } else {
  76        trace_mpqemu_send_io_error(msg->cmd, msg->size, nfds);
  77    }
  78
  79    if (iolock && !iothread && !qemu_in_coroutine()) {
  80        /* See above comment why skip locking here. */
  81        qemu_mutex_lock_iothread();
  82    }
  83
  84    return ret;
  85}
  86
  87/*
  88 * Read message from the ioc QIOChannel.
  89 * This function is safe to call from:
  90 * - From main loop in co-routine context. Will block the main loop if not in
  91 *   co-routine context;
  92 * - From vCPU thread with no co-routine context and if the channel is not part
  93 *   of the main loop handling;
  94 * - From IOThread within co-routine context, outside of co-routine context
  95 *   will block IOThread;
  96 */
  97static ssize_t mpqemu_read(QIOChannel *ioc, void *buf, size_t len, int **fds,
  98                           size_t *nfds, Error **errp)
  99{
 100    ERRP_GUARD();
 101    struct iovec iov = { .iov_base = buf, .iov_len = len };
 102    bool iolock = qemu_mutex_iothread_locked();
 103    bool iothread = qemu_in_iothread();
 104    int ret = -1;
 105
 106    /*
 107     * Dont use in IOThread out of co-routine context as
 108     * it will block IOThread.
 109     */
 110    assert(qemu_in_coroutine() || !iothread);
 111
 112    if (iolock && !iothread && !qemu_in_coroutine()) {
 113        qemu_mutex_unlock_iothread();
 114    }
 115
 116    ret = qio_channel_readv_full_all_eof(ioc, &iov, 1, fds, nfds, errp);
 117
 118    if (iolock && !iothread && !qemu_in_coroutine()) {
 119        qemu_mutex_lock_iothread();
 120    }
 121
 122    return (ret <= 0) ? ret : iov.iov_len;
 123}
 124
 125bool mpqemu_msg_recv(MPQemuMsg *msg, QIOChannel *ioc, Error **errp)
 126{
 127    ERRP_GUARD();
 128    g_autofree int *fds = NULL;
 129    size_t nfds = 0;
 130    ssize_t len;
 131    bool ret = false;
 132
 133    len = mpqemu_read(ioc, msg, MPQEMU_MSG_HDR_SIZE, &fds, &nfds, errp);
 134    if (len <= 0) {
 135        goto fail;
 136    } else if (len != MPQEMU_MSG_HDR_SIZE) {
 137        error_setg(errp, "Message header corrupted");
 138        goto fail;
 139    }
 140
 141    if (msg->size > sizeof(msg->data)) {
 142        error_setg(errp, "Invalid size for message");
 143        goto fail;
 144    }
 145
 146    if (!msg->size) {
 147        goto copy_fds;
 148    }
 149
 150    len = mpqemu_read(ioc, &msg->data, msg->size, NULL, NULL, errp);
 151    if (len <= 0) {
 152        goto fail;
 153    }
 154    if (len != msg->size) {
 155        error_setg(errp, "Unable to read full message");
 156        goto fail;
 157    }
 158
 159copy_fds:
 160    msg->num_fds = nfds;
 161    if (nfds > G_N_ELEMENTS(msg->fds)) {
 162        error_setg(errp,
 163                   "Overflow error: received %zu fds, more than max of %d fds",
 164                   nfds, REMOTE_MAX_FDS);
 165        goto fail;
 166    }
 167    if (nfds) {
 168        memcpy(msg->fds, fds, nfds * sizeof(int));
 169    }
 170
 171    ret = true;
 172
 173fail:
 174    if (*errp) {
 175        trace_mpqemu_recv_io_error(msg->cmd, msg->size, nfds);
 176    }
 177    while (*errp && nfds) {
 178        close(fds[nfds - 1]);
 179        nfds--;
 180    }
 181
 182    return ret;
 183}
 184
 185/*
 186 * Send msg and wait for a reply with command code RET_MSG.
 187 * Returns the message received of size u64 or UINT64_MAX
 188 * on error.
 189 * Called from VCPU thread in non-coroutine context.
 190 * Used by the Proxy object to communicate to remote processes.
 191 */
 192uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
 193                                         Error **errp)
 194{
 195    ERRP_GUARD();
 196    MPQemuMsg msg_reply = {0};
 197    uint64_t ret = UINT64_MAX;
 198
 199    assert(!qemu_in_coroutine());
 200
 201    QEMU_LOCK_GUARD(&pdev->io_mutex);
 202    if (!mpqemu_msg_send(msg, pdev->ioc, errp)) {
 203        return ret;
 204    }
 205
 206    if (!mpqemu_msg_recv(&msg_reply, pdev->ioc, errp)) {
 207        return ret;
 208    }
 209
 210    if (!mpqemu_msg_valid(&msg_reply) || msg_reply.cmd != MPQEMU_CMD_RET) {
 211        error_setg(errp, "ERROR: Invalid reply received for command %d",
 212                         msg->cmd);
 213        return ret;
 214    }
 215
 216    return msg_reply.data.u64;
 217}
 218
 219bool mpqemu_msg_valid(MPQemuMsg *msg)
 220{
 221    if (msg->cmd >= MPQEMU_CMD_MAX && msg->cmd < 0) {
 222        return false;
 223    }
 224
 225    /* Verify FDs. */
 226    if (msg->num_fds >= REMOTE_MAX_FDS) {
 227        return false;
 228    }
 229
 230    if (msg->num_fds > 0) {
 231        for (int i = 0; i < msg->num_fds; i++) {
 232            if (fcntl(msg->fds[i], F_GETFL) == -1) {
 233                return false;
 234            }
 235        }
 236    }
 237
 238     /* Verify message specific fields. */
 239    switch (msg->cmd) {
 240    case MPQEMU_CMD_SYNC_SYSMEM:
 241        if (msg->num_fds == 0 || msg->size != sizeof(SyncSysmemMsg)) {
 242            return false;
 243        }
 244        break;
 245    case MPQEMU_CMD_PCI_CFGWRITE:
 246    case MPQEMU_CMD_PCI_CFGREAD:
 247        if (msg->size != sizeof(PciConfDataMsg)) {
 248            return false;
 249        }
 250        break;
 251    case MPQEMU_CMD_BAR_WRITE:
 252    case MPQEMU_CMD_BAR_READ:
 253        if ((msg->size != sizeof(BarAccessMsg)) || (msg->num_fds != 0)) {
 254            return false;
 255        }
 256        break;
 257    case MPQEMU_CMD_SET_IRQFD:
 258        if (msg->size || (msg->num_fds != 2)) {
 259            return false;
 260        }
 261        break;
 262    default:
 263        break;
 264    }
 265
 266    return true;
 267}
 268