qemu/hw/misc/tz-ppc.c
<<
>>
Prefs
   1/*
   2 * ARM TrustZone peripheral protection controller emulation
   3 *
   4 * Copyright (c) 2018 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#include "qemu/osdep.h"
  13#include "qemu/log.h"
  14#include "qemu/module.h"
  15#include "qapi/error.h"
  16#include "trace.h"
  17#include "hw/sysbus.h"
  18#include "hw/registerfields.h"
  19#include "hw/misc/tz-ppc.h"
  20
  21static void tz_ppc_update_irq(TZPPC *s)
  22{
  23    bool level = s->irq_status && s->irq_enable;
  24
  25    trace_tz_ppc_update_irq(level);
  26    qemu_set_irq(s->irq, level);
  27}
  28
  29static void tz_ppc_cfg_nonsec(void *opaque, int n, int level)
  30{
  31    TZPPC *s = TZ_PPC(opaque);
  32
  33    assert(n < TZ_NUM_PORTS);
  34    trace_tz_ppc_cfg_nonsec(n, level);
  35    s->cfg_nonsec[n] = level;
  36}
  37
  38static void tz_ppc_cfg_ap(void *opaque, int n, int level)
  39{
  40    TZPPC *s = TZ_PPC(opaque);
  41
  42    assert(n < TZ_NUM_PORTS);
  43    trace_tz_ppc_cfg_ap(n, level);
  44    s->cfg_ap[n] = level;
  45}
  46
  47static void tz_ppc_cfg_sec_resp(void *opaque, int n, int level)
  48{
  49    TZPPC *s = TZ_PPC(opaque);
  50
  51    trace_tz_ppc_cfg_sec_resp(level);
  52    s->cfg_sec_resp = level;
  53}
  54
  55static void tz_ppc_irq_enable(void *opaque, int n, int level)
  56{
  57    TZPPC *s = TZ_PPC(opaque);
  58
  59    trace_tz_ppc_irq_enable(level);
  60    s->irq_enable = level;
  61    tz_ppc_update_irq(s);
  62}
  63
  64static void tz_ppc_irq_clear(void *opaque, int n, int level)
  65{
  66    TZPPC *s = TZ_PPC(opaque);
  67
  68    trace_tz_ppc_irq_clear(level);
  69
  70    s->irq_clear = level;
  71    if (level) {
  72        s->irq_status = false;
  73        tz_ppc_update_irq(s);
  74    }
  75}
  76
  77static bool tz_ppc_check(TZPPC *s, int n, MemTxAttrs attrs)
  78{
  79    /* Check whether to allow an access to port n; return true if
  80     * the check passes, and false if the transaction must be blocked.
  81     * If the latter, the caller must check cfg_sec_resp to determine
  82     * whether to abort or RAZ/WI the transaction.
  83     * The checks are:
  84     *  + nonsec_mask suppresses any check of the secure attribute
  85     *  + otherwise, block if cfg_nonsec is 1 and transaction is secure,
  86     *    or if cfg_nonsec is 0 and transaction is non-secure
  87     *  + block if transaction is usermode and cfg_ap is 0
  88     */
  89    if ((attrs.secure == s->cfg_nonsec[n] && !(s->nonsec_mask & (1 << n))) ||
  90        (attrs.user && !s->cfg_ap[n])) {
  91        /* Block the transaction. */
  92        if (!s->irq_clear) {
  93            /* Note that holding irq_clear high suppresses interrupts */
  94            s->irq_status = true;
  95            tz_ppc_update_irq(s);
  96        }
  97        return false;
  98    }
  99    return true;
 100}
 101
 102static MemTxResult tz_ppc_read(void *opaque, hwaddr addr, uint64_t *pdata,
 103                               unsigned size, MemTxAttrs attrs)
 104{
 105    TZPPCPort *p = opaque;
 106    TZPPC *s = p->ppc;
 107    int n = p - s->port;
 108    AddressSpace *as = &p->downstream_as;
 109    uint64_t data;
 110    MemTxResult res;
 111
 112    if (!tz_ppc_check(s, n, attrs)) {
 113        trace_tz_ppc_read_blocked(n, addr, attrs.secure, attrs.user);
 114        if (s->cfg_sec_resp) {
 115            return MEMTX_ERROR;
 116        } else {
 117            *pdata = 0;
 118            return MEMTX_OK;
 119        }
 120    }
 121
 122    switch (size) {
 123    case 1:
 124        data = address_space_ldub(as, addr, attrs, &res);
 125        break;
 126    case 2:
 127        data = address_space_lduw_le(as, addr, attrs, &res);
 128        break;
 129    case 4:
 130        data = address_space_ldl_le(as, addr, attrs, &res);
 131        break;
 132    case 8:
 133        data = address_space_ldq_le(as, addr, attrs, &res);
 134        break;
 135    default:
 136        g_assert_not_reached();
 137    }
 138    *pdata = data;
 139    return res;
 140}
 141
 142static MemTxResult tz_ppc_write(void *opaque, hwaddr addr, uint64_t val,
 143                                unsigned size, MemTxAttrs attrs)
 144{
 145    TZPPCPort *p = opaque;
 146    TZPPC *s = p->ppc;
 147    AddressSpace *as = &p->downstream_as;
 148    int n = p - s->port;
 149    MemTxResult res;
 150
 151    if (!tz_ppc_check(s, n, attrs)) {
 152        trace_tz_ppc_write_blocked(n, addr, attrs.secure, attrs.user);
 153        if (s->cfg_sec_resp) {
 154            return MEMTX_ERROR;
 155        } else {
 156            return MEMTX_OK;
 157        }
 158    }
 159
 160    switch (size) {
 161    case 1:
 162        address_space_stb(as, addr, val, attrs, &res);
 163        break;
 164    case 2:
 165        address_space_stw_le(as, addr, val, attrs, &res);
 166        break;
 167    case 4:
 168        address_space_stl_le(as, addr, val, attrs, &res);
 169        break;
 170    case 8:
 171        address_space_stq_le(as, addr, val, attrs, &res);
 172        break;
 173    default:
 174        g_assert_not_reached();
 175    }
 176    return res;
 177}
 178
 179static const MemoryRegionOps tz_ppc_ops = {
 180    .read_with_attrs = tz_ppc_read,
 181    .write_with_attrs = tz_ppc_write,
 182    .endianness = DEVICE_LITTLE_ENDIAN,
 183};
 184
 185static bool tz_ppc_dummy_accepts(void *opaque, hwaddr addr,
 186                                 unsigned size, bool is_write,
 187                                 MemTxAttrs attrs)
 188{
 189    /*
 190     * Board code should never map the upstream end of an unused port,
 191     * so we should never try to make a memory access to it.
 192     */
 193    g_assert_not_reached();
 194}
 195
 196static const MemoryRegionOps tz_ppc_dummy_ops = {
 197    .valid.accepts = tz_ppc_dummy_accepts,
 198};
 199
 200static void tz_ppc_reset(DeviceState *dev)
 201{
 202    TZPPC *s = TZ_PPC(dev);
 203
 204    trace_tz_ppc_reset();
 205    s->cfg_sec_resp = false;
 206    memset(s->cfg_nonsec, 0, sizeof(s->cfg_nonsec));
 207    memset(s->cfg_ap, 0, sizeof(s->cfg_ap));
 208}
 209
 210static void tz_ppc_init(Object *obj)
 211{
 212    DeviceState *dev = DEVICE(obj);
 213    TZPPC *s = TZ_PPC(obj);
 214
 215    qdev_init_gpio_in_named(dev, tz_ppc_cfg_nonsec, "cfg_nonsec", TZ_NUM_PORTS);
 216    qdev_init_gpio_in_named(dev, tz_ppc_cfg_ap, "cfg_ap", TZ_NUM_PORTS);
 217    qdev_init_gpio_in_named(dev, tz_ppc_cfg_sec_resp, "cfg_sec_resp", 1);
 218    qdev_init_gpio_in_named(dev, tz_ppc_irq_enable, "irq_enable", 1);
 219    qdev_init_gpio_in_named(dev, tz_ppc_irq_clear, "irq_clear", 1);
 220    qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
 221}
 222
 223static void tz_ppc_realize(DeviceState *dev, Error **errp)
 224{
 225    Object *obj = OBJECT(dev);
 226    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 227    TZPPC *s = TZ_PPC(dev);
 228    int i;
 229    int max_port = 0;
 230
 231    /* We can't create the upstream end of the port until realize,
 232     * as we don't know the size of the MR used as the downstream until then.
 233     */
 234    for (i = 0; i < TZ_NUM_PORTS; i++) {
 235        if (s->port[i].downstream) {
 236            max_port = i;
 237        }
 238    }
 239
 240    for (i = 0; i <= max_port; i++) {
 241        TZPPCPort *port = &s->port[i];
 242        char *name;
 243        uint64_t size;
 244
 245        if (!port->downstream) {
 246            /*
 247             * Create dummy sysbus MMIO region so the sysbus region
 248             * numbering doesn't get out of sync with the port numbers.
 249             * The size is entirely arbitrary.
 250             */
 251            name = g_strdup_printf("tz-ppc-dummy-port[%d]", i);
 252            memory_region_init_io(&port->upstream, obj, &tz_ppc_dummy_ops,
 253                                  port, name, 0x10000);
 254            sysbus_init_mmio(sbd, &port->upstream);
 255            g_free(name);
 256            continue;
 257        }
 258
 259        name = g_strdup_printf("tz-ppc-port[%d]", i);
 260
 261        port->ppc = s;
 262        address_space_init(&port->downstream_as, port->downstream, name);
 263
 264        size = memory_region_size(port->downstream);
 265        memory_region_init_io(&port->upstream, obj, &tz_ppc_ops,
 266                              port, name, size);
 267        sysbus_init_mmio(sbd, &port->upstream);
 268        g_free(name);
 269    }
 270}
 271
 272static const VMStateDescription tz_ppc_vmstate = {
 273    .name = "tz-ppc",
 274    .version_id = 1,
 275    .minimum_version_id = 1,
 276    .fields = (VMStateField[]) {
 277        VMSTATE_BOOL_ARRAY(cfg_nonsec, TZPPC, 16),
 278        VMSTATE_BOOL_ARRAY(cfg_ap, TZPPC, 16),
 279        VMSTATE_BOOL(cfg_sec_resp, TZPPC),
 280        VMSTATE_BOOL(irq_enable, TZPPC),
 281        VMSTATE_BOOL(irq_clear, TZPPC),
 282        VMSTATE_BOOL(irq_status, TZPPC),
 283        VMSTATE_END_OF_LIST()
 284    }
 285};
 286
 287#define DEFINE_PORT(N)                                          \
 288    DEFINE_PROP_LINK("port[" #N "]", TZPPC, port[N].downstream, \
 289                     TYPE_MEMORY_REGION, MemoryRegion *)
 290
 291static Property tz_ppc_properties[] = {
 292    DEFINE_PROP_UINT32("NONSEC_MASK", TZPPC, nonsec_mask, 0),
 293    DEFINE_PORT(0),
 294    DEFINE_PORT(1),
 295    DEFINE_PORT(2),
 296    DEFINE_PORT(3),
 297    DEFINE_PORT(4),
 298    DEFINE_PORT(5),
 299    DEFINE_PORT(6),
 300    DEFINE_PORT(7),
 301    DEFINE_PORT(8),
 302    DEFINE_PORT(9),
 303    DEFINE_PORT(10),
 304    DEFINE_PORT(11),
 305    DEFINE_PORT(12),
 306    DEFINE_PORT(13),
 307    DEFINE_PORT(14),
 308    DEFINE_PORT(15),
 309    DEFINE_PROP_END_OF_LIST(),
 310};
 311
 312static void tz_ppc_class_init(ObjectClass *klass, void *data)
 313{
 314    DeviceClass *dc = DEVICE_CLASS(klass);
 315
 316    dc->realize = tz_ppc_realize;
 317    dc->vmsd = &tz_ppc_vmstate;
 318    dc->reset = tz_ppc_reset;
 319    dc->props = tz_ppc_properties;
 320}
 321
 322static const TypeInfo tz_ppc_info = {
 323    .name = TYPE_TZ_PPC,
 324    .parent = TYPE_SYS_BUS_DEVICE,
 325    .instance_size = sizeof(TZPPC),
 326    .instance_init = tz_ppc_init,
 327    .class_init = tz_ppc_class_init,
 328};
 329
 330static void tz_ppc_register_types(void)
 331{
 332    type_register_static(&tz_ppc_info);
 333}
 334
 335type_init(tz_ppc_register_types);
 336