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

mcf_intc.c (5232B)


      1/*
      2 * ColdFire Interrupt Controller emulation.
      3 *
      4 * Copyright (c) 2007 CodeSourcery.
      5 *
      6 * This code is licensed under the GPL
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qapi/error.h"
     11#include "qemu/module.h"
     12#include "qemu/log.h"
     13#include "cpu.h"
     14#include "hw/irq.h"
     15#include "hw/sysbus.h"
     16#include "hw/m68k/mcf.h"
     17#include "qom/object.h"
     18
     19#define TYPE_MCF_INTC "mcf-intc"
     20OBJECT_DECLARE_SIMPLE_TYPE(mcf_intc_state, MCF_INTC)
     21
     22struct mcf_intc_state {
     23    SysBusDevice parent_obj;
     24
     25    MemoryRegion iomem;
     26    uint64_t ipr;
     27    uint64_t imr;
     28    uint64_t ifr;
     29    uint64_t enabled;
     30    uint8_t icr[64];
     31    M68kCPU *cpu;
     32    int active_vector;
     33};
     34
     35static void mcf_intc_update(mcf_intc_state *s)
     36{
     37    uint64_t active;
     38    int i;
     39    int best;
     40    int best_level;
     41
     42    active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
     43    best_level = 0;
     44    best = 64;
     45    if (active) {
     46        for (i = 0; i < 64; i++) {
     47            if ((active & 1) != 0 && s->icr[i] >= best_level) {
     48                best_level = s->icr[i];
     49                best = i;
     50            }
     51            active >>= 1;
     52        }
     53    }
     54    s->active_vector = ((best == 64) ? 24 : (best + 64));
     55    m68k_set_irq_level(s->cpu, best_level, s->active_vector);
     56}
     57
     58static uint64_t mcf_intc_read(void *opaque, hwaddr addr,
     59                              unsigned size)
     60{
     61    int offset;
     62    mcf_intc_state *s = (mcf_intc_state *)opaque;
     63    offset = addr & 0xff;
     64    if (offset >= 0x40 && offset < 0x80) {
     65        return s->icr[offset - 0x40];
     66    }
     67    switch (offset) {
     68    case 0x00:
     69        return (uint32_t)(s->ipr >> 32);
     70    case 0x04:
     71        return (uint32_t)s->ipr;
     72    case 0x08:
     73        return (uint32_t)(s->imr >> 32);
     74    case 0x0c:
     75        return (uint32_t)s->imr;
     76    case 0x10:
     77        return (uint32_t)(s->ifr >> 32);
     78    case 0x14:
     79        return (uint32_t)s->ifr;
     80    case 0xe0: /* SWIACK.  */
     81        return s->active_vector;
     82    case 0xe1: case 0xe2: case 0xe3: case 0xe4:
     83    case 0xe5: case 0xe6: case 0xe7:
     84        /* LnIACK */
     85        qemu_log_mask(LOG_UNIMP, "%s: LnIACK not implemented (offset 0x%02x)\n",
     86                      __func__, offset);
     87        /* fallthru */
     88    default:
     89        return 0;
     90    }
     91}
     92
     93static void mcf_intc_write(void *opaque, hwaddr addr,
     94                           uint64_t val, unsigned size)
     95{
     96    int offset;
     97    mcf_intc_state *s = (mcf_intc_state *)opaque;
     98    offset = addr & 0xff;
     99    if (offset >= 0x40 && offset < 0x80) {
    100        int n = offset - 0x40;
    101        s->icr[n] = val;
    102        if (val == 0)
    103            s->enabled &= ~(1ull << n);
    104        else
    105            s->enabled |= (1ull << n);
    106        mcf_intc_update(s);
    107        return;
    108    }
    109    switch (offset) {
    110    case 0x00: case 0x04:
    111        /* Ignore IPR writes.  */
    112        return;
    113    case 0x08:
    114        s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
    115        break;
    116    case 0x0c:
    117        s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
    118        break;
    119    case 0x1c:
    120        if (val & 0x40) {
    121            s->imr = ~0ull;
    122        } else {
    123            s->imr |= (0x1ull << (val & 0x3f));
    124        }
    125        break;
    126    case 0x1d:
    127        if (val & 0x40) {
    128            s->imr = 0ull;
    129        } else {
    130            s->imr &= ~(0x1ull << (val & 0x3f));
    131        }
    132        break;
    133    default:
    134        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%02x\n",
    135                      __func__, offset);
    136        return;
    137    }
    138    mcf_intc_update(s);
    139}
    140
    141static void mcf_intc_set_irq(void *opaque, int irq, int level)
    142{
    143    mcf_intc_state *s = (mcf_intc_state *)opaque;
    144    if (irq >= 64)
    145        return;
    146    if (level)
    147        s->ipr |= 1ull << irq;
    148    else
    149        s->ipr &= ~(1ull << irq);
    150    mcf_intc_update(s);
    151}
    152
    153static void mcf_intc_reset(DeviceState *dev)
    154{
    155    mcf_intc_state *s = MCF_INTC(dev);
    156
    157    s->imr = ~0ull;
    158    s->ipr = 0;
    159    s->ifr = 0;
    160    s->enabled = 0;
    161    memset(s->icr, 0, 64);
    162    s->active_vector = 24;
    163}
    164
    165static const MemoryRegionOps mcf_intc_ops = {
    166    .read = mcf_intc_read,
    167    .write = mcf_intc_write,
    168    .endianness = DEVICE_NATIVE_ENDIAN,
    169};
    170
    171static void mcf_intc_instance_init(Object *obj)
    172{
    173    mcf_intc_state *s = MCF_INTC(obj);
    174
    175    memory_region_init_io(&s->iomem, obj, &mcf_intc_ops, s, "mcf", 0x100);
    176}
    177
    178static void mcf_intc_class_init(ObjectClass *oc, void *data)
    179{
    180    DeviceClass *dc = DEVICE_CLASS(oc);
    181
    182    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    183    dc->reset = mcf_intc_reset;
    184}
    185
    186static const TypeInfo mcf_intc_gate_info = {
    187    .name          = TYPE_MCF_INTC,
    188    .parent        = TYPE_SYS_BUS_DEVICE,
    189    .instance_size = sizeof(mcf_intc_state),
    190    .instance_init = mcf_intc_instance_init,
    191    .class_init    = mcf_intc_class_init,
    192};
    193
    194static void mcf_intc_register_types(void)
    195{
    196    type_register_static(&mcf_intc_gate_info);
    197}
    198
    199type_init(mcf_intc_register_types)
    200
    201qemu_irq *mcf_intc_init(MemoryRegion *sysmem,
    202                        hwaddr base,
    203                        M68kCPU *cpu)
    204{
    205    DeviceState  *dev;
    206    mcf_intc_state *s;
    207
    208    dev = qdev_new(TYPE_MCF_INTC);
    209    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
    210
    211    s = MCF_INTC(dev);
    212    s->cpu = cpu;
    213
    214    memory_region_add_subregion(sysmem, base, &s->iomem);
    215
    216    return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
    217}