From patchwork Wed Jun 20 13:20:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139328 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785551lji; Wed, 20 Jun 2018 06:20:35 -0700 (PDT) X-Google-Smtp-Source: ADUXVKIvzTJz/HE9hwMOoOEScXuY+KWxpYY5a8zZyzu0acYteCSLABZKJc9IgP3HjVclHpwP/y3l X-Received: by 2002:adf:8e6d:: with SMTP id n100-v6mr17933033wrb.159.1529500835590; Wed, 20 Jun 2018 06:20:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500835; cv=none; d=google.com; s=arc-20160816; b=geEZsmu5llN0vzbMWP3VTLf3ZIaKXAhdEaEQ0uaIBlmGawl8bmEpzqlmOwDp1SX7vz DKsTUSgvV/C5UCyGr1WA4c+lUO1Dkh86DrLdbs0BlFN+0NKS0GEpfAaNNEcsV/99TIKW oqVtt5NcxW7KP4P4bgTEecztoR4P7OaRbxRpo7yrzgXZIDLq0yjcon+np3SdCD1MkIub 60oCP9Fn0URgUEayk5QH2176Q2HilZYamiUuoNe98mAJvExAwyUaTuuy6zoDVOrC2Zhl B9rXL2ixQHQSBXbazhVc2zdNYEY5fIjHaNV+rv/M+Wvi+Ng32xONC3Fh8Q2mZSxrPrKG rwcg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=HimwawmmPJ5xpgcpVr3NaFXan5WYha9FgMFOR/MlVgU=; b=jzYqFtQVAhTTjhtoDpe7Z8wNTraE2QB17JLtw3+oYq1a7hC1BXQvHRqSsczIw8xle8 qEUVjMR3Yr2Kjwzppm2FO86fNgggKfcmJqSAKjctWtI49MHQ7oUX0RxkVu6jmcV67EKd VDr2hxxc9QdrFXORKtSIcizndQ8AOKl0Bs4dk3xwPqIuTpXy+0xMymyhdXDSaqzAMNw7 iVnE+mG5BXxj81B9x0T9yUXPd0Yj8pqK65bANziSXM50tG9YLoc4HKrcaq8U8RibGdMq kRB3NByMPKczDwm31IooEjyxLpTNN2ckYRNZSuLslO2Nq+g7iX4BI0VKmidr69jp8icJ Ks4g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id e81-v6si2357077wmi.207.2018.06.20.06.20.35 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2I-0001Yf-Vp; Wed, 20 Jun 2018 14:20:34 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 1/8] hw/misc/tz-mpc.c: Implement the Arm TrustZone Memory Protection Controller Date: Wed, 20 Jun 2018 14:20:25 +0100 Message-Id: <20180620132032.28865-2-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> MIME-Version: 1.0 Implement the Arm TrustZone Memory Protection Controller, which sits in front of RAM and allows secure software to configure it to either pass through or reject transactions. We implement the MPC as a QEMU IOMMU, which will direct transactions either through to the devices and memory behind it or to a special "never works" AddressSpace if they are blocked. This initial commit implements the skeleton of the device: * it always permits accesses * it doesn't implement most of the registers * it doesn't implement the interrupt or other behaviour for blocked transactions Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Eric Auger --- hw/misc/Makefile.objs | 1 + include/hw/misc/tz-mpc.h | 70 ++++++ hw/misc/tz-mpc.c | 399 ++++++++++++++++++++++++++++++++ MAINTAINERS | 2 + default-configs/arm-softmmu.mak | 1 + hw/misc/trace-events | 7 + 6 files changed, 480 insertions(+) create mode 100644 include/hw/misc/tz-mpc.h create mode 100644 hw/misc/tz-mpc.c -- 2.17.1 diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs index ecd8d610984..93509008451 100644 --- a/hw/misc/Makefile.objs +++ b/hw/misc/Makefile.objs @@ -62,6 +62,7 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o obj-$(CONFIG_MPS2_SCC) += mps2-scc.o +obj-$(CONFIG_TZ_MPC) += tz-mpc.o obj-$(CONFIG_TZ_PPC) += tz-ppc.o obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h new file mode 100644 index 00000000000..d1a65fd9a38 --- /dev/null +++ b/include/hw/misc/tz-mpc.h @@ -0,0 +1,70 @@ +/* + * ARM AHB5 TrustZone Memory Protection Controller emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +/* This is a model of the TrustZone memory protection controller (MPC). + * It is documented in the ARM CoreLink SIE-200 System IP for Embedded TRM + * (DDI 0571G): + * https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g + * + * The MPC sits in front of memory and allows secure software to + * configure it to either pass through or reject transactions. + * Rejected transactions may be configured to either be aborted, or to + * behave as RAZ/WI. An interrupt can be signalled for a rejected transaction. + * + * The MPC has a register interface which the guest uses to configure it. + * + * QEMU interface: + * + sysbus MMIO region 0: MemoryRegion for the MPC's config registers + * + sysbus MMIO region 1: MemoryRegion for the upstream end of the MPC + * + Property "downstream": MemoryRegion defining the downstream memory + * + Named GPIO output "irq": set for a transaction-failed interrupt + */ + +#ifndef TZ_MPC_H +#define TZ_MPC_H + +#include "hw/sysbus.h" + +#define TYPE_TZ_MPC "tz-mpc" +#define TZ_MPC(obj) OBJECT_CHECK(TZMPC, (obj), TYPE_TZ_MPC) + +#define TZ_NUM_PORTS 16 + +#define TYPE_TZ_MPC_IOMMU_MEMORY_REGION "tz-mpc-iommu-memory-region" + +typedef struct TZMPC TZMPC; + +struct TZMPC { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + + qemu_irq irq; + + /* Properties */ + MemoryRegion *downstream; + + hwaddr blocksize; + uint32_t blk_max; + + /* MemoryRegions exposed to user */ + MemoryRegion regmr; + IOMMUMemoryRegion upstream; + + /* MemoryRegion used internally */ + MemoryRegion blocked_io; + + AddressSpace downstream_as; + AddressSpace blocked_io_as; +}; + +#endif diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c new file mode 100644 index 00000000000..569bccfda7a --- /dev/null +++ b/hw/misc/tz-mpc.c @@ -0,0 +1,399 @@ +/* + * ARM AHB5 TrustZone Memory Protection Controller emulation + * + * Copyright (c) 2018 Linaro Limited + * Written by Peter Maydell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or + * (at your option) any later version. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qapi/error.h" +#include "trace.h" +#include "hw/sysbus.h" +#include "hw/registerfields.h" +#include "hw/misc/tz-mpc.h" + +/* Our IOMMU has two IOMMU indexes, one for secure transactions and one for + * non-secure transactions. + */ +enum { + IOMMU_IDX_S, + IOMMU_IDX_NS, + IOMMU_NUM_INDEXES, +}; + +/* Config registers */ +REG32(CTRL, 0x00) +REG32(BLK_MAX, 0x10) +REG32(BLK_CFG, 0x14) +REG32(BLK_IDX, 0x18) +REG32(BLK_LUT, 0x1c) +REG32(INT_STAT, 0x20) +REG32(INT_CLEAR, 0x24) +REG32(INT_EN, 0x28) +REG32(INT_INFO1, 0x2c) +REG32(INT_INFO2, 0x30) +REG32(INT_SET, 0x34) +REG32(PIDR4, 0xfd0) +REG32(PIDR5, 0xfd4) +REG32(PIDR6, 0xfd8) +REG32(PIDR7, 0xfdc) +REG32(PIDR0, 0xfe0) +REG32(PIDR1, 0xfe4) +REG32(PIDR2, 0xfe8) +REG32(PIDR3, 0xfec) +REG32(CIDR0, 0xff0) +REG32(CIDR1, 0xff4) +REG32(CIDR2, 0xff8) +REG32(CIDR3, 0xffc) + +static const uint8_t tz_mpc_idregs[] = { + 0x04, 0x00, 0x00, 0x00, + 0x60, 0xb8, 0x1b, 0x00, + 0x0d, 0xf0, 0x05, 0xb1, +}; + +static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr, + uint64_t *pdata, + unsigned size, MemTxAttrs attrs) +{ + uint64_t r; + uint32_t offset = addr & ~0x3; + + if (!attrs.secure && offset < A_PIDR4) { + /* NS accesses can only see the ID registers */ + qemu_log_mask(LOG_GUEST_ERROR, + "TZ MPC register read: NS access to offset 0x%x\n", + offset); + r = 0; + goto read_out; + } + + switch (offset) { + case A_PIDR4: + case A_PIDR5: + case A_PIDR6: + case A_PIDR7: + case A_PIDR0: + case A_PIDR1: + case A_PIDR2: + case A_PIDR3: + case A_CIDR0: + case A_CIDR1: + case A_CIDR2: + case A_CIDR3: + r = tz_mpc_idregs[(offset - A_PIDR4) / 4]; + break; + case A_INT_CLEAR: + case A_INT_SET: + qemu_log_mask(LOG_GUEST_ERROR, + "TZ MPC register read: write-only offset 0x%x\n", + offset); + r = 0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "TZ MPC register read: bad offset 0x%x\n", offset); + r = 0; + break; + } + + if (size != 4) { + /* None of our registers are read-sensitive (except BLK_LUT, + * which can special case the "size not 4" case), so just + * pull the right bytes out of the word read result. + */ + r = extract32(r, (addr & 3) * 8, size * 8); + } + +read_out: + trace_tz_mpc_reg_read(addr, r, size); + *pdata = r; + return MEMTX_OK; +} + +static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, + uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + uint32_t offset = addr & ~0x3; + + trace_tz_mpc_reg_write(addr, value, size); + + if (!attrs.secure && offset < A_PIDR4) { + /* NS accesses can only see the ID registers */ + qemu_log_mask(LOG_GUEST_ERROR, + "TZ MPC register read: NS access to offset 0x%x\n", + offset); + return MEMTX_OK; + } + + if (size != 4) { + /* Expand the byte or halfword write to a full word size. + * In most cases we can do this with zeroes; the exceptions + * are CTRL, BLK_IDX and BLK_LUT. + */ + uint32_t oldval; + + switch (offset) { + /* As we add support for registers which need expansions + * other than zeroes we'll fill in cases here. + */ + default: + oldval = 0; + break; + } + value = deposit32(oldval, (addr & 3) * 8, size * 8, value); + } + + switch (offset) { + case A_PIDR4: + case A_PIDR5: + case A_PIDR6: + case A_PIDR7: + case A_PIDR0: + case A_PIDR1: + case A_PIDR2: + case A_PIDR3: + case A_CIDR0: + case A_CIDR1: + case A_CIDR2: + case A_CIDR3: + qemu_log_mask(LOG_GUEST_ERROR, + "TZ MPC register write: read-only offset 0x%x\n", offset); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "TZ MPC register write: bad offset 0x%x\n", offset); + break; + } + + return MEMTX_OK; +} + +static const MemoryRegionOps tz_mpc_reg_ops = { + .read_with_attrs = tz_mpc_reg_read, + .write_with_attrs = tz_mpc_reg_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 1, + .impl.max_access_size = 4, +}; + +/* Accesses only reach these read and write functions if the MPC is + * blocking them; non-blocked accesses go directly to the downstream + * memory region without passing through this code. + */ +static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr, + uint64_t *pdata, + unsigned size, MemTxAttrs attrs) +{ + trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure); + + *pdata = 0; + return MEMTX_OK; +} + +static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr, + uint64_t value, + unsigned size, MemTxAttrs attrs) +{ + trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure); + + return MEMTX_OK; +} + +static const MemoryRegionOps tz_mpc_mem_blocked_ops = { + .read_with_attrs = tz_mpc_mem_blocked_read, + .write_with_attrs = tz_mpc_mem_blocked_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 8, + .impl.min_access_size = 1, + .impl.max_access_size = 8, +}; + +static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu, + hwaddr addr, IOMMUAccessFlags flags, + int iommu_idx) +{ + TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream)); + bool ok; + + IOMMUTLBEntry ret = { + .iova = addr & ~(s->blocksize - 1), + .translated_addr = addr & ~(s->blocksize - 1), + .addr_mask = s->blocksize - 1, + .perm = IOMMU_RW, + }; + + /* Look at the per-block configuration for this address, and + * return a TLB entry directing the transaction at either + * downstream_as or blocked_io_as, as appropriate. + * For the moment, always permit accesses. + */ + ok = true; + + trace_tz_mpc_translate(addr, flags, + iommu_idx == IOMMU_IDX_S ? "S" : "NS", + ok ? "pass" : "block"); + + ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as; + return ret; +} + +static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs) +{ + /* We treat unspecified attributes like secure. Transactions with + * unspecified attributes come from places like + * cpu_physical_memory_write_rom() for initial image load, and we want + * those to pass through the from-reset "everything is secure" config. + * All the real during-emulation transactions from the CPU will + * specify attributes. + */ + return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS; +} + +static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu) +{ + return IOMMU_NUM_INDEXES; +} + +static void tz_mpc_reset(DeviceState *dev) +{ +} + +static void tz_mpc_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + TZMPC *s = TZ_MPC(obj); + + qdev_init_gpio_out_named(dev, &s->irq, "irq", 1); +} + +static void tz_mpc_realize(DeviceState *dev, Error **errp) +{ + Object *obj = OBJECT(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + TZMPC *s = TZ_MPC(dev); + uint64_t size; + + /* We can't create the upstream end of the port until realize, + * as we don't know the size of the MR used as the downstream until then. + * We insist on having a downstream, to avoid complicating the code + * with handling the "don't know how big this is" case. It's easy + * enough for the user to create an unimplemented_device as downstream + * if they have nothing else to plug into this. + */ + if (!s->downstream) { + error_setg(errp, "MPC 'downstream' link not set"); + return; + } + + size = memory_region_size(s->downstream); + + memory_region_init_iommu(&s->upstream, sizeof(s->upstream), + TYPE_TZ_MPC_IOMMU_MEMORY_REGION, + obj, "tz-mpc-upstream", size); + + /* In real hardware the block size is configurable. In QEMU we could + * make it configurable but will need it to be at least as big as the + * target page size so we can execute out of the resulting MRs. Guest + * software is supposed to check the block size using the BLK_CFG + * register, so make it fixed at the page size. + */ + s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream); + if (size % s->blocksize != 0) { + error_setg(errp, + "MPC 'downstream' size %" PRId64 + " is not a multiple of %" HWADDR_PRIx " bytes", + size, s->blocksize); + object_unref(OBJECT(&s->upstream)); + return; + } + + /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit + * words, each bit of which indicates one block. + */ + s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32); + + memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops, + s, "tz-mpc-regs", 0x1000); + sysbus_init_mmio(sbd, &s->regmr); + + sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream)); + + /* This memory region is not exposed to users of this device as a + * sysbus MMIO region, but is instead used internally as something + * that our IOMMU translate function might direct accesses to. + */ + memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops, + s, "tz-mpc-blocked-io", size); + + address_space_init(&s->downstream_as, s->downstream, + "tz-mpc-downstream"); + address_space_init(&s->blocked_io_as, &s->blocked_io, + "tz-mpc-blocked-io"); +} + +static const VMStateDescription tz_mpc_vmstate = { + .name = "tz-mpc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; + +static Property tz_mpc_properties[] = { + DEFINE_PROP_LINK("downstream", TZMPC, downstream, + TYPE_MEMORY_REGION, MemoryRegion *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tz_mpc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = tz_mpc_realize; + dc->vmsd = &tz_mpc_vmstate; + dc->reset = tz_mpc_reset; + dc->props = tz_mpc_properties; +} + +static const TypeInfo tz_mpc_info = { + .name = TYPE_TZ_MPC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(TZMPC), + .instance_init = tz_mpc_init, + .class_init = tz_mpc_class_init, +}; + +static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass, + void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate = tz_mpc_translate; + imrc->attrs_to_index = tz_mpc_attrs_to_index; + imrc->num_indexes = tz_mpc_num_indexes; +} + +static const TypeInfo tz_mpc_iommu_memory_region_info = { + .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION, + .parent = TYPE_IOMMU_MEMORY_REGION, + .class_init = tz_mpc_iommu_memory_region_class_init, +}; + +static void tz_mpc_register_types(void) +{ + type_register_static(&tz_mpc_info); + type_register_static(&tz_mpc_iommu_memory_region_info); +} + +type_init(tz_mpc_register_types); diff --git a/MAINTAINERS b/MAINTAINERS index da91501c7a6..babbaaf5355 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -449,6 +449,8 @@ F: hw/char/cmsdk-apb-uart.c F: include/hw/char/cmsdk-apb-uart.h F: hw/misc/tz-ppc.c F: include/hw/misc/tz-ppc.h +F: hw/misc/tz-mpc.c +F: include/hw/misc/tz-mpc.h ARM cores M: Peter Maydell diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 7cf73d2f273..834d45cfaf9 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -108,6 +108,7 @@ CONFIG_CMSDK_APB_UART=y CONFIG_MPS2_FPGAIO=y CONFIG_MPS2_SCC=y +CONFIG_TZ_MPC=y CONFIG_TZ_PPC=y CONFIG_IOTKIT=y CONFIG_IOTKIT_SECCTL=y diff --git a/hw/misc/trace-events b/hw/misc/trace-events index ec5a9f0da13..72bf9d57000 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -84,6 +84,13 @@ mos6522_set_sr_int(void) "set sr_int" mos6522_write(uint64_t addr, uint64_t val) "reg=0x%"PRIx64 " val=0x%"PRIx64 mos6522_read(uint64_t addr, unsigned val) "reg=0x%"PRIx64 " val=0x%x" +# hw/misc/tz-mpc.c +tz_mpc_reg_read(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs read: offset 0x%x data 0x%" PRIx64 " size %u" +tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs write: offset 0x%x data 0x%" PRIx64 " size %u" +tz_mpc_mem_blocked_read(uint64_t addr, unsigned size, bool secure) "TZ MPC blocked read: offset 0x%" PRIx64 " size %u secure %d" +tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secure) "TZ MPC blocked write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" +tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s" + # hw/misc/tz-ppc.c tz_ppc_reset(void) "TZ PPC: reset" tz_ppc_cfg_nonsec(int n, int level) "TZ PPC: cfg_nonsec[%d] = %d" From patchwork Wed Jun 20 13:20:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139329 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785565lji; Wed, 20 Jun 2018 06:20:36 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLMNXawnIlhaaPw/L75AGOicuaEXSwYtZjW001esy8YRmMJ86gY3TGYS+7h9h2NIYO9KnRo X-Received: by 2002:a1c:ec47:: with SMTP id k68-v6mr1780017wmh.109.1529500836478; Wed, 20 Jun 2018 06:20:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500836; cv=none; d=google.com; s=arc-20160816; b=TvGuMqr28vdRPkEG7CixmsL01Q2VizIShJfTDAetYrDXHEcKVEyGL+iEvNq4Xil4Rh cpSglTKPD+QDCiHrwaZcLTACx/eKV/f3dwfHD34JawfBttrpGMrB+VbzQODV/nlWdJX2 gdVaCc4sENjIWrllrfsKFa3RfFK3UXV9/K/A8OOogX3AfVj4NkDMffbbZiyfsMhgMDkP gS8k0ZAFPb+MVpMOvtH44ZrA0iTYDdPLhadikM7TyTEm7ropz3PlPfUcbZsuFZdE5PjU UbVk5xwTLC+qU/iytsg8QwjixF+sB1l1FGVtv4+v7hX/kjVLu/huVPHvc6Sc/4le0Fgw UnlA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=TaREnZsPBAhfshZjB2OlVRTEFP1Xhwbc6pS+JxPaRWo=; b=o2q8XjmbjKmMzO8lpaVRSGbkemUpfq0etncXf3rrTG8VHbJBUcsZ+iHpHAZ0pQioHU F2ZxkGPGr4wah5AiLVe5BCTUM/pdTHoE/YV4G1cGXwpJyxpDHmhe9hMT4KK3oO6ZqkRg YsU1OkJkB2QOC6N7fFDfM+mm4ZX9Gvu7lVjMmY6f08zHT12Tj9CrAD5PCCV4amNeUSke 3ejjB26fPMl2aoAhJ2AMY/aavCVCvXTVX3TOpH8Wj73X8uGS3BHlOJnD7kOAQt9q0cdz FRWjb0j6MOiwzZ7BiePIw0xKxJJUnHOlth4Bbz0Yof3Beeh2sw0LmDTUPrlQWZkQ0O+x xjQA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id x2-v6si2273989wrr.281.2018.06.20.06.20.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:36 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2J-0001Yw-Vg; Wed, 20 Jun 2018 14:20:35 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 2/8] hw/misc/tz-mpc.c: Implement registers Date: Wed, 20 Jun 2018 14:20:26 +0100 Message-Id: <20180620132032.28865-3-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> Implement the missing registers for the TZ MPC. Signed-off-by: Peter Maydell --- include/hw/misc/tz-mpc.h | 10 +++ hw/misc/tz-mpc.c | 142 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 148 insertions(+), 4 deletions(-) -- 2.17.1 Reviewed-by: Eric Auger diff --git a/include/hw/misc/tz-mpc.h b/include/hw/misc/tz-mpc.h index d1a65fd9a38..6f15945410d 100644 --- a/include/hw/misc/tz-mpc.h +++ b/include/hw/misc/tz-mpc.h @@ -48,6 +48,16 @@ struct TZMPC { /*< public >*/ + /* State */ + uint32_t ctrl; + uint32_t blk_idx; + uint32_t int_stat; + uint32_t int_en; + uint32_t int_info1; + uint32_t int_info2; + + uint32_t *blk_lut; + qemu_irq irq; /* Properties */ diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c index 569bccfda7a..e5b91bf81a3 100644 --- a/hw/misc/tz-mpc.c +++ b/hw/misc/tz-mpc.c @@ -28,16 +28,23 @@ enum { /* Config registers */ REG32(CTRL, 0x00) + FIELD(CTRL, SEC_RESP, 4, 1) + FIELD(CTRL, AUTOINC, 8, 1) + FIELD(CTRL, LOCKDOWN, 31, 1) REG32(BLK_MAX, 0x10) REG32(BLK_CFG, 0x14) REG32(BLK_IDX, 0x18) REG32(BLK_LUT, 0x1c) REG32(INT_STAT, 0x20) + FIELD(INT_STAT, IRQ, 0, 1) REG32(INT_CLEAR, 0x24) + FIELD(INT_CLEAR, IRQ, 0, 1) REG32(INT_EN, 0x28) + FIELD(INT_EN, IRQ, 0, 1) REG32(INT_INFO1, 0x2c) REG32(INT_INFO2, 0x30) REG32(INT_SET, 0x34) + FIELD(INT_SET, IRQ, 0, 1) REG32(PIDR4, 0xfd0) REG32(PIDR5, 0xfd4) REG32(PIDR6, 0xfd8) @@ -57,10 +64,25 @@ static const uint8_t tz_mpc_idregs[] = { 0x0d, 0xf0, 0x05, 0xb1, }; +static void tz_mpc_irq_update(TZMPC *s) +{ + qemu_set_irq(s->irq, s->int_stat && s->int_en); +} + +static void tz_mpc_autoinc_idx(TZMPC *s, unsigned access_size) +{ + /* Auto-increment BLK_IDX if necessary */ + if (access_size == 4 && (s->ctrl & R_CTRL_AUTOINC_MASK)) { + s->blk_idx++; + s->blk_idx %= s->blk_max; + } +} + static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr, uint64_t *pdata, unsigned size, MemTxAttrs attrs) { + TZMPC *s = TZ_MPC(opaque); uint64_t r; uint32_t offset = addr & ~0x3; @@ -74,6 +96,38 @@ static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr, } switch (offset) { + case A_CTRL: + r = s->ctrl; + break; + case A_BLK_MAX: + r = s->blk_max; + break; + case A_BLK_CFG: + /* We are never in "init in progress state", so this just indicates + * the block size. s->blocksize == (1 << BLK_CFG + 5), so + * BLK_CFG == ctz32(s->blocksize) - 5 + */ + r = ctz32(s->blocksize) - 5; + break; + case A_BLK_IDX: + r = s->blk_idx; + break; + case A_BLK_LUT: + r = s->blk_lut[s->blk_idx]; + tz_mpc_autoinc_idx(s, size); + break; + case A_INT_STAT: + r = s->int_stat; + break; + case A_INT_EN: + r = s->int_en; + break; + case A_INT_INFO1: + r = s->int_info1; + break; + case A_INT_INFO2: + r = s->int_info2; + break; case A_PIDR4: case A_PIDR5: case A_PIDR6: @@ -120,6 +174,7 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { + TZMPC *s = TZ_MPC(opaque); uint32_t offset = addr & ~0x3; trace_tz_mpc_reg_write(addr, value, size); @@ -127,7 +182,7 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, if (!attrs.secure && offset < A_PIDR4) { /* NS accesses can only see the ID registers */ qemu_log_mask(LOG_GUEST_ERROR, - "TZ MPC register read: NS access to offset 0x%x\n", + "TZ MPC register write: NS access to offset 0x%x\n", offset); return MEMTX_OK; } @@ -140,9 +195,15 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, uint32_t oldval; switch (offset) { - /* As we add support for registers which need expansions - * other than zeroes we'll fill in cases here. - */ + case A_CTRL: + oldval = s->ctrl; + break; + case A_BLK_IDX: + oldval = s->blk_idx; + break; + case A_BLK_LUT: + oldval = s->blk_lut[s->blk_idx]; + break; default: oldval = 0; break; @@ -150,7 +211,48 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, value = deposit32(oldval, (addr & 3) * 8, size * 8, value); } + if ((s->ctrl & R_CTRL_LOCKDOWN_MASK) && + (offset == A_CTRL || offset == A_BLK_LUT || offset == A_INT_EN)) { + /* Lockdown mode makes these three registers read-only, and + * the only way out of it is to reset the device. + */ + qemu_log_mask(LOG_GUEST_ERROR, "TZ MPC register write to offset 0x%x " + "while MPC is in lockdown mode\n", offset); + return MEMTX_OK; + } + switch (offset) { + case A_CTRL: + /* We don't implement the 'data gating' feature so all other bits + * are reserved and we make them RAZ/WI. + */ + s->ctrl = value & (R_CTRL_SEC_RESP_MASK | + R_CTRL_AUTOINC_MASK | + R_CTRL_LOCKDOWN_MASK); + break; + case A_BLK_IDX: + s->blk_idx = value % s->blk_max; + break; + case A_BLK_LUT: + s->blk_lut[s->blk_idx] = value; + tz_mpc_autoinc_idx(s, size); + break; + case A_INT_CLEAR: + if (value & R_INT_CLEAR_IRQ_MASK) { + s->int_stat = 0; + tz_mpc_irq_update(s); + } + break; + case A_INT_EN: + s->int_en = value & R_INT_EN_IRQ_MASK; + tz_mpc_irq_update(s); + break; + case A_INT_SET: + if (value & R_INT_SET_IRQ_MASK) { + s->int_stat = R_INT_STAT_IRQ_MASK; + tz_mpc_irq_update(s); + } + break; case A_PIDR4: case A_PIDR5: case A_PIDR6: @@ -266,6 +368,16 @@ static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu) static void tz_mpc_reset(DeviceState *dev) { + TZMPC *s = TZ_MPC(dev); + + s->ctrl = 0x00000100; + s->blk_idx = 0; + s->int_stat = 0; + s->int_en = 1; + s->int_info1 = 0; + s->int_info2 = 0; + + memset(s->blk_lut, 0, s->blk_max * sizeof(uint32_t)); } static void tz_mpc_init(Object *obj) @@ -339,13 +451,35 @@ static void tz_mpc_realize(DeviceState *dev, Error **errp) "tz-mpc-downstream"); address_space_init(&s->blocked_io_as, &s->blocked_io, "tz-mpc-blocked-io"); + + s->blk_lut = g_new(uint32_t, s->blk_max); +} + +static int tz_mpc_post_load(void *opaque, int version_id) +{ + TZMPC *s = TZ_MPC(opaque); + + /* Check the incoming data doesn't point blk_idx off the end of blk_lut. */ + if (s->blk_idx >= s->blk_max) { + return -1; + } + return 0; } static const VMStateDescription tz_mpc_vmstate = { .name = "tz-mpc", .version_id = 1, .minimum_version_id = 1, + .post_load = tz_mpc_post_load, .fields = (VMStateField[]) { + VMSTATE_UINT32(ctrl, TZMPC), + VMSTATE_UINT32(blk_idx, TZMPC), + VMSTATE_UINT32(int_stat, TZMPC), + VMSTATE_UINT32(int_en, TZMPC), + VMSTATE_UINT32(int_info1, TZMPC), + VMSTATE_UINT32(int_info2, TZMPC), + VMSTATE_VARRAY_UINT32(blk_lut, TZMPC, blk_max, + 0, vmstate_info_uint32, uint32_t), VMSTATE_END_OF_LIST() } }; From patchwork Wed Jun 20 13:20:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139330 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785587lji; Wed, 20 Jun 2018 06:20:37 -0700 (PDT) X-Google-Smtp-Source: ADUXVKLmSHw7dwnl+G6hPu471PAUUVrcLH/TTFv36LVBcqur7f/pwKpoAbF1XuzocuRge9PbxmiD X-Received: by 2002:a1c:cfc2:: with SMTP id f185-v6mr1714692wmg.101.1529500837380; Wed, 20 Jun 2018 06:20:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500837; cv=none; d=google.com; s=arc-20160816; b=qzQ/SFq/DAvLCabbifVQnG3L9eH70FvR4ym8W0X3o4gQRP7O1EC9B8pn8vUFiCJ360 0HYrNgfxQvDyMHwNSgJ/nnMNscK6taNWhCDHAb0zIvLFDfqwNEzBU2WwcvXSRfY05vwG hJr62CuyixN+rx6BxDP+4H/aYogshsOIkbQvto9Uq4rKj5qoMoBAG7Z4KXF/k9Xm1i9u 83nU4kLmN+YqXK/ORvAJxdM2KrdSuhfTYvbgUJym4QxXF2xp8mi9VPv3XeatgTzL28X+ m2PFCfpEho+x69mw9WkIRNdMpyoNrW7xdK4wrQKKb61JP9X4sUYbA8t5EbJYNZaGKcl+ dPmw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=wKYAO+hdtl/mLa70+yordnQuFmw1WNTSP4ELq+07L8I=; b=wlUEnZK73Syc+ptNdUw6K9AIdrSk5fpDUT6bsjT5pK4fEkKxrVHRsHtVRgTLPXu7Fu UqWgykSqHvyRtuXifnMJlRdnHsg7GLgzfciOc3mTlCIVSe0JTnnzha+gSnc9b6d8jGvA JglF4EEpOevpOr2tGWnlqHXZKPaQKHbgF4VffLKZCqG/ItAhsrbX7uGeXfe2y7ldmp3d gLfurARS0SUEdScxt35L48ViXAbT8dzZOw5953hiJpYBjM/1CdMxixe7X+fLONPkYn2D /PQiGOIG36lgeDzgVGYDXDq+yFees/xGE030HMxl0e8h8uUEhKpklpcNGFUN5ZX61M28 c+rA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id w201-v6si2293393wmw.64.2018.06.20.06.20.37 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2K-0001Zk-TT; Wed, 20 Jun 2018 14:20:36 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 3/8] hw/misc/tz-mpc.c: Implement correct blocked-access behaviour Date: Wed, 20 Jun 2018 14:20:27 +0100 Message-Id: <20180620132032.28865-4-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> The MPC is guest-configurable for whether blocked accesses: * should be RAZ/WI or cause a bus error * should generate an interrupt or not Implement this behaviour in the blocked-access handlers. Signed-off-by: Peter Maydell Reviewed-by: Eric Auger --- hw/misc/tz-mpc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) -- 2.17.1 diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c index e5b91bf81a3..fded5922a21 100644 --- a/hw/misc/tz-mpc.c +++ b/hw/misc/tz-mpc.c @@ -43,6 +43,9 @@ REG32(INT_EN, 0x28) FIELD(INT_EN, IRQ, 0, 1) REG32(INT_INFO1, 0x2c) REG32(INT_INFO2, 0x30) + FIELD(INT_INFO2, HMASTER, 0, 16) + FIELD(INT_INFO2, HNONSEC, 16, 1) + FIELD(INT_INFO2, CFG_NS, 17, 1) REG32(INT_SET, 0x34) FIELD(INT_SET, IRQ, 0, 1) REG32(PIDR4, 0xfd0) @@ -287,6 +290,45 @@ static const MemoryRegionOps tz_mpc_reg_ops = { .impl.max_access_size = 4, }; +static inline bool tz_mpc_cfg_ns(TZMPC *s, hwaddr addr) +{ + /* Return the cfg_ns bit from the LUT for the specified address */ + hwaddr blknum = addr / s->blocksize; + hwaddr blkword = blknum / 32; + uint32_t blkbit = 1U << (blknum % 32); + + /* This would imply the address was larger than the size we + * defined this memory region to be, so it can't happen. + */ + assert(blkword < s->blk_max); + return s->blk_lut[blkword] & blkbit; +} + +static MemTxResult tz_mpc_handle_block(TZMPC *s, hwaddr addr, MemTxAttrs attrs) +{ + /* Handle a blocked transaction: raise IRQ, capture info, etc */ + if (!s->int_stat) { + /* First blocked transfer: capture information into INT_INFO1 and + * INT_INFO2. Subsequent transfers are still blocked but don't + * capture information until the guest clears the interrupt. + */ + + s->int_info1 = addr; + s->int_info2 = 0; + s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HMASTER, + attrs.requester_id & 0xffff); + s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HNONSEC, + ~attrs.secure); + s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, CFG_NS, + tz_mpc_cfg_ns(s, addr)); + s->int_stat |= R_INT_STAT_IRQ_MASK; + tz_mpc_irq_update(s); + } + + /* Generate bus error if desired; otherwise RAZ/WI */ + return (s->ctrl & R_CTRL_SEC_RESP_MASK) ? MEMTX_ERROR : MEMTX_OK; +} + /* Accesses only reach these read and write functions if the MPC is * blocking them; non-blocked accesses go directly to the downstream * memory region without passing through this code. @@ -295,19 +337,23 @@ static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr, uint64_t *pdata, unsigned size, MemTxAttrs attrs) { + TZMPC *s = TZ_MPC(opaque); + trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure); *pdata = 0; - return MEMTX_OK; + return tz_mpc_handle_block(s, addr, attrs); } static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr, uint64_t value, unsigned size, MemTxAttrs attrs) { + TZMPC *s = TZ_MPC(opaque); + trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure); - return MEMTX_OK; + return tz_mpc_handle_block(s, addr, attrs); } static const MemoryRegionOps tz_mpc_mem_blocked_ops = { From patchwork Wed Jun 20 13:20:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139331 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785598lji; Wed, 20 Jun 2018 06:20:38 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKuuBIB0OJQ/LtVq7KafEOf0GN6Wti4/eJH8FkB3Fs7JNnsuTvuOgx30uJiRFARUIuGfuw5 X-Received: by 2002:adf:ab96:: with SMTP id s22-v6mr18813382wrc.90.1529500838219; Wed, 20 Jun 2018 06:20:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500838; cv=none; d=google.com; s=arc-20160816; b=mreCxspQNkpNX8ANb2SPwQorOKZgKOFucuVj8yVhd8YuV7xJPwNBnAJW4AmlcJyiKC FNlDCYhPv7U8WkzhMci3G+3mMiOU4X8n6AkJ2CVdGVrcvYiZHJfCTqkA/vyOc6QazFre n6WXnblpMcOTdRoEMuYHFZM7ip9bibwkG58s/GzvtbXKfhZcKVYznMx2c9ER1z6OhbGr YV+BNHt3LNjscpMJ/QfPNP/8R0K/qI1LeHP3c2rywnc+gW6fzjNOD9g0AM2E91ulZG/5 BRaDO7DQJkoEf7pQNQuTC/brgRl/0FQ527vQWakAkx5RZHjKTB2wf2jQKm43z+sxQ5ED 9/6A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=mdFPRQCW4BCIlfNDT23ZYFxxl6l7liMYhPOLb4yRR9w=; b=gFUaWryPF7amLazru/mguno/LDOhVaj0Z5ExgL6Q+zA+OqfZvX1zMXJqz74eEpg0eI ihuy2lQB71j0a5PiwvWGaC8KbMUGzgzMPDaKcsy0ACvuiym1nv67zBCXB/qOhzG+xJap 9BmMntQ6VNm0Wx/sxi/YaHQ3esOVvAjhBZmC6J0qu1Jam2FGHlXdaD9+iEU58/UN/ORD Q1rkWSnxnzLWYA18AFoYLGMDVewhvqzjvVPkZne/9p3qPncBY11v3nH48kDNAnY4TEcA yrLgAgZfUjDDQmGlaLefNPuwOrVQo2UO6exh881BY0TQ4MECV0Gwx335PD2ftJ1ulGjM HYNQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id c49-v6si2816228wrc.208.2018.06.20.06.20.38 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:38 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2L-0001a4-NC; Wed, 20 Jun 2018 14:20:37 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 4/8] hw/misc/tz_mpc.c: Honour the BLK_LUT settings in translate Date: Wed, 20 Jun 2018 14:20:28 +0100 Message-Id: <20180620132032.28865-5-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> The final part of the Memory Protection Controller we need to implement is actually using the BLK_LUT data programmed by the guest to determine whether to block the transaction or not. Since this means we now change transaction mappings when the guest writes to BLK_LUT, we must also call the IOMMU notifiers at that point. Signed-off-by: Peter Maydell --- hw/misc/tz-mpc.c | 53 ++++++++++++++++++++++++++++++++++++++++++-- hw/misc/trace-events | 1 + 2 files changed, 52 insertions(+), 2 deletions(-) -- 2.17.1 Reviewed-by: Eric Auger diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c index fded5922a21..8316079b4bf 100644 --- a/hw/misc/tz-mpc.c +++ b/hw/misc/tz-mpc.c @@ -72,6 +72,53 @@ static void tz_mpc_irq_update(TZMPC *s) qemu_set_irq(s->irq, s->int_stat && s->int_en); } +static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx, + uint32_t oldlut, uint32_t newlut) +{ + /* Called when the LUT word at lutidx has changed from oldlut to newlut; + * must call the IOMMU notifiers for the changed blocks. + */ + IOMMUTLBEntry entry = { + .addr_mask = s->blocksize - 1, + }; + hwaddr addr = lutidx * s->blocksize * 32; + int i; + + for (i = 0; i < 32; i++, addr += s->blocksize) { + bool block_is_ns; + + if (!((oldlut ^ newlut) & (1 << i))) { + continue; + } + /* This changes the mappings for both the S and the NS space, + * so we need to do four notifies: an UNMAP then a MAP for each. + */ + block_is_ns = newlut & (1 << i); + + trace_tz_mpc_iommu_notify(addr); + entry.iova = addr; + entry.translated_addr = addr; + + entry.perm = IOMMU_NONE; + memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); + memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); + + entry.perm = IOMMU_RW; + if (block_is_ns) { + entry.target_as = &s->blocked_io_as; + } else { + entry.target_as = &s->downstream_as; + } + memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry); + if (block_is_ns) { + entry.target_as = &s->downstream_as; + } else { + entry.target_as = &s->blocked_io_as; + } + memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry); + } +} + static void tz_mpc_autoinc_idx(TZMPC *s, unsigned access_size) { /* Auto-increment BLK_IDX if necessary */ @@ -237,6 +284,7 @@ static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr, s->blk_idx = value % s->blk_max; break; case A_BLK_LUT: + tz_mpc_iommu_notify(s, s->blk_idx, s->blk_lut[s->blk_idx], value); s->blk_lut[s->blk_idx] = value; tz_mpc_autoinc_idx(s, size); break; @@ -383,9 +431,10 @@ static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu, /* Look at the per-block configuration for this address, and * return a TLB entry directing the transaction at either * downstream_as or blocked_io_as, as appropriate. - * For the moment, always permit accesses. + * If the LUT cfg_ns bit is 1, only non-secure transactions + * may pass. If the bit is 0, only secure transactions may pass. */ - ok = true; + ok = tz_mpc_cfg_ns(s, addr) == (iommu_idx == IOMMU_IDX_NS); trace_tz_mpc_translate(addr, flags, iommu_idx == IOMMU_IDX_S ? "S" : "NS", diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 72bf9d57000..c956e1419b7 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -90,6 +90,7 @@ tz_mpc_reg_write(uint32_t offset, uint64_t data, unsigned size) "TZ MPC regs wri tz_mpc_mem_blocked_read(uint64_t addr, unsigned size, bool secure) "TZ MPC blocked read: offset 0x%" PRIx64 " size %u secure %d" tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secure) "TZ MPC blocked write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d" tz_mpc_translate(uint64_t addr, int flags, const char *idx, const char *res) "TZ MPC translate: addr 0x%" PRIx64 " flags 0x%x iommu_idx %s: %s" +tz_mpc_iommu_notify(uint64_t addr) "TZ MPC iommu: notifying UNMAP/MAP for 0x%" PRIx64 # hw/misc/tz-ppc.c tz_ppc_reset(void) "TZ PPC: reset" From patchwork Wed Jun 20 13:20:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139333 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785621lji; Wed, 20 Jun 2018 06:20:39 -0700 (PDT) X-Google-Smtp-Source: ADUXVKK09/hNVqCsQeNWL9lO/qMbwuVJY6MxSeJ4ZdfsrzBK/p/FJCf00tsBe1bID1CvQXI9kwVp X-Received: by 2002:a1c:af95:: with SMTP id y143-v6mr1772925wme.28.1529500839279; Wed, 20 Jun 2018 06:20:39 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500839; cv=none; d=google.com; s=arc-20160816; b=PWLZH9+AMern+HZTcwQk1fBfKSQLYo8wqI5Fr9q1OhKkoh0Rks3tWy4/yRH+HzPEWH XwH1LyaEM2nmNp5XMfjdsYEqbtL7U+FsPxrG81pr+mU3d3PNf2f3jMoTLJUsM6NuJJ39 eAekg44/XFPq9pxzgTGl1744VjIkUARQ9wBoHmfjseKmq44Sl0B18Pe/KQyia/sij13y ab62uZ2vtO382X2lIXPNblm9TRoDdhrW1+ObHSi4w6a9jupduKiCU9JydLq/wsl3C2aV p8sqlke1jQO6B1DaAh5Kk5Ay2J6zWEdzwjl7KDMJ3xMbfzqdt207e3JlNMXtfcRAJUYC 8jZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=m73m1D3jF1u6/fPO7NJlqLCPaBmELMcfvEt2Dcf7X74=; b=epHlapjcNtTxkRKqnhbG1vm1hl9VY480oNwXJ3MOFpDxnIi7tJxRxJwJxXJmRw4d9W lQOZCl5Jwu42trFZuHjFpn/goDObw0GFHVhzcK9oKcY0MZh22OGrNn7sGzQHfo9rzTmc 1jD0yAbrzbvlgmPx6KJjAKGnQ+4yWyKNYUabtKErJE3Cr5eQjd/jQOlefHZdvPdp/mC2 8rsz3a305PAMPd0AfLAq2GvKqprFfnocfkRghEvHzN4FOSXHgtVuHyCTIVy9I20I9REy xEs2L/g8Q5Nz1En9nLbMM3l8sUE38I08Y+bTTRtkdRWk/hbQmzJ4+NivcxpJ6UQydEbe H+hg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id 65-v6si2410604wmj.25.2018.06.20.06.20.39 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:39 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2M-0001ad-Mi; Wed, 20 Jun 2018 14:20:38 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 5/8] hw/misc/iotkit-secctl.c: Implement SECMPCINTSTATUS Date: Wed, 20 Jun 2018 14:20:29 +0100 Message-Id: <20180620132032.28865-6-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> Implement the SECMPCINTSTATUS register. This is the only register in the security controller that deals with Memory Protection Controllers, and it simply provides a read-only view of the interrupt lines from the various MPCs in the system. Signed-off-by: Peter Maydell --- include/hw/misc/iotkit-secctl.h | 8 +++++++ hw/misc/iotkit-secctl.c | 38 +++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) -- 2.17.1 diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h index faad0c91901..082c14c925e 100644 --- a/include/hw/misc/iotkit-secctl.h +++ b/include/hw/misc/iotkit-secctl.h @@ -39,6 +39,11 @@ * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear * + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status + * Controlling the MPC in the IoTKit: + * + named GPIO input mpc_status + * Controlling each of the 16 expansion MPCs which a system using the IoTKit + * might provide: + * + named GPIO inputs mpcexp_status[0..15] */ #ifndef IOTKIT_SECCTL_H @@ -55,6 +60,8 @@ #define IOTS_NUM_APB_PPC 2 #define IOTS_NUM_APB_EXP_PPC 4 #define IOTS_NUM_AHB_EXP_PPC 4 +#define IOTS_NUM_EXP_MPC 16 +#define IOTS_NUM_MPC 1 typedef struct IoTKitSecCtl IoTKitSecCtl; @@ -94,6 +101,7 @@ struct IoTKitSecCtl { uint32_t secrespcfg; uint32_t nsccfg; uint32_t brginten; + uint32_t mpcintstatus; IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC]; IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC]; diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index ddd1584d341..de4fd8e36d2 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -139,6 +139,9 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, case A_NSCCFG: r = s->nsccfg; break; + case A_SECMPCINTSTATUS: + r = s->mpcintstatus; + break; case A_SECPPCINTSTAT: r = s->secppcintstat; break; @@ -186,7 +189,6 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, case A_APBSPPPCEXP3: r = s->apbexp[offset_to_ppc_idx(offset)].sp; break; - case A_SECMPCINTSTATUS: case A_SECMSCINTSTAT: case A_SECMSCINTEN: case A_NSMSCEXP: @@ -572,6 +574,20 @@ static void iotkit_secctl_reset(DeviceState *dev) foreach_ppc(s, iotkit_secctl_reset_ppc); } +static void iotkit_secctl_mpc_status(void *opaque, int n, int level) +{ + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); + + s->mpcintstatus = deposit32(s->mpcintstatus, 0, 1, !!level); +} + +static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level) +{ + IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); + + s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level); +} + static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level) { IoTKitSecCtlPPC *ppc = opaque; @@ -640,6 +656,10 @@ static void iotkit_secctl_init(Object *obj) qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg", 1); qdev_init_gpio_out_named(dev, &s->nsc_cfg_irq, "nsc_cfg", 1); + qdev_init_gpio_in_named(dev, iotkit_secctl_mpc_status, "mpc_status", 1); + qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status, + "mpcexp_status", IOTS_NUM_EXP_MPC); + memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops, s, "iotkit-secctl-s-regs", 0x1000); memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops, @@ -660,6 +680,16 @@ static const VMStateDescription iotkit_secctl_ppc_vmstate = { } }; +static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = { + .name = "iotkit-secctl-mpcintstatus", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(mpcintstatus, IoTKitSecCtl), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription iotkit_secctl_vmstate = { .name = "iotkit-secctl", .version_id = 1, @@ -677,7 +707,11 @@ static const VMStateDescription iotkit_secctl_vmstate = { VMSTATE_STRUCT_ARRAY(ahbexp, IoTKitSecCtl, IOTS_NUM_AHB_EXP_PPC, 1, iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), VMSTATE_END_OF_LIST() - } + }, + .subsections = (const VMStateDescription*[]) { + &iotkit_secctl_mpcintstatus_vmstate, + NULL + }, }; static void iotkit_secctl_class_init(ObjectClass *klass, void *data) From patchwork Wed Jun 20 13:20:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139332 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785649lji; Wed, 20 Jun 2018 06:20:40 -0700 (PDT) X-Google-Smtp-Source: ADUXVKIxDAIl8V/p9faJmkH8nnq3WiDsrz3OG9ncu5CScBWHWN8WKRVCvDKSZk0cKGQRb5XzKQEb X-Received: by 2002:a1c:8fd5:: with SMTP id r204-v6mr1864492wmd.77.1529500840278; Wed, 20 Jun 2018 06:20:40 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500840; cv=none; d=google.com; s=arc-20160816; b=itzcqyqkU7f4E7S1LjLo5VEs393ViH2TT7IIV3eXuxRJJXi6e/TjcpzroQSuMQ1nO8 l5A1ra9nNDhFV3u50LXktQRqyT0dI99TyUY5PWQH2w6GKnBHH9iJ0ABoiZ5P7zXatxzv CjvsgFxSIOA+t0KasOd5Wq01FMPBE71YLHP4cUAoINI/5pCUX3p+XPSHjxxRCae6L+0d gqN1TGWpXPgr6BqNxsKz/841ML679CbfP4PcBlFNaTpByf7+jxQfKtEPRe2akzHDeuSr pCF6Fliz06rO0eyyxsFSECz7B8qMfBpT+ybWaFLr624duc5wNnNH1KIxyuQsFSIKc5cm D5FA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=NdGvu8DSxSkqTnAcIC0lWaImKZxdeqClYOoKlOXbiTQ=; b=pxDoD3ApVdAI6hkKbRxHl9TasD7uqBOREJsYyQ1bVX/pohrX98sLm3CxpOxhPwTxr/ yn49XWtYjGDAMmStqsVCvjdGZ6jbez32216NwLRZ7dv6REtbmhQp1OrAHuMauDLLUuoZ y9Q7a6CWpVDeoMUZdtH1/Vb+TOnX5m55E9a05Hp8bY8ZZqNkbuxd9wDMBpDfXFILZN2A 3zCGNJhoDDiAbpJ9Q37hAfOJHIENc6MIW/baICe4OquBoN/1ujGkdyhbcQXxp9Wl3nCp IQPl/gGAKCGmI9g462LgJY6b5TgdyT62CQucqiVHyx00yExFk99tEqhYc3XeqF6HQOGQ eagw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id h26-v6si1199344wrc.223.2018.06.20.06.20.40 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:40 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2N-0001aw-PP; Wed, 20 Jun 2018 14:20:39 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 6/8] hw/arm/iotkit: Instantiate MPC Date: Wed, 20 Jun 2018 14:20:30 +0100 Message-Id: <20180620132032.28865-7-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> MIME-Version: 1.0 Wire up the one MPC that is part of the IoTKit itself. For the moment we don't wire up its interrupt line. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée --- include/hw/arm/iotkit.h | 2 ++ hw/arm/iotkit.c | 38 +++++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 11 deletions(-) -- 2.17.1 diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h index c6129d926b6..b21cf1ab9d1 100644 --- a/include/hw/arm/iotkit.h +++ b/include/hw/arm/iotkit.h @@ -51,6 +51,7 @@ #include "hw/arm/armv7m.h" #include "hw/misc/iotkit-secctl.h" #include "hw/misc/tz-ppc.h" +#include "hw/misc/tz-mpc.h" #include "hw/timer/cmsdk-apb-timer.h" #include "hw/misc/unimp.h" #include "hw/or-irq.h" @@ -74,6 +75,7 @@ typedef struct IoTKit { IoTKitSecCtl secctl; TZPPC apb_ppc0; TZPPC apb_ppc1; + TZMPC mpc; CMSDKAPBTIMER timer0; CMSDKAPBTIMER timer1; qemu_or_irq ppc_irq_orgate; diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c index 234185e8f78..160e40c7449 100644 --- a/hw/arm/iotkit.c +++ b/hw/arm/iotkit.c @@ -130,6 +130,7 @@ static void iotkit_init(Object *obj) TYPE_TZ_PPC); init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1), TYPE_TZ_PPC); + init_sysbus_child(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC); init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0), TYPE_CMSDK_APB_TIMER); init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1), @@ -266,15 +267,6 @@ static void iotkit_realize(DeviceState *dev, Error **errp) */ make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000); - /* This RAM should be behind a Memory Protection Controller, but we - * don't implement that yet. - */ - memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err); - if (err) { - error_propagate(errp, err); - return; - } - memory_region_add_subregion(&s->container, 0x20000000, &s->sram0); /* Security controller */ object_property_set_bool(OBJECT(&s->secctl), true, "realized", &err); @@ -310,6 +302,32 @@ static void iotkit_realize(DeviceState *dev, Error **errp) qdev_connect_gpio_out_named(dev_secctl, "sec_resp_cfg", 0, qdev_get_gpio_in(dev_splitter, 0)); + /* This RAM lives behind the Memory Protection Controller */ + memory_region_init_ram(&s->sram0, NULL, "iotkit.sram0", 0x00008000, &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_link(OBJECT(&s->mpc), OBJECT(&s->sram0), + "downstream", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(&s->mpc), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + /* Map the upstream end of the MPC into the right place... */ + memory_region_add_subregion(&s->container, 0x20000000, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc), + 1)); + /* ...and its register interface */ + memory_region_add_subregion(&s->container, 0x50083000, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc), + 0)); + /* Devices behind APB PPC0: * 0x40000000: timer0 * 0x40001000: timer1 @@ -473,8 +491,6 @@ static void iotkit_realize(DeviceState *dev, Error **errp) create_unimplemented_device("NS watchdog", 0x40081000, 0x1000); create_unimplemented_device("S watchdog", 0x50081000, 0x1000); - create_unimplemented_device("SRAM0 MPC", 0x50083000, 0x1000); - for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) { Object *splitter = OBJECT(&s->ppc_irq_splitter[i]); From patchwork Wed Jun 20 13:20:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139334 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785668lji; Wed, 20 Jun 2018 06:20:41 -0700 (PDT) X-Google-Smtp-Source: ADUXVKL70as+GKeJ9u3XVTLBNzZkT5ljyrNeFVSsK7WMkpPhC0KkMrXqA3jppjc9zHYqARNTuOte X-Received: by 2002:a1c:eacd:: with SMTP id g74-v6mr1624705wmi.103.1529500841151; Wed, 20 Jun 2018 06:20:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500841; cv=none; d=google.com; s=arc-20160816; b=gL4gt5npafkANQuqxsYXqhMZGwhYPliWO5kI6u581yPKqn/x1lYW4irFuEUu+YHMZG eqcPfvDxZv2Tkb6g28NeHGU+FNZIQ8+V8yG6ULGYgJDEWOh5PBsdZMn6KhgJ5CWrcn52 qZ84ZUteyPxX8F3rr7eEDuefzzc3VDUVyFTeCUFCE0+zYtUSTjDDNeNIDc9Upeqqziqo VfIXBbnfEuhNHvpsE1/LT2VQ0Ua5GeQbesiDCck3en3xpHDDwuRaE2qW5U3nBRyR2WKR 2rZPdf1Ooe6NmE4hMw7DqU+FT8bjgOw67AF6BFwVSqz/VaJEw+HLhUlSkUfxMO9NnPx+ cNyQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=e8kcVnzKdhgPmmNiRoTTVC8ABtqWInw316qKauMiA20=; b=A+bqJHB4l6y0aHSmIVgmubY/Y3PFDYBNbCsBMEGLs+iXhyAdS51SCQmNU3Z1veEaul xI60wgrl4LVjGNlA6PZNpcXBzIH69BQPA84+sRNxk99AtUpj6U9SbiR7kyUf2L/IPAYh WYj/Lsj/J9darTthD1+n7WmCzlfGwjmg+hjUvgFkW0eOCwAid3ycxAnX6uh4JevPjFw/ 5dx8nGKfjAwLIIpqF+mfumvGKGO870Q0Y5G53cquf8VNi1FC8b8Pa6bxhpG/RlNklBGx QsxrxKIIsHhLNIVa8wipOQm94F0c6prcPQXiP+laK0N1mjbGF65GSPLFqoZGOFEIzOQ7 diGg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id i64-v6si1920850wmg.194.2018.06.20.06.20.40 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2O-0001bi-K1; Wed, 20 Jun 2018 14:20:40 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 7/8] hw/arm/iotkit: Wire up MPC interrupt lines Date: Wed, 20 Jun 2018 14:20:31 +0100 Message-Id: <20180620132032.28865-8-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> MIME-Version: 1.0 The interrupt outputs from the MPC in the IoTKit and the expansion MPCs in the board must be wired up to the security controller, and also all ORed together to produce a single line to the NVIC. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée --- include/hw/arm/iotkit.h | 6 ++++ hw/arm/iotkit.c | 74 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) -- 2.17.1 diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h index b21cf1ab9d1..2cddde55dd1 100644 --- a/include/hw/arm/iotkit.h +++ b/include/hw/arm/iotkit.h @@ -42,6 +42,9 @@ * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_enable * + named GPIO outputs ahb_ppcexp{0,1,2,3}_irq_clear * + named GPIO inputs ahb_ppcexp{0,1,2,3}_irq_status + * Controlling each of the 16 expansion MPCs which a system using the IoTKit + * might provide: + * + named GPIO inputs mpcexp_status[0..15] */ #ifndef IOTKIT_H @@ -81,6 +84,8 @@ typedef struct IoTKit { qemu_or_irq ppc_irq_orgate; SplitIRQ sec_resp_splitter; SplitIRQ ppc_irq_splitter[NUM_PPCS]; + SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC]; + qemu_or_irq mpc_irq_orgate; UnimplementedDeviceState dualtimer; UnimplementedDeviceState s32ktimer; @@ -99,6 +104,7 @@ typedef struct IoTKit { qemu_irq nsc_cfg_in; qemu_irq irq_status_in[NUM_EXTERNAL_PPCS]; + qemu_irq mpcexp_status_in[IOTS_NUM_EXP_MPC]; uint32_t nsccfg; diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c index 160e40c7449..133d5bb34f4 100644 --- a/hw/arm/iotkit.c +++ b/hw/arm/iotkit.c @@ -131,6 +131,18 @@ static void iotkit_init(Object *obj) init_sysbus_child(obj, "apb-ppc1", &s->apb_ppc1, sizeof(s->apb_ppc1), TYPE_TZ_PPC); init_sysbus_child(obj, "mpc", &s->mpc, sizeof(s->mpc), TYPE_TZ_MPC); + object_initialize(&s->mpc_irq_orgate, sizeof(s->mpc_irq_orgate), + TYPE_OR_IRQ); + object_property_add_child(obj, "mpc-irq-orgate", + OBJECT(&s->mpc_irq_orgate), &error_abort); + for (i = 0; i < ARRAY_SIZE(s->mpc_irq_splitter); i++) { + char *name = g_strdup_printf("mpc-irq-splitter-%d", i); + SplitIRQ *splitter = &s->mpc_irq_splitter[i]; + + object_initialize(splitter, sizeof(*splitter), TYPE_SPLIT_IRQ); + object_property_add_child(obj, name, OBJECT(splitter), &error_abort); + g_free(name); + } init_sysbus_child(obj, "timer0", &s->timer0, sizeof(s->timer0), TYPE_CMSDK_APB_TIMER); init_sysbus_child(obj, "timer1", &s->timer1, sizeof(s->timer1), @@ -163,6 +175,12 @@ static void iotkit_exp_irq(void *opaque, int n, int level) qemu_set_irq(s->exp_irqs[n], level); } +static void iotkit_mpcexp_status(void *opaque, int n, int level) +{ + IoTKit *s = IOTKIT(opaque); + qemu_set_irq(s->mpcexp_status_in[n], level); +} + static void iotkit_realize(DeviceState *dev, Error **errp) { IoTKit *s = IOTKIT(dev); @@ -328,6 +346,22 @@ static void iotkit_realize(DeviceState *dev, Error **errp) sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->mpc), 0)); + /* We must OR together lines from the MPC splitters to go to the NVIC */ + object_property_set_int(OBJECT(&s->mpc_irq_orgate), + IOTS_NUM_EXP_MPC + IOTS_NUM_MPC, "num-lines", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(&s->mpc_irq_orgate), true, + "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + qdev_connect_gpio_out(DEVICE(&s->mpc_irq_orgate), 0, + qdev_get_gpio_in(DEVICE(&s->armv7m), 9)); + /* Devices behind APB PPC0: * 0x40000000: timer0 * 0x40001000: timer1 @@ -536,6 +570,46 @@ static void iotkit_realize(DeviceState *dev, Error **errp) g_free(gpioname); } + /* Wire up the splitters for the MPC IRQs */ + for (i = 0; i < IOTS_NUM_EXP_MPC + IOTS_NUM_MPC; i++) { + SplitIRQ *splitter = &s->mpc_irq_splitter[i]; + DeviceState *dev_splitter = DEVICE(splitter); + + object_property_set_int(OBJECT(splitter), 2, "num-lines", &err); + if (err) { + error_propagate(errp, err); + return; + } + object_property_set_bool(OBJECT(splitter), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + if (i < IOTS_NUM_EXP_MPC) { + /* Splitter input is from GPIO input line */ + s->mpcexp_status_in[i] = qdev_get_gpio_in(dev_splitter, 0); + qdev_connect_gpio_out(dev_splitter, 0, + qdev_get_gpio_in_named(dev_secctl, + "mpcexp_status", i)); + } else { + /* Splitter input is from our own MPC */ + qdev_connect_gpio_out_named(DEVICE(&s->mpc), "irq", 0, + qdev_get_gpio_in(dev_splitter, 0)); + qdev_connect_gpio_out(dev_splitter, 0, + qdev_get_gpio_in_named(dev_secctl, + "mpc_status", 0)); + } + + qdev_connect_gpio_out(dev_splitter, 1, + qdev_get_gpio_in(DEVICE(&s->mpc_irq_orgate), i)); + } + /* Create GPIO inputs which will pass the line state for our + * mpcexp_irq inputs to the correct splitter devices. + */ + qdev_init_gpio_in_named(dev, iotkit_mpcexp_status, "mpcexp_status", + IOTS_NUM_EXP_MPC); + iotkit_forward_sec_resp_cfg(s); system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq; From patchwork Wed Jun 20 13:20:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 139335 Delivered-To: patches@linaro.org Received: by 2002:a2e:970d:0:0:0:0:0 with SMTP id r13-v6csp785681lji; Wed, 20 Jun 2018 06:20:42 -0700 (PDT) X-Google-Smtp-Source: ADUXVKL9NJy5cPRglZEqKSHULU0IMqclrmNLa1CPNI2MO++gD+hORjqb25ycZjUysf4dr1aJpdzJ X-Received: by 2002:a1c:1695:: with SMTP id 143-v6mr1713028wmw.12.1529500841945; Wed, 20 Jun 2018 06:20:41 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1529500841; cv=none; d=google.com; s=arc-20160816; b=rbyef3rJLCytGn2QVRXIDqLT5/Noo/JA5NTcCiS7bqTzJlvX69SDXYv5A2B9OhxY2V IHjuxAgKZfzdBjM5GtjuMtwCNDluJvZQZEknmaTtoioZmKhibKC6Gy+OknMGKChfNo3/ nKFgubfbbyjq/OLmvak6CIfbwmyA7S2ZDevtQkF5Ectzz0UXoz6L0GlpJzwVywjhBpZm vcWivJdmNUMT/TGaI75JV5cszAJ9eetHVx9XCLVUJuG7wwtCyrJ0rhEcTp5B2P5LTOh/ gAvOqa7LHMdOiXCTu6nRa8tHAAkde9dAEBwYDjhQX0adhmD2dvJMkppWJtJ5/WYtXsyh xgZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:arc-authentication-results; bh=bnM3LH+WSZMu0ce7j4RyyFivQaOkmXzjLASm48hnMsQ=; b=YW9M1vzx3+L0vX69G4///C0RSHoFF41Vi5xKUgtMdG4Ntl1KrKfqn/B4uzhlcGRIjD 2f/ym/r+KEnVR6zqBuxEljQtrOXiR15PZ6tTiw1HFoatTvgCO1jigzLO7oREOHX2RRpa Afh3gLQbQxdi4Ip/kKRkKnnHD5vEuit0KS7KmOFYexfHnyGXdWKNNokCVNeUonBWrCe+ /CEzTE/aGJKDkFZIxRcZDpY34JjxlmNtg5EIMcM0dfaJeahOVyxwBfiJ7WbSnpockOhD USb46GATS9PGh4LG3QJE/VMxf2FmaQM77Evm/a1/HWFCohrIXgPfVxnvbGGCiQKN3tqs m4rw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from orth.archaic.org.uk (orth.archaic.org.uk. [2001:8b0:1d0::2]) by mx.google.com with ESMTPS id v203-v6si250681wma.96.2018.06.20.06.20.41 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 20 Jun 2018 06:20:41 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) client-ip=2001:8b0:1d0::2; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::2 as permitted sender) smtp.mailfrom=pm215@archaic.org.uk; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1fVd2P-0001cO-EN; Wed, 20 Jun 2018 14:20:41 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Cc: patches@linaro.org, =?utf-8?q?Alex_Benn=C3=A9e?= , Eric Auger Subject: [PATCH v3 8/8] hw/arm/mps2-tz.c: Instantiate MPCs Date: Wed, 20 Jun 2018 14:20:32 +0100 Message-Id: <20180620132032.28865-9-peter.maydell@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180620132032.28865-1-peter.maydell@linaro.org> References: <20180620132032.28865-1-peter.maydell@linaro.org> MIME-Version: 1.0 Instantiate and wire up the Memory Protection Controllers in the MPS2 board itself. Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée --- hw/arm/mps2-tz.c | 71 ++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 27 deletions(-) -- 2.17.1 diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index c5ef95e4cc0..22180c56fb7 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -44,6 +44,7 @@ #include "hw/timer/cmsdk-apb-timer.h" #include "hw/misc/mps2-scc.h" #include "hw/misc/mps2-fpgaio.h" +#include "hw/misc/tz-mpc.h" #include "hw/arm/iotkit.h" #include "hw/devices.h" #include "net/net.h" @@ -64,13 +65,12 @@ typedef struct { IoTKit iotkit; MemoryRegion psram; - MemoryRegion ssram1; + MemoryRegion ssram[3]; MemoryRegion ssram1_m; - MemoryRegion ssram23; MPS2SCC scc; MPS2FPGAIO fpgaio; TZPPC ppc[5]; - UnimplementedDeviceState ssram_mpc[3]; + TZMPC ssram_mpc[3]; UnimplementedDeviceState spi[5]; UnimplementedDeviceState i2c[4]; UnimplementedDeviceState i2s_audio; @@ -96,16 +96,6 @@ typedef struct { /* Main SYSCLK frequency in Hz */ #define SYSCLK_FRQ 20000000 -/* Initialize the auxiliary RAM region @mr and map it into - * the memory map at @base. - */ -static void make_ram(MemoryRegion *mr, const char *name, - hwaddr base, hwaddr size) -{ - memory_region_init_ram(mr, NULL, name, size, &error_fatal); - memory_region_add_subregion(get_system_memory(), base, mr); -} - /* Create an alias of an entire original MemoryRegion @orig * located at @base in the memory map. */ @@ -245,6 +235,44 @@ static MemoryRegion *make_eth_dev(MPS2TZMachineState *mms, void *opaque, return sysbus_mmio_get_region(s, 0); } +static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque, + const char *name, hwaddr size) +{ + TZMPC *mpc = opaque; + int i = mpc - &mms->ssram_mpc[0]; + MemoryRegion *ssram = &mms->ssram[i]; + MemoryRegion *upstream; + char *mpcname = g_strdup_printf("%s-mpc", name); + static uint32_t ramsize[] = { 0x00400000, 0x00200000, 0x00200000 }; + static uint32_t rambase[] = { 0x00000000, 0x28000000, 0x28200000 }; + + memory_region_init_ram(ssram, NULL, name, ramsize[i], &error_fatal); + + init_sysbus_child(OBJECT(mms), mpcname, mpc, + sizeof(mms->ssram_mpc[0]), TYPE_TZ_MPC); + object_property_set_link(OBJECT(mpc), OBJECT(ssram), + "downstream", &error_fatal); + object_property_set_bool(OBJECT(mpc), true, "realized", &error_fatal); + /* Map the upstream end of the MPC into system memory */ + upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 1); + memory_region_add_subregion(get_system_memory(), rambase[i], upstream); + /* and connect its interrupt to the IoTKit */ + qdev_connect_gpio_out_named(DEVICE(mpc), "irq", 0, + qdev_get_gpio_in_named(DEVICE(&mms->iotkit), + "mpcexp_status", i)); + + /* The first SSRAM is a special case as it has an alias; accesses to + * the alias region at 0x00400000 must also go to the MPC upstream. + */ + if (i == 0) { + make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", upstream, 0x00400000); + } + + g_free(mpcname); + /* Return the register interface MR for our caller to map behind the PPC */ + return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0); +} + static void mps2tz_common_init(MachineState *machine) { MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine); @@ -306,14 +334,6 @@ static void mps2tz_common_init(MachineState *machine) NULL, "mps.ram", 0x01000000); memory_region_add_subregion(system_memory, 0x80000000, &mms->psram); - /* The SSRAM memories should all be behind Memory Protection Controllers, - * but we don't implement that yet. - */ - make_ram(&mms->ssram1, "mps.ssram1", 0x00000000, 0x00400000); - make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x00400000); - - make_ram(&mms->ssram23, "mps.ssram23", 0x28000000, 0x00400000); - /* The overflow IRQs for all UARTs are ORed together. * Tx, Rx and "combined" IRQs are sent to the NVIC separately. * Create the OR gate for this. @@ -343,12 +363,9 @@ static void mps2tz_common_init(MachineState *machine) const PPCInfo ppcs[] = { { .name = "apb_ppcexp0", .ports = { - { "ssram-mpc0", make_unimp_dev, &mms->ssram_mpc[0], - 0x58007000, 0x1000 }, - { "ssram-mpc1", make_unimp_dev, &mms->ssram_mpc[1], - 0x58008000, 0x1000 }, - { "ssram-mpc2", make_unimp_dev, &mms->ssram_mpc[2], - 0x58009000, 0x1000 }, + { "ssram-0", make_mpc, &mms->ssram_mpc[0], 0x58007000, 0x1000 }, + { "ssram-1", make_mpc, &mms->ssram_mpc[1], 0x58008000, 0x1000 }, + { "ssram-2", make_mpc, &mms->ssram_mpc[2], 0x58009000, 0x1000 }, }, }, { .name = "apb_ppcexp1",