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

armsse-mhu.c (4985B)


      1/*
      2 * ARM SSE-200 Message Handling Unit (MHU)
      3 *
      4 * Copyright (c) 2019 Linaro Limited
      5 * Written by Peter Maydell
      6 *
      7 *  This program is free software; you can redistribute it and/or modify
      8 *  it under the terms of the GNU General Public License version 2 or
      9 *  (at your option) any later version.
     10 */
     11
     12/*
     13 * This is a model of the Message Handling Unit (MHU) which is part of the
     14 * Arm SSE-200 and documented in
     15 * https://developer.arm.com/documentation/101104/latest/
     16 */
     17
     18#include "qemu/osdep.h"
     19#include "qemu/log.h"
     20#include "qemu/module.h"
     21#include "trace.h"
     22#include "qapi/error.h"
     23#include "hw/sysbus.h"
     24#include "migration/vmstate.h"
     25#include "hw/registerfields.h"
     26#include "hw/irq.h"
     27#include "hw/misc/armsse-mhu.h"
     28
     29REG32(CPU0INTR_STAT, 0x0)
     30REG32(CPU0INTR_SET, 0x4)
     31REG32(CPU0INTR_CLR, 0x8)
     32REG32(CPU1INTR_STAT, 0x10)
     33REG32(CPU1INTR_SET, 0x14)
     34REG32(CPU1INTR_CLR, 0x18)
     35REG32(PID4, 0xfd0)
     36REG32(PID5, 0xfd4)
     37REG32(PID6, 0xfd8)
     38REG32(PID7, 0xfdc)
     39REG32(PID0, 0xfe0)
     40REG32(PID1, 0xfe4)
     41REG32(PID2, 0xfe8)
     42REG32(PID3, 0xfec)
     43REG32(CID0, 0xff0)
     44REG32(CID1, 0xff4)
     45REG32(CID2, 0xff8)
     46REG32(CID3, 0xffc)
     47
     48/* Valid bits in the interrupt registers. If any are set the IRQ is raised */
     49#define INTR_MASK 0xf
     50
     51/* PID/CID values */
     52static const int armsse_mhu_id[] = {
     53    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
     54    0x56, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
     55    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
     56};
     57
     58static void armsse_mhu_update(ARMSSEMHU *s)
     59{
     60    qemu_set_irq(s->cpu0irq, s->cpu0intr != 0);
     61    qemu_set_irq(s->cpu1irq, s->cpu1intr != 0);
     62}
     63
     64static uint64_t armsse_mhu_read(void *opaque, hwaddr offset, unsigned size)
     65{
     66    ARMSSEMHU *s = ARMSSE_MHU(opaque);
     67    uint64_t r;
     68
     69    switch (offset) {
     70    case A_CPU0INTR_STAT:
     71        r = s->cpu0intr;
     72        break;
     73
     74    case A_CPU1INTR_STAT:
     75        r = s->cpu1intr;
     76        break;
     77
     78    case A_PID4 ... A_CID3:
     79        r = armsse_mhu_id[(offset - A_PID4) / 4];
     80        break;
     81
     82    case A_CPU0INTR_SET:
     83    case A_CPU0INTR_CLR:
     84    case A_CPU1INTR_SET:
     85    case A_CPU1INTR_CLR:
     86        qemu_log_mask(LOG_GUEST_ERROR,
     87                      "SSE MHU: read of write-only register at offset 0x%x\n",
     88                      (int)offset);
     89        r = 0;
     90        break;
     91
     92    default:
     93        qemu_log_mask(LOG_GUEST_ERROR,
     94                      "SSE MHU read: bad offset 0x%x\n", (int)offset);
     95        r = 0;
     96        break;
     97    }
     98    trace_armsse_mhu_read(offset, r, size);
     99    return r;
    100}
    101
    102static void armsse_mhu_write(void *opaque, hwaddr offset,
    103                             uint64_t value, unsigned size)
    104{
    105    ARMSSEMHU *s = ARMSSE_MHU(opaque);
    106
    107    trace_armsse_mhu_write(offset, value, size);
    108
    109    switch (offset) {
    110    case A_CPU0INTR_SET:
    111        s->cpu0intr |= (value & INTR_MASK);
    112        break;
    113    case A_CPU0INTR_CLR:
    114        s->cpu0intr &= ~(value & INTR_MASK);
    115        break;
    116    case A_CPU1INTR_SET:
    117        s->cpu1intr |= (value & INTR_MASK);
    118        break;
    119    case A_CPU1INTR_CLR:
    120        s->cpu1intr &= ~(value & INTR_MASK);
    121        break;
    122
    123    case A_CPU0INTR_STAT:
    124    case A_CPU1INTR_STAT:
    125    case A_PID4 ... A_CID3:
    126        qemu_log_mask(LOG_GUEST_ERROR,
    127                      "SSE MHU: write to read-only register at offset 0x%x\n",
    128                      (int)offset);
    129        break;
    130
    131    default:
    132        qemu_log_mask(LOG_GUEST_ERROR,
    133                      "SSE MHU write: bad offset 0x%x\n", (int)offset);
    134        break;
    135    }
    136
    137    armsse_mhu_update(s);
    138}
    139
    140static const MemoryRegionOps armsse_mhu_ops = {
    141    .read = armsse_mhu_read,
    142    .write = armsse_mhu_write,
    143    .endianness = DEVICE_LITTLE_ENDIAN,
    144    .valid.min_access_size = 4,
    145    .valid.max_access_size = 4,
    146};
    147
    148static void armsse_mhu_reset(DeviceState *dev)
    149{
    150    ARMSSEMHU *s = ARMSSE_MHU(dev);
    151
    152    s->cpu0intr = 0;
    153    s->cpu1intr = 0;
    154}
    155
    156static const VMStateDescription armsse_mhu_vmstate = {
    157    .name = "armsse-mhu",
    158    .version_id = 1,
    159    .minimum_version_id = 1,
    160    .fields = (VMStateField[]) {
    161        VMSTATE_UINT32(cpu0intr, ARMSSEMHU),
    162        VMSTATE_UINT32(cpu1intr, ARMSSEMHU),
    163        VMSTATE_END_OF_LIST()
    164    },
    165};
    166
    167static void armsse_mhu_init(Object *obj)
    168{
    169    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    170    ARMSSEMHU *s = ARMSSE_MHU(obj);
    171
    172    memory_region_init_io(&s->iomem, obj, &armsse_mhu_ops,
    173                          s, "armsse-mhu", 0x1000);
    174    sysbus_init_mmio(sbd, &s->iomem);
    175    sysbus_init_irq(sbd, &s->cpu0irq);
    176    sysbus_init_irq(sbd, &s->cpu1irq);
    177}
    178
    179static void armsse_mhu_class_init(ObjectClass *klass, void *data)
    180{
    181    DeviceClass *dc = DEVICE_CLASS(klass);
    182
    183    dc->reset = armsse_mhu_reset;
    184    dc->vmsd = &armsse_mhu_vmstate;
    185}
    186
    187static const TypeInfo armsse_mhu_info = {
    188    .name = TYPE_ARMSSE_MHU,
    189    .parent = TYPE_SYS_BUS_DEVICE,
    190    .instance_size = sizeof(ARMSSEMHU),
    191    .instance_init = armsse_mhu_init,
    192    .class_init = armsse_mhu_class_init,
    193};
    194
    195static void armsse_mhu_register_types(void)
    196{
    197    type_register_static(&armsse_mhu_info);
    198}
    199
    200type_init(armsse_mhu_register_types);