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_gpio.c (9996B)


      1/*
      2 * SiFive System-on-Chip general purpose input/output register definition
      3 *
      4 * Copyright 2019 AdaCore
      5 *
      6 * Base on nrf51_gpio.c:
      7 *
      8 * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
      9 *
     10 * This code is licensed under the GPL version 2 or later.  See
     11 * the COPYING file in the top-level directory.
     12 */
     13
     14#include "qemu/osdep.h"
     15#include "qemu/log.h"
     16#include "hw/irq.h"
     17#include "hw/qdev-properties.h"
     18#include "hw/gpio/sifive_gpio.h"
     19#include "migration/vmstate.h"
     20#include "trace.h"
     21
     22static void update_output_irq(SIFIVEGPIOState *s)
     23{
     24    uint32_t pending;
     25    uint32_t pin;
     26
     27    pending = s->high_ip & s->high_ie;
     28    pending |= s->low_ip & s->low_ie;
     29    pending |= s->rise_ip & s->rise_ie;
     30    pending |= s->fall_ip & s->fall_ie;
     31
     32    for (int i = 0; i < s->ngpio; i++) {
     33        pin = 1 << i;
     34        qemu_set_irq(s->irq[i], (pending & pin) != 0);
     35        trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0);
     36    }
     37}
     38
     39static void update_state(SIFIVEGPIOState *s)
     40{
     41    size_t i;
     42    bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en,
     43        rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival;
     44
     45    for (i = 0; i < s->ngpio; i++) {
     46
     47        prev_ival = extract32(s->value, i, 1);
     48        in        = extract32(s->in, i, 1);
     49        in_mask   = extract32(s->in_mask, i, 1);
     50        port      = extract32(s->port, i, 1);
     51        out_xor   = extract32(s->out_xor, i, 1);
     52        pull      = extract32(s->pue, i, 1);
     53        output_en = extract32(s->output_en, i, 1);
     54        input_en  = extract32(s->input_en, i, 1);
     55        rise_ip   = extract32(s->rise_ip, i, 1);
     56        fall_ip   = extract32(s->fall_ip, i, 1);
     57        low_ip    = extract32(s->low_ip, i, 1);
     58        high_ip   = extract32(s->high_ip, i, 1);
     59
     60        /* Output value (IOF not supported) */
     61        oval = output_en && (port ^ out_xor);
     62
     63        /* Pin both driven externally and internally */
     64        if (output_en && in_mask) {
     65            qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i);
     66        }
     67
     68        if (in_mask) {
     69            /* The pin is driven by external device */
     70            actual_value = in;
     71        } else if (output_en) {
     72            /* The pin is driven by internal circuit */
     73            actual_value = oval;
     74        } else {
     75            /* Floating? Apply pull-up resistor */
     76            actual_value = pull;
     77        }
     78
     79        if (output_en) {
     80            qemu_set_irq(s->output[i], actual_value);
     81        }
     82
     83        /* Input value */
     84        ival = input_en && actual_value;
     85
     86        /* Interrupts */
     87        high_ip = high_ip || ival;
     88        s->high_ip = deposit32(s->high_ip, i, 1, high_ip);
     89
     90        low_ip = low_ip || !ival;
     91        s->low_ip = deposit32(s->low_ip,  i, 1, low_ip);
     92
     93        rise_ip = rise_ip || (ival && !prev_ival);
     94        s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip);
     95
     96        fall_ip = fall_ip || (!ival && prev_ival);
     97        s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip);
     98
     99        /* Update value */
    100        s->value = deposit32(s->value, i, 1, ival);
    101    }
    102    update_output_irq(s);
    103}
    104
    105static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size)
    106{
    107    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
    108    uint64_t r = 0;
    109
    110    switch (offset) {
    111    case SIFIVE_GPIO_REG_VALUE:
    112        r = s->value;
    113        break;
    114
    115    case SIFIVE_GPIO_REG_INPUT_EN:
    116        r = s->input_en;
    117        break;
    118
    119    case SIFIVE_GPIO_REG_OUTPUT_EN:
    120        r = s->output_en;
    121        break;
    122
    123    case SIFIVE_GPIO_REG_PORT:
    124        r = s->port;
    125        break;
    126
    127    case SIFIVE_GPIO_REG_PUE:
    128        r = s->pue;
    129        break;
    130
    131    case SIFIVE_GPIO_REG_DS:
    132        r = s->ds;
    133        break;
    134
    135    case SIFIVE_GPIO_REG_RISE_IE:
    136        r = s->rise_ie;
    137        break;
    138
    139    case SIFIVE_GPIO_REG_RISE_IP:
    140        r = s->rise_ip;
    141        break;
    142
    143    case SIFIVE_GPIO_REG_FALL_IE:
    144        r = s->fall_ie;
    145        break;
    146
    147    case SIFIVE_GPIO_REG_FALL_IP:
    148        r = s->fall_ip;
    149        break;
    150
    151    case SIFIVE_GPIO_REG_HIGH_IE:
    152        r = s->high_ie;
    153        break;
    154
    155    case SIFIVE_GPIO_REG_HIGH_IP:
    156        r = s->high_ip;
    157        break;
    158
    159    case SIFIVE_GPIO_REG_LOW_IE:
    160        r = s->low_ie;
    161        break;
    162
    163    case SIFIVE_GPIO_REG_LOW_IP:
    164        r = s->low_ip;
    165        break;
    166
    167    case SIFIVE_GPIO_REG_IOF_EN:
    168        r = s->iof_en;
    169        break;
    170
    171    case SIFIVE_GPIO_REG_IOF_SEL:
    172        r = s->iof_sel;
    173        break;
    174
    175    case SIFIVE_GPIO_REG_OUT_XOR:
    176        r = s->out_xor;
    177        break;
    178
    179    default:
    180        qemu_log_mask(LOG_GUEST_ERROR,
    181                "%s: bad read offset 0x%" HWADDR_PRIx "\n",
    182                      __func__, offset);
    183    }
    184
    185    trace_sifive_gpio_read(offset, r);
    186
    187    return r;
    188}
    189
    190static void sifive_gpio_write(void *opaque, hwaddr offset,
    191                              uint64_t value, unsigned int size)
    192{
    193    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
    194
    195    trace_sifive_gpio_write(offset, value);
    196
    197    switch (offset) {
    198
    199    case SIFIVE_GPIO_REG_INPUT_EN:
    200        s->input_en = value;
    201        break;
    202
    203    case SIFIVE_GPIO_REG_OUTPUT_EN:
    204        s->output_en = value;
    205        break;
    206
    207    case SIFIVE_GPIO_REG_PORT:
    208        s->port = value;
    209        break;
    210
    211    case SIFIVE_GPIO_REG_PUE:
    212        s->pue = value;
    213        break;
    214
    215    case SIFIVE_GPIO_REG_DS:
    216        s->ds = value;
    217        break;
    218
    219    case SIFIVE_GPIO_REG_RISE_IE:
    220        s->rise_ie = value;
    221        break;
    222
    223    case SIFIVE_GPIO_REG_RISE_IP:
    224         /* Write 1 to clear */
    225        s->rise_ip &= ~value;
    226        break;
    227
    228    case SIFIVE_GPIO_REG_FALL_IE:
    229        s->fall_ie = value;
    230        break;
    231
    232    case SIFIVE_GPIO_REG_FALL_IP:
    233         /* Write 1 to clear */
    234        s->fall_ip &= ~value;
    235        break;
    236
    237    case SIFIVE_GPIO_REG_HIGH_IE:
    238        s->high_ie = value;
    239        break;
    240
    241    case SIFIVE_GPIO_REG_HIGH_IP:
    242         /* Write 1 to clear */
    243        s->high_ip &= ~value;
    244        break;
    245
    246    case SIFIVE_GPIO_REG_LOW_IE:
    247        s->low_ie = value;
    248        break;
    249
    250    case SIFIVE_GPIO_REG_LOW_IP:
    251         /* Write 1 to clear */
    252        s->low_ip &= ~value;
    253        break;
    254
    255    case SIFIVE_GPIO_REG_IOF_EN:
    256        s->iof_en = value;
    257        break;
    258
    259    case SIFIVE_GPIO_REG_IOF_SEL:
    260        s->iof_sel = value;
    261        break;
    262
    263    case SIFIVE_GPIO_REG_OUT_XOR:
    264        s->out_xor = value;
    265        break;
    266
    267    default:
    268        qemu_log_mask(LOG_GUEST_ERROR,
    269                      "%s: bad write offset 0x%" HWADDR_PRIx "\n",
    270                      __func__, offset);
    271    }
    272
    273    update_state(s);
    274}
    275
    276static const MemoryRegionOps gpio_ops = {
    277    .read =  sifive_gpio_read,
    278    .write = sifive_gpio_write,
    279    .endianness = DEVICE_LITTLE_ENDIAN,
    280    .impl.min_access_size = 4,
    281    .impl.max_access_size = 4,
    282};
    283
    284static void sifive_gpio_set(void *opaque, int line, int value)
    285{
    286    SIFIVEGPIOState *s = SIFIVE_GPIO(opaque);
    287
    288    trace_sifive_gpio_set(line, value);
    289
    290    assert(line >= 0 && line < SIFIVE_GPIO_PINS);
    291
    292    s->in_mask = deposit32(s->in_mask, line, 1, value >= 0);
    293    if (value >= 0) {
    294        s->in = deposit32(s->in, line, 1, value != 0);
    295    }
    296
    297    update_state(s);
    298}
    299
    300static void sifive_gpio_reset(DeviceState *dev)
    301{
    302    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
    303
    304    s->value = 0;
    305    s->input_en = 0;
    306    s->output_en = 0;
    307    s->port = 0;
    308    s->pue = 0;
    309    s->ds = 0;
    310    s->rise_ie = 0;
    311    s->rise_ip = 0;
    312    s->fall_ie = 0;
    313    s->fall_ip = 0;
    314    s->high_ie = 0;
    315    s->high_ip = 0;
    316    s->low_ie = 0;
    317    s->low_ip = 0;
    318    s->iof_en = 0;
    319    s->iof_sel = 0;
    320    s->out_xor = 0;
    321    s->in = 0;
    322    s->in_mask = 0;
    323}
    324
    325static const VMStateDescription vmstate_sifive_gpio = {
    326    .name = TYPE_SIFIVE_GPIO,
    327    .version_id = 1,
    328    .minimum_version_id = 1,
    329    .fields = (VMStateField[]) {
    330        VMSTATE_UINT32(value,     SIFIVEGPIOState),
    331        VMSTATE_UINT32(input_en,  SIFIVEGPIOState),
    332        VMSTATE_UINT32(output_en, SIFIVEGPIOState),
    333        VMSTATE_UINT32(port,      SIFIVEGPIOState),
    334        VMSTATE_UINT32(pue,       SIFIVEGPIOState),
    335        VMSTATE_UINT32(rise_ie,   SIFIVEGPIOState),
    336        VMSTATE_UINT32(rise_ip,   SIFIVEGPIOState),
    337        VMSTATE_UINT32(fall_ie,   SIFIVEGPIOState),
    338        VMSTATE_UINT32(fall_ip,   SIFIVEGPIOState),
    339        VMSTATE_UINT32(high_ie,   SIFIVEGPIOState),
    340        VMSTATE_UINT32(high_ip,   SIFIVEGPIOState),
    341        VMSTATE_UINT32(low_ie,    SIFIVEGPIOState),
    342        VMSTATE_UINT32(low_ip,    SIFIVEGPIOState),
    343        VMSTATE_UINT32(iof_en,    SIFIVEGPIOState),
    344        VMSTATE_UINT32(iof_sel,   SIFIVEGPIOState),
    345        VMSTATE_UINT32(out_xor,   SIFIVEGPIOState),
    346        VMSTATE_UINT32(in,        SIFIVEGPIOState),
    347        VMSTATE_UINT32(in_mask,   SIFIVEGPIOState),
    348        VMSTATE_END_OF_LIST()
    349    }
    350};
    351
    352static Property sifive_gpio_properties[] = {
    353    DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS),
    354    DEFINE_PROP_END_OF_LIST(),
    355};
    356
    357static void sifive_gpio_realize(DeviceState *dev, Error **errp)
    358{
    359    SIFIVEGPIOState *s = SIFIVE_GPIO(dev);
    360
    361    memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s,
    362            TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE);
    363
    364    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
    365
    366    for (int i = 0; i < s->ngpio; i++) {
    367        sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
    368    }
    369
    370    qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio);
    371    qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio);
    372}
    373
    374static void sifive_gpio_class_init(ObjectClass *klass, void *data)
    375{
    376    DeviceClass *dc = DEVICE_CLASS(klass);
    377
    378    device_class_set_props(dc, sifive_gpio_properties);
    379    dc->vmsd = &vmstate_sifive_gpio;
    380    dc->realize = sifive_gpio_realize;
    381    dc->reset = sifive_gpio_reset;
    382    dc->desc = "SiFive GPIO";
    383}
    384
    385static const TypeInfo sifive_gpio_info = {
    386    .name = TYPE_SIFIVE_GPIO,
    387    .parent = TYPE_SYS_BUS_DEVICE,
    388    .instance_size = sizeof(SIFIVEGPIOState),
    389    .class_init = sifive_gpio_class_init
    390};
    391
    392static void sifive_gpio_register_types(void)
    393{
    394    type_register_static(&sifive_gpio_info);
    395}
    396
    397type_init(sifive_gpio_register_types)