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_ic.c (7093B)


      1/*
      2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
      3 * Refactoring for Pi2 Copyright (c) 2015, Microsoft. Written by Andrew Baumann.
      4 * Heavily based on pl190.c, copyright terms below:
      5 *
      6 * Arm PrimeCell PL190 Vector Interrupt Controller
      7 *
      8 * Copyright (c) 2006 CodeSourcery.
      9 * Written by Paul Brook
     10 *
     11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     12 * See the COPYING file in the top-level directory.
     13 */
     14
     15#include "qemu/osdep.h"
     16#include "hw/intc/bcm2835_ic.h"
     17#include "hw/irq.h"
     18#include "migration/vmstate.h"
     19#include "qemu/log.h"
     20#include "qemu/module.h"
     21#include "trace.h"
     22
     23#define GPU_IRQS 64
     24#define ARM_IRQS 8
     25
     26#define IRQ_PENDING_BASIC       0x00 /* IRQ basic pending */
     27#define IRQ_PENDING_1           0x04 /* IRQ pending 1 */
     28#define IRQ_PENDING_2           0x08 /* IRQ pending 2 */
     29#define FIQ_CONTROL             0x0C /* FIQ register */
     30#define IRQ_ENABLE_1            0x10 /* Interrupt enable register 1 */
     31#define IRQ_ENABLE_2            0x14 /* Interrupt enable register 2 */
     32#define IRQ_ENABLE_BASIC        0x18 /* Base interrupt enable register */
     33#define IRQ_DISABLE_1           0x1C /* Interrupt disable register 1 */
     34#define IRQ_DISABLE_2           0x20 /* Interrupt disable register 2 */
     35#define IRQ_DISABLE_BASIC       0x24 /* Base interrupt disable register */
     36
     37/* Update interrupts.  */
     38static void bcm2835_ic_update(BCM2835ICState *s)
     39{
     40    bool set = false;
     41
     42    if (s->fiq_enable) {
     43        if (s->fiq_select >= GPU_IRQS) {
     44            /* ARM IRQ */
     45            set = extract32(s->arm_irq_level, s->fiq_select - GPU_IRQS, 1);
     46        } else {
     47            set = extract64(s->gpu_irq_level, s->fiq_select, 1);
     48        }
     49    }
     50    qemu_set_irq(s->fiq, set);
     51
     52    set = (s->gpu_irq_level & s->gpu_irq_enable)
     53        || (s->arm_irq_level & s->arm_irq_enable);
     54    qemu_set_irq(s->irq, set);
     55}
     56
     57static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
     58{
     59    BCM2835ICState *s = opaque;
     60
     61    assert(irq >= 0 && irq < 64);
     62    trace_bcm2835_ic_set_gpu_irq(irq, level);
     63    s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
     64    bcm2835_ic_update(s);
     65}
     66
     67static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
     68{
     69    BCM2835ICState *s = opaque;
     70
     71    assert(irq >= 0 && irq < 8);
     72    trace_bcm2835_ic_set_cpu_irq(irq, level);
     73    s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
     74    bcm2835_ic_update(s);
     75}
     76
     77static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62 };
     78
     79static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset, unsigned size)
     80{
     81    BCM2835ICState *s = opaque;
     82    uint32_t res = 0;
     83    uint64_t gpu_pending = s->gpu_irq_level & s->gpu_irq_enable;
     84    int i;
     85
     86    switch (offset) {
     87    case IRQ_PENDING_BASIC:
     88        /* bits 0-7: ARM irqs */
     89        res = s->arm_irq_level & s->arm_irq_enable;
     90
     91        /* bits 8 & 9: pending registers 1 & 2 */
     92        res |= (((uint32_t)gpu_pending) != 0) << 8;
     93        res |= ((gpu_pending >> 32) != 0) << 9;
     94
     95        /* bits 10-20: selected GPU IRQs */
     96        for (i = 0; i < ARRAY_SIZE(irq_dups); i++) {
     97            res |= extract64(gpu_pending, irq_dups[i], 1) << (i + 10);
     98        }
     99        break;
    100    case IRQ_PENDING_1:
    101        res = gpu_pending;
    102        break;
    103    case IRQ_PENDING_2:
    104        res = gpu_pending >> 32;
    105        break;
    106    case FIQ_CONTROL:
    107        res = (s->fiq_enable << 7) | s->fiq_select;
    108        break;
    109    case IRQ_ENABLE_1:
    110        res = s->gpu_irq_enable;
    111        break;
    112    case IRQ_ENABLE_2:
    113        res = s->gpu_irq_enable >> 32;
    114        break;
    115    case IRQ_ENABLE_BASIC:
    116        res = s->arm_irq_enable;
    117        break;
    118    case IRQ_DISABLE_1:
    119        res = ~s->gpu_irq_enable;
    120        break;
    121    case IRQ_DISABLE_2:
    122        res = ~s->gpu_irq_enable >> 32;
    123        break;
    124    case IRQ_DISABLE_BASIC:
    125        res = ~s->arm_irq_enable;
    126        break;
    127    default:
    128        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
    129                      __func__, offset);
    130        return 0;
    131    }
    132
    133    return res;
    134}
    135
    136static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
    137                             unsigned size)
    138{
    139    BCM2835ICState *s = opaque;
    140
    141    switch (offset) {
    142    case FIQ_CONTROL:
    143        s->fiq_select = extract32(val, 0, 7);
    144        s->fiq_enable = extract32(val, 7, 1);
    145        break;
    146    case IRQ_ENABLE_1:
    147        s->gpu_irq_enable |= val;
    148        break;
    149    case IRQ_ENABLE_2:
    150        s->gpu_irq_enable |= val << 32;
    151        break;
    152    case IRQ_ENABLE_BASIC:
    153        s->arm_irq_enable |= val & 0xff;
    154        break;
    155    case IRQ_DISABLE_1:
    156        s->gpu_irq_enable &= ~val;
    157        break;
    158    case IRQ_DISABLE_2:
    159        s->gpu_irq_enable &= ~(val << 32);
    160        break;
    161    case IRQ_DISABLE_BASIC:
    162        s->arm_irq_enable &= ~val & 0xff;
    163        break;
    164    default:
    165        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
    166                      __func__, offset);
    167        return;
    168    }
    169    bcm2835_ic_update(s);
    170}
    171
    172static const MemoryRegionOps bcm2835_ic_ops = {
    173    .read = bcm2835_ic_read,
    174    .write = bcm2835_ic_write,
    175    .endianness = DEVICE_NATIVE_ENDIAN,
    176    .valid.min_access_size = 4,
    177    .valid.max_access_size = 4,
    178};
    179
    180static void bcm2835_ic_reset(DeviceState *d)
    181{
    182    BCM2835ICState *s = BCM2835_IC(d);
    183
    184    s->gpu_irq_enable = 0;
    185    s->arm_irq_enable = 0;
    186    s->fiq_enable = false;
    187    s->fiq_select = 0;
    188}
    189
    190static void bcm2835_ic_init(Object *obj)
    191{
    192    BCM2835ICState *s = BCM2835_IC(obj);
    193
    194    memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, TYPE_BCM2835_IC,
    195                          0x200);
    196    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
    197
    198    qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_gpu_irq,
    199                            BCM2835_IC_GPU_IRQ, GPU_IRQS);
    200    qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_arm_irq,
    201                            BCM2835_IC_ARM_IRQ, ARM_IRQS);
    202
    203    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
    204    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
    205}
    206
    207static const VMStateDescription vmstate_bcm2835_ic = {
    208    .name = TYPE_BCM2835_IC,
    209    .version_id = 1,
    210    .minimum_version_id = 1,
    211    .fields = (VMStateField[]) {
    212        VMSTATE_UINT64(gpu_irq_level, BCM2835ICState),
    213        VMSTATE_UINT64(gpu_irq_enable, BCM2835ICState),
    214        VMSTATE_UINT8(arm_irq_level, BCM2835ICState),
    215        VMSTATE_UINT8(arm_irq_enable, BCM2835ICState),
    216        VMSTATE_BOOL(fiq_enable, BCM2835ICState),
    217        VMSTATE_UINT8(fiq_select, BCM2835ICState),
    218        VMSTATE_END_OF_LIST()
    219    }
    220};
    221
    222static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
    223{
    224    DeviceClass *dc = DEVICE_CLASS(klass);
    225
    226    dc->reset = bcm2835_ic_reset;
    227    dc->vmsd = &vmstate_bcm2835_ic;
    228}
    229
    230static TypeInfo bcm2835_ic_info = {
    231    .name          = TYPE_BCM2835_IC,
    232    .parent        = TYPE_SYS_BUS_DEVICE,
    233    .instance_size = sizeof(BCM2835ICState),
    234    .class_init    = bcm2835_ic_class_init,
    235    .instance_init = bcm2835_ic_init,
    236};
    237
    238static void bcm2835_ic_register_types(void)
    239{
    240    type_register_static(&bcm2835_ic_info);
    241}
    242
    243type_init(bcm2835_ic_register_types)