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

sifive_spi.c (8810B)


      1/*
      2 * QEMU model of the SiFive SPI Controller
      3 *
      4 * Copyright (c) 2021 Wind River Systems, Inc.
      5 *
      6 * Author:
      7 *   Bin Meng <bin.meng@windriver.com>
      8 *
      9 * This program is free software; you can redistribute it and/or modify it
     10 * under the terms and conditions of the GNU General Public License,
     11 * version 2 or later, as published by the Free Software Foundation.
     12 *
     13 * This program is distributed in the hope it will be useful, but WITHOUT
     14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     16 * more details.
     17 *
     18 * You should have received a copy of the GNU General Public License along with
     19 * this program.  If not, see <http://www.gnu.org/licenses/>.
     20 */
     21
     22#include "qemu/osdep.h"
     23#include "hw/irq.h"
     24#include "hw/qdev-properties.h"
     25#include "hw/sysbus.h"
     26#include "hw/ssi/ssi.h"
     27#include "qemu/fifo8.h"
     28#include "qemu/log.h"
     29#include "qemu/module.h"
     30#include "hw/ssi/sifive_spi.h"
     31
     32#define R_SCKDIV        (0x00 / 4)
     33#define R_SCKMODE       (0x04 / 4)
     34#define R_CSID          (0x10 / 4)
     35#define R_CSDEF         (0x14 / 4)
     36#define R_CSMODE        (0x18 / 4)
     37#define R_DELAY0        (0x28 / 4)
     38#define R_DELAY1        (0x2C / 4)
     39#define R_FMT           (0x40 / 4)
     40#define R_TXDATA        (0x48 / 4)
     41#define R_RXDATA        (0x4C / 4)
     42#define R_TXMARK        (0x50 / 4)
     43#define R_RXMARK        (0x54 / 4)
     44#define R_FCTRL         (0x60 / 4)
     45#define R_FFMT          (0x64 / 4)
     46#define R_IE            (0x70 / 4)
     47#define R_IP            (0x74 / 4)
     48
     49#define FMT_DIR         (1 << 3)
     50
     51#define TXDATA_FULL     (1 << 31)
     52#define RXDATA_EMPTY    (1 << 31)
     53
     54#define IE_TXWM         (1 << 0)
     55#define IE_RXWM         (1 << 1)
     56
     57#define IP_TXWM         (1 << 0)
     58#define IP_RXWM         (1 << 1)
     59
     60#define FIFO_CAPACITY   8
     61
     62static void sifive_spi_txfifo_reset(SiFiveSPIState *s)
     63{
     64    fifo8_reset(&s->tx_fifo);
     65
     66    s->regs[R_TXDATA] &= ~TXDATA_FULL;
     67    s->regs[R_IP] &= ~IP_TXWM;
     68}
     69
     70static void sifive_spi_rxfifo_reset(SiFiveSPIState *s)
     71{
     72    fifo8_reset(&s->rx_fifo);
     73
     74    s->regs[R_RXDATA] |= RXDATA_EMPTY;
     75    s->regs[R_IP] &= ~IP_RXWM;
     76}
     77
     78static void sifive_spi_update_cs(SiFiveSPIState *s)
     79{
     80    int i;
     81
     82    for (i = 0; i < s->num_cs; i++) {
     83        if (s->regs[R_CSDEF] & (1 << i)) {
     84            qemu_set_irq(s->cs_lines[i], !(s->regs[R_CSMODE]));
     85        }
     86    }
     87}
     88
     89static void sifive_spi_update_irq(SiFiveSPIState *s)
     90{
     91    int level;
     92
     93    if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) {
     94        s->regs[R_IP] |= IP_TXWM;
     95    } else {
     96        s->regs[R_IP] &= ~IP_TXWM;
     97    }
     98
     99    if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) {
    100        s->regs[R_IP] |= IP_RXWM;
    101    } else {
    102        s->regs[R_IP] &= ~IP_RXWM;
    103    }
    104
    105    level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0;
    106    qemu_set_irq(s->irq, level);
    107}
    108
    109static void sifive_spi_reset(DeviceState *d)
    110{
    111    SiFiveSPIState *s = SIFIVE_SPI(d);
    112
    113    memset(s->regs, 0, sizeof(s->regs));
    114
    115    /* The reset value is high for all implemented CS pins */
    116    s->regs[R_CSDEF] = (1 << s->num_cs) - 1;
    117
    118    /* Populate register with their default value */
    119    s->regs[R_SCKDIV] = 0x03;
    120    s->regs[R_DELAY0] = 0x1001;
    121    s->regs[R_DELAY1] = 0x01;
    122
    123    sifive_spi_txfifo_reset(s);
    124    sifive_spi_rxfifo_reset(s);
    125
    126    sifive_spi_update_cs(s);
    127    sifive_spi_update_irq(s);
    128}
    129
    130static void sifive_spi_flush_txfifo(SiFiveSPIState *s)
    131{
    132    uint8_t tx;
    133    uint8_t rx;
    134
    135    while (!fifo8_is_empty(&s->tx_fifo)) {
    136        tx = fifo8_pop(&s->tx_fifo);
    137        rx = ssi_transfer(s->spi, tx);
    138
    139        if (!fifo8_is_full(&s->rx_fifo)) {
    140            if (!(s->regs[R_FMT] & FMT_DIR)) {
    141                fifo8_push(&s->rx_fifo, rx);
    142            }
    143        }
    144    }
    145}
    146
    147static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved)
    148{
    149    bool bad;
    150
    151    switch (addr) {
    152    /* reserved offsets */
    153    case 0x08:
    154    case 0x0C:
    155    case 0x1C:
    156    case 0x20:
    157    case 0x24:
    158    case 0x30:
    159    case 0x34:
    160    case 0x38:
    161    case 0x3C:
    162    case 0x44:
    163    case 0x58:
    164    case 0x5C:
    165    case 0x68:
    166    case 0x6C:
    167        bad = allow_reserved ? false : true;
    168        break;
    169    default:
    170        bad = false;
    171    }
    172
    173    if (addr >= (SIFIVE_SPI_REG_NUM << 2)) {
    174        bad = true;
    175    }
    176
    177    return bad;
    178}
    179
    180static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size)
    181{
    182    SiFiveSPIState *s = opaque;
    183    uint32_t r;
    184
    185    if (sifive_spi_is_bad_reg(addr, true)) {
    186        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read at address 0x%"
    187                      HWADDR_PRIx "\n", __func__, addr);
    188        return 0;
    189    }
    190
    191    addr >>= 2;
    192    switch (addr) {
    193    case R_TXDATA:
    194        if (fifo8_is_full(&s->tx_fifo)) {
    195            return TXDATA_FULL;
    196        }
    197        r = 0;
    198        break;
    199
    200    case R_RXDATA:
    201        if (fifo8_is_empty(&s->rx_fifo)) {
    202            return RXDATA_EMPTY;
    203        }
    204        r = fifo8_pop(&s->rx_fifo);
    205        break;
    206
    207    default:
    208        r = s->regs[addr];
    209        break;
    210    }
    211
    212    sifive_spi_update_irq(s);
    213
    214    return r;
    215}
    216
    217static void sifive_spi_write(void *opaque, hwaddr addr,
    218                             uint64_t val64, unsigned int size)
    219{
    220    SiFiveSPIState *s = opaque;
    221    uint32_t value = val64;
    222
    223    if (sifive_spi_is_bad_reg(addr, false)) {
    224        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write at addr=0x%"
    225                      HWADDR_PRIx " value=0x%x\n", __func__, addr, value);
    226        return;
    227    }
    228
    229    addr >>= 2;
    230    switch (addr) {
    231    case R_CSID:
    232        if (value >= s->num_cs) {
    233            qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csid %d\n",
    234                          __func__, value);
    235        } else {
    236            s->regs[R_CSID] = value;
    237            sifive_spi_update_cs(s);
    238        }
    239        break;
    240
    241    case R_CSDEF:
    242        if (value >= (1 << s->num_cs)) {
    243            qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csdef %x\n",
    244                          __func__, value);
    245        } else {
    246            s->regs[R_CSDEF] = value;
    247        }
    248        break;
    249
    250    case R_CSMODE:
    251        if (value > 3) {
    252            qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csmode %x\n",
    253                          __func__, value);
    254        } else {
    255            s->regs[R_CSMODE] = value;
    256            sifive_spi_update_cs(s);
    257        }
    258        break;
    259
    260    case R_TXDATA:
    261        if (!fifo8_is_full(&s->tx_fifo)) {
    262            fifo8_push(&s->tx_fifo, (uint8_t)value);
    263            sifive_spi_flush_txfifo(s);
    264        }
    265        break;
    266
    267    case R_RXDATA:
    268    case R_IP:
    269        qemu_log_mask(LOG_GUEST_ERROR,
    270                      "%s: invalid write to read-only reigster 0x%"
    271                      HWADDR_PRIx " with 0x%x\n", __func__, addr << 2, value);
    272        break;
    273
    274    case R_TXMARK:
    275    case R_RXMARK:
    276        if (value >= FIFO_CAPACITY) {
    277            qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid watermark %d\n",
    278                          __func__, value);
    279        } else {
    280            s->regs[addr] = value;
    281        }
    282        break;
    283
    284    case R_FCTRL:
    285    case R_FFMT:
    286        qemu_log_mask(LOG_UNIMP,
    287                      "%s: direct-map flash interface unimplemented\n",
    288                      __func__);
    289        break;
    290
    291    default:
    292        s->regs[addr] = value;
    293        break;
    294    }
    295
    296    sifive_spi_update_irq(s);
    297}
    298
    299static const MemoryRegionOps sifive_spi_ops = {
    300    .read = sifive_spi_read,
    301    .write = sifive_spi_write,
    302    .endianness = DEVICE_LITTLE_ENDIAN,
    303    .valid = {
    304        .min_access_size = 4,
    305        .max_access_size = 4
    306    }
    307};
    308
    309static void sifive_spi_realize(DeviceState *dev, Error **errp)
    310{
    311    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    312    SiFiveSPIState *s = SIFIVE_SPI(dev);
    313    int i;
    314
    315    s->spi = ssi_create_bus(dev, "spi");
    316    sysbus_init_irq(sbd, &s->irq);
    317
    318    s->cs_lines = g_new0(qemu_irq, s->num_cs);
    319    for (i = 0; i < s->num_cs; i++) {
    320        sysbus_init_irq(sbd, &s->cs_lines[i]);
    321    }
    322
    323    memory_region_init_io(&s->mmio, OBJECT(s), &sifive_spi_ops, s,
    324                          TYPE_SIFIVE_SPI, 0x1000);
    325    sysbus_init_mmio(sbd, &s->mmio);
    326
    327    fifo8_create(&s->tx_fifo, FIFO_CAPACITY);
    328    fifo8_create(&s->rx_fifo, FIFO_CAPACITY);
    329}
    330
    331static Property sifive_spi_properties[] = {
    332    DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1),
    333    DEFINE_PROP_END_OF_LIST(),
    334};
    335
    336static void sifive_spi_class_init(ObjectClass *klass, void *data)
    337{
    338    DeviceClass *dc = DEVICE_CLASS(klass);
    339
    340    device_class_set_props(dc, sifive_spi_properties);
    341    dc->reset = sifive_spi_reset;
    342    dc->realize = sifive_spi_realize;
    343}
    344
    345static const TypeInfo sifive_spi_info = {
    346    .name           = TYPE_SIFIVE_SPI,
    347    .parent         = TYPE_SYS_BUS_DEVICE,
    348    .instance_size  = sizeof(SiFiveSPIState),
    349    .class_init     = sifive_spi_class_init,
    350};
    351
    352static void sifive_spi_register_types(void)
    353{
    354    type_register_static(&sifive_spi_info);
    355}
    356
    357type_init(sifive_spi_register_types)