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

imx_avic.c (10911B)


      1/*
      2 * i.MX31 Vectored Interrupt Controller
      3 *
      4 * Note this is NOT the PL192 provided by ARM, but
      5 * a custom implementation by Freescale.
      6 *
      7 * Copyright (c) 2008 OKL
      8 * Copyright (c) 2011 NICTA Pty Ltd
      9 * Originally written by Hans Jiang
     10 * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
     11 *
     12 * This code is licensed under the GPL version 2 or later.  See
     13 * the COPYING file in the top-level directory.
     14 *
     15 * TODO: implement vectors.
     16 */
     17
     18#include "qemu/osdep.h"
     19#include "hw/intc/imx_avic.h"
     20#include "hw/irq.h"
     21#include "migration/vmstate.h"
     22#include "qemu/log.h"
     23#include "qemu/module.h"
     24
     25#ifndef DEBUG_IMX_AVIC
     26#define DEBUG_IMX_AVIC 0
     27#endif
     28
     29#define DPRINTF(fmt, args...) \
     30    do { \
     31        if (DEBUG_IMX_AVIC) { \
     32            fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_AVIC, \
     33                                             __func__, ##args); \
     34        } \
     35    } while (0)
     36
     37static const VMStateDescription vmstate_imx_avic = {
     38    .name = TYPE_IMX_AVIC,
     39    .version_id = 1,
     40    .minimum_version_id = 1,
     41    .fields = (VMStateField[]) {
     42        VMSTATE_UINT64(pending, IMXAVICState),
     43        VMSTATE_UINT64(enabled, IMXAVICState),
     44        VMSTATE_UINT64(is_fiq, IMXAVICState),
     45        VMSTATE_UINT32(intcntl, IMXAVICState),
     46        VMSTATE_UINT32(intmask, IMXAVICState),
     47        VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
     48        VMSTATE_END_OF_LIST()
     49    },
     50};
     51
     52static inline int imx_avic_prio(IMXAVICState *s, int irq)
     53{
     54    uint32_t word = irq / PRIO_PER_WORD;
     55    uint32_t part = 4 * (irq % PRIO_PER_WORD);
     56    return 0xf & (s->prio[word] >> part);
     57}
     58
     59/* Update interrupts.  */
     60static void imx_avic_update(IMXAVICState *s)
     61{
     62    int i;
     63    uint64_t new = s->pending & s->enabled;
     64    uint64_t flags;
     65
     66    flags = new & s->is_fiq;
     67    qemu_set_irq(s->fiq, !!flags);
     68
     69    flags = new & ~s->is_fiq;
     70    if (!flags || (s->intmask == 0x1f)) {
     71        qemu_set_irq(s->irq, !!flags);
     72        return;
     73    }
     74
     75    /*
     76     * Take interrupt if there's a pending interrupt with
     77     * priority higher than the value of intmask
     78     */
     79    for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
     80        if (flags & (1UL << i)) {
     81            if (imx_avic_prio(s, i) > s->intmask) {
     82                qemu_set_irq(s->irq, 1);
     83                return;
     84            }
     85        }
     86    }
     87    qemu_set_irq(s->irq, 0);
     88}
     89
     90static void imx_avic_set_irq(void *opaque, int irq, int level)
     91{
     92    IMXAVICState *s = (IMXAVICState *)opaque;
     93
     94    if (level) {
     95        DPRINTF("Raising IRQ %d, prio %d\n",
     96                irq, imx_avic_prio(s, irq));
     97        s->pending |= (1ULL << irq);
     98    } else {
     99        DPRINTF("Clearing IRQ %d, prio %d\n",
    100                irq, imx_avic_prio(s, irq));
    101        s->pending &= ~(1ULL << irq);
    102    }
    103
    104    imx_avic_update(s);
    105}
    106
    107
    108static uint64_t imx_avic_read(void *opaque,
    109                             hwaddr offset, unsigned size)
    110{
    111    IMXAVICState *s = (IMXAVICState *)opaque;
    112
    113    DPRINTF("read(offset = 0x%" HWADDR_PRIx ")\n", offset);
    114
    115    switch (offset >> 2) {
    116    case 0: /* INTCNTL */
    117        return s->intcntl;
    118
    119    case 1: /* Normal Interrupt Mask Register, NIMASK */
    120        return s->intmask;
    121
    122    case 2: /* Interrupt Enable Number Register, INTENNUM */
    123    case 3: /* Interrupt Disable Number Register, INTDISNUM */
    124        return 0;
    125
    126    case 4: /* Interrupt Enabled Number Register High */
    127        return s->enabled >> 32;
    128
    129    case 5: /* Interrupt Enabled Number Register Low */
    130        return s->enabled & 0xffffffffULL;
    131
    132    case 6: /* Interrupt Type Register High */
    133        return s->is_fiq >> 32;
    134
    135    case 7: /* Interrupt Type Register Low */
    136        return s->is_fiq & 0xffffffffULL;
    137
    138    case 8: /* Normal Interrupt Priority Register 7 */
    139    case 9: /* Normal Interrupt Priority Register 6 */
    140    case 10:/* Normal Interrupt Priority Register 5 */
    141    case 11:/* Normal Interrupt Priority Register 4 */
    142    case 12:/* Normal Interrupt Priority Register 3 */
    143    case 13:/* Normal Interrupt Priority Register 2 */
    144    case 14:/* Normal Interrupt Priority Register 1 */
    145    case 15:/* Normal Interrupt Priority Register 0 */
    146        return s->prio[15-(offset>>2)];
    147
    148    case 16: /* Normal interrupt vector and status register */
    149    {
    150        /*
    151         * This returns the highest priority
    152         * outstanding interrupt.  Where there is more than
    153         * one pending IRQ with the same priority,
    154         * take the highest numbered one.
    155         */
    156        uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
    157        int i;
    158        int prio = -1;
    159        int irq = -1;
    160        for (i = 63; i >= 0; --i) {
    161            if (flags & (1ULL<<i)) {
    162                int irq_prio = imx_avic_prio(s, i);
    163                if (irq_prio > prio) {
    164                    irq = i;
    165                    prio = irq_prio;
    166                }
    167            }
    168        }
    169        if (irq >= 0) {
    170            imx_avic_set_irq(s, irq, 0);
    171            return irq << 16 | prio;
    172        }
    173        return 0xffffffffULL;
    174    }
    175    case 17:/* Fast Interrupt vector and status register */
    176    {
    177        uint64_t flags = s->pending & s->enabled & s->is_fiq;
    178        int i = ctz64(flags);
    179        if (i < 64) {
    180            imx_avic_set_irq(opaque, i, 0);
    181            return i;
    182        }
    183        return 0xffffffffULL;
    184    }
    185    case 18:/* Interrupt source register high */
    186        return s->pending >> 32;
    187
    188    case 19:/* Interrupt source register low */
    189        return s->pending & 0xffffffffULL;
    190
    191    case 20:/* Interrupt Force Register high */
    192    case 21:/* Interrupt Force Register low */
    193        return 0;
    194
    195    case 22:/* Normal Interrupt Pending Register High */
    196        return (s->pending & s->enabled & ~s->is_fiq) >> 32;
    197
    198    case 23:/* Normal Interrupt Pending Register Low */
    199        return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
    200
    201    case 24: /* Fast Interrupt Pending Register High  */
    202        return (s->pending & s->enabled & s->is_fiq) >> 32;
    203
    204    case 25: /* Fast Interrupt Pending Register Low  */
    205        return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
    206
    207    case 0x40:            /* AVIC vector 0, use for WFI WAR */
    208        return 0x4;
    209
    210    default:
    211        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    212                      HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
    213        return 0;
    214    }
    215}
    216
    217static void imx_avic_write(void *opaque, hwaddr offset,
    218                          uint64_t val, unsigned size)
    219{
    220    IMXAVICState *s = (IMXAVICState *)opaque;
    221
    222    /* Vector Registers not yet supported */
    223    if (offset >= 0x100 && offset <= 0x2fc) {
    224        qemu_log_mask(LOG_UNIMP, "[%s]%s: vector %d ignored\n",
    225                      TYPE_IMX_AVIC, __func__, (int)((offset - 0x100) >> 2));
    226        return;
    227    }
    228
    229    DPRINTF("(0x%" HWADDR_PRIx ") = 0x%x\n", offset, (unsigned int)val);
    230
    231    switch (offset >> 2) {
    232    case 0: /* Interrupt Control Register, INTCNTL */
    233        s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
    234        if (s->intcntl & ABFEN) {
    235            s->intcntl &= ~(val & ABFLAG);
    236        }
    237        break;
    238
    239    case 1: /* Normal Interrupt Mask Register, NIMASK */
    240        s->intmask = val & 0x1f;
    241        break;
    242
    243    case 2: /* Interrupt Enable Number Register, INTENNUM */
    244        DPRINTF("enable(%d)\n", (int)val);
    245        val &= 0x3f;
    246        s->enabled |= (1ULL << val);
    247        break;
    248
    249    case 3: /* Interrupt Disable Number Register, INTDISNUM */
    250        DPRINTF("disable(%d)\n", (int)val);
    251        val &= 0x3f;
    252        s->enabled &= ~(1ULL << val);
    253        break;
    254
    255    case 4: /* Interrupt Enable Number Register High */
    256        s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
    257        break;
    258
    259    case 5: /* Interrupt Enable Number Register Low */
    260        s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
    261        break;
    262
    263    case 6: /* Interrupt Type Register High */
    264        s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
    265        break;
    266
    267    case 7: /* Interrupt Type Register Low */
    268        s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
    269        break;
    270
    271    case 8: /* Normal Interrupt Priority Register 7 */
    272    case 9: /* Normal Interrupt Priority Register 6 */
    273    case 10:/* Normal Interrupt Priority Register 5 */
    274    case 11:/* Normal Interrupt Priority Register 4 */
    275    case 12:/* Normal Interrupt Priority Register 3 */
    276    case 13:/* Normal Interrupt Priority Register 2 */
    277    case 14:/* Normal Interrupt Priority Register 1 */
    278    case 15:/* Normal Interrupt Priority Register 0 */
    279        s->prio[15-(offset>>2)] = val;
    280        break;
    281
    282        /* Read-only registers, writes ignored */
    283    case 16:/* Normal Interrupt Vector and Status register */
    284    case 17:/* Fast Interrupt vector and status register */
    285    case 18:/* Interrupt source register high */
    286    case 19:/* Interrupt source register low */
    287        return;
    288
    289    case 20:/* Interrupt Force Register high */
    290        s->pending = (s->pending & 0xffffffffULL) | (val << 32);
    291        break;
    292
    293    case 21:/* Interrupt Force Register low */
    294        s->pending = (s->pending & 0xffffffff00000000ULL) | val;
    295        break;
    296
    297    case 22:/* Normal Interrupt Pending Register High */
    298    case 23:/* Normal Interrupt Pending Register Low */
    299    case 24: /* Fast Interrupt Pending Register High  */
    300    case 25: /* Fast Interrupt Pending Register Low  */
    301        return;
    302
    303    default:
    304        qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    305                      HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
    306    }
    307    imx_avic_update(s);
    308}
    309
    310static const MemoryRegionOps imx_avic_ops = {
    311    .read = imx_avic_read,
    312    .write = imx_avic_write,
    313    .endianness = DEVICE_NATIVE_ENDIAN,
    314};
    315
    316static void imx_avic_reset(DeviceState *dev)
    317{
    318    IMXAVICState *s = IMX_AVIC(dev);
    319
    320    s->pending = 0;
    321    s->enabled = 0;
    322    s->is_fiq = 0;
    323    s->intmask = 0x1f;
    324    s->intcntl = 0;
    325    memset(s->prio, 0, sizeof s->prio);
    326}
    327
    328static void imx_avic_init(Object *obj)
    329{
    330    DeviceState *dev = DEVICE(obj);
    331    IMXAVICState *s = IMX_AVIC(obj);
    332    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    333
    334    memory_region_init_io(&s->iomem, obj, &imx_avic_ops, s,
    335                          TYPE_IMX_AVIC, 0x1000);
    336    sysbus_init_mmio(sbd, &s->iomem);
    337
    338    qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
    339    sysbus_init_irq(sbd, &s->irq);
    340    sysbus_init_irq(sbd, &s->fiq);
    341}
    342
    343
    344static void imx_avic_class_init(ObjectClass *klass, void *data)
    345{
    346    DeviceClass *dc = DEVICE_CLASS(klass);
    347
    348    dc->vmsd = &vmstate_imx_avic;
    349    dc->reset = imx_avic_reset;
    350    dc->desc = "i.MX Advanced Vector Interrupt Controller";
    351}
    352
    353static const TypeInfo imx_avic_info = {
    354    .name = TYPE_IMX_AVIC,
    355    .parent = TYPE_SYS_BUS_DEVICE,
    356    .instance_size = sizeof(IMXAVICState),
    357    .instance_init = imx_avic_init,
    358    .class_init = imx_avic_class_init,
    359};
    360
    361static void imx_avic_register_types(void)
    362{
    363    type_register_static(&imx_avic_info);
    364}
    365
    366type_init(imx_avic_register_types)