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