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

imx_serial.c (10474B)


      1/*
      2 * IMX31 UARTS
      3 *
      4 * Copyright (c) 2008 OKL
      5 * Originally Written by Hans Jiang
      6 * Copyright (c) 2011 NICTA Pty Ltd.
      7 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
      8 *
      9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10 * See the COPYING file in the top-level directory.
     11 *
     12 * This is a `bare-bones' implementation of the IMX series serial ports.
     13 * TODO:
     14 *  -- implement FIFOs.  The real hardware has 32 word transmit
     15 *                       and receive FIFOs; we currently use a 1-char buffer
     16 *  -- implement DMA
     17 *  -- implement BAUD-rate and modem lines, for when the backend
     18 *     is a real serial device.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "hw/char/imx_serial.h"
     23#include "hw/irq.h"
     24#include "hw/qdev-properties.h"
     25#include "hw/qdev-properties-system.h"
     26#include "migration/vmstate.h"
     27#include "qemu/log.h"
     28#include "qemu/module.h"
     29
     30#ifndef DEBUG_IMX_UART
     31#define DEBUG_IMX_UART 0
     32#endif
     33
     34#define DPRINTF(fmt, args...) \
     35    do { \
     36        if (DEBUG_IMX_UART) { \
     37            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_SERIAL, \
     38                                             __func__, ##args); \
     39        } \
     40    } while (0)
     41
     42static const VMStateDescription vmstate_imx_serial = {
     43    .name = TYPE_IMX_SERIAL,
     44    .version_id = 2,
     45    .minimum_version_id = 2,
     46    .fields = (VMStateField[]) {
     47        VMSTATE_INT32(readbuff, IMXSerialState),
     48        VMSTATE_UINT32(usr1, IMXSerialState),
     49        VMSTATE_UINT32(usr2, IMXSerialState),
     50        VMSTATE_UINT32(ucr1, IMXSerialState),
     51        VMSTATE_UINT32(uts1, IMXSerialState),
     52        VMSTATE_UINT32(onems, IMXSerialState),
     53        VMSTATE_UINT32(ufcr, IMXSerialState),
     54        VMSTATE_UINT32(ubmr, IMXSerialState),
     55        VMSTATE_UINT32(ubrc, IMXSerialState),
     56        VMSTATE_UINT32(ucr3, IMXSerialState),
     57        VMSTATE_UINT32(ucr4, IMXSerialState),
     58        VMSTATE_END_OF_LIST()
     59    },
     60};
     61
     62static void imx_update(IMXSerialState *s)
     63{
     64    uint32_t usr1;
     65    uint32_t usr2;
     66    uint32_t mask;
     67
     68    /*
     69     * Lucky for us TRDY and RRDY has the same offset in both USR1 and
     70     * UCR1, so we can get away with something as simple as the
     71     * following:
     72     */
     73    usr1 = s->usr1 & s->ucr1 & (USR1_TRDY | USR1_RRDY);
     74    /*
     75     * Bits that we want in USR2 are not as conveniently laid out,
     76     * unfortunately.
     77     */
     78    mask = (s->ucr1 & UCR1_TXMPTYEN) ? USR2_TXFE : 0;
     79    /*
     80     * TCEN and TXDC are both bit 3
     81     * RDR and DREN are both bit 0
     82     */
     83    mask |= s->ucr4 & (UCR4_TCEN | UCR4_DREN);
     84
     85    usr2 = s->usr2 & mask;
     86
     87    qemu_set_irq(s->irq, usr1 || usr2);
     88}
     89
     90static void imx_serial_reset(IMXSerialState *s)
     91{
     92
     93    s->usr1 = USR1_TRDY | USR1_RXDS;
     94    /*
     95     * Fake attachment of a terminal: assert RTS.
     96     */
     97    s->usr1 |= USR1_RTSS;
     98    s->usr2 = USR2_TXFE | USR2_TXDC | USR2_DCDIN;
     99    s->uts1 = UTS1_RXEMPTY | UTS1_TXEMPTY;
    100    s->ucr1 = 0;
    101    s->ucr2 = UCR2_SRST;
    102    s->ucr3 = 0x700;
    103    s->ubmr = 0;
    104    s->ubrc = 4;
    105    s->readbuff = URXD_ERR;
    106}
    107
    108static void imx_serial_reset_at_boot(DeviceState *dev)
    109{
    110    IMXSerialState *s = IMX_SERIAL(dev);
    111
    112    imx_serial_reset(s);
    113
    114    /*
    115     * enable the uart on boot, so messages from the linux decompresser
    116     * are visible.  On real hardware this is done by the boot rom
    117     * before anything else is loaded.
    118     */
    119    s->ucr1 = UCR1_UARTEN;
    120    s->ucr2 = UCR2_TXEN;
    121
    122}
    123
    124static uint64_t imx_serial_read(void *opaque, hwaddr offset,
    125                                unsigned size)
    126{
    127    IMXSerialState *s = (IMXSerialState *)opaque;
    128    uint32_t c;
    129
    130    DPRINTF("read(offset=0x%" HWADDR_PRIx ")\n", offset);
    131
    132    switch (offset >> 2) {
    133    case 0x0: /* URXD */
    134        c = s->readbuff;
    135        if (!(s->uts1 & UTS1_RXEMPTY)) {
    136            /* Character is valid */
    137            c |= URXD_CHARRDY;
    138            s->usr1 &= ~USR1_RRDY;
    139            s->usr2 &= ~USR2_RDR;
    140            s->uts1 |= UTS1_RXEMPTY;
    141            imx_update(s);
    142            qemu_chr_fe_accept_input(&s->chr);
    143        }
    144        return c;
    145
    146    case 0x20: /* UCR1 */
    147        return s->ucr1;
    148
    149    case 0x21: /* UCR2 */
    150        return s->ucr2;
    151
    152    case 0x25: /* USR1 */
    153        return s->usr1;
    154
    155    case 0x26: /* USR2 */
    156        return s->usr2;
    157
    158    case 0x2A: /* BRM Modulator */
    159        return s->ubmr;
    160
    161    case 0x2B: /* Baud Rate Count */
    162        return s->ubrc;
    163
    164    case 0x2d: /* Test register */
    165        return s->uts1;
    166
    167    case 0x24: /* UFCR */
    168        return s->ufcr;
    169
    170    case 0x2c:
    171        return s->onems;
    172
    173    case 0x22: /* UCR3 */
    174        return s->ucr3;
    175
    176    case 0x23: /* UCR4 */
    177        return s->ucr4;
    178
    179    case 0x29: /* BRM Incremental */
    180        return 0x0; /* TODO */
    181
    182    default:
    183        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    184                      HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
    185        return 0;
    186    }
    187}
    188
    189static void imx_serial_write(void *opaque, hwaddr offset,
    190                             uint64_t value, unsigned size)
    191{
    192    IMXSerialState *s = (IMXSerialState *)opaque;
    193    Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
    194    unsigned char ch;
    195
    196    DPRINTF("write(offset=0x%" HWADDR_PRIx ", value = 0x%x) to %s\n",
    197            offset, (unsigned int)value, chr ? chr->label : "NODEV");
    198
    199    switch (offset >> 2) {
    200    case 0x10: /* UTXD */
    201        ch = value;
    202        if (s->ucr2 & UCR2_TXEN) {
    203            /* XXX this blocks entire thread. Rewrite to use
    204             * qemu_chr_fe_write and background I/O callbacks */
    205            qemu_chr_fe_write_all(&s->chr, &ch, 1);
    206            s->usr1 &= ~USR1_TRDY;
    207            s->usr2 &= ~USR2_TXDC;
    208            imx_update(s);
    209            s->usr1 |= USR1_TRDY;
    210            s->usr2 |= USR2_TXDC;
    211            imx_update(s);
    212        }
    213        break;
    214
    215    case 0x20: /* UCR1 */
    216        s->ucr1 = value & 0xffff;
    217
    218        DPRINTF("write(ucr1=%x)\n", (unsigned int)value);
    219
    220        imx_update(s);
    221        break;
    222
    223    case 0x21: /* UCR2 */
    224        /*
    225         * Only a few bits in control register 2 are implemented as yet.
    226         * If it's intended to use a real serial device as a back-end, this
    227         * register will have to be implemented more fully.
    228         */
    229        if (!(value & UCR2_SRST)) {
    230            imx_serial_reset(s);
    231            imx_update(s);
    232            value |= UCR2_SRST;
    233        }
    234        if (value & UCR2_RXEN) {
    235            if (!(s->ucr2 & UCR2_RXEN)) {
    236                qemu_chr_fe_accept_input(&s->chr);
    237            }
    238        }
    239        s->ucr2 = value & 0xffff;
    240        break;
    241
    242    case 0x25: /* USR1 */
    243        value &= USR1_AWAKE | USR1_AIRINT | USR1_DTRD | USR1_AGTIM |
    244                 USR1_FRAMERR | USR1_ESCF | USR1_RTSD | USR1_PARTYER;
    245        s->usr1 &= ~value;
    246        break;
    247
    248    case 0x26: /* USR2 */
    249        /*
    250         * Writing 1 to some bits clears them; all other
    251         * values are ignored
    252         */
    253        value &= USR2_ADET | USR2_DTRF | USR2_IDLE | USR2_ACST |
    254                 USR2_RIDELT | USR2_IRINT | USR2_WAKE |
    255                 USR2_DCDDELT | USR2_RTSF | USR2_BRCD | USR2_ORE;
    256        s->usr2 &= ~value;
    257        break;
    258
    259    /*
    260     * Linux expects to see what it writes to these registers
    261     * We don't currently alter the baud rate
    262     */
    263    case 0x29: /* UBIR */
    264        s->ubrc = value & 0xffff;
    265        break;
    266
    267    case 0x2a: /* UBMR */
    268        s->ubmr = value & 0xffff;
    269        break;
    270
    271    case 0x2c: /* One ms reg */
    272        s->onems = value & 0xffff;
    273        break;
    274
    275    case 0x24: /* FIFO control register */
    276        s->ufcr = value & 0xffff;
    277        break;
    278
    279    case 0x22: /* UCR3 */
    280        s->ucr3 = value & 0xffff;
    281        break;
    282
    283    case 0x23: /* UCR4 */
    284        s->ucr4 = value & 0xffff;
    285        imx_update(s);
    286        break;
    287
    288    case 0x2d: /* UTS1 */
    289        qemu_log_mask(LOG_UNIMP, "[%s]%s: Unimplemented reg 0x%"
    290                      HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
    291        /* TODO */
    292        break;
    293
    294    default:
    295        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    296                      HWADDR_PRIx "\n", TYPE_IMX_SERIAL, __func__, offset);
    297    }
    298}
    299
    300static int imx_can_receive(void *opaque)
    301{
    302    IMXSerialState *s = (IMXSerialState *)opaque;
    303    return !(s->usr1 & USR1_RRDY);
    304}
    305
    306static void imx_put_data(void *opaque, uint32_t value)
    307{
    308    IMXSerialState *s = (IMXSerialState *)opaque;
    309
    310    DPRINTF("received char\n");
    311
    312    s->usr1 |= USR1_RRDY;
    313    s->usr2 |= USR2_RDR;
    314    s->uts1 &= ~UTS1_RXEMPTY;
    315    s->readbuff = value;
    316    if (value & URXD_BRK) {
    317        s->usr2 |= USR2_BRCD;
    318    }
    319    imx_update(s);
    320}
    321
    322static void imx_receive(void *opaque, const uint8_t *buf, int size)
    323{
    324    imx_put_data(opaque, *buf);
    325}
    326
    327static void imx_event(void *opaque, QEMUChrEvent event)
    328{
    329    if (event == CHR_EVENT_BREAK) {
    330        imx_put_data(opaque, URXD_BRK | URXD_FRMERR | URXD_ERR);
    331    }
    332}
    333
    334
    335static const struct MemoryRegionOps imx_serial_ops = {
    336    .read = imx_serial_read,
    337    .write = imx_serial_write,
    338    .endianness = DEVICE_NATIVE_ENDIAN,
    339};
    340
    341static void imx_serial_realize(DeviceState *dev, Error **errp)
    342{
    343    IMXSerialState *s = IMX_SERIAL(dev);
    344
    345    DPRINTF("char dev for uart: %p\n", qemu_chr_fe_get_driver(&s->chr));
    346
    347    qemu_chr_fe_set_handlers(&s->chr, imx_can_receive, imx_receive,
    348                             imx_event, NULL, s, NULL, true);
    349}
    350
    351static void imx_serial_init(Object *obj)
    352{
    353    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    354    IMXSerialState *s = IMX_SERIAL(obj);
    355
    356    memory_region_init_io(&s->iomem, obj, &imx_serial_ops, s,
    357                          TYPE_IMX_SERIAL, 0x1000);
    358    sysbus_init_mmio(sbd, &s->iomem);
    359    sysbus_init_irq(sbd, &s->irq);
    360}
    361
    362static Property imx_serial_properties[] = {
    363    DEFINE_PROP_CHR("chardev", IMXSerialState, chr),
    364    DEFINE_PROP_END_OF_LIST(),
    365};
    366
    367static void imx_serial_class_init(ObjectClass *klass, void *data)
    368{
    369    DeviceClass *dc = DEVICE_CLASS(klass);
    370
    371    dc->realize = imx_serial_realize;
    372    dc->vmsd = &vmstate_imx_serial;
    373    dc->reset = imx_serial_reset_at_boot;
    374    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    375    dc->desc = "i.MX series UART";
    376    device_class_set_props(dc, imx_serial_properties);
    377}
    378
    379static const TypeInfo imx_serial_info = {
    380    .name           = TYPE_IMX_SERIAL,
    381    .parent         = TYPE_SYS_BUS_DEVICE,
    382    .instance_size  = sizeof(IMXSerialState),
    383    .instance_init  = imx_serial_init,
    384    .class_init     = imx_serial_class_init,
    385};
    386
    387static void imx_serial_register_types(void)
    388{
    389    type_register_static(&imx_serial_info);
    390}
    391
    392type_init(imx_serial_register_types)