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

rocker_desc.c (8276B)


      1/*
      2 * QEMU rocker switch emulation - Descriptor ring support
      3 *
      4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
      5 *
      6 * This program is free software; you can redistribute it and/or modify
      7 * it under the terms of the GNU General Public License as published by
      8 * the Free Software Foundation; either version 2 of the License, or
      9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     14 * GNU General Public License for more details.
     15 */
     16
     17#include "qemu/osdep.h"
     18#include "net/net.h"
     19#include "hw/pci/pci.h"
     20
     21#include "rocker.h"
     22#include "rocker_hw.h"
     23#include "rocker_desc.h"
     24
     25struct desc_ring {
     26    hwaddr base_addr;
     27    uint32_t size;
     28    uint32_t head;
     29    uint32_t tail;
     30    uint32_t ctrl;
     31    uint32_t credits;
     32    Rocker *r;
     33    DescInfo *info;
     34    int index;
     35    desc_ring_consume *consume;
     36    unsigned msix_vector;
     37};
     38
     39struct desc_info {
     40    DescRing *ring;
     41    RockerDesc desc;
     42    char *buf;
     43    size_t buf_size;
     44};
     45
     46uint16_t desc_buf_size(DescInfo *info)
     47{
     48    return le16_to_cpu(info->desc.buf_size);
     49}
     50
     51uint16_t desc_tlv_size(DescInfo *info)
     52{
     53    return le16_to_cpu(info->desc.tlv_size);
     54}
     55
     56char *desc_get_buf(DescInfo *info, bool read_only)
     57{
     58    PCIDevice *dev = PCI_DEVICE(info->ring->r);
     59    size_t size = read_only ? le16_to_cpu(info->desc.tlv_size) :
     60                              le16_to_cpu(info->desc.buf_size);
     61
     62    if (size > info->buf_size) {
     63        info->buf = g_realloc(info->buf, size);
     64        info->buf_size = size;
     65    }
     66
     67    pci_dma_read(dev, le64_to_cpu(info->desc.buf_addr), info->buf, size);
     68
     69    return info->buf;
     70}
     71
     72int desc_set_buf(DescInfo *info, size_t tlv_size)
     73{
     74    PCIDevice *dev = PCI_DEVICE(info->ring->r);
     75
     76    if (tlv_size > info->buf_size) {
     77        DPRINTF("ERROR: trying to write more to desc buf than it "
     78                "can hold buf_size %zu tlv_size %zu\n",
     79                info->buf_size, tlv_size);
     80        return -ROCKER_EMSGSIZE;
     81    }
     82
     83    info->desc.tlv_size = cpu_to_le16(tlv_size);
     84    pci_dma_write(dev, le64_to_cpu(info->desc.buf_addr), info->buf, tlv_size);
     85
     86    return ROCKER_OK;
     87}
     88
     89DescRing *desc_get_ring(DescInfo *info)
     90{
     91    return info->ring;
     92}
     93
     94int desc_ring_index(DescRing *ring)
     95{
     96    return ring->index;
     97}
     98
     99static bool desc_ring_empty(DescRing *ring)
    100{
    101    return ring->head == ring->tail;
    102}
    103
    104bool desc_ring_set_base_addr(DescRing *ring, uint64_t base_addr)
    105{
    106    if (base_addr & 0x7) {
    107        DPRINTF("ERROR: ring[%d] desc base addr (0x" TARGET_FMT_plx
    108                ") not 8-byte aligned\n", ring->index, base_addr);
    109        return false;
    110    }
    111
    112    ring->base_addr = base_addr;
    113
    114    return true;
    115}
    116
    117uint64_t desc_ring_get_base_addr(DescRing *ring)
    118{
    119    return ring->base_addr;
    120}
    121
    122bool desc_ring_set_size(DescRing *ring, uint32_t size)
    123{
    124    int i;
    125
    126    if (size < 2 || size > 0x10000 || (size & (size - 1))) {
    127        DPRINTF("ERROR: ring[%d] size (%d) not a power of 2 "
    128                "or in range [2, 64K]\n", ring->index, size);
    129        return false;
    130    }
    131
    132    for (i = 0; i < ring->size; i++) {
    133        g_free(ring->info[i].buf);
    134    }
    135
    136    ring->size = size;
    137    ring->head = ring->tail = 0;
    138
    139    ring->info = g_renew(DescInfo, ring->info, size);
    140
    141    memset(ring->info, 0, size * sizeof(DescInfo));
    142
    143    for (i = 0; i < size; i++) {
    144        ring->info[i].ring = ring;
    145    }
    146
    147    return true;
    148}
    149
    150uint32_t desc_ring_get_size(DescRing *ring)
    151{
    152    return ring->size;
    153}
    154
    155static DescInfo *desc_read(DescRing *ring, uint32_t index)
    156{
    157    PCIDevice *dev = PCI_DEVICE(ring->r);
    158    DescInfo *info = &ring->info[index];
    159    hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
    160
    161    pci_dma_read(dev, addr, &info->desc, sizeof(info->desc));
    162
    163    return info;
    164}
    165
    166static void desc_write(DescRing *ring, uint32_t index)
    167{
    168    PCIDevice *dev = PCI_DEVICE(ring->r);
    169    DescInfo *info = &ring->info[index];
    170    hwaddr addr = ring->base_addr + (sizeof(RockerDesc) * index);
    171
    172    pci_dma_write(dev, addr, &info->desc, sizeof(info->desc));
    173}
    174
    175static bool desc_ring_base_addr_check(DescRing *ring)
    176{
    177    if (!ring->base_addr) {
    178        DPRINTF("ERROR: ring[%d] not-initialized desc base address!\n",
    179                ring->index);
    180        return false;
    181    }
    182    return true;
    183}
    184
    185static DescInfo *__desc_ring_fetch_desc(DescRing *ring)
    186{
    187    return desc_read(ring, ring->tail);
    188}
    189
    190DescInfo *desc_ring_fetch_desc(DescRing *ring)
    191{
    192    if (desc_ring_empty(ring) || !desc_ring_base_addr_check(ring)) {
    193        return NULL;
    194    }
    195
    196    return desc_read(ring, ring->tail);
    197}
    198
    199static bool __desc_ring_post_desc(DescRing *ring, int err)
    200{
    201    uint16_t comp_err = 0x8000 | (uint16_t)-err;
    202    DescInfo *info = &ring->info[ring->tail];
    203
    204    info->desc.comp_err = cpu_to_le16(comp_err);
    205    desc_write(ring, ring->tail);
    206    ring->tail = (ring->tail + 1) % ring->size;
    207
    208    /* return true if starting credit count */
    209
    210    return ring->credits++ == 0;
    211}
    212
    213bool desc_ring_post_desc(DescRing *ring, int err)
    214{
    215    if (desc_ring_empty(ring)) {
    216        DPRINTF("ERROR: ring[%d] trying to post desc to empty ring\n",
    217                ring->index);
    218        return false;
    219    }
    220
    221    if (!desc_ring_base_addr_check(ring)) {
    222        return false;
    223    }
    224
    225    return __desc_ring_post_desc(ring, err);
    226}
    227
    228static bool ring_pump(DescRing *ring)
    229{
    230    DescInfo *info;
    231    bool primed = false;
    232    int err;
    233
    234    /* If the ring has a consumer, call consumer for each
    235     * desc starting at tail and stopping when tail reaches
    236     * head (the empty ring condition).
    237     */
    238
    239    if (ring->consume) {
    240        while (ring->head != ring->tail) {
    241            info = __desc_ring_fetch_desc(ring);
    242            err = ring->consume(ring->r, info);
    243            if (__desc_ring_post_desc(ring, err)) {
    244                primed = true;
    245            }
    246        }
    247    }
    248
    249    return primed;
    250}
    251
    252bool desc_ring_set_head(DescRing *ring, uint32_t new)
    253{
    254    uint32_t tail = ring->tail;
    255    uint32_t head = ring->head;
    256
    257    if (!desc_ring_base_addr_check(ring)) {
    258        return false;
    259    }
    260
    261    if (new >= ring->size) {
    262        DPRINTF("ERROR: trying to set head (%d) past ring[%d] size (%d)\n",
    263                new, ring->index, ring->size);
    264        return false;
    265    }
    266
    267    if (((head < tail) && ((new >= tail) || (new < head))) ||
    268        ((head > tail) && ((new >= tail) && (new < head)))) {
    269        DPRINTF("ERROR: trying to wrap ring[%d] "
    270                "(head %d, tail %d, new head %d)\n",
    271                ring->index, head, tail, new);
    272        return false;
    273    }
    274
    275    if (new == ring->head) {
    276        DPRINTF("WARNING: setting head (%d) to current head position\n", new);
    277    }
    278
    279    ring->head = new;
    280
    281    return ring_pump(ring);
    282}
    283
    284uint32_t desc_ring_get_head(DescRing *ring)
    285{
    286    return ring->head;
    287}
    288
    289uint32_t desc_ring_get_tail(DescRing *ring)
    290{
    291    return ring->tail;
    292}
    293
    294void desc_ring_set_ctrl(DescRing *ring, uint32_t val)
    295{
    296    if (val & ROCKER_DMA_DESC_CTRL_RESET) {
    297        DPRINTF("ring[%d] resetting\n", ring->index);
    298        desc_ring_reset(ring);
    299    }
    300}
    301
    302bool desc_ring_ret_credits(DescRing *ring, uint32_t credits)
    303{
    304    if (credits > ring->credits) {
    305        DPRINTF("ERROR: trying to return more credits (%d) "
    306                "than are outstanding (%d)\n", credits, ring->credits);
    307        ring->credits = 0;
    308        return false;
    309    }
    310
    311    ring->credits -= credits;
    312
    313    /* return true if credits are still outstanding */
    314
    315    return ring->credits > 0;
    316}
    317
    318uint32_t desc_ring_get_credits(DescRing *ring)
    319{
    320    return ring->credits;
    321}
    322
    323void desc_ring_set_consume(DescRing *ring, desc_ring_consume *consume,
    324                           unsigned vector)
    325{
    326    ring->consume = consume;
    327    ring->msix_vector = vector;
    328}
    329
    330unsigned desc_ring_get_msix_vector(DescRing *ring)
    331{
    332    return ring->msix_vector;
    333}
    334
    335DescRing *desc_ring_alloc(Rocker *r, int index)
    336{
    337    DescRing *ring;
    338
    339    ring = g_new0(DescRing, 1);
    340
    341    ring->r = r;
    342    ring->index = index;
    343
    344    return ring;
    345}
    346
    347void desc_ring_free(DescRing *ring)
    348{
    349    g_free(ring->info);
    350    g_free(ring);
    351}
    352
    353void desc_ring_reset(DescRing *ring)
    354{
    355    ring->base_addr = 0;
    356    ring->size = 0;
    357    ring->head = 0;
    358    ring->tail = 0;
    359    ring->ctrl = 0;
    360    ring->credits = 0;
    361}