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

mipsnet.c (7996B)


      1#include "qemu/osdep.h"
      2#include "hw/irq.h"
      3#include "hw/qdev-properties.h"
      4#include "net/net.h"
      5#include "qemu/module.h"
      6#include "trace.h"
      7#include "hw/sysbus.h"
      8#include "migration/vmstate.h"
      9#include "qom/object.h"
     10
     11/* MIPSnet register offsets */
     12
     13#define MIPSNET_DEV_ID          0x00
     14#define MIPSNET_BUSY            0x08
     15#define MIPSNET_RX_DATA_COUNT   0x0c
     16#define MIPSNET_TX_DATA_COUNT   0x10
     17#define MIPSNET_INT_CTL         0x14
     18# define MIPSNET_INTCTL_TXDONE          0x00000001
     19# define MIPSNET_INTCTL_RXDONE          0x00000002
     20# define MIPSNET_INTCTL_TESTBIT         0x80000000
     21#define MIPSNET_INTERRUPT_INFO  0x18
     22#define MIPSNET_RX_DATA_BUFFER  0x1c
     23#define MIPSNET_TX_DATA_BUFFER  0x20
     24
     25#define MAX_ETH_FRAME_SIZE      1514
     26
     27#define TYPE_MIPS_NET "mipsnet"
     28OBJECT_DECLARE_SIMPLE_TYPE(MIPSnetState, MIPS_NET)
     29
     30struct MIPSnetState {
     31    SysBusDevice parent_obj;
     32
     33    uint32_t busy;
     34    uint32_t rx_count;
     35    uint32_t rx_read;
     36    uint32_t tx_count;
     37    uint32_t tx_written;
     38    uint32_t intctl;
     39    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
     40    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
     41    MemoryRegion io;
     42    qemu_irq irq;
     43    NICState *nic;
     44    NICConf conf;
     45};
     46
     47static void mipsnet_reset(MIPSnetState *s)
     48{
     49    s->busy = 1;
     50    s->rx_count = 0;
     51    s->rx_read = 0;
     52    s->tx_count = 0;
     53    s->tx_written = 0;
     54    s->intctl = 0;
     55    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
     56    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
     57}
     58
     59static void mipsnet_update_irq(MIPSnetState *s)
     60{
     61    int isr = !!s->intctl;
     62    trace_mipsnet_irq(isr, s->intctl);
     63    qemu_set_irq(s->irq, isr);
     64}
     65
     66static int mipsnet_buffer_full(MIPSnetState *s)
     67{
     68    if (s->rx_count >= MAX_ETH_FRAME_SIZE) {
     69        return 1;
     70    }
     71    return 0;
     72}
     73
     74static int mipsnet_can_receive(NetClientState *nc)
     75{
     76    MIPSnetState *s = qemu_get_nic_opaque(nc);
     77
     78    if (s->busy) {
     79        return 0;
     80    }
     81    return !mipsnet_buffer_full(s);
     82}
     83
     84static ssize_t mipsnet_receive(NetClientState *nc,
     85                               const uint8_t *buf, size_t size)
     86{
     87    MIPSnetState *s = qemu_get_nic_opaque(nc);
     88
     89    trace_mipsnet_receive(size);
     90    if (!mipsnet_can_receive(nc)) {
     91        return 0;
     92    }
     93
     94    if (size >= sizeof(s->rx_buffer)) {
     95        return 0;
     96    }
     97    s->busy = 1;
     98
     99    /* Just accept everything. */
    100
    101    /* Write packet data. */
    102    memcpy(s->rx_buffer, buf, size);
    103
    104    s->rx_count = size;
    105    s->rx_read = 0;
    106
    107    /* Now we can signal we have received something. */
    108    s->intctl |= MIPSNET_INTCTL_RXDONE;
    109    mipsnet_update_irq(s);
    110
    111    return size;
    112}
    113
    114static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
    115                                    unsigned int size)
    116{
    117    MIPSnetState *s = opaque;
    118    int ret = 0;
    119
    120    addr &= 0x3f;
    121    switch (addr) {
    122    case MIPSNET_DEV_ID:
    123        ret = be32_to_cpu(0x4d495053);          /* MIPS */
    124        break;
    125    case MIPSNET_DEV_ID + 4:
    126        ret = be32_to_cpu(0x4e455430);          /* NET0 */
    127        break;
    128    case MIPSNET_BUSY:
    129        ret = s->busy;
    130        break;
    131    case MIPSNET_RX_DATA_COUNT:
    132        ret = s->rx_count;
    133        break;
    134    case MIPSNET_TX_DATA_COUNT:
    135        ret = s->tx_count;
    136        break;
    137    case MIPSNET_INT_CTL:
    138        ret = s->intctl;
    139        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
    140        break;
    141    case MIPSNET_INTERRUPT_INFO:
    142        /* XXX: This seems to be a per-VPE interrupt number. */
    143        ret = 0;
    144        break;
    145    case MIPSNET_RX_DATA_BUFFER:
    146        if (s->rx_count) {
    147            s->rx_count--;
    148            ret = s->rx_buffer[s->rx_read++];
    149            if (mipsnet_can_receive(s->nic->ncs)) {
    150                qemu_flush_queued_packets(qemu_get_queue(s->nic));
    151            }
    152        }
    153        break;
    154    /* Reads as zero. */
    155    case MIPSNET_TX_DATA_BUFFER:
    156    default:
    157        break;
    158    }
    159    trace_mipsnet_read(addr, ret);
    160    return ret;
    161}
    162
    163static void mipsnet_ioport_write(void *opaque, hwaddr addr,
    164                                 uint64_t val, unsigned int size)
    165{
    166    MIPSnetState *s = opaque;
    167
    168    addr &= 0x3f;
    169    trace_mipsnet_write(addr, val);
    170    switch (addr) {
    171    case MIPSNET_TX_DATA_COUNT:
    172        s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
    173        s->tx_written = 0;
    174        break;
    175    case MIPSNET_INT_CTL:
    176        if (val & MIPSNET_INTCTL_TXDONE) {
    177            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
    178        } else if (val & MIPSNET_INTCTL_RXDONE) {
    179            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
    180        } else if (val & MIPSNET_INTCTL_TESTBIT) {
    181            mipsnet_reset(s);
    182            s->intctl |= MIPSNET_INTCTL_TESTBIT;
    183        } else if (!val) {
    184            /* ACK testbit interrupt, flag was cleared on read. */
    185        }
    186        s->busy = !!s->intctl;
    187        mipsnet_update_irq(s);
    188        if (mipsnet_can_receive(s->nic->ncs)) {
    189            qemu_flush_queued_packets(qemu_get_queue(s->nic));
    190        }
    191        break;
    192    case MIPSNET_TX_DATA_BUFFER:
    193        s->tx_buffer[s->tx_written++] = val;
    194        if ((s->tx_written >= MAX_ETH_FRAME_SIZE)
    195            || (s->tx_written == s->tx_count)) {
    196            /* Send buffer. */
    197            trace_mipsnet_send(s->tx_written);
    198            qemu_send_packet(qemu_get_queue(s->nic),
    199                                s->tx_buffer, s->tx_written);
    200            s->tx_count = s->tx_written = 0;
    201            s->intctl |= MIPSNET_INTCTL_TXDONE;
    202            s->busy = 1;
    203            mipsnet_update_irq(s);
    204        }
    205        break;
    206    /* Read-only registers */
    207    case MIPSNET_DEV_ID:
    208    case MIPSNET_BUSY:
    209    case MIPSNET_RX_DATA_COUNT:
    210    case MIPSNET_INTERRUPT_INFO:
    211    case MIPSNET_RX_DATA_BUFFER:
    212    default:
    213        break;
    214    }
    215}
    216
    217static const VMStateDescription vmstate_mipsnet = {
    218    .name = "mipsnet",
    219    .version_id = 0,
    220    .minimum_version_id = 0,
    221    .fields = (VMStateField[]) {
    222        VMSTATE_UINT32(busy, MIPSnetState),
    223        VMSTATE_UINT32(rx_count, MIPSnetState),
    224        VMSTATE_UINT32(rx_read, MIPSnetState),
    225        VMSTATE_UINT32(tx_count, MIPSnetState),
    226        VMSTATE_UINT32(tx_written, MIPSnetState),
    227        VMSTATE_UINT32(intctl, MIPSnetState),
    228        VMSTATE_BUFFER(rx_buffer, MIPSnetState),
    229        VMSTATE_BUFFER(tx_buffer, MIPSnetState),
    230        VMSTATE_END_OF_LIST()
    231    }
    232};
    233
    234static NetClientInfo net_mipsnet_info = {
    235    .type = NET_CLIENT_DRIVER_NIC,
    236    .size = sizeof(NICState),
    237    .receive = mipsnet_receive,
    238};
    239
    240static const MemoryRegionOps mipsnet_ioport_ops = {
    241    .read = mipsnet_ioport_read,
    242    .write = mipsnet_ioport_write,
    243    .impl.min_access_size = 1,
    244    .impl.max_access_size = 4,
    245};
    246
    247static void mipsnet_realize(DeviceState *dev, Error **errp)
    248{
    249    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    250    MIPSnetState *s = MIPS_NET(dev);
    251
    252    memory_region_init_io(&s->io, OBJECT(dev), &mipsnet_ioport_ops, s,
    253                          "mipsnet-io", 36);
    254    sysbus_init_mmio(sbd, &s->io);
    255    sysbus_init_irq(sbd, &s->irq);
    256
    257    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
    258                          object_get_typename(OBJECT(dev)), dev->id, s);
    259    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
    260}
    261
    262static void mipsnet_sysbus_reset(DeviceState *dev)
    263{
    264    MIPSnetState *s = MIPS_NET(dev);
    265    mipsnet_reset(s);
    266}
    267
    268static Property mipsnet_properties[] = {
    269    DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
    270    DEFINE_PROP_END_OF_LIST(),
    271};
    272
    273static void mipsnet_class_init(ObjectClass *klass, void *data)
    274{
    275    DeviceClass *dc = DEVICE_CLASS(klass);
    276
    277    dc->realize = mipsnet_realize;
    278    set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
    279    dc->desc = "MIPS Simulator network device";
    280    dc->reset = mipsnet_sysbus_reset;
    281    dc->vmsd = &vmstate_mipsnet;
    282    device_class_set_props(dc, mipsnet_properties);
    283}
    284
    285static const TypeInfo mipsnet_info = {
    286    .name          = TYPE_MIPS_NET,
    287    .parent        = TYPE_SYS_BUS_DEVICE,
    288    .instance_size = sizeof(MIPSnetState),
    289    .class_init    = mipsnet_class_init,
    290};
    291
    292static void mipsnet_register_types(void)
    293{
    294    type_register_static(&mipsnet_info);
    295}
    296
    297type_init(mipsnet_register_types)