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

mips_cpc.c (5338B)


      1/*
      2 * Cluster Power Controller emulation
      3 *
      4 * Copyright (c) 2016 Imagination Technologies
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18 */
     19
     20#include "qemu/osdep.h"
     21#include "qapi/error.h"
     22#include "cpu.h"
     23#include "qemu/log.h"
     24#include "qemu/module.h"
     25#include "hw/sysbus.h"
     26#include "migration/vmstate.h"
     27
     28#include "hw/misc/mips_cpc.h"
     29#include "hw/qdev-properties.h"
     30
     31static inline uint64_t cpc_vp_run_mask(MIPSCPCState *cpc)
     32{
     33    return (1ULL << cpc->num_vp) - 1;
     34}
     35
     36static void mips_cpu_reset_async_work(CPUState *cs, run_on_cpu_data data)
     37{
     38    MIPSCPCState *cpc = (MIPSCPCState *) data.host_ptr;
     39
     40    cpu_reset(cs);
     41    cs->halted = 0;
     42    cpc->vp_running |= 1ULL << cs->cpu_index;
     43}
     44
     45static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run)
     46{
     47    CPUState *cs = first_cpu;
     48
     49    CPU_FOREACH(cs) {
     50        uint64_t i = 1ULL << cs->cpu_index;
     51        if (i & vp_run & ~cpc->vp_running) {
     52            /*
     53             * To avoid racing with a CPU we are just kicking off.
     54             * We do the final bit of preparation for the work in
     55             * the target CPUs context.
     56             */
     57            async_safe_run_on_cpu(cs, mips_cpu_reset_async_work,
     58                                  RUN_ON_CPU_HOST_PTR(cpc));
     59        }
     60    }
     61}
     62
     63static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop)
     64{
     65    CPUState *cs = first_cpu;
     66
     67    CPU_FOREACH(cs) {
     68        uint64_t i = 1ULL << cs->cpu_index;
     69        if (i & vp_stop & cpc->vp_running) {
     70            cpu_interrupt(cs, CPU_INTERRUPT_HALT);
     71            cpc->vp_running &= ~i;
     72        }
     73    }
     74}
     75
     76static void cpc_write(void *opaque, hwaddr offset, uint64_t data,
     77                      unsigned size)
     78{
     79    MIPSCPCState *s = opaque;
     80
     81    switch (offset) {
     82    case CPC_CL_BASE_OFS + CPC_VP_RUN_OFS:
     83    case CPC_CO_BASE_OFS + CPC_VP_RUN_OFS:
     84        cpc_run_vp(s, data & cpc_vp_run_mask(s));
     85        break;
     86    case CPC_CL_BASE_OFS + CPC_VP_STOP_OFS:
     87    case CPC_CO_BASE_OFS + CPC_VP_STOP_OFS:
     88        cpc_stop_vp(s, data & cpc_vp_run_mask(s));
     89        break;
     90    default:
     91        qemu_log_mask(LOG_UNIMP,
     92                      "%s: Bad offset 0x%x\n",  __func__, (int)offset);
     93        break;
     94    }
     95
     96    return;
     97}
     98
     99static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size)
    100{
    101    MIPSCPCState *s = opaque;
    102
    103    switch (offset) {
    104    case CPC_CL_BASE_OFS + CPC_VP_RUNNING_OFS:
    105    case CPC_CO_BASE_OFS + CPC_VP_RUNNING_OFS:
    106        return s->vp_running;
    107    default:
    108        qemu_log_mask(LOG_UNIMP,
    109                      "%s: Bad offset 0x%x\n",  __func__, (int)offset);
    110        return 0;
    111    }
    112}
    113
    114static const MemoryRegionOps cpc_ops = {
    115    .read = cpc_read,
    116    .write = cpc_write,
    117    .endianness = DEVICE_NATIVE_ENDIAN,
    118    .impl = {
    119        .max_access_size = 8,
    120    },
    121};
    122
    123static void mips_cpc_init(Object *obj)
    124{
    125    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    126    MIPSCPCState *s = MIPS_CPC(obj);
    127
    128    memory_region_init_io(&s->mr, OBJECT(s), &cpc_ops, s, "mips-cpc",
    129                          CPC_ADDRSPACE_SZ);
    130    sysbus_init_mmio(sbd, &s->mr);
    131}
    132
    133static void mips_cpc_realize(DeviceState *dev, Error **errp)
    134{
    135    MIPSCPCState *s = MIPS_CPC(dev);
    136
    137    if (s->vp_start_running > cpc_vp_run_mask(s)) {
    138        error_setg(errp,
    139                   "incorrect vp_start_running 0x%" PRIx64 " for num_vp = %d",
    140                   s->vp_running, s->num_vp);
    141        return;
    142    }
    143}
    144
    145static void mips_cpc_reset(DeviceState *dev)
    146{
    147    MIPSCPCState *s = MIPS_CPC(dev);
    148
    149    /* Reflect the fact that all VPs are halted on reset */
    150    s->vp_running = 0;
    151
    152    /* Put selected VPs into run state */
    153    cpc_run_vp(s, s->vp_start_running);
    154}
    155
    156static const VMStateDescription vmstate_mips_cpc = {
    157    .name = "mips-cpc",
    158    .version_id = 0,
    159    .minimum_version_id = 0,
    160    .fields = (VMStateField[]) {
    161        VMSTATE_UINT64(vp_running, MIPSCPCState),
    162        VMSTATE_END_OF_LIST()
    163    },
    164};
    165
    166static Property mips_cpc_properties[] = {
    167    DEFINE_PROP_UINT32("num-vp", MIPSCPCState, num_vp, 0x1),
    168    DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1),
    169    DEFINE_PROP_END_OF_LIST(),
    170};
    171
    172static void mips_cpc_class_init(ObjectClass *klass, void *data)
    173{
    174    DeviceClass *dc = DEVICE_CLASS(klass);
    175
    176    dc->realize = mips_cpc_realize;
    177    dc->reset = mips_cpc_reset;
    178    dc->vmsd = &vmstate_mips_cpc;
    179    device_class_set_props(dc, mips_cpc_properties);
    180}
    181
    182static const TypeInfo mips_cpc_info = {
    183    .name          = TYPE_MIPS_CPC,
    184    .parent        = TYPE_SYS_BUS_DEVICE,
    185    .instance_size = sizeof(MIPSCPCState),
    186    .instance_init = mips_cpc_init,
    187    .class_init    = mips_cpc_class_init,
    188};
    189
    190static void mips_cpc_register_types(void)
    191{
    192    type_register_static(&mips_cpc_info);
    193}
    194
    195type_init(mips_cpc_register_types)