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

pl181.c (16741B)


      1/*
      2 * Arm PrimeCell PL181 MultiMedia Card Interface
      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 "sysemu/blockdev.h"
     12#include "hw/sysbus.h"
     13#include "migration/vmstate.h"
     14#include "hw/irq.h"
     15#include "hw/sd/sd.h"
     16#include "qemu/log.h"
     17#include "qemu/module.h"
     18#include "qemu/error-report.h"
     19#include "qapi/error.h"
     20#include "trace.h"
     21#include "qom/object.h"
     22
     23#define PL181_FIFO_LEN 16
     24
     25#define TYPE_PL181 "pl181"
     26OBJECT_DECLARE_SIMPLE_TYPE(PL181State, PL181)
     27
     28#define TYPE_PL181_BUS "pl181-bus"
     29
     30struct PL181State {
     31    SysBusDevice parent_obj;
     32
     33    MemoryRegion iomem;
     34    SDBus sdbus;
     35    uint32_t clock;
     36    uint32_t power;
     37    uint32_t cmdarg;
     38    uint32_t cmd;
     39    uint32_t datatimer;
     40    uint32_t datalength;
     41    uint32_t respcmd;
     42    uint32_t response[4];
     43    uint32_t datactrl;
     44    uint32_t datacnt;
     45    uint32_t status;
     46    uint32_t mask[2];
     47    int32_t fifo_pos;
     48    int32_t fifo_len;
     49    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
     50       while it is reading the FIFO.  We hack around this by deferring
     51       subsequent transfers until after the driver polls the status word.
     52       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
     53     */
     54    int32_t linux_hack;
     55    uint32_t fifo[PL181_FIFO_LEN]; /* TODO use Fifo32 */
     56    qemu_irq irq[2];
     57    /* GPIO outputs for 'card is readonly' and 'card inserted' */
     58    qemu_irq card_readonly;
     59    qemu_irq card_inserted;
     60};
     61
     62static const VMStateDescription vmstate_pl181 = {
     63    .name = "pl181",
     64    .version_id = 1,
     65    .minimum_version_id = 1,
     66    .fields = (VMStateField[]) {
     67        VMSTATE_UINT32(clock, PL181State),
     68        VMSTATE_UINT32(power, PL181State),
     69        VMSTATE_UINT32(cmdarg, PL181State),
     70        VMSTATE_UINT32(cmd, PL181State),
     71        VMSTATE_UINT32(datatimer, PL181State),
     72        VMSTATE_UINT32(datalength, PL181State),
     73        VMSTATE_UINT32(respcmd, PL181State),
     74        VMSTATE_UINT32_ARRAY(response, PL181State, 4),
     75        VMSTATE_UINT32(datactrl, PL181State),
     76        VMSTATE_UINT32(datacnt, PL181State),
     77        VMSTATE_UINT32(status, PL181State),
     78        VMSTATE_UINT32_ARRAY(mask, PL181State, 2),
     79        VMSTATE_INT32(fifo_pos, PL181State),
     80        VMSTATE_INT32(fifo_len, PL181State),
     81        VMSTATE_INT32(linux_hack, PL181State),
     82        VMSTATE_UINT32_ARRAY(fifo, PL181State, PL181_FIFO_LEN),
     83        VMSTATE_END_OF_LIST()
     84    }
     85};
     86
     87#define PL181_CMD_INDEX     0x3f
     88#define PL181_CMD_RESPONSE  (1 << 6)
     89#define PL181_CMD_LONGRESP  (1 << 7)
     90#define PL181_CMD_INTERRUPT (1 << 8)
     91#define PL181_CMD_PENDING   (1 << 9)
     92#define PL181_CMD_ENABLE    (1 << 10)
     93
     94#define PL181_DATA_ENABLE             (1 << 0)
     95#define PL181_DATA_DIRECTION          (1 << 1)
     96#define PL181_DATA_MODE               (1 << 2)
     97#define PL181_DATA_DMAENABLE          (1 << 3)
     98
     99#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
    100#define PL181_STATUS_DATACRCFAIL      (1 << 1)
    101#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
    102#define PL181_STATUS_DATATIMEOUT      (1 << 3)
    103#define PL181_STATUS_TXUNDERRUN       (1 << 4)
    104#define PL181_STATUS_RXOVERRUN        (1 << 5)
    105#define PL181_STATUS_CMDRESPEND       (1 << 6)
    106#define PL181_STATUS_CMDSENT          (1 << 7)
    107#define PL181_STATUS_DATAEND          (1 << 8)
    108#define PL181_STATUS_DATABLOCKEND     (1 << 10)
    109#define PL181_STATUS_CMDACTIVE        (1 << 11)
    110#define PL181_STATUS_TXACTIVE         (1 << 12)
    111#define PL181_STATUS_RXACTIVE         (1 << 13)
    112#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
    113#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
    114#define PL181_STATUS_TXFIFOFULL       (1 << 16)
    115#define PL181_STATUS_RXFIFOFULL       (1 << 17)
    116#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
    117#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
    118#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
    119#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
    120
    121#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
    122                             |PL181_STATUS_TXFIFOHALFEMPTY \
    123                             |PL181_STATUS_TXFIFOFULL \
    124                             |PL181_STATUS_TXFIFOEMPTY \
    125                             |PL181_STATUS_TXDATAAVLBL)
    126#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
    127                             |PL181_STATUS_RXFIFOHALFFULL \
    128                             |PL181_STATUS_RXFIFOFULL \
    129                             |PL181_STATUS_RXFIFOEMPTY \
    130                             |PL181_STATUS_RXDATAAVLBL)
    131
    132static const unsigned char pl181_id[] =
    133{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
    134
    135static void pl181_update(PL181State *s)
    136{
    137    int i;
    138    for (i = 0; i < 2; i++) {
    139        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
    140    }
    141}
    142
    143static void pl181_fifo_push(PL181State *s, uint32_t value)
    144{
    145    int n;
    146
    147    if (s->fifo_len == PL181_FIFO_LEN) {
    148        error_report("%s: FIFO overflow", __func__);
    149        return;
    150    }
    151    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
    152    s->fifo_len++;
    153    s->fifo[n] = value;
    154    trace_pl181_fifo_push(value);
    155}
    156
    157static uint32_t pl181_fifo_pop(PL181State *s)
    158{
    159    uint32_t value;
    160
    161    if (s->fifo_len == 0) {
    162        error_report("%s: FIFO underflow", __func__);
    163        return 0;
    164    }
    165    value = s->fifo[s->fifo_pos];
    166    s->fifo_len--;
    167    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
    168    trace_pl181_fifo_pop(value);
    169    return value;
    170}
    171
    172static void pl181_do_command(PL181State *s)
    173{
    174    SDRequest request;
    175    uint8_t response[16];
    176    int rlen;
    177
    178    request.cmd = s->cmd & PL181_CMD_INDEX;
    179    request.arg = s->cmdarg;
    180    trace_pl181_command_send(request.cmd, request.arg);
    181    rlen = sdbus_do_command(&s->sdbus, &request, response);
    182    if (rlen < 0)
    183        goto error;
    184    if (s->cmd & PL181_CMD_RESPONSE) {
    185        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
    186            goto error;
    187        if (rlen != 4 && rlen != 16)
    188            goto error;
    189        s->response[0] = ldl_be_p(&response[0]);
    190        if (rlen == 4) {
    191            s->response[1] = s->response[2] = s->response[3] = 0;
    192        } else {
    193            s->response[1] = ldl_be_p(&response[4]);
    194            s->response[2] = ldl_be_p(&response[8]);
    195            s->response[3] = ldl_be_p(&response[12]) & ~1;
    196        }
    197        trace_pl181_command_response_pending();
    198        s->status |= PL181_STATUS_CMDRESPEND;
    199    } else {
    200        trace_pl181_command_sent();
    201        s->status |= PL181_STATUS_CMDSENT;
    202    }
    203    return;
    204
    205error:
    206    trace_pl181_command_timeout();
    207    s->status |= PL181_STATUS_CMDTIMEOUT;
    208}
    209
    210/* Transfer data between the card and the FIFO.  This is complicated by
    211   the FIFO holding 32-bit words and the card taking data in single byte
    212   chunks.  FIFO bytes are transferred in little-endian order.  */
    213
    214static void pl181_fifo_run(PL181State *s)
    215{
    216    uint32_t bits;
    217    uint32_t value = 0;
    218    int n;
    219    int is_read;
    220
    221    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
    222    if (s->datacnt != 0 && (!is_read || sdbus_data_ready(&s->sdbus))
    223            && !s->linux_hack) {
    224        if (is_read) {
    225            n = 0;
    226            while (s->datacnt && s->fifo_len < PL181_FIFO_LEN) {
    227                value |= (uint32_t)sdbus_read_byte(&s->sdbus) << (n * 8);
    228                s->datacnt--;
    229                n++;
    230                if (n == 4) {
    231                    pl181_fifo_push(s, value);
    232                    n = 0;
    233                    value = 0;
    234                }
    235            }
    236            if (n != 0) {
    237                pl181_fifo_push(s, value);
    238            }
    239        } else { /* write */
    240            n = 0;
    241            while (s->datacnt > 0 && (s->fifo_len > 0 || n > 0)) {
    242                if (n == 0) {
    243                    value = pl181_fifo_pop(s);
    244                    n = 4;
    245                }
    246                n--;
    247                s->datacnt--;
    248                sdbus_write_byte(&s->sdbus, value & 0xff);
    249                value >>= 8;
    250            }
    251        }
    252    }
    253    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
    254    if (s->datacnt == 0) {
    255        s->status |= PL181_STATUS_DATAEND;
    256        /* HACK: */
    257        s->status |= PL181_STATUS_DATABLOCKEND;
    258        trace_pl181_fifo_transfer_complete();
    259    }
    260    if (s->datacnt == 0 && s->fifo_len == 0) {
    261        s->datactrl &= ~PL181_DATA_ENABLE;
    262        trace_pl181_data_engine_idle();
    263    } else {
    264        /* Update FIFO bits.  */
    265        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
    266        if (s->fifo_len == 0) {
    267            bits |= PL181_STATUS_TXFIFOEMPTY;
    268            bits |= PL181_STATUS_RXFIFOEMPTY;
    269        } else {
    270            bits |= PL181_STATUS_TXDATAAVLBL;
    271            bits |= PL181_STATUS_RXDATAAVLBL;
    272        }
    273        if (s->fifo_len == 16) {
    274            bits |= PL181_STATUS_TXFIFOFULL;
    275            bits |= PL181_STATUS_RXFIFOFULL;
    276        }
    277        if (s->fifo_len <= 8) {
    278            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
    279        }
    280        if (s->fifo_len >= 8) {
    281            bits |= PL181_STATUS_RXFIFOHALFFULL;
    282        }
    283        if (s->datactrl & PL181_DATA_DIRECTION) {
    284            bits &= PL181_STATUS_RX_FIFO;
    285        } else {
    286            bits &= PL181_STATUS_TX_FIFO;
    287        }
    288        s->status |= bits;
    289    }
    290}
    291
    292static uint64_t pl181_read(void *opaque, hwaddr offset,
    293                           unsigned size)
    294{
    295    PL181State *s = (PL181State *)opaque;
    296    uint32_t tmp;
    297
    298    if (offset >= 0xfe0 && offset < 0x1000) {
    299        return pl181_id[(offset - 0xfe0) >> 2];
    300    }
    301    switch (offset) {
    302    case 0x00: /* Power */
    303        return s->power;
    304    case 0x04: /* Clock */
    305        return s->clock;
    306    case 0x08: /* Argument */
    307        return s->cmdarg;
    308    case 0x0c: /* Command */
    309        return s->cmd;
    310    case 0x10: /* RespCmd */
    311        return s->respcmd;
    312    case 0x14: /* Response0 */
    313        return s->response[0];
    314    case 0x18: /* Response1 */
    315        return s->response[1];
    316    case 0x1c: /* Response2 */
    317        return s->response[2];
    318    case 0x20: /* Response3 */
    319        return s->response[3];
    320    case 0x24: /* DataTimer */
    321        return s->datatimer;
    322    case 0x28: /* DataLength */
    323        return s->datalength;
    324    case 0x2c: /* DataCtrl */
    325        return s->datactrl;
    326    case 0x30: /* DataCnt */
    327        return s->datacnt;
    328    case 0x34: /* Status */
    329        tmp = s->status;
    330        if (s->linux_hack) {
    331            s->linux_hack = 0;
    332            pl181_fifo_run(s);
    333            pl181_update(s);
    334        }
    335        return tmp;
    336    case 0x3c: /* Mask0 */
    337        return s->mask[0];
    338    case 0x40: /* Mask1 */
    339        return s->mask[1];
    340    case 0x48: /* FifoCnt */
    341        /* The documentation is somewhat vague about exactly what FifoCnt
    342           does.  On real hardware it appears to be when decrememnted
    343           when a word is transferred between the FIFO and the serial
    344           data engine.  DataCnt is decremented after each byte is
    345           transferred between the serial engine and the card.
    346           We don't emulate this level of detail, so both can be the same.  */
    347        tmp = (s->datacnt + 3) >> 2;
    348        if (s->linux_hack) {
    349            s->linux_hack = 0;
    350            pl181_fifo_run(s);
    351            pl181_update(s);
    352        }
    353        return tmp;
    354    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
    355    case 0x90: case 0x94: case 0x98: case 0x9c:
    356    case 0xa0: case 0xa4: case 0xa8: case 0xac:
    357    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
    358        if (s->fifo_len == 0) {
    359            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO read\n");
    360            return 0;
    361        } else {
    362            uint32_t value;
    363            value = pl181_fifo_pop(s);
    364            s->linux_hack = 1;
    365            pl181_fifo_run(s);
    366            pl181_update(s);
    367            return value;
    368        }
    369    default:
    370        qemu_log_mask(LOG_GUEST_ERROR,
    371                      "pl181_read: Bad offset %x\n", (int)offset);
    372        return 0;
    373    }
    374}
    375
    376static void pl181_write(void *opaque, hwaddr offset,
    377                        uint64_t value, unsigned size)
    378{
    379    PL181State *s = (PL181State *)opaque;
    380
    381    switch (offset) {
    382    case 0x00: /* Power */
    383        s->power = value & 0xff;
    384        break;
    385    case 0x04: /* Clock */
    386        s->clock = value & 0xff;
    387        break;
    388    case 0x08: /* Argument */
    389        s->cmdarg = value;
    390        break;
    391    case 0x0c: /* Command */
    392        s->cmd = value;
    393        if (s->cmd & PL181_CMD_ENABLE) {
    394            if (s->cmd & PL181_CMD_INTERRUPT) {
    395                qemu_log_mask(LOG_UNIMP,
    396                              "pl181: Interrupt mode not implemented\n");
    397            } if (s->cmd & PL181_CMD_PENDING) {
    398                qemu_log_mask(LOG_UNIMP,
    399                              "pl181: Pending commands not implemented\n");
    400            } else {
    401                pl181_do_command(s);
    402                pl181_fifo_run(s);
    403            }
    404            /* The command has completed one way or the other.  */
    405            s->cmd &= ~PL181_CMD_ENABLE;
    406        }
    407        break;
    408    case 0x24: /* DataTimer */
    409        s->datatimer = value;
    410        break;
    411    case 0x28: /* DataLength */
    412        s->datalength = value & 0xffff;
    413        break;
    414    case 0x2c: /* DataCtrl */
    415        s->datactrl = value & 0xff;
    416        if (value & PL181_DATA_ENABLE) {
    417            s->datacnt = s->datalength;
    418            pl181_fifo_run(s);
    419        }
    420        break;
    421    case 0x38: /* Clear */
    422        s->status &= ~(value & 0x7ff);
    423        break;
    424    case 0x3c: /* Mask0 */
    425        s->mask[0] = value;
    426        break;
    427    case 0x40: /* Mask1 */
    428        s->mask[1] = value;
    429        break;
    430    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
    431    case 0x90: case 0x94: case 0x98: case 0x9c:
    432    case 0xa0: case 0xa4: case 0xa8: case 0xac:
    433    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
    434        if (s->datacnt == 0) {
    435            qemu_log_mask(LOG_GUEST_ERROR, "pl181: Unexpected FIFO write\n");
    436        } else {
    437            pl181_fifo_push(s, value);
    438            pl181_fifo_run(s);
    439        }
    440        break;
    441    default:
    442        qemu_log_mask(LOG_GUEST_ERROR,
    443                      "pl181_write: Bad offset %x\n", (int)offset);
    444    }
    445    pl181_update(s);
    446}
    447
    448static const MemoryRegionOps pl181_ops = {
    449    .read = pl181_read,
    450    .write = pl181_write,
    451    .endianness = DEVICE_NATIVE_ENDIAN,
    452};
    453
    454static void pl181_set_readonly(DeviceState *dev, bool level)
    455{
    456    PL181State *s = (PL181State *)dev;
    457
    458    qemu_set_irq(s->card_readonly, level);
    459}
    460
    461static void pl181_set_inserted(DeviceState *dev, bool level)
    462{
    463    PL181State *s = (PL181State *)dev;
    464
    465    qemu_set_irq(s->card_inserted, level);
    466}
    467
    468static void pl181_reset(DeviceState *d)
    469{
    470    PL181State *s = PL181(d);
    471
    472    s->power = 0;
    473    s->cmdarg = 0;
    474    s->cmd = 0;
    475    s->datatimer = 0;
    476    s->datalength = 0;
    477    s->respcmd = 0;
    478    s->response[0] = 0;
    479    s->response[1] = 0;
    480    s->response[2] = 0;
    481    s->response[3] = 0;
    482    s->datatimer = 0;
    483    s->datalength = 0;
    484    s->datactrl = 0;
    485    s->datacnt = 0;
    486    s->status = 0;
    487    s->linux_hack = 0;
    488    s->mask[0] = 0;
    489    s->mask[1] = 0;
    490
    491    /* Reset other state based on current card insertion/readonly status */
    492    pl181_set_inserted(DEVICE(s), sdbus_get_inserted(&s->sdbus));
    493    pl181_set_readonly(DEVICE(s), sdbus_get_readonly(&s->sdbus));
    494}
    495
    496static void pl181_init(Object *obj)
    497{
    498    DeviceState *dev = DEVICE(obj);
    499    PL181State *s = PL181(obj);
    500    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    501
    502    memory_region_init_io(&s->iomem, obj, &pl181_ops, s, "pl181", 0x1000);
    503    sysbus_init_mmio(sbd, &s->iomem);
    504    sysbus_init_irq(sbd, &s->irq[0]);
    505    sysbus_init_irq(sbd, &s->irq[1]);
    506    qdev_init_gpio_out_named(dev, &s->card_readonly, "card-read-only", 1);
    507    qdev_init_gpio_out_named(dev, &s->card_inserted, "card-inserted", 1);
    508
    509    qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_PL181_BUS, dev, "sd-bus");
    510}
    511
    512static void pl181_class_init(ObjectClass *klass, void *data)
    513{
    514    DeviceClass *k = DEVICE_CLASS(klass);
    515
    516    k->vmsd = &vmstate_pl181;
    517    k->reset = pl181_reset;
    518    /* Reason: output IRQs should be wired up */
    519    k->user_creatable = false;
    520}
    521
    522static const TypeInfo pl181_info = {
    523    .name          = TYPE_PL181,
    524    .parent        = TYPE_SYS_BUS_DEVICE,
    525    .instance_size = sizeof(PL181State),
    526    .instance_init = pl181_init,
    527    .class_init    = pl181_class_init,
    528};
    529
    530static void pl181_bus_class_init(ObjectClass *klass, void *data)
    531{
    532    SDBusClass *sbc = SD_BUS_CLASS(klass);
    533
    534    sbc->set_inserted = pl181_set_inserted;
    535    sbc->set_readonly = pl181_set_readonly;
    536}
    537
    538static const TypeInfo pl181_bus_info = {
    539    .name = TYPE_PL181_BUS,
    540    .parent = TYPE_SD_BUS,
    541    .instance_size = sizeof(SDBus),
    542    .class_init = pl181_bus_class_init,
    543};
    544
    545static void pl181_register_types(void)
    546{
    547    type_register_static(&pl181_info);
    548    type_register_static(&pl181_bus_info);
    549}
    550
    551type_init(pl181_register_types)