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

ppc-uic.c (8846B)


      1/*
      2 * "Universal" Interrupt Controller for PowerPPC 4xx embedded processors
      3 *
      4 * Copyright (c) 2007 Jocelyn Mayer
      5 *
      6 * Permission is hereby granted, free of charge, to any person obtaining a copy
      7 * of this software and associated documentation files (the "Software"), to deal
      8 * in the Software without restriction, including without limitation the rights
      9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 * copies of the Software, and to permit persons to whom the Software is
     11 * furnished to do so, subject to the following conditions:
     12 *
     13 * The above copyright notice and this permission notice shall be included in
     14 * all copies or substantial portions of the Software.
     15 *
     16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22 * THE SOFTWARE.
     23 */
     24
     25#include "qemu/osdep.h"
     26#include "hw/intc/ppc-uic.h"
     27#include "hw/irq.h"
     28#include "cpu.h"
     29#include "hw/ppc/ppc.h"
     30#include "hw/qdev-properties.h"
     31#include "migration/vmstate.h"
     32#include "qapi/error.h"
     33
     34enum {
     35    DCR_UICSR  = 0x000,
     36    DCR_UICSRS = 0x001,
     37    DCR_UICER  = 0x002,
     38    DCR_UICCR  = 0x003,
     39    DCR_UICPR  = 0x004,
     40    DCR_UICTR  = 0x005,
     41    DCR_UICMSR = 0x006,
     42    DCR_UICVR  = 0x007,
     43    DCR_UICVCR = 0x008,
     44    DCR_UICMAX = 0x009,
     45};
     46
     47/*#define DEBUG_UIC*/
     48
     49#ifdef DEBUG_UIC
     50#  define LOG_UIC(...) qemu_log_mask(CPU_LOG_INT, ## __VA_ARGS__)
     51#else
     52#  define LOG_UIC(...) do { } while (0)
     53#endif
     54
     55static void ppcuic_trigger_irq(PPCUIC *uic)
     56{
     57    uint32_t ir, cr;
     58    int start, end, inc, i;
     59
     60    /* Trigger interrupt if any is pending */
     61    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
     62    cr = uic->uicsr & uic->uicer & uic->uiccr;
     63    LOG_UIC("%s: uicsr %08" PRIx32 " uicer %08" PRIx32
     64                " uiccr %08" PRIx32 "\n"
     65                "   %08" PRIx32 " ir %08" PRIx32 " cr %08" PRIx32 "\n",
     66                __func__, uic->uicsr, uic->uicer, uic->uiccr,
     67                uic->uicsr & uic->uicer, ir, cr);
     68    if (ir != 0x0000000) {
     69        LOG_UIC("Raise UIC interrupt\n");
     70        qemu_irq_raise(uic->output_int);
     71    } else {
     72        LOG_UIC("Lower UIC interrupt\n");
     73        qemu_irq_lower(uic->output_int);
     74    }
     75    /* Trigger critical interrupt if any is pending and update vector */
     76    if (cr != 0x0000000) {
     77        qemu_irq_raise(uic->output_cint);
     78        if (uic->use_vectors) {
     79            /* Compute critical IRQ vector */
     80            if (uic->uicvcr & 1) {
     81                start = 31;
     82                end = 0;
     83                inc = -1;
     84            } else {
     85                start = 0;
     86                end = 31;
     87                inc = 1;
     88            }
     89            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
     90            for (i = start; i <= end; i += inc) {
     91                if (cr & (1 << i)) {
     92                    uic->uicvr += (i - start) * 512 * inc;
     93                    break;
     94                }
     95            }
     96        }
     97        LOG_UIC("Raise UIC critical interrupt - "
     98                    "vector %08" PRIx32 "\n", uic->uicvr);
     99    } else {
    100        LOG_UIC("Lower UIC critical interrupt\n");
    101        qemu_irq_lower(uic->output_cint);
    102        uic->uicvr = 0x00000000;
    103    }
    104}
    105
    106static void ppcuic_set_irq(void *opaque, int irq_num, int level)
    107{
    108    PPCUIC *uic;
    109    uint32_t mask, sr;
    110
    111    uic = opaque;
    112    mask = 1U << (31 - irq_num);
    113    LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
    114                " mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
    115                __func__, irq_num, level,
    116                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
    117    if (irq_num < 0 || irq_num > 31) {
    118        return;
    119    }
    120    sr = uic->uicsr;
    121
    122    /* Update status register */
    123    if (uic->uictr & mask) {
    124        /* Edge sensitive interrupt */
    125        if (level == 1) {
    126            uic->uicsr |= mask;
    127        }
    128    } else {
    129        /* Level sensitive interrupt */
    130        if (level == 1) {
    131            uic->uicsr |= mask;
    132            uic->level |= mask;
    133        } else {
    134            uic->uicsr &= ~mask;
    135            uic->level &= ~mask;
    136        }
    137    }
    138    LOG_UIC("%s: irq %d level %d sr %" PRIx32 " => "
    139                "%08" PRIx32 "\n", __func__, irq_num, level, uic->uicsr, sr);
    140    if (sr != uic->uicsr) {
    141        ppcuic_trigger_irq(uic);
    142    }
    143}
    144
    145static uint32_t dcr_read_uic(void *opaque, int dcrn)
    146{
    147    PPCUIC *uic;
    148    uint32_t ret;
    149
    150    uic = opaque;
    151    dcrn -= uic->dcr_base;
    152    switch (dcrn) {
    153    case DCR_UICSR:
    154    case DCR_UICSRS:
    155        ret = uic->uicsr;
    156        break;
    157    case DCR_UICER:
    158        ret = uic->uicer;
    159        break;
    160    case DCR_UICCR:
    161        ret = uic->uiccr;
    162        break;
    163    case DCR_UICPR:
    164        ret = uic->uicpr;
    165        break;
    166    case DCR_UICTR:
    167        ret = uic->uictr;
    168        break;
    169    case DCR_UICMSR:
    170        ret = uic->uicsr & uic->uicer;
    171        break;
    172    case DCR_UICVR:
    173        if (!uic->use_vectors) {
    174            goto no_read;
    175        }
    176        ret = uic->uicvr;
    177        break;
    178    case DCR_UICVCR:
    179        if (!uic->use_vectors) {
    180            goto no_read;
    181        }
    182        ret = uic->uicvcr;
    183        break;
    184    default:
    185    no_read:
    186        ret = 0x00000000;
    187        break;
    188    }
    189
    190    return ret;
    191}
    192
    193static void dcr_write_uic(void *opaque, int dcrn, uint32_t val)
    194{
    195    PPCUIC *uic;
    196
    197    uic = opaque;
    198    dcrn -= uic->dcr_base;
    199    LOG_UIC("%s: dcr %d val 0x%x\n", __func__, dcrn, val);
    200    switch (dcrn) {
    201    case DCR_UICSR:
    202        uic->uicsr &= ~val;
    203        uic->uicsr |= uic->level;
    204        ppcuic_trigger_irq(uic);
    205        break;
    206    case DCR_UICSRS:
    207        uic->uicsr |= val;
    208        ppcuic_trigger_irq(uic);
    209        break;
    210    case DCR_UICER:
    211        uic->uicer = val;
    212        ppcuic_trigger_irq(uic);
    213        break;
    214    case DCR_UICCR:
    215        uic->uiccr = val;
    216        ppcuic_trigger_irq(uic);
    217        break;
    218    case DCR_UICPR:
    219        uic->uicpr = val;
    220        break;
    221    case DCR_UICTR:
    222        uic->uictr = val;
    223        ppcuic_trigger_irq(uic);
    224        break;
    225    case DCR_UICMSR:
    226        break;
    227    case DCR_UICVR:
    228        break;
    229    case DCR_UICVCR:
    230        uic->uicvcr = val & 0xFFFFFFFD;
    231        ppcuic_trigger_irq(uic);
    232        break;
    233    }
    234}
    235
    236static void ppc_uic_reset(DeviceState *dev)
    237{
    238    PPCUIC *uic = PPC_UIC(dev);
    239
    240    uic->uiccr = 0x00000000;
    241    uic->uicer = 0x00000000;
    242    uic->uicpr = 0x00000000;
    243    uic->uicsr = 0x00000000;
    244    uic->uictr = 0x00000000;
    245    if (uic->use_vectors) {
    246        uic->uicvcr = 0x00000000;
    247        uic->uicvr = 0x0000000;
    248    }
    249}
    250
    251static void ppc_uic_realize(DeviceState *dev, Error **errp)
    252{
    253    PPCUIC *uic = PPC_UIC(dev);
    254    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    255    PowerPCCPU *cpu;
    256    int i;
    257
    258    if (!uic->cpu) {
    259        /* This is a programming error in the code using this device */
    260        error_setg(errp, "ppc-uic 'cpu' link property was not set");
    261        return;
    262    }
    263
    264    cpu = POWERPC_CPU(uic->cpu);
    265    for (i = 0; i < DCR_UICMAX; i++) {
    266        ppc_dcr_register(&cpu->env, uic->dcr_base + i, uic,
    267                         &dcr_read_uic, &dcr_write_uic);
    268    }
    269
    270    sysbus_init_irq(sbd, &uic->output_int);
    271    sysbus_init_irq(sbd, &uic->output_cint);
    272    qdev_init_gpio_in(dev, ppcuic_set_irq, UIC_MAX_IRQ);
    273}
    274
    275static Property ppc_uic_properties[] = {
    276    DEFINE_PROP_LINK("cpu", PPCUIC, cpu, TYPE_CPU, CPUState *),
    277    DEFINE_PROP_UINT32("dcr-base", PPCUIC, dcr_base, 0xc0),
    278    DEFINE_PROP_BOOL("use-vectors", PPCUIC, use_vectors, true),
    279    DEFINE_PROP_END_OF_LIST()
    280};
    281
    282static const VMStateDescription ppc_uic_vmstate = {
    283    .name = "ppc-uic",
    284    .version_id = 1,
    285    .minimum_version_id = 1,
    286    .fields = (VMStateField[]) {
    287        VMSTATE_UINT32(level, PPCUIC),
    288        VMSTATE_UINT32(uicsr, PPCUIC),
    289        VMSTATE_UINT32(uicer, PPCUIC),
    290        VMSTATE_UINT32(uiccr, PPCUIC),
    291        VMSTATE_UINT32(uicpr, PPCUIC),
    292        VMSTATE_UINT32(uictr, PPCUIC),
    293        VMSTATE_UINT32(uicvcr, PPCUIC),
    294        VMSTATE_UINT32(uicvr, PPCUIC),
    295        VMSTATE_END_OF_LIST()
    296    },
    297};
    298
    299static void ppc_uic_class_init(ObjectClass *klass, void *data)
    300{
    301    DeviceClass *dc = DEVICE_CLASS(klass);
    302
    303    dc->reset = ppc_uic_reset;
    304    dc->realize = ppc_uic_realize;
    305    dc->vmsd = &ppc_uic_vmstate;
    306    device_class_set_props(dc, ppc_uic_properties);
    307}
    308
    309static const TypeInfo ppc_uic_info = {
    310    .name = TYPE_PPC_UIC,
    311    .parent = TYPE_SYS_BUS_DEVICE,
    312    .instance_size = sizeof(PPCUIC),
    313    .class_init = ppc_uic_class_init,
    314};
    315
    316static void ppc_uic_register_types(void)
    317{
    318    type_register_static(&ppc_uic_info);
    319}
    320
    321type_init(ppc_uic_register_types);