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