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

pl022.c (9001B)


      1/*
      2 * Arm PrimeCell PL022 Synchronous Serial Port
      3 *
      4 * Copyright (c) 2007 CodeSourcery.
      5 * Written by Paul Brook
      6 *
      7 * This code is licensed under the GPL.
      8 */
      9
     10#include "qemu/osdep.h"
     11#include "hw/sysbus.h"
     12#include "migration/vmstate.h"
     13#include "hw/irq.h"
     14#include "hw/ssi/pl022.h"
     15#include "hw/ssi/ssi.h"
     16#include "qemu/log.h"
     17#include "qemu/module.h"
     18
     19//#define DEBUG_PL022 1
     20
     21#ifdef DEBUG_PL022
     22#define DPRINTF(fmt, ...) \
     23do { printf("pl022: " fmt , ## __VA_ARGS__); } while (0)
     24#define BADF(fmt, ...) \
     25do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
     26#else
     27#define DPRINTF(fmt, ...) do {} while(0)
     28#define BADF(fmt, ...) \
     29do { fprintf(stderr, "pl022: error: " fmt , ## __VA_ARGS__);} while (0)
     30#endif
     31
     32#define PL022_CR1_LBM 0x01
     33#define PL022_CR1_SSE 0x02
     34#define PL022_CR1_MS  0x04
     35#define PL022_CR1_SDO 0x08
     36
     37#define PL022_SR_TFE  0x01
     38#define PL022_SR_TNF  0x02
     39#define PL022_SR_RNE  0x04
     40#define PL022_SR_RFF  0x08
     41#define PL022_SR_BSY  0x10
     42
     43#define PL022_INT_ROR 0x01
     44#define PL022_INT_RT  0x02
     45#define PL022_INT_RX  0x04
     46#define PL022_INT_TX  0x08
     47
     48static const unsigned char pl022_id[8] =
     49  { 0x22, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
     50
     51static void pl022_update(PL022State *s)
     52{
     53    s->sr = 0;
     54    if (s->tx_fifo_len == 0)
     55        s->sr |= PL022_SR_TFE;
     56    if (s->tx_fifo_len != 8)
     57        s->sr |= PL022_SR_TNF;
     58    if (s->rx_fifo_len != 0)
     59        s->sr |= PL022_SR_RNE;
     60    if (s->rx_fifo_len == 8)
     61        s->sr |= PL022_SR_RFF;
     62    if (s->tx_fifo_len)
     63        s->sr |= PL022_SR_BSY;
     64    s->is = 0;
     65    if (s->rx_fifo_len >= 4)
     66        s->is |= PL022_INT_RX;
     67    if (s->tx_fifo_len <= 4)
     68        s->is |= PL022_INT_TX;
     69
     70    qemu_set_irq(s->irq, (s->is & s->im) != 0);
     71}
     72
     73static void pl022_xfer(PL022State *s)
     74{
     75    int i;
     76    int o;
     77    int val;
     78
     79    if ((s->cr1 & PL022_CR1_SSE) == 0) {
     80        pl022_update(s);
     81        DPRINTF("Disabled\n");
     82        return;
     83    }
     84
     85    DPRINTF("Maybe xfer %d/%d\n", s->tx_fifo_len, s->rx_fifo_len);
     86    i = (s->tx_fifo_head - s->tx_fifo_len) & 7;
     87    o = s->rx_fifo_head;
     88    /* ??? We do not emulate the line speed.
     89       This may break some applications.  The are two problematic cases:
     90        (a) A driver feeds data into the TX FIFO until it is full,
     91         and only then drains the RX FIFO.  On real hardware the CPU can
     92         feed data fast enough that the RX fifo never gets chance to overflow.
     93        (b) A driver transmits data, deliberately allowing the RX FIFO to
     94         overflow because it ignores the RX data anyway.
     95
     96       We choose to support (a) by stalling the transmit engine if it would
     97       cause the RX FIFO to overflow.  In practice much transmit-only code
     98       falls into (a) because it flushes the RX FIFO to determine when
     99       the transfer has completed.  */
    100    while (s->tx_fifo_len && s->rx_fifo_len < 8) {
    101        DPRINTF("xfer\n");
    102        val = s->tx_fifo[i];
    103        if (s->cr1 & PL022_CR1_LBM) {
    104            /* Loopback mode.  */
    105        } else {
    106            val = ssi_transfer(s->ssi, val);
    107        }
    108        s->rx_fifo[o] = val & s->bitmask;
    109        i = (i + 1) & 7;
    110        o = (o + 1) & 7;
    111        s->tx_fifo_len--;
    112        s->rx_fifo_len++;
    113    }
    114    s->rx_fifo_head = o;
    115    pl022_update(s);
    116}
    117
    118static uint64_t pl022_read(void *opaque, hwaddr offset,
    119                           unsigned size)
    120{
    121    PL022State *s = (PL022State *)opaque;
    122    int val;
    123
    124    if (offset >= 0xfe0 && offset < 0x1000) {
    125        return pl022_id[(offset - 0xfe0) >> 2];
    126    }
    127    switch (offset) {
    128    case 0x00: /* CR0 */
    129      return s->cr0;
    130    case 0x04: /* CR1 */
    131      return s->cr1;
    132    case 0x08: /* DR */
    133        if (s->rx_fifo_len) {
    134            val = s->rx_fifo[(s->rx_fifo_head - s->rx_fifo_len) & 7];
    135            DPRINTF("RX %02x\n", val);
    136            s->rx_fifo_len--;
    137            pl022_xfer(s);
    138        } else {
    139            val = 0;
    140        }
    141        return val;
    142    case 0x0c: /* SR */
    143        return s->sr;
    144    case 0x10: /* CPSR */
    145        return s->cpsr;
    146    case 0x14: /* IMSC */
    147        return s->im;
    148    case 0x18: /* RIS */
    149        return s->is;
    150    case 0x1c: /* MIS */
    151        return s->im & s->is;
    152    case 0x24: /* DMACR */
    153        /* Not implemented.  */
    154        return 0;
    155    default:
    156        qemu_log_mask(LOG_GUEST_ERROR,
    157                      "pl022_read: Bad offset %x\n", (int)offset);
    158        return 0;
    159    }
    160}
    161
    162static void pl022_write(void *opaque, hwaddr offset,
    163                        uint64_t value, unsigned size)
    164{
    165    PL022State *s = (PL022State *)opaque;
    166
    167    switch (offset) {
    168    case 0x00: /* CR0 */
    169        s->cr0 = value;
    170        /* Clock rate and format are ignored.  */
    171        s->bitmask = (1 << ((value & 15) + 1)) - 1;
    172        break;
    173    case 0x04: /* CR1 */
    174        s->cr1 = value;
    175        if ((s->cr1 & (PL022_CR1_MS | PL022_CR1_SSE))
    176                   == (PL022_CR1_MS | PL022_CR1_SSE)) {
    177            BADF("SPI peripheral mode not implemented\n");
    178        }
    179        pl022_xfer(s);
    180        break;
    181    case 0x08: /* DR */
    182        if (s->tx_fifo_len < 8) {
    183            DPRINTF("TX %02x\n", (unsigned)value);
    184            s->tx_fifo[s->tx_fifo_head] = value & s->bitmask;
    185            s->tx_fifo_head = (s->tx_fifo_head + 1) & 7;
    186            s->tx_fifo_len++;
    187            pl022_xfer(s);
    188        }
    189        break;
    190    case 0x10: /* CPSR */
    191        /* Prescaler.  Ignored.  */
    192        s->cpsr = value & 0xff;
    193        break;
    194    case 0x14: /* IMSC */
    195        s->im = value;
    196        pl022_update(s);
    197        break;
    198    case 0x20: /* ICR */
    199        /*
    200         * write-1-to-clear: bit 0 clears ROR, bit 1 clears RT;
    201         * RX and TX interrupts cannot be cleared this way.
    202         */
    203        value &= PL022_INT_ROR | PL022_INT_RT;
    204        s->is &= ~value;
    205        break;
    206    case 0x24: /* DMACR */
    207        if (value) {
    208            qemu_log_mask(LOG_UNIMP, "pl022: DMA not implemented\n");
    209        }
    210        break;
    211    default:
    212        qemu_log_mask(LOG_GUEST_ERROR,
    213                      "pl022_write: Bad offset %x\n", (int)offset);
    214    }
    215}
    216
    217static void pl022_reset(DeviceState *dev)
    218{
    219    PL022State *s = PL022(dev);
    220
    221    s->rx_fifo_len = 0;
    222    s->tx_fifo_len = 0;
    223    s->im = 0;
    224    s->is = PL022_INT_TX;
    225    s->sr = PL022_SR_TFE | PL022_SR_TNF;
    226}
    227
    228static const MemoryRegionOps pl022_ops = {
    229    .read = pl022_read,
    230    .write = pl022_write,
    231    .endianness = DEVICE_NATIVE_ENDIAN,
    232};
    233
    234static int pl022_post_load(void *opaque, int version_id)
    235{
    236    PL022State *s = opaque;
    237
    238    if (s->tx_fifo_head < 0 ||
    239        s->tx_fifo_head >= ARRAY_SIZE(s->tx_fifo) ||
    240        s->rx_fifo_head < 0 ||
    241        s->rx_fifo_head >= ARRAY_SIZE(s->rx_fifo)) {
    242        return -1;
    243    }
    244    return 0;
    245}
    246
    247static const VMStateDescription vmstate_pl022 = {
    248    .name = "pl022_ssp",
    249    .version_id = 1,
    250    .minimum_version_id = 1,
    251    .post_load = pl022_post_load,
    252    .fields = (VMStateField[]) {
    253        VMSTATE_UINT32(cr0, PL022State),
    254        VMSTATE_UINT32(cr1, PL022State),
    255        VMSTATE_UINT32(bitmask, PL022State),
    256        VMSTATE_UINT32(sr, PL022State),
    257        VMSTATE_UINT32(cpsr, PL022State),
    258        VMSTATE_UINT32(is, PL022State),
    259        VMSTATE_UINT32(im, PL022State),
    260        VMSTATE_INT32(tx_fifo_head, PL022State),
    261        VMSTATE_INT32(rx_fifo_head, PL022State),
    262        VMSTATE_INT32(tx_fifo_len, PL022State),
    263        VMSTATE_INT32(rx_fifo_len, PL022State),
    264        VMSTATE_UINT16(tx_fifo[0], PL022State),
    265        VMSTATE_UINT16(rx_fifo[0], PL022State),
    266        VMSTATE_UINT16(tx_fifo[1], PL022State),
    267        VMSTATE_UINT16(rx_fifo[1], PL022State),
    268        VMSTATE_UINT16(tx_fifo[2], PL022State),
    269        VMSTATE_UINT16(rx_fifo[2], PL022State),
    270        VMSTATE_UINT16(tx_fifo[3], PL022State),
    271        VMSTATE_UINT16(rx_fifo[3], PL022State),
    272        VMSTATE_UINT16(tx_fifo[4], PL022State),
    273        VMSTATE_UINT16(rx_fifo[4], PL022State),
    274        VMSTATE_UINT16(tx_fifo[5], PL022State),
    275        VMSTATE_UINT16(rx_fifo[5], PL022State),
    276        VMSTATE_UINT16(tx_fifo[6], PL022State),
    277        VMSTATE_UINT16(rx_fifo[6], PL022State),
    278        VMSTATE_UINT16(tx_fifo[7], PL022State),
    279        VMSTATE_UINT16(rx_fifo[7], PL022State),
    280        VMSTATE_END_OF_LIST()
    281    }
    282};
    283
    284static void pl022_realize(DeviceState *dev, Error **errp)
    285{
    286    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    287    PL022State *s = PL022(dev);
    288
    289    memory_region_init_io(&s->iomem, OBJECT(s), &pl022_ops, s, "pl022", 0x1000);
    290    sysbus_init_mmio(sbd, &s->iomem);
    291    sysbus_init_irq(sbd, &s->irq);
    292    s->ssi = ssi_create_bus(dev, "ssi");
    293}
    294
    295static void pl022_class_init(ObjectClass *klass, void *data)
    296{
    297    DeviceClass *dc = DEVICE_CLASS(klass);
    298
    299    dc->reset = pl022_reset;
    300    dc->vmsd = &vmstate_pl022;
    301    dc->realize = pl022_realize;
    302}
    303
    304static const TypeInfo pl022_info = {
    305    .name          = TYPE_PL022,
    306    .parent        = TYPE_SYS_BUS_DEVICE,
    307    .instance_size = sizeof(PL022State),
    308    .class_init    = pl022_class_init,
    309};
    310
    311static void pl022_register_types(void)
    312{
    313    type_register_static(&pl022_info);
    314}
    315
    316type_init(pl022_register_types)