cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

xen-9p-backend.c (15878B)


      1/*
      2 * Xen 9p backend
      3 *
      4 * Copyright Aporeto 2017
      5 *
      6 * Authors:
      7 *  Stefano Stabellini <stefano@aporeto.com>
      8 *
      9 */
     10
     11/*
     12 * Not so fast! You might want to read the 9p developer docs first:
     13 * https://wiki.qemu.org/Documentation/9p
     14 */
     15
     16#include "qemu/osdep.h"
     17
     18#include "hw/9pfs/9p.h"
     19#include "hw/xen/xen-legacy-backend.h"
     20#include "hw/9pfs/xen-9pfs.h"
     21#include "qapi/error.h"
     22#include "qemu/config-file.h"
     23#include "qemu/main-loop.h"
     24#include "qemu/option.h"
     25#include "fsdev/qemu-fsdev.h"
     26
     27#define VERSIONS "1"
     28#define MAX_RINGS 8
     29#define MAX_RING_ORDER 9
     30
     31typedef struct Xen9pfsRing {
     32    struct Xen9pfsDev *priv;
     33
     34    int ref;
     35    xenevtchn_handle   *evtchndev;
     36    int evtchn;
     37    int local_port;
     38    int ring_order;
     39    struct xen_9pfs_data_intf *intf;
     40    unsigned char *data;
     41    struct xen_9pfs_data ring;
     42
     43    struct iovec *sg;
     44    QEMUBH *bh;
     45    Coroutine *co;
     46
     47    /* local copies, so that we can read/write PDU data directly from
     48     * the ring */
     49    RING_IDX out_cons, out_size, in_cons;
     50    bool inprogress;
     51} Xen9pfsRing;
     52
     53typedef struct Xen9pfsDev {
     54    struct XenLegacyDevice xendev;  /* must be first */
     55    V9fsState state;
     56    char *path;
     57    char *security_model;
     58    char *tag;
     59    char *id;
     60
     61    int num_rings;
     62    Xen9pfsRing *rings;
     63} Xen9pfsDev;
     64
     65static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev);
     66
     67static void xen_9pfs_in_sg(Xen9pfsRing *ring,
     68                           struct iovec *in_sg,
     69                           int *num,
     70                           uint32_t idx,
     71                           uint32_t size)
     72{
     73    RING_IDX cons, prod, masked_prod, masked_cons;
     74
     75    cons = ring->intf->in_cons;
     76    prod = ring->intf->in_prod;
     77    xen_rmb();
     78    masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
     79    masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
     80
     81    if (masked_prod < masked_cons) {
     82        in_sg[0].iov_base = ring->ring.in + masked_prod;
     83        in_sg[0].iov_len = masked_cons - masked_prod;
     84        *num = 1;
     85    } else {
     86        in_sg[0].iov_base = ring->ring.in + masked_prod;
     87        in_sg[0].iov_len = XEN_FLEX_RING_SIZE(ring->ring_order) - masked_prod;
     88        in_sg[1].iov_base = ring->ring.in;
     89        in_sg[1].iov_len = masked_cons;
     90        *num = 2;
     91    }
     92}
     93
     94static void xen_9pfs_out_sg(Xen9pfsRing *ring,
     95                            struct iovec *out_sg,
     96                            int *num,
     97                            uint32_t idx)
     98{
     99    RING_IDX cons, prod, masked_prod, masked_cons;
    100
    101    cons = ring->intf->out_cons;
    102    prod = ring->intf->out_prod;
    103    xen_rmb();
    104    masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
    105    masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
    106
    107    if (masked_cons < masked_prod) {
    108        out_sg[0].iov_base = ring->ring.out + masked_cons;
    109        out_sg[0].iov_len = ring->out_size;
    110        *num = 1;
    111    } else {
    112        if (ring->out_size >
    113            (XEN_FLEX_RING_SIZE(ring->ring_order) - masked_cons)) {
    114            out_sg[0].iov_base = ring->ring.out + masked_cons;
    115            out_sg[0].iov_len = XEN_FLEX_RING_SIZE(ring->ring_order) -
    116                                masked_cons;
    117            out_sg[1].iov_base = ring->ring.out;
    118            out_sg[1].iov_len = ring->out_size -
    119                                (XEN_FLEX_RING_SIZE(ring->ring_order) -
    120                                 masked_cons);
    121            *num = 2;
    122        } else {
    123            out_sg[0].iov_base = ring->ring.out + masked_cons;
    124            out_sg[0].iov_len = ring->out_size;
    125            *num = 1;
    126        }
    127    }
    128}
    129
    130static ssize_t xen_9pfs_pdu_vmarshal(V9fsPDU *pdu,
    131                                     size_t offset,
    132                                     const char *fmt,
    133                                     va_list ap)
    134{
    135    Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
    136    struct iovec in_sg[2];
    137    int num;
    138    ssize_t ret;
    139
    140    xen_9pfs_in_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
    141                   in_sg, &num, pdu->idx, ROUND_UP(offset + 128, 512));
    142
    143    ret = v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
    144    if (ret < 0) {
    145        xen_pv_printf(&xen_9pfs->xendev, 0,
    146                      "Failed to encode VirtFS reply type %d\n",
    147                      pdu->id + 1);
    148        xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
    149        xen_9pfs_disconnect(&xen_9pfs->xendev);
    150    }
    151    return ret;
    152}
    153
    154static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
    155                                       size_t offset,
    156                                       const char *fmt,
    157                                       va_list ap)
    158{
    159    Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
    160    struct iovec out_sg[2];
    161    int num;
    162    ssize_t ret;
    163
    164    xen_9pfs_out_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
    165                    out_sg, &num, pdu->idx);
    166
    167    ret = v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
    168    if (ret < 0) {
    169        xen_pv_printf(&xen_9pfs->xendev, 0,
    170                      "Failed to decode VirtFS request type %d\n", pdu->id);
    171        xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
    172        xen_9pfs_disconnect(&xen_9pfs->xendev);
    173    }
    174    return ret;
    175}
    176
    177static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
    178                                           struct iovec **piov,
    179                                           unsigned int *pniov,
    180                                           size_t size)
    181{
    182    Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
    183    Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
    184    int num;
    185
    186    g_free(ring->sg);
    187
    188    ring->sg = g_new0(struct iovec, 2);
    189    xen_9pfs_out_sg(ring, ring->sg, &num, pdu->idx);
    190    *piov = ring->sg;
    191    *pniov = num;
    192}
    193
    194static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
    195                                          struct iovec **piov,
    196                                          unsigned int *pniov,
    197                                          size_t size)
    198{
    199    Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
    200    Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
    201    int num;
    202    size_t buf_size;
    203
    204    g_free(ring->sg);
    205
    206    ring->sg = g_new0(struct iovec, 2);
    207    ring->co = qemu_coroutine_self();
    208    /* make sure other threads see ring->co changes before continuing */
    209    smp_wmb();
    210
    211again:
    212    xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
    213    buf_size = iov_size(ring->sg, num);
    214    if (buf_size  < size) {
    215        qemu_coroutine_yield();
    216        goto again;
    217    }
    218    ring->co = NULL;
    219    /* make sure other threads see ring->co changes before continuing */
    220    smp_wmb();
    221
    222    *piov = ring->sg;
    223    *pniov = num;
    224}
    225
    226static void xen_9pfs_push_and_notify(V9fsPDU *pdu)
    227{
    228    RING_IDX prod;
    229    Xen9pfsDev *priv = container_of(pdu->s, Xen9pfsDev, state);
    230    Xen9pfsRing *ring = &priv->rings[pdu->tag % priv->num_rings];
    231
    232    g_free(ring->sg);
    233    ring->sg = NULL;
    234
    235    ring->intf->out_cons = ring->out_cons;
    236    xen_wmb();
    237
    238    prod = ring->intf->in_prod;
    239    xen_rmb();
    240    ring->intf->in_prod = prod + pdu->size;
    241    xen_wmb();
    242
    243    ring->inprogress = false;
    244    xenevtchn_notify(ring->evtchndev, ring->local_port);
    245
    246    qemu_bh_schedule(ring->bh);
    247}
    248
    249static const V9fsTransport xen_9p_transport = {
    250    .pdu_vmarshal = xen_9pfs_pdu_vmarshal,
    251    .pdu_vunmarshal = xen_9pfs_pdu_vunmarshal,
    252    .init_in_iov_from_pdu = xen_9pfs_init_in_iov_from_pdu,
    253    .init_out_iov_from_pdu = xen_9pfs_init_out_iov_from_pdu,
    254    .push_and_notify = xen_9pfs_push_and_notify,
    255};
    256
    257static int xen_9pfs_init(struct XenLegacyDevice *xendev)
    258{
    259    return 0;
    260}
    261
    262static int xen_9pfs_receive(Xen9pfsRing *ring)
    263{
    264    P9MsgHeader h;
    265    RING_IDX cons, prod, masked_prod, masked_cons, queued;
    266    V9fsPDU *pdu;
    267
    268    if (ring->inprogress) {
    269        return 0;
    270    }
    271
    272    cons = ring->intf->out_cons;
    273    prod = ring->intf->out_prod;
    274    xen_rmb();
    275
    276    queued = xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order));
    277    if (queued < sizeof(h)) {
    278        return 0;
    279    }
    280    ring->inprogress = true;
    281
    282    masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
    283    masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
    284
    285    xen_9pfs_read_packet((uint8_t *) &h, ring->ring.out, sizeof(h),
    286                         masked_prod, &masked_cons,
    287                         XEN_FLEX_RING_SIZE(ring->ring_order));
    288    if (queued < le32_to_cpu(h.size_le)) {
    289        return 0;
    290    }
    291
    292    /* cannot fail, because we only handle one request per ring at a time */
    293    pdu = pdu_alloc(&ring->priv->state);
    294    ring->out_size = le32_to_cpu(h.size_le);
    295    ring->out_cons = cons + le32_to_cpu(h.size_le);
    296
    297    pdu_submit(pdu, &h);
    298
    299    return 0;
    300}
    301
    302static void xen_9pfs_bh(void *opaque)
    303{
    304    Xen9pfsRing *ring = opaque;
    305    bool wait;
    306
    307again:
    308    wait = ring->co != NULL && qemu_coroutine_entered(ring->co);
    309    /* paired with the smb_wmb barriers in xen_9pfs_init_in_iov_from_pdu */
    310    smp_rmb();
    311    if (wait) {
    312        cpu_relax();
    313        goto again;
    314    }
    315
    316    if (ring->co != NULL) {
    317        qemu_coroutine_enter_if_inactive(ring->co);
    318    }
    319    xen_9pfs_receive(ring);
    320}
    321
    322static void xen_9pfs_evtchn_event(void *opaque)
    323{
    324    Xen9pfsRing *ring = opaque;
    325    evtchn_port_t port;
    326
    327    port = xenevtchn_pending(ring->evtchndev);
    328    xenevtchn_unmask(ring->evtchndev, port);
    329
    330    qemu_bh_schedule(ring->bh);
    331}
    332
    333static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
    334{
    335    Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
    336    int i;
    337
    338    for (i = 0; i < xen_9pdev->num_rings; i++) {
    339        if (xen_9pdev->rings[i].evtchndev != NULL) {
    340            qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
    341                    NULL, NULL, NULL);
    342            xenevtchn_unbind(xen_9pdev->rings[i].evtchndev,
    343                             xen_9pdev->rings[i].local_port);
    344            xen_9pdev->rings[i].evtchndev = NULL;
    345        }
    346    }
    347}
    348
    349static int xen_9pfs_free(struct XenLegacyDevice *xendev)
    350{
    351    Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
    352    int i;
    353
    354    if (xen_9pdev->rings[0].evtchndev != NULL) {
    355        xen_9pfs_disconnect(xendev);
    356    }
    357
    358    for (i = 0; i < xen_9pdev->num_rings; i++) {
    359        if (xen_9pdev->rings[i].data != NULL) {
    360            xen_be_unmap_grant_refs(&xen_9pdev->xendev,
    361                                    xen_9pdev->rings[i].data,
    362                                    (1 << xen_9pdev->rings[i].ring_order));
    363        }
    364        if (xen_9pdev->rings[i].intf != NULL) {
    365            xen_be_unmap_grant_refs(&xen_9pdev->xendev,
    366                                    xen_9pdev->rings[i].intf,
    367                                    1);
    368        }
    369        if (xen_9pdev->rings[i].bh != NULL) {
    370            qemu_bh_delete(xen_9pdev->rings[i].bh);
    371        }
    372    }
    373
    374    g_free(xen_9pdev->id);
    375    g_free(xen_9pdev->tag);
    376    g_free(xen_9pdev->path);
    377    g_free(xen_9pdev->security_model);
    378    g_free(xen_9pdev->rings);
    379    return 0;
    380}
    381
    382static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
    383{
    384    Error *err = NULL;
    385    int i;
    386    Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
    387    V9fsState *s = &xen_9pdev->state;
    388    QemuOpts *fsdev;
    389
    390    if (xenstore_read_fe_int(&xen_9pdev->xendev, "num-rings",
    391                             &xen_9pdev->num_rings) == -1 ||
    392        xen_9pdev->num_rings > MAX_RINGS || xen_9pdev->num_rings < 1) {
    393        return -1;
    394    }
    395
    396    xen_9pdev->rings = g_new0(Xen9pfsRing, xen_9pdev->num_rings);
    397    for (i = 0; i < xen_9pdev->num_rings; i++) {
    398        char *str;
    399        int ring_order;
    400
    401        xen_9pdev->rings[i].priv = xen_9pdev;
    402        xen_9pdev->rings[i].evtchn = -1;
    403        xen_9pdev->rings[i].local_port = -1;
    404
    405        str = g_strdup_printf("ring-ref%u", i);
    406        if (xenstore_read_fe_int(&xen_9pdev->xendev, str,
    407                                 &xen_9pdev->rings[i].ref) == -1) {
    408            g_free(str);
    409            goto out;
    410        }
    411        g_free(str);
    412        str = g_strdup_printf("event-channel-%u", i);
    413        if (xenstore_read_fe_int(&xen_9pdev->xendev, str,
    414                                 &xen_9pdev->rings[i].evtchn) == -1) {
    415            g_free(str);
    416            goto out;
    417        }
    418        g_free(str);
    419
    420        xen_9pdev->rings[i].intf =
    421            xen_be_map_grant_ref(&xen_9pdev->xendev,
    422                                 xen_9pdev->rings[i].ref,
    423                                 PROT_READ | PROT_WRITE);
    424        if (!xen_9pdev->rings[i].intf) {
    425            goto out;
    426        }
    427        ring_order = xen_9pdev->rings[i].intf->ring_order;
    428        if (ring_order > MAX_RING_ORDER) {
    429            goto out;
    430        }
    431        xen_9pdev->rings[i].ring_order = ring_order;
    432        xen_9pdev->rings[i].data =
    433            xen_be_map_grant_refs(&xen_9pdev->xendev,
    434                                  xen_9pdev->rings[i].intf->ref,
    435                                  (1 << ring_order),
    436                                  PROT_READ | PROT_WRITE);
    437        if (!xen_9pdev->rings[i].data) {
    438            goto out;
    439        }
    440        xen_9pdev->rings[i].ring.in = xen_9pdev->rings[i].data;
    441        xen_9pdev->rings[i].ring.out = xen_9pdev->rings[i].data +
    442                                       XEN_FLEX_RING_SIZE(ring_order);
    443
    444        xen_9pdev->rings[i].bh = qemu_bh_new(xen_9pfs_bh, &xen_9pdev->rings[i]);
    445        xen_9pdev->rings[i].out_cons = 0;
    446        xen_9pdev->rings[i].out_size = 0;
    447        xen_9pdev->rings[i].inprogress = false;
    448
    449
    450        xen_9pdev->rings[i].evtchndev = xenevtchn_open(NULL, 0);
    451        if (xen_9pdev->rings[i].evtchndev == NULL) {
    452            goto out;
    453        }
    454        qemu_set_cloexec(xenevtchn_fd(xen_9pdev->rings[i].evtchndev));
    455        xen_9pdev->rings[i].local_port = xenevtchn_bind_interdomain
    456                                            (xen_9pdev->rings[i].evtchndev,
    457                                             xendev->dom,
    458                                             xen_9pdev->rings[i].evtchn);
    459        if (xen_9pdev->rings[i].local_port == -1) {
    460            xen_pv_printf(xendev, 0,
    461                          "xenevtchn_bind_interdomain failed port=%d\n",
    462                          xen_9pdev->rings[i].evtchn);
    463            goto out;
    464        }
    465        xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
    466        qemu_set_fd_handler(xenevtchn_fd(xen_9pdev->rings[i].evtchndev),
    467                xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings[i]);
    468    }
    469
    470    xen_9pdev->security_model = xenstore_read_be_str(xendev, "security_model");
    471    xen_9pdev->path = xenstore_read_be_str(xendev, "path");
    472    xen_9pdev->id = s->fsconf.fsdev_id =
    473        g_strdup_printf("xen9p%d", xendev->dev);
    474    xen_9pdev->tag = s->fsconf.tag = xenstore_read_fe_str(xendev, "tag");
    475    fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
    476            s->fsconf.tag,
    477            1, NULL);
    478    qemu_opt_set(fsdev, "fsdriver", "local", NULL);
    479    qemu_opt_set(fsdev, "path", xen_9pdev->path, NULL);
    480    qemu_opt_set(fsdev, "security_model", xen_9pdev->security_model, NULL);
    481    qemu_opts_set_id(fsdev, s->fsconf.fsdev_id);
    482    qemu_fsdev_add(fsdev, &err);
    483    if (err) {
    484        error_report_err(err);
    485    }
    486    v9fs_device_realize_common(s, &xen_9p_transport, NULL);
    487
    488    return 0;
    489
    490out:
    491    xen_9pfs_free(xendev);
    492    return -1;
    493}
    494
    495static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
    496{
    497    xenstore_write_be_str(xendev, "versions", VERSIONS);
    498    xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
    499    xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
    500}
    501
    502struct XenDevOps xen_9pfs_ops = {
    503    .size       = sizeof(Xen9pfsDev),
    504    .flags      = DEVOPS_FLAG_NEED_GNTDEV,
    505    .alloc      = xen_9pfs_alloc,
    506    .init       = xen_9pfs_init,
    507    .initialise = xen_9pfs_connect,
    508    .disconnect = xen_9pfs_disconnect,
    509    .free       = xen_9pfs_free,
    510};