qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

mpqemu-link.c (6997B)


      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  */
     34 bool 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  */
     95 static 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 
    122 bool 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 
    156 copy_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 
    170 fail:
    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  */
    189 uint64_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 
    215 bool 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 }