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

pl011.c (11888B)


      1/*
      2 * Arm PrimeCell PL011 UART
      3 *
      4 * Copyright (c) 2006 CodeSourcery.
      5 * Written by Paul Brook
      6 *
      7 * This code is licensed under the GPL.
      8 */
      9
     10/*
     11 * QEMU interface:
     12 *  + sysbus MMIO region 0: device registers
     13 *  + sysbus IRQ 0: UARTINTR (combined interrupt line)
     14 *  + sysbus IRQ 1: UARTRXINTR (receive FIFO interrupt line)
     15 *  + sysbus IRQ 2: UARTTXINTR (transmit FIFO interrupt line)
     16 *  + sysbus IRQ 3: UARTRTINTR (receive timeout interrupt line)
     17 *  + sysbus IRQ 4: UARTMSINTR (momem status interrupt line)
     18 *  + sysbus IRQ 5: UARTEINTR (error interrupt line)
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "hw/char/pl011.h"
     23#include "hw/irq.h"
     24#include "hw/sysbus.h"
     25#include "hw/qdev-clock.h"
     26#include "hw/qdev-properties-system.h"
     27#include "migration/vmstate.h"
     28#include "chardev/char-fe.h"
     29#include "chardev/char-serial.h"
     30#include "qemu/log.h"
     31#include "qemu/module.h"
     32#include "trace.h"
     33
     34#define PL011_INT_TX 0x20
     35#define PL011_INT_RX 0x10
     36
     37#define PL011_FLAG_TXFE 0x80
     38#define PL011_FLAG_RXFF 0x40
     39#define PL011_FLAG_TXFF 0x20
     40#define PL011_FLAG_RXFE 0x10
     41
     42/* Interrupt status bits in UARTRIS, UARTMIS, UARTIMSC */
     43#define INT_OE (1 << 10)
     44#define INT_BE (1 << 9)
     45#define INT_PE (1 << 8)
     46#define INT_FE (1 << 7)
     47#define INT_RT (1 << 6)
     48#define INT_TX (1 << 5)
     49#define INT_RX (1 << 4)
     50#define INT_DSR (1 << 3)
     51#define INT_DCD (1 << 2)
     52#define INT_CTS (1 << 1)
     53#define INT_RI (1 << 0)
     54#define INT_E (INT_OE | INT_BE | INT_PE | INT_FE)
     55#define INT_MS (INT_RI | INT_DSR | INT_DCD | INT_CTS)
     56
     57static const unsigned char pl011_id_arm[8] =
     58  { 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
     59static const unsigned char pl011_id_luminary[8] =
     60  { 0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1 };
     61
     62/* Which bits in the interrupt status matter for each outbound IRQ line ? */
     63static const uint32_t irqmask[] = {
     64    INT_E | INT_MS | INT_RT | INT_TX | INT_RX, /* combined IRQ */
     65    INT_RX,
     66    INT_TX,
     67    INT_RT,
     68    INT_MS,
     69    INT_E,
     70};
     71
     72static void pl011_update(PL011State *s)
     73{
     74    uint32_t flags;
     75    int i;
     76
     77    flags = s->int_level & s->int_enabled;
     78    trace_pl011_irq_state(flags != 0);
     79    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
     80        qemu_set_irq(s->irq[i], (flags & irqmask[i]) != 0);
     81    }
     82}
     83
     84static uint64_t pl011_read(void *opaque, hwaddr offset,
     85                           unsigned size)
     86{
     87    PL011State *s = (PL011State *)opaque;
     88    uint32_t c;
     89    uint64_t r;
     90
     91    switch (offset >> 2) {
     92    case 0: /* UARTDR */
     93        s->flags &= ~PL011_FLAG_RXFF;
     94        c = s->read_fifo[s->read_pos];
     95        if (s->read_count > 0) {
     96            s->read_count--;
     97            if (++s->read_pos == 16)
     98                s->read_pos = 0;
     99        }
    100        if (s->read_count == 0) {
    101            s->flags |= PL011_FLAG_RXFE;
    102        }
    103        if (s->read_count == s->read_trigger - 1)
    104            s->int_level &= ~ PL011_INT_RX;
    105        trace_pl011_read_fifo(s->read_count);
    106        s->rsr = c >> 8;
    107        pl011_update(s);
    108        qemu_chr_fe_accept_input(&s->chr);
    109        r = c;
    110        break;
    111    case 1: /* UARTRSR */
    112        r = s->rsr;
    113        break;
    114    case 6: /* UARTFR */
    115        r = s->flags;
    116        break;
    117    case 8: /* UARTILPR */
    118        r = s->ilpr;
    119        break;
    120    case 9: /* UARTIBRD */
    121        r = s->ibrd;
    122        break;
    123    case 10: /* UARTFBRD */
    124        r = s->fbrd;
    125        break;
    126    case 11: /* UARTLCR_H */
    127        r = s->lcr;
    128        break;
    129    case 12: /* UARTCR */
    130        r = s->cr;
    131        break;
    132    case 13: /* UARTIFLS */
    133        r = s->ifl;
    134        break;
    135    case 14: /* UARTIMSC */
    136        r = s->int_enabled;
    137        break;
    138    case 15: /* UARTRIS */
    139        r = s->int_level;
    140        break;
    141    case 16: /* UARTMIS */
    142        r = s->int_level & s->int_enabled;
    143        break;
    144    case 18: /* UARTDMACR */
    145        r = s->dmacr;
    146        break;
    147    case 0x3f8 ... 0x400:
    148        r = s->id[(offset - 0xfe0) >> 2];
    149        break;
    150    default:
    151        qemu_log_mask(LOG_GUEST_ERROR,
    152                      "pl011_read: Bad offset 0x%x\n", (int)offset);
    153        r = 0;
    154        break;
    155    }
    156
    157    trace_pl011_read(offset, r);
    158    return r;
    159}
    160
    161static void pl011_set_read_trigger(PL011State *s)
    162{
    163#if 0
    164    /* The docs say the RX interrupt is triggered when the FIFO exceeds
    165       the threshold.  However linux only reads the FIFO in response to an
    166       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
    167       to make things work.  */
    168    if (s->lcr & 0x10)
    169        s->read_trigger = (s->ifl >> 1) & 0x1c;
    170    else
    171#endif
    172        s->read_trigger = 1;
    173}
    174
    175static unsigned int pl011_get_baudrate(const PL011State *s)
    176{
    177    uint64_t clk;
    178
    179    if (s->fbrd == 0) {
    180        return 0;
    181    }
    182
    183    clk = clock_get_hz(s->clk);
    184    return (clk / ((s->ibrd << 6) + s->fbrd)) << 2;
    185}
    186
    187static void pl011_trace_baudrate_change(const PL011State *s)
    188{
    189    trace_pl011_baudrate_change(pl011_get_baudrate(s),
    190                                clock_get_hz(s->clk),
    191                                s->ibrd, s->fbrd);
    192}
    193
    194static void pl011_write(void *opaque, hwaddr offset,
    195                        uint64_t value, unsigned size)
    196{
    197    PL011State *s = (PL011State *)opaque;
    198    unsigned char ch;
    199
    200    trace_pl011_write(offset, value);
    201
    202    switch (offset >> 2) {
    203    case 0: /* UARTDR */
    204        /* ??? Check if transmitter is enabled.  */
    205        ch = value;
    206        /* XXX this blocks entire thread. Rewrite to use
    207         * qemu_chr_fe_write and background I/O callbacks */
    208        qemu_chr_fe_write_all(&s->chr, &ch, 1);
    209        s->int_level |= PL011_INT_TX;
    210        pl011_update(s);
    211        break;
    212    case 1: /* UARTRSR/UARTECR */
    213        s->rsr = 0;
    214        break;
    215    case 6: /* UARTFR */
    216        /* Writes to Flag register are ignored.  */
    217        break;
    218    case 8: /* UARTUARTILPR */
    219        s->ilpr = value;
    220        break;
    221    case 9: /* UARTIBRD */
    222        s->ibrd = value;
    223        pl011_trace_baudrate_change(s);
    224        break;
    225    case 10: /* UARTFBRD */
    226        s->fbrd = value;
    227        pl011_trace_baudrate_change(s);
    228        break;
    229    case 11: /* UARTLCR_H */
    230        /* Reset the FIFO state on FIFO enable or disable */
    231        if ((s->lcr ^ value) & 0x10) {
    232            s->read_count = 0;
    233            s->read_pos = 0;
    234        }
    235        if ((s->lcr ^ value) & 0x1) {
    236            int break_enable = value & 0x1;
    237            qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
    238                              &break_enable);
    239        }
    240        s->lcr = value;
    241        pl011_set_read_trigger(s);
    242        break;
    243    case 12: /* UARTCR */
    244        /* ??? Need to implement the enable and loopback bits.  */
    245        s->cr = value;
    246        break;
    247    case 13: /* UARTIFS */
    248        s->ifl = value;
    249        pl011_set_read_trigger(s);
    250        break;
    251    case 14: /* UARTIMSC */
    252        s->int_enabled = value;
    253        pl011_update(s);
    254        break;
    255    case 17: /* UARTICR */
    256        s->int_level &= ~value;
    257        pl011_update(s);
    258        break;
    259    case 18: /* UARTDMACR */
    260        s->dmacr = value;
    261        if (value & 3) {
    262            qemu_log_mask(LOG_UNIMP, "pl011: DMA not implemented\n");
    263        }
    264        break;
    265    default:
    266        qemu_log_mask(LOG_GUEST_ERROR,
    267                      "pl011_write: Bad offset 0x%x\n", (int)offset);
    268    }
    269}
    270
    271static int pl011_can_receive(void *opaque)
    272{
    273    PL011State *s = (PL011State *)opaque;
    274    int r;
    275
    276    if (s->lcr & 0x10) {
    277        r = s->read_count < 16;
    278    } else {
    279        r = s->read_count < 1;
    280    }
    281    trace_pl011_can_receive(s->lcr, s->read_count, r);
    282    return r;
    283}
    284
    285static void pl011_put_fifo(void *opaque, uint32_t value)
    286{
    287    PL011State *s = (PL011State *)opaque;
    288    int slot;
    289
    290    slot = s->read_pos + s->read_count;
    291    if (slot >= 16)
    292        slot -= 16;
    293    s->read_fifo[slot] = value;
    294    s->read_count++;
    295    s->flags &= ~PL011_FLAG_RXFE;
    296    trace_pl011_put_fifo(value, s->read_count);
    297    if (!(s->lcr & 0x10) || s->read_count == 16) {
    298        trace_pl011_put_fifo_full();
    299        s->flags |= PL011_FLAG_RXFF;
    300    }
    301    if (s->read_count == s->read_trigger) {
    302        s->int_level |= PL011_INT_RX;
    303        pl011_update(s);
    304    }
    305}
    306
    307static void pl011_receive(void *opaque, const uint8_t *buf, int size)
    308{
    309    pl011_put_fifo(opaque, *buf);
    310}
    311
    312static void pl011_event(void *opaque, QEMUChrEvent event)
    313{
    314    if (event == CHR_EVENT_BREAK)
    315        pl011_put_fifo(opaque, 0x400);
    316}
    317
    318static void pl011_clock_update(void *opaque, ClockEvent event)
    319{
    320    PL011State *s = PL011(opaque);
    321
    322    pl011_trace_baudrate_change(s);
    323}
    324
    325static const MemoryRegionOps pl011_ops = {
    326    .read = pl011_read,
    327    .write = pl011_write,
    328    .endianness = DEVICE_NATIVE_ENDIAN,
    329};
    330
    331static bool pl011_clock_needed(void *opaque)
    332{
    333    PL011State *s = PL011(opaque);
    334
    335    return s->migrate_clk;
    336}
    337
    338static const VMStateDescription vmstate_pl011_clock = {
    339    .name = "pl011/clock",
    340    .version_id = 1,
    341    .minimum_version_id = 1,
    342    .needed = pl011_clock_needed,
    343    .fields = (VMStateField[]) {
    344        VMSTATE_CLOCK(clk, PL011State),
    345        VMSTATE_END_OF_LIST()
    346    }
    347};
    348
    349static const VMStateDescription vmstate_pl011 = {
    350    .name = "pl011",
    351    .version_id = 2,
    352    .minimum_version_id = 2,
    353    .fields = (VMStateField[]) {
    354        VMSTATE_UINT32(readbuff, PL011State),
    355        VMSTATE_UINT32(flags, PL011State),
    356        VMSTATE_UINT32(lcr, PL011State),
    357        VMSTATE_UINT32(rsr, PL011State),
    358        VMSTATE_UINT32(cr, PL011State),
    359        VMSTATE_UINT32(dmacr, PL011State),
    360        VMSTATE_UINT32(int_enabled, PL011State),
    361        VMSTATE_UINT32(int_level, PL011State),
    362        VMSTATE_UINT32_ARRAY(read_fifo, PL011State, 16),
    363        VMSTATE_UINT32(ilpr, PL011State),
    364        VMSTATE_UINT32(ibrd, PL011State),
    365        VMSTATE_UINT32(fbrd, PL011State),
    366        VMSTATE_UINT32(ifl, PL011State),
    367        VMSTATE_INT32(read_pos, PL011State),
    368        VMSTATE_INT32(read_count, PL011State),
    369        VMSTATE_INT32(read_trigger, PL011State),
    370        VMSTATE_END_OF_LIST()
    371    },
    372    .subsections = (const VMStateDescription * []) {
    373        &vmstate_pl011_clock,
    374        NULL
    375    }
    376};
    377
    378static Property pl011_properties[] = {
    379    DEFINE_PROP_CHR("chardev", PL011State, chr),
    380    DEFINE_PROP_BOOL("migrate-clk", PL011State, migrate_clk, true),
    381    DEFINE_PROP_END_OF_LIST(),
    382};
    383
    384static void pl011_init(Object *obj)
    385{
    386    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    387    PL011State *s = PL011(obj);
    388    int i;
    389
    390    memory_region_init_io(&s->iomem, OBJECT(s), &pl011_ops, s, "pl011", 0x1000);
    391    sysbus_init_mmio(sbd, &s->iomem);
    392    for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
    393        sysbus_init_irq(sbd, &s->irq[i]);
    394    }
    395
    396    s->clk = qdev_init_clock_in(DEVICE(obj), "clk", pl011_clock_update, s,
    397                                ClockUpdate);
    398
    399    s->read_trigger = 1;
    400    s->ifl = 0x12;
    401    s->cr = 0x300;
    402    s->flags = 0x90;
    403
    404    s->id = pl011_id_arm;
    405}
    406
    407static void pl011_realize(DeviceState *dev, Error **errp)
    408{
    409    PL011State *s = PL011(dev);
    410
    411    qemu_chr_fe_set_handlers(&s->chr, pl011_can_receive, pl011_receive,
    412                             pl011_event, NULL, s, NULL, true);
    413}
    414
    415static void pl011_class_init(ObjectClass *oc, void *data)
    416{
    417    DeviceClass *dc = DEVICE_CLASS(oc);
    418
    419    dc->realize = pl011_realize;
    420    dc->vmsd = &vmstate_pl011;
    421    device_class_set_props(dc, pl011_properties);
    422}
    423
    424static const TypeInfo pl011_arm_info = {
    425    .name          = TYPE_PL011,
    426    .parent        = TYPE_SYS_BUS_DEVICE,
    427    .instance_size = sizeof(PL011State),
    428    .instance_init = pl011_init,
    429    .class_init    = pl011_class_init,
    430};
    431
    432static void pl011_luminary_init(Object *obj)
    433{
    434    PL011State *s = PL011(obj);
    435
    436    s->id = pl011_id_luminary;
    437}
    438
    439static const TypeInfo pl011_luminary_info = {
    440    .name          = TYPE_PL011_LUMINARY,
    441    .parent        = TYPE_PL011,
    442    .instance_init = pl011_luminary_init,
    443};
    444
    445static void pl011_register_types(void)
    446{
    447    type_register_static(&pl011_arm_info);
    448    type_register_static(&pl011_luminary_info);
    449}
    450
    451type_init(pl011_register_types)