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

mpc8xxx.c (5651B)


      1/*
      2 *  GPIO Controller for a lot of Freescale SoCs
      3 *
      4 * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved.
      5 *
      6 * Author: Alexander Graf, <agraf@suse.de>
      7 *
      8 * This library is free software; you can redistribute it and/or
      9 * modify it under the terms of the GNU Lesser General Public
     10 * License as published by the Free Software Foundation; either
     11 * version 2.1 of the License, or (at your option) any later version.
     12 *
     13 * This library is distributed in the hope that it will be useful,
     14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16 * Lesser General Public License for more details.
     17 *
     18 * You should have received a copy of the GNU Lesser General Public
     19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     20 */
     21
     22#include "qemu/osdep.h"
     23#include "hw/irq.h"
     24#include "hw/sysbus.h"
     25#include "migration/vmstate.h"
     26#include "qemu/module.h"
     27#include "qom/object.h"
     28
     29#define TYPE_MPC8XXX_GPIO "mpc8xxx_gpio"
     30OBJECT_DECLARE_SIMPLE_TYPE(MPC8XXXGPIOState, MPC8XXX_GPIO)
     31
     32struct MPC8XXXGPIOState {
     33    SysBusDevice parent_obj;
     34
     35    MemoryRegion iomem;
     36    qemu_irq irq;
     37    qemu_irq out[32];
     38
     39    uint32_t dir;
     40    uint32_t odr;
     41    uint32_t dat;
     42    uint32_t ier;
     43    uint32_t imr;
     44    uint32_t icr;
     45};
     46
     47static const VMStateDescription vmstate_mpc8xxx_gpio = {
     48    .name = "mpc8xxx_gpio",
     49    .version_id = 1,
     50    .minimum_version_id = 1,
     51    .fields = (VMStateField[]) {
     52        VMSTATE_UINT32(dir, MPC8XXXGPIOState),
     53        VMSTATE_UINT32(odr, MPC8XXXGPIOState),
     54        VMSTATE_UINT32(dat, MPC8XXXGPIOState),
     55        VMSTATE_UINT32(ier, MPC8XXXGPIOState),
     56        VMSTATE_UINT32(imr, MPC8XXXGPIOState),
     57        VMSTATE_UINT32(icr, MPC8XXXGPIOState),
     58        VMSTATE_END_OF_LIST()
     59    }
     60};
     61
     62static void mpc8xxx_gpio_update(MPC8XXXGPIOState *s)
     63{
     64    qemu_set_irq(s->irq, !!(s->ier & s->imr));
     65}
     66
     67static uint64_t mpc8xxx_gpio_read(void *opaque, hwaddr offset,
     68                                  unsigned size)
     69{
     70    MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
     71
     72    if (size != 4) {
     73        /* All registers are 32bit */
     74        return 0;
     75    }
     76
     77    switch (offset) {
     78    case 0x0: /* Direction */
     79        return s->dir;
     80    case 0x4: /* Open Drain */
     81        return s->odr;
     82    case 0x8: /* Data */
     83        return s->dat;
     84    case 0xC: /* Interrupt Event */
     85        return s->ier;
     86    case 0x10: /* Interrupt Mask */
     87        return s->imr;
     88    case 0x14: /* Interrupt Control */
     89        return s->icr;
     90    default:
     91        return 0;
     92    }
     93}
     94
     95static void mpc8xxx_write_data(MPC8XXXGPIOState *s, uint32_t new_data)
     96{
     97    uint32_t old_data = s->dat;
     98    uint32_t diff = old_data ^ new_data;
     99    int i;
    100
    101    for (i = 0; i < 32; i++) {
    102        uint32_t mask = 0x80000000 >> i;
    103        if (!(diff & mask)) {
    104            continue;
    105        }
    106
    107        if (s->dir & mask) {
    108            /* Output */
    109            qemu_set_irq(s->out[i], (new_data & mask) != 0);
    110        }
    111    }
    112
    113    s->dat = new_data;
    114}
    115
    116static void mpc8xxx_gpio_write(void *opaque, hwaddr offset,
    117                        uint64_t value, unsigned size)
    118{
    119    MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
    120
    121    if (size != 4) {
    122        /* All registers are 32bit */
    123        return;
    124    }
    125
    126    switch (offset) {
    127    case 0x0: /* Direction */
    128        s->dir = value;
    129        break;
    130    case 0x4: /* Open Drain */
    131        s->odr = value;
    132        break;
    133    case 0x8: /* Data */
    134        mpc8xxx_write_data(s, value);
    135        break;
    136    case 0xC: /* Interrupt Event */
    137        s->ier &= ~value;
    138        break;
    139    case 0x10: /* Interrupt Mask */
    140        s->imr = value;
    141        break;
    142    case 0x14: /* Interrupt Control */
    143        s->icr = value;
    144        break;
    145    }
    146
    147    mpc8xxx_gpio_update(s);
    148}
    149
    150static void mpc8xxx_gpio_reset(DeviceState *dev)
    151{
    152    MPC8XXXGPIOState *s = MPC8XXX_GPIO(dev);
    153
    154    s->dir = 0;
    155    s->odr = 0;
    156    s->dat = 0;
    157    s->ier = 0;
    158    s->imr = 0;
    159    s->icr = 0;
    160}
    161
    162static void mpc8xxx_gpio_set_irq(void * opaque, int irq, int level)
    163{
    164    MPC8XXXGPIOState *s = (MPC8XXXGPIOState *)opaque;
    165    uint32_t mask;
    166
    167    mask = 0x80000000 >> irq;
    168    if ((s->dir & mask) == 0) {
    169        uint32_t old_value = s->dat & mask;
    170
    171        s->dat &= ~mask;
    172        if (level)
    173            s->dat |= mask;
    174
    175        if (!(s->icr & irq) || (old_value && !level)) {
    176            s->ier |= mask;
    177        }
    178
    179        mpc8xxx_gpio_update(s);
    180    }
    181}
    182
    183static const MemoryRegionOps mpc8xxx_gpio_ops = {
    184    .read = mpc8xxx_gpio_read,
    185    .write = mpc8xxx_gpio_write,
    186    .endianness = DEVICE_BIG_ENDIAN,
    187};
    188
    189static void mpc8xxx_gpio_initfn(Object *obj)
    190{
    191    DeviceState *dev = DEVICE(obj);
    192    MPC8XXXGPIOState *s = MPC8XXX_GPIO(obj);
    193    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    194
    195    memory_region_init_io(&s->iomem, obj, &mpc8xxx_gpio_ops,
    196                          s, "mpc8xxx_gpio", 0x1000);
    197    sysbus_init_mmio(sbd, &s->iomem);
    198    sysbus_init_irq(sbd, &s->irq);
    199    qdev_init_gpio_in(dev, mpc8xxx_gpio_set_irq, 32);
    200    qdev_init_gpio_out(dev, s->out, 32);
    201}
    202
    203static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data)
    204{
    205    DeviceClass *dc = DEVICE_CLASS(klass);
    206
    207    dc->vmsd = &vmstate_mpc8xxx_gpio;
    208    dc->reset = mpc8xxx_gpio_reset;
    209}
    210
    211static const TypeInfo mpc8xxx_gpio_info = {
    212    .name          = TYPE_MPC8XXX_GPIO,
    213    .parent        = TYPE_SYS_BUS_DEVICE,
    214    .instance_size = sizeof(MPC8XXXGPIOState),
    215    .instance_init = mpc8xxx_gpio_initfn,
    216    .class_init    = mpc8xxx_gpio_class_init,
    217};
    218
    219static void mpc8xxx_gpio_register_types(void)
    220{
    221    type_register_static(&mpc8xxx_gpio_info);
    222}
    223
    224type_init(mpc8xxx_gpio_register_types)