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

etsec.c (13172B)


      1/*
      2 * QEMU Freescale eTSEC Emulator
      3 *
      4 * Copyright (c) 2011-2013 AdaCore
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25/*
     26 * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
     27 */
     28
     29#include "qemu/osdep.h"
     30#include "qemu-common.h"
     31#include "hw/sysbus.h"
     32#include "hw/irq.h"
     33#include "hw/ptimer.h"
     34#include "hw/qdev-properties.h"
     35#include "etsec.h"
     36#include "registers.h"
     37#include "qapi/error.h"
     38#include "qemu/log.h"
     39#include "qemu/module.h"
     40
     41/* #define HEX_DUMP */
     42/* #define DEBUG_REGISTER */
     43
     44#ifdef DEBUG_REGISTER
     45static const int debug_etsec = 1;
     46#else
     47static const int debug_etsec;
     48#endif
     49
     50#define DPRINTF(fmt, ...) do {                 \
     51    if (debug_etsec) {                         \
     52        qemu_log(fmt , ## __VA_ARGS__);        \
     53    }                                          \
     54    } while (0)
     55
     56/* call after any change to IEVENT or IMASK */
     57void etsec_update_irq(eTSEC *etsec)
     58{
     59    uint32_t ievent = etsec->regs[IEVENT].value;
     60    uint32_t imask  = etsec->regs[IMASK].value;
     61    uint32_t active = ievent & imask;
     62
     63    int tx  = !!(active & IEVENT_TX_MASK);
     64    int rx  = !!(active & IEVENT_RX_MASK);
     65    int err = !!(active & IEVENT_ERR_MASK);
     66
     67    DPRINTF("%s IRQ ievent=%"PRIx32" imask=%"PRIx32" %c%c%c",
     68            __func__, ievent, imask,
     69            tx  ? 'T' : '_',
     70            rx  ? 'R' : '_',
     71            err ? 'E' : '_');
     72
     73    qemu_set_irq(etsec->tx_irq, tx);
     74    qemu_set_irq(etsec->rx_irq, rx);
     75    qemu_set_irq(etsec->err_irq, err);
     76}
     77
     78static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
     79{
     80    eTSEC          *etsec     = opaque;
     81    uint32_t        reg_index = addr / 4;
     82    eTSEC_Register *reg       = NULL;
     83    uint32_t        ret       = 0x0;
     84
     85    assert(reg_index < ETSEC_REG_NUMBER);
     86
     87    reg = &etsec->regs[reg_index];
     88
     89
     90    switch (reg->access) {
     91    case ACC_WO:
     92        ret = 0x00000000;
     93        break;
     94
     95    case ACC_RW:
     96    case ACC_W1C:
     97    case ACC_RO:
     98    default:
     99        ret = reg->value;
    100        break;
    101    }
    102
    103    DPRINTF("Read  0x%08x @ 0x" TARGET_FMT_plx
    104            "                            : %s (%s)\n",
    105            ret, addr, reg->name, reg->desc);
    106
    107    return ret;
    108}
    109
    110static void write_tstat(eTSEC          *etsec,
    111                        eTSEC_Register *reg,
    112                        uint32_t        reg_index,
    113                        uint32_t        value)
    114{
    115    int i = 0;
    116
    117    for (i = 0; i < 8; i++) {
    118        /* Check THLTi flag in TSTAT */
    119        if (value & (1 << (31 - i))) {
    120            etsec_walk_tx_ring(etsec, i);
    121        }
    122    }
    123
    124    /* Write 1 to clear */
    125    reg->value &= ~value;
    126}
    127
    128static void write_rstat(eTSEC          *etsec,
    129                        eTSEC_Register *reg,
    130                        uint32_t        reg_index,
    131                        uint32_t        value)
    132{
    133    int i = 0;
    134
    135    for (i = 0; i < 8; i++) {
    136        /* Check QHLTi flag in RSTAT */
    137        if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
    138            etsec_walk_rx_ring(etsec, i);
    139        }
    140    }
    141
    142    /* Write 1 to clear */
    143    reg->value &= ~value;
    144}
    145
    146static void write_tbasex(eTSEC          *etsec,
    147                         eTSEC_Register *reg,
    148                         uint32_t        reg_index,
    149                         uint32_t        value)
    150{
    151    reg->value = value & ~0x7;
    152
    153    /* Copy this value in the ring's TxBD pointer */
    154    etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
    155}
    156
    157static void write_rbasex(eTSEC          *etsec,
    158                         eTSEC_Register *reg,
    159                         uint32_t        reg_index,
    160                         uint32_t        value)
    161{
    162    reg->value = value & ~0x7;
    163
    164    /* Copy this value in the ring's RxBD pointer */
    165    etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
    166}
    167
    168static void write_dmactrl(eTSEC          *etsec,
    169                          eTSEC_Register *reg,
    170                          uint32_t        reg_index,
    171                          uint32_t        value)
    172{
    173    reg->value = value;
    174
    175    if (value & DMACTRL_GRS) {
    176
    177        if (etsec->rx_buffer_len != 0) {
    178            /* Graceful receive stop delayed until end of frame */
    179        } else {
    180            /* Graceful receive stop now */
    181            etsec->regs[IEVENT].value |= IEVENT_GRSC;
    182            etsec_update_irq(etsec);
    183        }
    184    }
    185
    186    if (value & DMACTRL_GTS) {
    187
    188        if (etsec->tx_buffer_len != 0) {
    189            /* Graceful transmit stop delayed until end of frame */
    190        } else {
    191            /* Graceful transmit stop now */
    192            etsec->regs[IEVENT].value |= IEVENT_GTSC;
    193            etsec_update_irq(etsec);
    194        }
    195    }
    196
    197    if (!(value & DMACTRL_WOP)) {
    198        /* Start polling */
    199        ptimer_transaction_begin(etsec->ptimer);
    200        ptimer_stop(etsec->ptimer);
    201        ptimer_set_count(etsec->ptimer, 1);
    202        ptimer_run(etsec->ptimer, 1);
    203        ptimer_transaction_commit(etsec->ptimer);
    204    }
    205}
    206
    207static void etsec_write(void     *opaque,
    208                        hwaddr    addr,
    209                        uint64_t  value,
    210                        unsigned  size)
    211{
    212    eTSEC          *etsec     = opaque;
    213    uint32_t        reg_index = addr / 4;
    214    eTSEC_Register *reg       = NULL;
    215    uint32_t        before    = 0x0;
    216
    217    assert(reg_index < ETSEC_REG_NUMBER);
    218
    219    reg = &etsec->regs[reg_index];
    220    before = reg->value;
    221
    222    switch (reg_index) {
    223    case IEVENT:
    224        /* Write 1 to clear */
    225        reg->value &= ~value;
    226
    227        etsec_update_irq(etsec);
    228        break;
    229
    230    case IMASK:
    231        reg->value = value;
    232
    233        etsec_update_irq(etsec);
    234        break;
    235
    236    case DMACTRL:
    237        write_dmactrl(etsec, reg, reg_index, value);
    238        break;
    239
    240    case TSTAT:
    241        write_tstat(etsec, reg, reg_index, value);
    242        break;
    243
    244    case RSTAT:
    245        write_rstat(etsec, reg, reg_index, value);
    246        break;
    247
    248    case TBASE0 ... TBASE7:
    249        write_tbasex(etsec, reg, reg_index, value);
    250        break;
    251
    252    case RBASE0 ... RBASE7:
    253        write_rbasex(etsec, reg, reg_index, value);
    254        break;
    255
    256    case MIIMCFG ... MIIMIND:
    257        etsec_write_miim(etsec, reg, reg_index, value);
    258        break;
    259
    260    default:
    261        /* Default handling */
    262        switch (reg->access) {
    263
    264        case ACC_RW:
    265        case ACC_WO:
    266            reg->value = value;
    267            break;
    268
    269        case ACC_W1C:
    270            reg->value &= ~value;
    271            break;
    272
    273        case ACC_RO:
    274        default:
    275            /* Read Only or Unknown register */
    276            break;
    277        }
    278    }
    279
    280    DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
    281            " val:0x%08x->0x%08x : %s (%s)\n",
    282            (unsigned int)value, addr, before, reg->value,
    283            reg->name, reg->desc);
    284}
    285
    286static const MemoryRegionOps etsec_ops = {
    287    .read = etsec_read,
    288    .write = etsec_write,
    289    .endianness = DEVICE_NATIVE_ENDIAN,
    290    .impl = {
    291        .min_access_size = 4,
    292        .max_access_size = 4,
    293    },
    294};
    295
    296static void etsec_timer_hit(void *opaque)
    297{
    298    eTSEC *etsec = opaque;
    299
    300    ptimer_stop(etsec->ptimer);
    301
    302    if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
    303
    304        if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
    305            etsec_walk_tx_ring(etsec, 0);
    306        }
    307        ptimer_set_count(etsec->ptimer, 1);
    308        ptimer_run(etsec->ptimer, 1);
    309    }
    310}
    311
    312static void etsec_reset(DeviceState *d)
    313{
    314    eTSEC *etsec = ETSEC_COMMON(d);
    315    int i = 0;
    316    int reg_index = 0;
    317
    318    /* Default value for all registers */
    319    for (i = 0; i < ETSEC_REG_NUMBER; i++) {
    320        etsec->regs[i].name   = "Reserved";
    321        etsec->regs[i].desc   = "";
    322        etsec->regs[i].access = ACC_UNKNOWN;
    323        etsec->regs[i].value  = 0x00000000;
    324    }
    325
    326    /* Set-up known registers */
    327    for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
    328
    329        reg_index = eTSEC_registers_def[i].offset / 4;
    330
    331        etsec->regs[reg_index].name   = eTSEC_registers_def[i].name;
    332        etsec->regs[reg_index].desc   = eTSEC_registers_def[i].desc;
    333        etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
    334        etsec->regs[reg_index].value  = eTSEC_registers_def[i].reset;
    335    }
    336
    337    etsec->tx_buffer     = NULL;
    338    etsec->tx_buffer_len = 0;
    339    etsec->rx_buffer     = NULL;
    340    etsec->rx_buffer_len = 0;
    341
    342    etsec->phy_status =
    343        MII_SR_EXTENDED_CAPS    | MII_SR_LINK_STATUS   | MII_SR_AUTONEG_CAPS  |
    344        MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
    345        MII_SR_EXTENDED_STATUS  | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
    346        MII_SR_10T_HD_CAPS      | MII_SR_10T_FD_CAPS   | MII_SR_100X_HD_CAPS  |
    347        MII_SR_100X_FD_CAPS     | MII_SR_100T4_CAPS;
    348
    349    etsec_update_irq(etsec);
    350}
    351
    352static ssize_t etsec_receive(NetClientState *nc,
    353                             const uint8_t  *buf,
    354                             size_t          size)
    355{
    356    ssize_t ret;
    357    eTSEC *etsec = qemu_get_nic_opaque(nc);
    358
    359#if defined(HEX_DUMP)
    360    fprintf(stderr, "%s receive size:%zd\n", nc->name, size);
    361    qemu_hexdump(stderr, "", buf, size);
    362#endif
    363    /* Flush is unnecessary as are already in receiving path */
    364    etsec->need_flush = false;
    365    ret = etsec_rx_ring_write(etsec, buf, size);
    366    if (ret == 0) {
    367        /* The packet will be queued, let's flush it when buffer is available
    368         * again. */
    369        etsec->need_flush = true;
    370    }
    371    return ret;
    372}
    373
    374
    375static void etsec_set_link_status(NetClientState *nc)
    376{
    377    eTSEC *etsec = qemu_get_nic_opaque(nc);
    378
    379    etsec_miim_link_status(etsec, nc);
    380}
    381
    382static NetClientInfo net_etsec_info = {
    383    .type = NET_CLIENT_DRIVER_NIC,
    384    .size = sizeof(NICState),
    385    .receive = etsec_receive,
    386    .link_status_changed = etsec_set_link_status,
    387};
    388
    389static void etsec_realize(DeviceState *dev, Error **errp)
    390{
    391    eTSEC        *etsec = ETSEC_COMMON(dev);
    392
    393    etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
    394                              object_get_typename(OBJECT(dev)), dev->id, etsec);
    395    qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
    396
    397    etsec->ptimer = ptimer_init(etsec_timer_hit, etsec, PTIMER_POLICY_DEFAULT);
    398    ptimer_transaction_begin(etsec->ptimer);
    399    ptimer_set_freq(etsec->ptimer, 100);
    400    ptimer_transaction_commit(etsec->ptimer);
    401}
    402
    403static void etsec_instance_init(Object *obj)
    404{
    405    eTSEC        *etsec = ETSEC_COMMON(obj);
    406    SysBusDevice *sbd   = SYS_BUS_DEVICE(obj);
    407
    408    memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
    409                          "eTSEC", 0x1000);
    410    sysbus_init_mmio(sbd, &etsec->io_area);
    411
    412    sysbus_init_irq(sbd, &etsec->tx_irq);
    413    sysbus_init_irq(sbd, &etsec->rx_irq);
    414    sysbus_init_irq(sbd, &etsec->err_irq);
    415}
    416
    417static Property etsec_properties[] = {
    418    DEFINE_NIC_PROPERTIES(eTSEC, conf),
    419    DEFINE_PROP_END_OF_LIST(),
    420};
    421
    422static void etsec_class_init(ObjectClass *klass, void *data)
    423{
    424    DeviceClass *dc = DEVICE_CLASS(klass);
    425
    426    dc->realize = etsec_realize;
    427    dc->reset = etsec_reset;
    428    device_class_set_props(dc, etsec_properties);
    429    /* Supported by ppce500 machine */
    430    dc->user_creatable = true;
    431}
    432
    433static TypeInfo etsec_info = {
    434    .name                  = TYPE_ETSEC_COMMON,
    435    .parent                = TYPE_SYS_BUS_DEVICE,
    436    .instance_size         = sizeof(eTSEC),
    437    .class_init            = etsec_class_init,
    438    .instance_init         = etsec_instance_init,
    439};
    440
    441static void etsec_register_types(void)
    442{
    443    type_register_static(&etsec_info);
    444}
    445
    446type_init(etsec_register_types)
    447
    448DeviceState *etsec_create(hwaddr         base,
    449                          MemoryRegion * mr,
    450                          NICInfo      * nd,
    451                          qemu_irq       tx_irq,
    452                          qemu_irq       rx_irq,
    453                          qemu_irq       err_irq)
    454{
    455    DeviceState *dev;
    456
    457    dev = qdev_new("eTSEC");
    458    qdev_set_nic_properties(dev, nd);
    459    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
    460
    461    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
    462    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
    463    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
    464
    465    memory_region_add_subregion(mr, base,
    466                                SYS_BUS_DEVICE(dev)->mmio[0].memory);
    467
    468    return dev;
    469}