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

exynos4210_gic.c (15165B)


      1/*
      2 * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
      3 *
      4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
      5 * All rights reserved.
      6 *
      7 * Evgeny Voevodin <e.voevodin@samsung.com>
      8 *
      9 * This program is free software; you can redistribute it and/or modify it
     10 * under the terms of the GNU General Public License as published by the
     11 * Free Software Foundation; either version 2 of the License, or (at your
     12 * option) any later version.
     13 *
     14 * This program is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     17 * See the GNU General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU General Public License along
     20 * with this program; if not, see <http://www.gnu.org/licenses/>.
     21 */
     22
     23#include "qemu/osdep.h"
     24#include "hw/sysbus.h"
     25#include "migration/vmstate.h"
     26#include "qapi/error.h"
     27#include "qemu/module.h"
     28#include "hw/irq.h"
     29#include "hw/qdev-properties.h"
     30#include "hw/arm/exynos4210.h"
     31#include "qom/object.h"
     32
     33enum ExtGicId {
     34    EXT_GIC_ID_MDMA_LCD0 = 66,
     35    EXT_GIC_ID_PDMA0,
     36    EXT_GIC_ID_PDMA1,
     37    EXT_GIC_ID_TIMER0,
     38    EXT_GIC_ID_TIMER1,
     39    EXT_GIC_ID_TIMER2,
     40    EXT_GIC_ID_TIMER3,
     41    EXT_GIC_ID_TIMER4,
     42    EXT_GIC_ID_MCT_L0,
     43    EXT_GIC_ID_WDT,
     44    EXT_GIC_ID_RTC_ALARM,
     45    EXT_GIC_ID_RTC_TIC,
     46    EXT_GIC_ID_GPIO_XB,
     47    EXT_GIC_ID_GPIO_XA,
     48    EXT_GIC_ID_MCT_L1,
     49    EXT_GIC_ID_IEM_APC,
     50    EXT_GIC_ID_IEM_IEC,
     51    EXT_GIC_ID_NFC,
     52    EXT_GIC_ID_UART0,
     53    EXT_GIC_ID_UART1,
     54    EXT_GIC_ID_UART2,
     55    EXT_GIC_ID_UART3,
     56    EXT_GIC_ID_UART4,
     57    EXT_GIC_ID_MCT_G0,
     58    EXT_GIC_ID_I2C0,
     59    EXT_GIC_ID_I2C1,
     60    EXT_GIC_ID_I2C2,
     61    EXT_GIC_ID_I2C3,
     62    EXT_GIC_ID_I2C4,
     63    EXT_GIC_ID_I2C5,
     64    EXT_GIC_ID_I2C6,
     65    EXT_GIC_ID_I2C7,
     66    EXT_GIC_ID_SPI0,
     67    EXT_GIC_ID_SPI1,
     68    EXT_GIC_ID_SPI2,
     69    EXT_GIC_ID_MCT_G1,
     70    EXT_GIC_ID_USB_HOST,
     71    EXT_GIC_ID_USB_DEVICE,
     72    EXT_GIC_ID_MODEMIF,
     73    EXT_GIC_ID_HSMMC0,
     74    EXT_GIC_ID_HSMMC1,
     75    EXT_GIC_ID_HSMMC2,
     76    EXT_GIC_ID_HSMMC3,
     77    EXT_GIC_ID_SDMMC,
     78    EXT_GIC_ID_MIPI_CSI_4LANE,
     79    EXT_GIC_ID_MIPI_DSI_4LANE,
     80    EXT_GIC_ID_MIPI_CSI_2LANE,
     81    EXT_GIC_ID_MIPI_DSI_2LANE,
     82    EXT_GIC_ID_ONENAND_AUDI,
     83    EXT_GIC_ID_ROTATOR,
     84    EXT_GIC_ID_FIMC0,
     85    EXT_GIC_ID_FIMC1,
     86    EXT_GIC_ID_FIMC2,
     87    EXT_GIC_ID_FIMC3,
     88    EXT_GIC_ID_JPEG,
     89    EXT_GIC_ID_2D,
     90    EXT_GIC_ID_PCIe,
     91    EXT_GIC_ID_MIXER,
     92    EXT_GIC_ID_HDMI,
     93    EXT_GIC_ID_HDMI_I2C,
     94    EXT_GIC_ID_MFC,
     95    EXT_GIC_ID_TVENC,
     96};
     97
     98enum ExtInt {
     99    EXT_GIC_ID_EXTINT0 = 48,
    100    EXT_GIC_ID_EXTINT1,
    101    EXT_GIC_ID_EXTINT2,
    102    EXT_GIC_ID_EXTINT3,
    103    EXT_GIC_ID_EXTINT4,
    104    EXT_GIC_ID_EXTINT5,
    105    EXT_GIC_ID_EXTINT6,
    106    EXT_GIC_ID_EXTINT7,
    107    EXT_GIC_ID_EXTINT8,
    108    EXT_GIC_ID_EXTINT9,
    109    EXT_GIC_ID_EXTINT10,
    110    EXT_GIC_ID_EXTINT11,
    111    EXT_GIC_ID_EXTINT12,
    112    EXT_GIC_ID_EXTINT13,
    113    EXT_GIC_ID_EXTINT14,
    114    EXT_GIC_ID_EXTINT15
    115};
    116
    117/*
    118 * External GIC sources which are not from External Interrupt Combiner or
    119 * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
    120 * which is INTG16 in Internal Interrupt Combiner.
    121 */
    122
    123static const uint32_t
    124combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
    125    /* int combiner groups 16-19 */
    126    { }, { }, { }, { },
    127    /* int combiner group 20 */
    128    { 0, EXT_GIC_ID_MDMA_LCD0 },
    129    /* int combiner group 21 */
    130    { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
    131    /* int combiner group 22 */
    132    { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
    133            EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
    134    /* int combiner group 23 */
    135    { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
    136    /* int combiner group 24 */
    137    { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
    138    /* int combiner group 25 */
    139    { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
    140    /* int combiner group 26 */
    141    { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
    142            EXT_GIC_ID_UART4 },
    143    /* int combiner group 27 */
    144    { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
    145            EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
    146            EXT_GIC_ID_I2C7 },
    147    /* int combiner group 28 */
    148    { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 , EXT_GIC_ID_USB_HOST},
    149    /* int combiner group 29 */
    150    { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
    151     EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
    152    /* int combiner group 30 */
    153    { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
    154    /* int combiner group 31 */
    155    { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
    156    /* int combiner group 32 */
    157    { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
    158    /* int combiner group 33 */
    159    { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
    160    /* int combiner group 34 */
    161    { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
    162    /* int combiner group 35 */
    163    { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
    164    /* int combiner group 36 */
    165    { EXT_GIC_ID_MIXER },
    166    /* int combiner group 37 */
    167    { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
    168     EXT_GIC_ID_EXTINT7 },
    169    /* groups 38-50 */
    170    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { },
    171    /* int combiner group 51 */
    172    { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
    173    /* group 52 */
    174    { },
    175    /* int combiner group 53 */
    176    { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
    177    /* groups 54-63 */
    178    { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
    179};
    180
    181#define EXYNOS4210_GIC_NIRQ 160
    182
    183#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE     0x10000
    184#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE    0x10000
    185
    186#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET      0x8000
    187#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
    188    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
    189#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
    190    ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
    191
    192#define EXYNOS4210_GIC_CPU_REGION_SIZE  0x100
    193#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
    194
    195static void exynos4210_irq_handler(void *opaque, int irq, int level)
    196{
    197    Exynos4210Irq *s = (Exynos4210Irq *)opaque;
    198
    199    /* Bypass */
    200    qemu_set_irq(s->board_irqs[irq], level);
    201}
    202
    203/*
    204 * Initialize exynos4210 IRQ subsystem stub.
    205 */
    206qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
    207{
    208    return qemu_allocate_irqs(exynos4210_irq_handler, s,
    209            EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
    210}
    211
    212/*
    213 * Initialize board IRQs.
    214 * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
    215 */
    216void exynos4210_init_board_irqs(Exynos4210Irq *s)
    217{
    218    uint32_t grp, bit, irq_id, n;
    219
    220    for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
    221        irq_id = 0;
    222        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
    223                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
    224            /* MCT_G0 is passed to External GIC */
    225            irq_id = EXT_GIC_ID_MCT_G0;
    226        }
    227        if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
    228                n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
    229            /* MCT_G1 is passed to External and GIC */
    230            irq_id = EXT_GIC_ID_MCT_G1;
    231        }
    232        if (irq_id) {
    233            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
    234                    s->ext_gic_irq[irq_id-32]);
    235        } else {
    236            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
    237                    s->ext_combiner_irq[n]);
    238        }
    239    }
    240    for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
    241        /* these IDs are passed to Internal Combiner and External GIC */
    242        grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
    243        bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
    244        irq_id = combiner_grp_to_gic_id[grp -
    245                     EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
    246
    247        if (irq_id) {
    248            s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
    249                    s->ext_gic_irq[irq_id-32]);
    250        }
    251    }
    252}
    253
    254/*
    255 * Get IRQ number from exynos4210 IRQ subsystem stub.
    256 * To identify IRQ source use internal combiner group and bit number
    257 *  grp - group number
    258 *  bit - bit number inside group
    259 */
    260uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
    261{
    262    return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
    263}
    264
    265/********* GIC part *********/
    266
    267#define TYPE_EXYNOS4210_GIC "exynos4210.gic"
    268OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210GicState, EXYNOS4210_GIC)
    269
    270struct Exynos4210GicState {
    271    SysBusDevice parent_obj;
    272
    273    MemoryRegion cpu_container;
    274    MemoryRegion dist_container;
    275    MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
    276    MemoryRegion dist_alias[EXYNOS4210_NCPUS];
    277    uint32_t num_cpu;
    278    DeviceState *gic;
    279};
    280
    281static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
    282{
    283    Exynos4210GicState *s = (Exynos4210GicState *)opaque;
    284    qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
    285}
    286
    287static void exynos4210_gic_realize(DeviceState *dev, Error **errp)
    288{
    289    Object *obj = OBJECT(dev);
    290    Exynos4210GicState *s = EXYNOS4210_GIC(obj);
    291    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    292    const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
    293    const char dist_prefix[] = "exynos4210-gic-alias_dist";
    294    char cpu_alias_name[sizeof(cpu_prefix) + 3];
    295    char dist_alias_name[sizeof(cpu_prefix) + 3];
    296    SysBusDevice *gicbusdev;
    297    uint32_t n = s->num_cpu;
    298    uint32_t i;
    299
    300    s->gic = qdev_new("arm_gic");
    301    qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
    302    qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
    303    gicbusdev = SYS_BUS_DEVICE(s->gic);
    304    sysbus_realize_and_unref(gicbusdev, &error_fatal);
    305
    306    /* Pass through outbound IRQ lines from the GIC */
    307    sysbus_pass_irq(sbd, gicbusdev);
    308
    309    /* Pass through inbound GPIO lines to the GIC */
    310    qdev_init_gpio_in(dev, exynos4210_gic_set_irq,
    311                      EXYNOS4210_GIC_NIRQ - 32);
    312
    313    memory_region_init(&s->cpu_container, obj, "exynos4210-cpu-container",
    314            EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
    315    memory_region_init(&s->dist_container, obj, "exynos4210-dist-container",
    316            EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
    317
    318    /*
    319     * This clues in gcc that our on-stack buffers do, in fact have
    320     * enough room for the cpu numbers.  gcc 9.2.1 on 32-bit x86
    321     * doesn't figure this out, otherwise and gives spurious warnings.
    322     */
    323    assert(n <= EXYNOS4210_NCPUS);
    324    for (i = 0; i < n; i++) {
    325        /* Map CPU interface per SMP Core */
    326        sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
    327        memory_region_init_alias(&s->cpu_alias[i], obj,
    328                                 cpu_alias_name,
    329                                 sysbus_mmio_get_region(gicbusdev, 1),
    330                                 0,
    331                                 EXYNOS4210_GIC_CPU_REGION_SIZE);
    332        memory_region_add_subregion(&s->cpu_container,
    333                EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
    334
    335        /* Map Distributor per SMP Core */
    336        sprintf(dist_alias_name, "%s%x", dist_prefix, i);
    337        memory_region_init_alias(&s->dist_alias[i], obj,
    338                                 dist_alias_name,
    339                                 sysbus_mmio_get_region(gicbusdev, 0),
    340                                 0,
    341                                 EXYNOS4210_GIC_DIST_REGION_SIZE);
    342        memory_region_add_subregion(&s->dist_container,
    343                EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
    344    }
    345
    346    sysbus_init_mmio(sbd, &s->cpu_container);
    347    sysbus_init_mmio(sbd, &s->dist_container);
    348}
    349
    350static Property exynos4210_gic_properties[] = {
    351    DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
    352    DEFINE_PROP_END_OF_LIST(),
    353};
    354
    355static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
    356{
    357    DeviceClass *dc = DEVICE_CLASS(klass);
    358
    359    device_class_set_props(dc, exynos4210_gic_properties);
    360    dc->realize = exynos4210_gic_realize;
    361}
    362
    363static const TypeInfo exynos4210_gic_info = {
    364    .name          = TYPE_EXYNOS4210_GIC,
    365    .parent        = TYPE_SYS_BUS_DEVICE,
    366    .instance_size = sizeof(Exynos4210GicState),
    367    .class_init    = exynos4210_gic_class_init,
    368};
    369
    370static void exynos4210_gic_register_types(void)
    371{
    372    type_register_static(&exynos4210_gic_info);
    373}
    374
    375type_init(exynos4210_gic_register_types)
    376
    377/* IRQ OR Gate struct.
    378 *
    379 * This device models an OR gate. There are n_in input qdev gpio lines and one
    380 * output sysbus IRQ line. The output IRQ level is formed as OR between all
    381 * gpio inputs.
    382 */
    383
    384#define TYPE_EXYNOS4210_IRQ_GATE "exynos4210.irq_gate"
    385OBJECT_DECLARE_SIMPLE_TYPE(Exynos4210IRQGateState, EXYNOS4210_IRQ_GATE)
    386
    387struct Exynos4210IRQGateState {
    388    SysBusDevice parent_obj;
    389
    390    uint32_t n_in;      /* inputs amount */
    391    uint32_t *level;    /* input levels */
    392    qemu_irq out;       /* output IRQ */
    393};
    394
    395static Property exynos4210_irq_gate_properties[] = {
    396    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
    397    DEFINE_PROP_END_OF_LIST(),
    398};
    399
    400static const VMStateDescription vmstate_exynos4210_irq_gate = {
    401    .name = "exynos4210.irq_gate",
    402    .version_id = 2,
    403    .minimum_version_id = 2,
    404    .fields = (VMStateField[]) {
    405        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, n_in),
    406        VMSTATE_END_OF_LIST()
    407    }
    408};
    409
    410/* Process a change in IRQ input. */
    411static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
    412{
    413    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
    414    uint32_t i;
    415
    416    assert(irq < s->n_in);
    417
    418    s->level[irq] = level;
    419
    420    for (i = 0; i < s->n_in; i++) {
    421        if (s->level[i] >= 1) {
    422            qemu_irq_raise(s->out);
    423            return;
    424        }
    425    }
    426
    427    qemu_irq_lower(s->out);
    428}
    429
    430static void exynos4210_irq_gate_reset(DeviceState *d)
    431{
    432    Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(d);
    433
    434    memset(s->level, 0, s->n_in * sizeof(*s->level));
    435}
    436
    437/*
    438 * IRQ Gate initialization.
    439 */
    440static void exynos4210_irq_gate_init(Object *obj)
    441{
    442    Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(obj);
    443    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    444
    445    sysbus_init_irq(sbd, &s->out);
    446}
    447
    448static void exynos4210_irq_gate_realize(DeviceState *dev, Error **errp)
    449{
    450    Exynos4210IRQGateState *s = EXYNOS4210_IRQ_GATE(dev);
    451
    452    /* Allocate general purpose input signals and connect a handler to each of
    453     * them */
    454    qdev_init_gpio_in(dev, exynos4210_irq_gate_handler, s->n_in);
    455
    456    s->level = g_malloc0(s->n_in * sizeof(*s->level));
    457}
    458
    459static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
    460{
    461    DeviceClass *dc = DEVICE_CLASS(klass);
    462
    463    dc->reset = exynos4210_irq_gate_reset;
    464    dc->vmsd = &vmstate_exynos4210_irq_gate;
    465    device_class_set_props(dc, exynos4210_irq_gate_properties);
    466    dc->realize = exynos4210_irq_gate_realize;
    467}
    468
    469static const TypeInfo exynos4210_irq_gate_info = {
    470    .name          = TYPE_EXYNOS4210_IRQ_GATE,
    471    .parent        = TYPE_SYS_BUS_DEVICE,
    472    .instance_size = sizeof(Exynos4210IRQGateState),
    473    .instance_init = exynos4210_irq_gate_init,
    474    .class_init    = exynos4210_irq_gate_class_init,
    475};
    476
    477static void exynos4210_irq_gate_register_types(void)
    478{
    479    type_register_static(&exynos4210_irq_gate_info);
    480}
    481
    482type_init(exynos4210_irq_gate_register_types)