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

bcm2835_gpio.c (8353B)


      1/*
      2 * Raspberry Pi (BCM2835) GPIO Controller
      3 *
      4 * Copyright (c) 2017 Antfield SAS
      5 *
      6 * Authors:
      7 *  Clement Deschamps <clement.deschamps@antfield.fr>
      8 *  Luc Michel <luc.michel@antfield.fr>
      9 *
     10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     11 * See the COPYING file in the top-level directory.
     12 */
     13
     14#include "qemu/osdep.h"
     15#include "qemu/log.h"
     16#include "qemu/module.h"
     17#include "qemu/timer.h"
     18#include "qapi/error.h"
     19#include "hw/sysbus.h"
     20#include "migration/vmstate.h"
     21#include "hw/sd/sd.h"
     22#include "hw/gpio/bcm2835_gpio.h"
     23#include "hw/irq.h"
     24
     25#define GPFSEL0   0x00
     26#define GPFSEL1   0x04
     27#define GPFSEL2   0x08
     28#define GPFSEL3   0x0C
     29#define GPFSEL4   0x10
     30#define GPFSEL5   0x14
     31#define GPSET0    0x1C
     32#define GPSET1    0x20
     33#define GPCLR0    0x28
     34#define GPCLR1    0x2C
     35#define GPLEV0    0x34
     36#define GPLEV1    0x38
     37#define GPEDS0    0x40
     38#define GPEDS1    0x44
     39#define GPREN0    0x4C
     40#define GPREN1    0x50
     41#define GPFEN0    0x58
     42#define GPFEN1    0x5C
     43#define GPHEN0    0x64
     44#define GPHEN1    0x68
     45#define GPLEN0    0x70
     46#define GPLEN1    0x74
     47#define GPAREN0   0x7C
     48#define GPAREN1   0x80
     49#define GPAFEN0   0x88
     50#define GPAFEN1   0x8C
     51#define GPPUD     0x94
     52#define GPPUDCLK0 0x98
     53#define GPPUDCLK1 0x9C
     54
     55static uint32_t gpfsel_get(BCM2835GpioState *s, uint8_t reg)
     56{
     57    int i;
     58    uint32_t value = 0;
     59    for (i = 0; i < 10; i++) {
     60        uint32_t index = 10 * reg + i;
     61        if (index < sizeof(s->fsel)) {
     62            value |= (s->fsel[index] & 0x7) << (3 * i);
     63        }
     64    }
     65    return value;
     66}
     67
     68static void gpfsel_set(BCM2835GpioState *s, uint8_t reg, uint32_t value)
     69{
     70    int i;
     71    for (i = 0; i < 10; i++) {
     72        uint32_t index = 10 * reg + i;
     73        if (index < sizeof(s->fsel)) {
     74            int fsel = (value >> (3 * i)) & 0x7;
     75            s->fsel[index] = fsel;
     76        }
     77    }
     78
     79    /* SD controller selection (48-53) */
     80    if (s->sd_fsel != 0
     81            && (s->fsel[48] == 0) /* SD_CLK_R */
     82            && (s->fsel[49] == 0) /* SD_CMD_R */
     83            && (s->fsel[50] == 0) /* SD_DATA0_R */
     84            && (s->fsel[51] == 0) /* SD_DATA1_R */
     85            && (s->fsel[52] == 0) /* SD_DATA2_R */
     86            && (s->fsel[53] == 0) /* SD_DATA3_R */
     87            ) {
     88        /* SDHCI controller selected */
     89        sdbus_reparent_card(s->sdbus_sdhost, s->sdbus_sdhci);
     90        s->sd_fsel = 0;
     91    } else if (s->sd_fsel != 4
     92            && (s->fsel[48] == 4) /* SD_CLK_R */
     93            && (s->fsel[49] == 4) /* SD_CMD_R */
     94            && (s->fsel[50] == 4) /* SD_DATA0_R */
     95            && (s->fsel[51] == 4) /* SD_DATA1_R */
     96            && (s->fsel[52] == 4) /* SD_DATA2_R */
     97            && (s->fsel[53] == 4) /* SD_DATA3_R */
     98            ) {
     99        /* SDHost controller selected */
    100        sdbus_reparent_card(s->sdbus_sdhci, s->sdbus_sdhost);
    101        s->sd_fsel = 4;
    102    }
    103}
    104
    105static int gpfsel_is_out(BCM2835GpioState *s, int index)
    106{
    107    if (index >= 0 && index < 54) {
    108        return s->fsel[index] == 1;
    109    }
    110    return 0;
    111}
    112
    113static void gpset(BCM2835GpioState *s,
    114        uint32_t val, uint8_t start, uint8_t count, uint32_t *lev)
    115{
    116    uint32_t changes = val & ~*lev;
    117    uint32_t cur = 1;
    118
    119    int i;
    120    for (i = 0; i < count; i++) {
    121        if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
    122            qemu_set_irq(s->out[start + i], 1);
    123        }
    124        cur <<= 1;
    125    }
    126
    127    *lev |= val;
    128}
    129
    130static void gpclr(BCM2835GpioState *s,
    131        uint32_t val, uint8_t start, uint8_t count, uint32_t *lev)
    132{
    133    uint32_t changes = val & *lev;
    134    uint32_t cur = 1;
    135
    136    int i;
    137    for (i = 0; i < count; i++) {
    138        if ((changes & cur) && (gpfsel_is_out(s, start + i))) {
    139            qemu_set_irq(s->out[start + i], 0);
    140        }
    141        cur <<= 1;
    142    }
    143
    144    *lev &= ~val;
    145}
    146
    147static uint64_t bcm2835_gpio_read(void *opaque, hwaddr offset,
    148        unsigned size)
    149{
    150    BCM2835GpioState *s = (BCM2835GpioState *)opaque;
    151
    152    switch (offset) {
    153    case GPFSEL0:
    154    case GPFSEL1:
    155    case GPFSEL2:
    156    case GPFSEL3:
    157    case GPFSEL4:
    158    case GPFSEL5:
    159        return gpfsel_get(s, offset / 4);
    160    case GPSET0:
    161    case GPSET1:
    162        /* Write Only */
    163        return 0;
    164    case GPCLR0:
    165    case GPCLR1:
    166        /* Write Only */
    167        return 0;
    168    case GPLEV0:
    169        return s->lev0;
    170    case GPLEV1:
    171        return s->lev1;
    172    case GPEDS0:
    173    case GPEDS1:
    174    case GPREN0:
    175    case GPREN1:
    176    case GPFEN0:
    177    case GPFEN1:
    178    case GPHEN0:
    179    case GPHEN1:
    180    case GPLEN0:
    181    case GPLEN1:
    182    case GPAREN0:
    183    case GPAREN1:
    184    case GPAFEN0:
    185    case GPAFEN1:
    186    case GPPUD:
    187    case GPPUDCLK0:
    188    case GPPUDCLK1:
    189        /* Not implemented */
    190        return 0;
    191    default:
    192        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
    193                __func__, offset);
    194        break;
    195    }
    196
    197    return 0;
    198}
    199
    200static void bcm2835_gpio_write(void *opaque, hwaddr offset,
    201        uint64_t value, unsigned size)
    202{
    203    BCM2835GpioState *s = (BCM2835GpioState *)opaque;
    204
    205    switch (offset) {
    206    case GPFSEL0:
    207    case GPFSEL1:
    208    case GPFSEL2:
    209    case GPFSEL3:
    210    case GPFSEL4:
    211    case GPFSEL5:
    212        gpfsel_set(s, offset / 4, value);
    213        break;
    214    case GPSET0:
    215        gpset(s, value, 0, 32, &s->lev0);
    216        break;
    217    case GPSET1:
    218        gpset(s, value, 32, 22, &s->lev1);
    219        break;
    220    case GPCLR0:
    221        gpclr(s, value, 0, 32, &s->lev0);
    222        break;
    223    case GPCLR1:
    224        gpclr(s, value, 32, 22, &s->lev1);
    225        break;
    226    case GPLEV0:
    227    case GPLEV1:
    228        /* Read Only */
    229        break;
    230    case GPEDS0:
    231    case GPEDS1:
    232    case GPREN0:
    233    case GPREN1:
    234    case GPFEN0:
    235    case GPFEN1:
    236    case GPHEN0:
    237    case GPHEN1:
    238    case GPLEN0:
    239    case GPLEN1:
    240    case GPAREN0:
    241    case GPAREN1:
    242    case GPAFEN0:
    243    case GPAFEN1:
    244    case GPPUD:
    245    case GPPUDCLK0:
    246    case GPPUDCLK1:
    247        /* Not implemented */
    248        break;
    249    default:
    250        goto err_out;
    251    }
    252    return;
    253
    254err_out:
    255    qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
    256            __func__, offset);
    257}
    258
    259static void bcm2835_gpio_reset(DeviceState *dev)
    260{
    261    BCM2835GpioState *s = BCM2835_GPIO(dev);
    262
    263    int i;
    264    for (i = 0; i < 6; i++) {
    265        gpfsel_set(s, i, 0);
    266    }
    267
    268    s->sd_fsel = 0;
    269
    270    /* SDHCI is selected by default */
    271    sdbus_reparent_card(&s->sdbus, s->sdbus_sdhci);
    272
    273    s->lev0 = 0;
    274    s->lev1 = 0;
    275}
    276
    277static const MemoryRegionOps bcm2835_gpio_ops = {
    278    .read = bcm2835_gpio_read,
    279    .write = bcm2835_gpio_write,
    280    .endianness = DEVICE_NATIVE_ENDIAN,
    281};
    282
    283static const VMStateDescription vmstate_bcm2835_gpio = {
    284    .name = "bcm2835_gpio",
    285    .version_id = 1,
    286    .minimum_version_id = 1,
    287    .fields = (VMStateField[]) {
    288        VMSTATE_UINT8_ARRAY(fsel, BCM2835GpioState, 54),
    289        VMSTATE_UINT32(lev0, BCM2835GpioState),
    290        VMSTATE_UINT32(lev1, BCM2835GpioState),
    291        VMSTATE_UINT8(sd_fsel, BCM2835GpioState),
    292        VMSTATE_END_OF_LIST()
    293    }
    294};
    295
    296static void bcm2835_gpio_init(Object *obj)
    297{
    298    BCM2835GpioState *s = BCM2835_GPIO(obj);
    299    DeviceState *dev = DEVICE(obj);
    300    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    301
    302    qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(s), "sd-bus");
    303
    304    memory_region_init_io(&s->iomem, obj,
    305            &bcm2835_gpio_ops, s, "bcm2835_gpio", 0x1000);
    306    sysbus_init_mmio(sbd, &s->iomem);
    307    qdev_init_gpio_out(dev, s->out, 54);
    308}
    309
    310static void bcm2835_gpio_realize(DeviceState *dev, Error **errp)
    311{
    312    BCM2835GpioState *s = BCM2835_GPIO(dev);
    313    Object *obj;
    314
    315    obj = object_property_get_link(OBJECT(dev), "sdbus-sdhci", &error_abort);
    316    s->sdbus_sdhci = SD_BUS(obj);
    317
    318    obj = object_property_get_link(OBJECT(dev), "sdbus-sdhost", &error_abort);
    319    s->sdbus_sdhost = SD_BUS(obj);
    320}
    321
    322static void bcm2835_gpio_class_init(ObjectClass *klass, void *data)
    323{
    324    DeviceClass *dc = DEVICE_CLASS(klass);
    325
    326    dc->vmsd = &vmstate_bcm2835_gpio;
    327    dc->realize = &bcm2835_gpio_realize;
    328    dc->reset = &bcm2835_gpio_reset;
    329}
    330
    331static const TypeInfo bcm2835_gpio_info = {
    332    .name          = TYPE_BCM2835_GPIO,
    333    .parent        = TYPE_SYS_BUS_DEVICE,
    334    .instance_size = sizeof(BCM2835GpioState),
    335    .instance_init = bcm2835_gpio_init,
    336    .class_init    = bcm2835_gpio_class_init,
    337};
    338
    339static void bcm2835_gpio_register_types(void)
    340{
    341    type_register_static(&bcm2835_gpio_info);
    342}
    343
    344type_init(bcm2835_gpio_register_types)