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

aspeed_vic.c (10661B)


      1/*
      2 * ASPEED Interrupt Controller (New)
      3 *
      4 * Andrew Jeffery <andrew@aj.id.au>
      5 *
      6 * Copyright 2015, 2016 IBM Corp.
      7 *
      8 * This code is licensed under the GPL version 2 or later.  See
      9 * the COPYING file in the top-level directory.
     10 */
     11
     12/* The hardware exposes two register sets, a legacy set and a 'new' set. The
     13 * model implements the 'new' register set, and logs warnings on accesses to
     14 * the legacy IO space.
     15 *
     16 * The hardware uses 32bit registers to manage 51 IRQs, with low and high
     17 * registers for each conceptual register. The device model's implementation
     18 * uses 64bit data types to store both low and high register values (in the one
     19 * member), but must cope with access offset values in multiples of 4 passed to
     20 * the callbacks. As such the read() and write() implementations process the
     21 * provided offset to understand whether the access is requesting the lower or
     22 * upper 32 bits of the 64bit member.
     23 *
     24 * Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt"
     25 * fields have separate "enable"/"status" and "clear" registers, where set bits
     26 * are written to one or the other to change state (avoiding a
     27 * read-modify-write sequence).
     28 */
     29
     30#include "qemu/osdep.h"
     31#include "hw/intc/aspeed_vic.h"
     32#include "hw/irq.h"
     33#include "migration/vmstate.h"
     34#include "qemu/bitops.h"
     35#include "qemu/log.h"
     36#include "qemu/module.h"
     37#include "trace.h"
     38
     39#define AVIC_NEW_BASE_OFFSET 0x80
     40
     41#define AVIC_L_MASK 0xFFFFFFFFU
     42#define AVIC_H_MASK 0x0007FFFFU
     43#define AVIC_EVENT_W_MASK (0x78000ULL << 32)
     44
     45static void aspeed_vic_update(AspeedVICState *s)
     46{
     47    uint64_t new = (s->raw & s->enable);
     48    uint64_t flags;
     49
     50    flags = new & s->select;
     51    trace_aspeed_vic_update_fiq(!!flags);
     52    qemu_set_irq(s->fiq, !!flags);
     53
     54    flags = new & ~s->select;
     55    trace_aspeed_vic_update_irq(!!flags);
     56    qemu_set_irq(s->irq, !!flags);
     57}
     58
     59static void aspeed_vic_set_irq(void *opaque, int irq, int level)
     60{
     61    uint64_t irq_mask;
     62    bool raise;
     63    AspeedVICState *s = (AspeedVICState *)opaque;
     64
     65    if (irq > ASPEED_VIC_NR_IRQS) {
     66        qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
     67                      __func__, irq);
     68        return;
     69    }
     70
     71    trace_aspeed_vic_set_irq(irq, level);
     72
     73    irq_mask = BIT(irq);
     74    if (s->sense & irq_mask) {
     75        /* level-triggered */
     76        if (s->event & irq_mask) {
     77            /* high-sensitive */
     78            raise = level;
     79        } else {
     80            /* low-sensitive */
     81            raise = !level;
     82        }
     83        s->raw = deposit64(s->raw, irq, 1, raise);
     84    } else {
     85        uint64_t old_level = s->level & irq_mask;
     86
     87        /* edge-triggered */
     88        if (s->dual_edge & irq_mask) {
     89            raise = (!!old_level) != (!!level);
     90        } else {
     91            if (s->event & irq_mask) {
     92                /* rising-sensitive */
     93                raise = !old_level && level;
     94            } else {
     95                /* falling-sensitive */
     96                raise = old_level && !level;
     97            }
     98        }
     99        if (raise) {
    100            s->raw = deposit64(s->raw, irq, 1, raise);
    101        }
    102    }
    103    s->level = deposit64(s->level, irq, 1, level);
    104    aspeed_vic_update(s);
    105}
    106
    107static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
    108{
    109    AspeedVICState *s = (AspeedVICState *)opaque;
    110    hwaddr n_offset;
    111    uint64_t val;
    112    bool high;
    113
    114    if (offset < AVIC_NEW_BASE_OFFSET) {
    115        high = false;
    116        n_offset = offset;
    117    } else {
    118        high = !!(offset & 0x4);
    119        n_offset = (offset & ~0x4);
    120    }
    121
    122    switch (n_offset) {
    123    case 0x80: /* IRQ Status */
    124    case 0x00:
    125        val = s->raw & ~s->select & s->enable;
    126        break;
    127    case 0x88: /* FIQ Status */
    128    case 0x04:
    129        val = s->raw & s->select & s->enable;
    130        break;
    131    case 0x90: /* Raw Interrupt Status */
    132    case 0x08:
    133        val = s->raw;
    134        break;
    135    case 0x98: /* Interrupt Selection */
    136    case 0x0c:
    137        val = s->select;
    138        break;
    139    case 0xa0: /* Interrupt Enable */
    140    case 0x10:
    141        val = s->enable;
    142        break;
    143    case 0xb0: /* Software Interrupt */
    144    case 0x18:
    145        val = s->trigger;
    146        break;
    147    case 0xc0: /* Interrupt Sensitivity */
    148    case 0x24:
    149        val = s->sense;
    150        break;
    151    case 0xc8: /* Interrupt Both Edge Trigger Control */
    152    case 0x28:
    153        val = s->dual_edge;
    154        break;
    155    case 0xd0: /* Interrupt Event */
    156    case 0x2c:
    157        val = s->event;
    158        break;
    159    case 0xe0: /* Edge Triggered Interrupt Status */
    160        val = s->raw & ~s->sense;
    161        break;
    162        /* Illegal */
    163    case 0xa8: /* Interrupt Enable Clear */
    164    case 0xb8: /* Software Interrupt Clear */
    165    case 0xd8: /* Edge Triggered Interrupt Clear */
    166        qemu_log_mask(LOG_GUEST_ERROR,
    167                      "%s: Read of write-only register with offset 0x%"
    168                      HWADDR_PRIx "\n", __func__, offset);
    169        val = 0;
    170        break;
    171    default:
    172        qemu_log_mask(LOG_GUEST_ERROR,
    173                      "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
    174                      __func__, offset);
    175        val = 0;
    176        break;
    177    }
    178    if (high) {
    179        val = extract64(val, 32, 19);
    180    } else {
    181        val = extract64(val, 0, 32);
    182    }
    183    trace_aspeed_vic_read(offset, size, val);
    184    return val;
    185}
    186
    187static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
    188                             unsigned size)
    189{
    190    AspeedVICState *s = (AspeedVICState *)opaque;
    191    hwaddr n_offset;
    192    bool high;
    193
    194    if (offset < AVIC_NEW_BASE_OFFSET) {
    195        high = false;
    196        n_offset = offset;
    197    } else {
    198        high = !!(offset & 0x4);
    199        n_offset = (offset & ~0x4);
    200    }
    201
    202    trace_aspeed_vic_write(offset, size, data);
    203
    204    /* Given we have members using separate enable/clear registers, deposit64()
    205     * isn't quite the tool for the job. Instead, relocate the incoming bits to
    206     * the required bit offset based on the provided access address
    207     */
    208    if (high) {
    209        data &= AVIC_H_MASK;
    210        data <<= 32;
    211    } else {
    212        data &= AVIC_L_MASK;
    213    }
    214
    215    switch (n_offset) {
    216    case 0x98: /* Interrupt Selection */
    217    case 0x0c:
    218        /* Register has deposit64() semantics - overwrite requested 32 bits */
    219        if (high) {
    220            s->select &= AVIC_L_MASK;
    221        } else {
    222            s->select &= ((uint64_t) AVIC_H_MASK) << 32;
    223        }
    224        s->select |= data;
    225        break;
    226    case 0xa0: /* Interrupt Enable */
    227    case 0x10:
    228        s->enable |= data;
    229        break;
    230    case 0xa8: /* Interrupt Enable Clear */
    231    case 0x14:
    232        s->enable &= ~data;
    233        break;
    234    case 0xb0: /* Software Interrupt */
    235    case 0x18:
    236        qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
    237                      "IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
    238        break;
    239    case 0xb8: /* Software Interrupt Clear */
    240    case 0x1c:
    241        qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
    242                      "IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
    243        break;
    244    case 0xd0: /* Interrupt Event */
    245        /* Register has deposit64() semantics - overwrite the top four valid
    246         * IRQ bits, as only the top four IRQs (GPIOs) can change their event
    247         * type */
    248        if (high) {
    249            s->event &= ~AVIC_EVENT_W_MASK;
    250            s->event |= (data & AVIC_EVENT_W_MASK);
    251        } else {
    252            qemu_log_mask(LOG_GUEST_ERROR,
    253                          "Ignoring invalid write to interrupt event register");
    254        }
    255        break;
    256    case 0xd8: /* Edge Triggered Interrupt Clear */
    257    case 0x38:
    258        s->raw &= ~(data & ~s->sense);
    259        break;
    260    case 0x80: /* IRQ Status */
    261    case 0x00:
    262    case 0x88: /* FIQ Status */
    263    case 0x04:
    264    case 0x90: /* Raw Interrupt Status */
    265    case 0x08:
    266    case 0xc0: /* Interrupt Sensitivity */
    267    case 0x24:
    268    case 0xc8: /* Interrupt Both Edge Trigger Control */
    269    case 0x28:
    270    case 0xe0: /* Edge Triggered Interrupt Status */
    271        qemu_log_mask(LOG_GUEST_ERROR,
    272                      "%s: Write of read-only register with offset 0x%"
    273                      HWADDR_PRIx "\n", __func__, offset);
    274        break;
    275
    276    default:
    277        qemu_log_mask(LOG_GUEST_ERROR,
    278                      "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
    279                      __func__, offset);
    280        break;
    281    }
    282    aspeed_vic_update(s);
    283}
    284
    285static const MemoryRegionOps aspeed_vic_ops = {
    286    .read = aspeed_vic_read,
    287    .write = aspeed_vic_write,
    288    .endianness = DEVICE_LITTLE_ENDIAN,
    289    .valid.min_access_size = 4,
    290    .valid.max_access_size = 4,
    291    .valid.unaligned = false,
    292};
    293
    294static void aspeed_vic_reset(DeviceState *dev)
    295{
    296    AspeedVICState *s = ASPEED_VIC(dev);
    297
    298    s->level = 0;
    299    s->raw = 0;
    300    s->select = 0;
    301    s->enable = 0;
    302    s->trigger = 0;
    303    s->sense = 0x1F07FFF8FFFFULL;
    304    s->dual_edge = 0xF800070000ULL;
    305    s->event = 0x5F07FFF8FFFFULL;
    306}
    307
    308#define AVIC_IO_REGION_SIZE 0x20000
    309
    310static void aspeed_vic_realize(DeviceState *dev, Error **errp)
    311{
    312    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    313    AspeedVICState *s = ASPEED_VIC(dev);
    314
    315    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s,
    316                          TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE);
    317
    318    sysbus_init_mmio(sbd, &s->iomem);
    319
    320    qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS);
    321    sysbus_init_irq(sbd, &s->irq);
    322    sysbus_init_irq(sbd, &s->fiq);
    323}
    324
    325static const VMStateDescription vmstate_aspeed_vic = {
    326    .name = "aspeed.new-vic",
    327    .version_id = 1,
    328    .minimum_version_id = 1,
    329    .fields = (VMStateField[]) {
    330        VMSTATE_UINT64(level, AspeedVICState),
    331        VMSTATE_UINT64(raw, AspeedVICState),
    332        VMSTATE_UINT64(select, AspeedVICState),
    333        VMSTATE_UINT64(enable, AspeedVICState),
    334        VMSTATE_UINT64(trigger, AspeedVICState),
    335        VMSTATE_UINT64(sense, AspeedVICState),
    336        VMSTATE_UINT64(dual_edge, AspeedVICState),
    337        VMSTATE_UINT64(event, AspeedVICState),
    338        VMSTATE_END_OF_LIST()
    339    }
    340};
    341
    342static void aspeed_vic_class_init(ObjectClass *klass, void *data)
    343{
    344    DeviceClass *dc = DEVICE_CLASS(klass);
    345    dc->realize = aspeed_vic_realize;
    346    dc->reset = aspeed_vic_reset;
    347    dc->desc = "ASPEED Interrupt Controller (New)";
    348    dc->vmsd = &vmstate_aspeed_vic;
    349}
    350
    351static const TypeInfo aspeed_vic_info = {
    352    .name = TYPE_ASPEED_VIC,
    353    .parent = TYPE_SYS_BUS_DEVICE,
    354    .instance_size = sizeof(AspeedVICState),
    355    .class_init = aspeed_vic_class_init,
    356};
    357
    358static void aspeed_vic_register_types(void)
    359{
    360    type_register_static(&aspeed_vic_info);
    361}
    362
    363type_init(aspeed_vic_register_types);