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

grlib_apbuart.c (8355B)


      1/*
      2 * QEMU GRLIB APB UART Emulator
      3 *
      4 * Copyright (c) 2010-2019 AdaCore
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "hw/irq.h"
     27#include "hw/qdev-properties.h"
     28#include "hw/qdev-properties-system.h"
     29#include "hw/sparc/grlib.h"
     30#include "hw/sysbus.h"
     31#include "qemu/module.h"
     32#include "chardev/char-fe.h"
     33
     34#include "trace.h"
     35#include "qom/object.h"
     36
     37#define UART_REG_SIZE 20     /* Size of memory mapped registers */
     38
     39/* UART status register fields */
     40#define UART_DATA_READY           (1 <<  0)
     41#define UART_TRANSMIT_SHIFT_EMPTY (1 <<  1)
     42#define UART_TRANSMIT_FIFO_EMPTY  (1 <<  2)
     43#define UART_BREAK_RECEIVED       (1 <<  3)
     44#define UART_OVERRUN              (1 <<  4)
     45#define UART_PARITY_ERROR         (1 <<  5)
     46#define UART_FRAMING_ERROR        (1 <<  6)
     47#define UART_TRANSMIT_FIFO_HALF   (1 <<  7)
     48#define UART_RECEIVE_FIFO_HALF    (1 <<  8)
     49#define UART_TRANSMIT_FIFO_FULL   (1 <<  9)
     50#define UART_RECEIVE_FIFO_FULL    (1 << 10)
     51
     52/* UART control register fields */
     53#define UART_RECEIVE_ENABLE          (1 <<  0)
     54#define UART_TRANSMIT_ENABLE         (1 <<  1)
     55#define UART_RECEIVE_INTERRUPT       (1 <<  2)
     56#define UART_TRANSMIT_INTERRUPT      (1 <<  3)
     57#define UART_PARITY_SELECT           (1 <<  4)
     58#define UART_PARITY_ENABLE           (1 <<  5)
     59#define UART_FLOW_CONTROL            (1 <<  6)
     60#define UART_LOOPBACK                (1 <<  7)
     61#define UART_EXTERNAL_CLOCK          (1 <<  8)
     62#define UART_RECEIVE_FIFO_INTERRUPT  (1 <<  9)
     63#define UART_TRANSMIT_FIFO_INTERRUPT (1 << 10)
     64#define UART_FIFO_DEBUG_MODE         (1 << 11)
     65#define UART_OUTPUT_ENABLE           (1 << 12)
     66#define UART_FIFO_AVAILABLE          (1 << 31)
     67
     68/* Memory mapped register offsets */
     69#define DATA_OFFSET       0x00
     70#define STATUS_OFFSET     0x04
     71#define CONTROL_OFFSET    0x08
     72#define SCALER_OFFSET     0x0C  /* not supported */
     73#define FIFO_DEBUG_OFFSET 0x10  /* not supported */
     74
     75#define FIFO_LENGTH 1024
     76
     77OBJECT_DECLARE_SIMPLE_TYPE(UART, GRLIB_APB_UART)
     78
     79struct UART {
     80    SysBusDevice parent_obj;
     81
     82    MemoryRegion iomem;
     83    qemu_irq irq;
     84
     85    CharBackend chr;
     86
     87    /* registers */
     88    uint32_t status;
     89    uint32_t control;
     90
     91    /* FIFO */
     92    char buffer[FIFO_LENGTH];
     93    int  len;
     94    int  current;
     95};
     96
     97static int uart_data_to_read(UART *uart)
     98{
     99    return uart->current < uart->len;
    100}
    101
    102static char uart_pop(UART *uart)
    103{
    104    char ret;
    105
    106    if (uart->len == 0) {
    107        uart->status &= ~UART_DATA_READY;
    108        return 0;
    109    }
    110
    111    ret = uart->buffer[uart->current++];
    112
    113    if (uart->current >= uart->len) {
    114        /* Flush */
    115        uart->len     = 0;
    116        uart->current = 0;
    117    }
    118
    119    if (!uart_data_to_read(uart)) {
    120        uart->status &= ~UART_DATA_READY;
    121    }
    122
    123    return ret;
    124}
    125
    126static void uart_add_to_fifo(UART          *uart,
    127                             const uint8_t *buffer,
    128                             int            length)
    129{
    130    if (uart->len + length > FIFO_LENGTH) {
    131        abort();
    132    }
    133    memcpy(uart->buffer + uart->len, buffer, length);
    134    uart->len += length;
    135}
    136
    137static int grlib_apbuart_can_receive(void *opaque)
    138{
    139    UART *uart = opaque;
    140
    141    return FIFO_LENGTH - uart->len;
    142}
    143
    144static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
    145{
    146    UART *uart = opaque;
    147
    148    if (uart->control & UART_RECEIVE_ENABLE) {
    149        uart_add_to_fifo(uart, buf, size);
    150
    151        uart->status |= UART_DATA_READY;
    152
    153        if (uart->control & UART_RECEIVE_INTERRUPT) {
    154            qemu_irq_pulse(uart->irq);
    155        }
    156    }
    157}
    158
    159static void grlib_apbuart_event(void *opaque, QEMUChrEvent event)
    160{
    161    trace_grlib_apbuart_event(event);
    162}
    163
    164
    165static uint64_t grlib_apbuart_read(void *opaque, hwaddr addr,
    166                                   unsigned size)
    167{
    168    UART     *uart = opaque;
    169
    170    addr &= 0xff;
    171
    172    /* Unit registers */
    173    switch (addr) {
    174    case DATA_OFFSET:
    175    case DATA_OFFSET + 3:       /* when only one byte read */
    176        return uart_pop(uart);
    177
    178    case STATUS_OFFSET:
    179        /* Read Only */
    180        return uart->status;
    181
    182    case CONTROL_OFFSET:
    183        return uart->control;
    184
    185    case SCALER_OFFSET:
    186        /* Not supported */
    187        return 0;
    188
    189    default:
    190        trace_grlib_apbuart_readl_unknown(addr);
    191        return 0;
    192    }
    193}
    194
    195static void grlib_apbuart_write(void *opaque, hwaddr addr,
    196                                uint64_t value, unsigned size)
    197{
    198    UART          *uart = opaque;
    199    unsigned char  c    = 0;
    200
    201    addr &= 0xff;
    202
    203    /* Unit registers */
    204    switch (addr) {
    205    case DATA_OFFSET:
    206    case DATA_OFFSET + 3:       /* When only one byte write */
    207        /* Transmit when character device available and transmitter enabled */
    208        if (qemu_chr_fe_backend_connected(&uart->chr) &&
    209            (uart->control & UART_TRANSMIT_ENABLE)) {
    210            c = value & 0xFF;
    211            /* XXX this blocks entire thread. Rewrite to use
    212             * qemu_chr_fe_write and background I/O callbacks */
    213            qemu_chr_fe_write_all(&uart->chr, &c, 1);
    214            /* Generate interrupt */
    215            if (uart->control & UART_TRANSMIT_INTERRUPT) {
    216                qemu_irq_pulse(uart->irq);
    217            }
    218        }
    219        return;
    220
    221    case STATUS_OFFSET:
    222        /* Read Only */
    223        return;
    224
    225    case CONTROL_OFFSET:
    226        uart->control = value;
    227        return;
    228
    229    case SCALER_OFFSET:
    230        /* Not supported */
    231        return;
    232
    233    default:
    234        break;
    235    }
    236
    237    trace_grlib_apbuart_writel_unknown(addr, value);
    238}
    239
    240static const MemoryRegionOps grlib_apbuart_ops = {
    241    .write      = grlib_apbuart_write,
    242    .read       = grlib_apbuart_read,
    243    .endianness = DEVICE_NATIVE_ENDIAN,
    244};
    245
    246static void grlib_apbuart_realize(DeviceState *dev, Error **errp)
    247{
    248    UART *uart = GRLIB_APB_UART(dev);
    249    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    250
    251    qemu_chr_fe_set_handlers(&uart->chr,
    252                             grlib_apbuart_can_receive,
    253                             grlib_apbuart_receive,
    254                             grlib_apbuart_event,
    255                             NULL, uart, NULL, true);
    256
    257    sysbus_init_irq(sbd, &uart->irq);
    258
    259    memory_region_init_io(&uart->iomem, OBJECT(uart), &grlib_apbuart_ops, uart,
    260                          "uart", UART_REG_SIZE);
    261
    262    sysbus_init_mmio(sbd, &uart->iomem);
    263}
    264
    265static void grlib_apbuart_reset(DeviceState *d)
    266{
    267    UART *uart = GRLIB_APB_UART(d);
    268
    269    /* Transmitter FIFO and shift registers are always empty in QEMU */
    270    uart->status =  UART_TRANSMIT_FIFO_EMPTY | UART_TRANSMIT_SHIFT_EMPTY;
    271    /* Everything is off */
    272    uart->control = 0;
    273    /* Flush receive FIFO */
    274    uart->len = 0;
    275    uart->current = 0;
    276}
    277
    278static Property grlib_apbuart_properties[] = {
    279    DEFINE_PROP_CHR("chrdev", UART, chr),
    280    DEFINE_PROP_END_OF_LIST(),
    281};
    282
    283static void grlib_apbuart_class_init(ObjectClass *klass, void *data)
    284{
    285    DeviceClass *dc = DEVICE_CLASS(klass);
    286
    287    dc->realize = grlib_apbuart_realize;
    288    dc->reset = grlib_apbuart_reset;
    289    device_class_set_props(dc, grlib_apbuart_properties);
    290}
    291
    292static const TypeInfo grlib_apbuart_info = {
    293    .name          = TYPE_GRLIB_APB_UART,
    294    .parent        = TYPE_SYS_BUS_DEVICE,
    295    .instance_size = sizeof(UART),
    296    .class_init    = grlib_apbuart_class_init,
    297};
    298
    299static void grlib_apbuart_register_types(void)
    300{
    301    type_register_static(&grlib_apbuart_info);
    302}
    303
    304type_init(grlib_apbuart_register_types)