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

ppce500_spin.c (5503B)


      1/*
      2 * QEMU PowerPC e500v2 ePAPR spinning code
      3 *
      4 * Copyright (C) 2011 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 * This code is not really a device, but models an interface that usually
     22 * firmware takes care of. It's used when QEMU plays the role of firmware.
     23 *
     24 * Specification:
     25 *
     26 * https://www.power.org/resources/downloads/Power_ePAPR_APPROVED_v1.1.pdf
     27 *
     28 */
     29
     30#include "qemu/osdep.h"
     31#include "qemu/module.h"
     32#include "qemu/units.h"
     33#include "hw/hw.h"
     34#include "hw/sysbus.h"
     35#include "sysemu/hw_accel.h"
     36#include "e500.h"
     37#include "qom/object.h"
     38
     39#define MAX_CPUS 32
     40
     41typedef struct spin_info {
     42    uint64_t addr;
     43    uint64_t r3;
     44    uint32_t resv;
     45    uint32_t pir;
     46    uint64_t reserved;
     47} QEMU_PACKED SpinInfo;
     48
     49#define TYPE_E500_SPIN "e500-spin"
     50OBJECT_DECLARE_SIMPLE_TYPE(SpinState, E500_SPIN)
     51
     52struct SpinState {
     53    SysBusDevice parent_obj;
     54
     55    MemoryRegion iomem;
     56    SpinInfo spin[MAX_CPUS];
     57};
     58
     59static void spin_reset(DeviceState *dev)
     60{
     61    SpinState *s = E500_SPIN(dev);
     62    int i;
     63
     64    for (i = 0; i < MAX_CPUS; i++) {
     65        SpinInfo *info = &s->spin[i];
     66
     67        stl_p(&info->pir, i);
     68        stq_p(&info->r3, i);
     69        stq_p(&info->addr, 1);
     70    }
     71}
     72
     73static void mmubooke_create_initial_mapping(CPUPPCState *env,
     74                                     target_ulong va,
     75                                     hwaddr pa,
     76                                     hwaddr len)
     77{
     78    ppcmas_tlb_t *tlb = booke206_get_tlbm(env, 1, 0, 1);
     79    hwaddr size;
     80
     81    size = (booke206_page_size_to_tlb(len) << MAS1_TSIZE_SHIFT);
     82    tlb->mas1 = MAS1_VALID | size;
     83    tlb->mas2 = (va & TARGET_PAGE_MASK) | MAS2_M;
     84    tlb->mas7_3 = pa & TARGET_PAGE_MASK;
     85    tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX;
     86    env->tlb_dirty = true;
     87}
     88
     89static void spin_kick(CPUState *cs, run_on_cpu_data data)
     90{
     91    PowerPCCPU *cpu = POWERPC_CPU(cs);
     92    CPUPPCState *env = &cpu->env;
     93    SpinInfo *curspin = data.host_ptr;
     94    hwaddr map_size = 64 * MiB;
     95    hwaddr map_start;
     96
     97    cpu_synchronize_state(cs);
     98    stl_p(&curspin->pir, env->spr[SPR_BOOKE_PIR]);
     99    env->nip = ldq_p(&curspin->addr) & (map_size - 1);
    100    env->gpr[3] = ldq_p(&curspin->r3);
    101    env->gpr[4] = 0;
    102    env->gpr[5] = 0;
    103    env->gpr[6] = 0;
    104    env->gpr[7] = map_size;
    105    env->gpr[8] = 0;
    106    env->gpr[9] = 0;
    107
    108    map_start = ldq_p(&curspin->addr) & ~(map_size - 1);
    109    mmubooke_create_initial_mapping(env, 0, map_start, map_size);
    110
    111    cs->halted = 0;
    112    cs->exception_index = -1;
    113    cs->stopped = false;
    114    qemu_cpu_kick(cs);
    115}
    116
    117static void spin_write(void *opaque, hwaddr addr, uint64_t value,
    118                       unsigned len)
    119{
    120    SpinState *s = opaque;
    121    int env_idx = addr / sizeof(SpinInfo);
    122    CPUState *cpu;
    123    SpinInfo *curspin = &s->spin[env_idx];
    124    uint8_t *curspin_p = (uint8_t*)curspin;
    125
    126    cpu = qemu_get_cpu(env_idx);
    127    if (cpu == NULL) {
    128        /* Unknown CPU */
    129        return;
    130    }
    131
    132    if (cpu->cpu_index == 0) {
    133        /* primary CPU doesn't spin */
    134        return;
    135    }
    136
    137    curspin_p = &curspin_p[addr % sizeof(SpinInfo)];
    138    switch (len) {
    139    case 1:
    140        stb_p(curspin_p, value);
    141        break;
    142    case 2:
    143        stw_p(curspin_p, value);
    144        break;
    145    case 4:
    146        stl_p(curspin_p, value);
    147        break;
    148    }
    149
    150    if (!(ldq_p(&curspin->addr) & 1)) {
    151        /* run CPU */
    152        run_on_cpu(cpu, spin_kick, RUN_ON_CPU_HOST_PTR(curspin));
    153    }
    154}
    155
    156static uint64_t spin_read(void *opaque, hwaddr addr, unsigned len)
    157{
    158    SpinState *s = opaque;
    159    uint8_t *spin_p = &((uint8_t*)s->spin)[addr];
    160
    161    switch (len) {
    162    case 1:
    163        return ldub_p(spin_p);
    164    case 2:
    165        return lduw_p(spin_p);
    166    case 4:
    167        return ldl_p(spin_p);
    168    default:
    169        hw_error("ppce500: unexpected %s with len = %u", __func__, len);
    170    }
    171}
    172
    173static const MemoryRegionOps spin_rw_ops = {
    174    .read = spin_read,
    175    .write = spin_write,
    176    .endianness = DEVICE_BIG_ENDIAN,
    177};
    178
    179static void ppce500_spin_initfn(Object *obj)
    180{
    181    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
    182    SpinState *s = E500_SPIN(dev);
    183
    184    memory_region_init_io(&s->iomem, obj, &spin_rw_ops, s,
    185                          "e500 spin pv device", sizeof(SpinInfo) * MAX_CPUS);
    186    sysbus_init_mmio(dev, &s->iomem);
    187}
    188
    189static void ppce500_spin_class_init(ObjectClass *klass, void *data)
    190{
    191    DeviceClass *dc = DEVICE_CLASS(klass);
    192
    193    dc->reset = spin_reset;
    194}
    195
    196static const TypeInfo ppce500_spin_info = {
    197    .name          = TYPE_E500_SPIN,
    198    .parent        = TYPE_SYS_BUS_DEVICE,
    199    .instance_size = sizeof(SpinState),
    200    .instance_init = ppce500_spin_initfn,
    201    .class_init    = ppce500_spin_class_init,
    202};
    203
    204static void ppce500_spin_register_types(void)
    205{
    206    type_register_static(&ppce500_spin_info);
    207}
    208
    209type_init(ppce500_spin_register_types)