All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA
@ 2018-08-09 13:00 Peter Maydell
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module Peter Maydell
                   ` (16 more replies)
  0 siblings, 17 replies; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:00 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

This patchset adds some more missing devices to the MPS2 AN505
board model:

Patches 1-3 implement and wire up the CMSDK APB watchdog devices.

Patch 4 adds a CMSDK timer device that had been forgotten.

Ppatches 5-6 implement and wire up the "system control element",
which is some simple control/ID registers in the IoTKit

Patches 7-16 are the meat of the patchset, and add support
for the DMA controllers and their associated Master Security
Controllers. A TrustZone MSC sits in front of a device which
can be a bus master (such as a DMA controller) and allows secure
software to configure it to either pass through or reject transactions
made by that bus master. 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 AN505 has four
PL081 DMA controllers, each with its own MSC.

Patches 10-15 are various minor cleanups and bugfixes in
the PL081 model that are needed for its use in the AN505.
In particular the PL081 was previously entirely broken as
it would hw_error() as soon as the guest enabled the DMA
engine. I assume this was either accidentally left-in debug code,
or a deliberate choice to guard a never-tested implementation
so as to be able to identify when we had guest code to test it
with. (Linux for the realview/versatile boards never tries to
use the PL08x there for DMA.)

This patchset is sufficient for the "DMA" test in the AN505
self-test binary to pass. (I suspect it is not giving the
PL081 or MSC a very thorough workout, though.)

Based-on: <20180730162458.23186-1-peter.maydell@linaro.org>
("[PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer")

thanks
-- PMM

Peter Maydell (16):
  hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module
  nvic: Expose NMI line
  hw/arm/iotkit: Wire up the watchdogs
  hw/arm/iotkit: Wire up the S32KTIMER
  hw/misc/iotkit-sysctl: Implement IoTKit system control element
  hw/misc/iotkit: Wire up the system control element
  hw/misc/tz-msc: Model TrustZone Master Security Controller
  hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
  hw/arm/iotkit: Wire up the lines for MSCs
  hw/dma/pl080: Allow use as embedded-struct device
  hw/dma/pl080: Support all three interrupt lines
  hw/dma/pl080: Don't use CPU address space for DMA accesses
  hw/dma/pl080: Provide device reset function
  hw/dma/pl080: Correct bug in register address decode logic
  hw/dma/pl080: Remove hw_error() if DMA is enabled
  hw/arm/mps2-tz: Create PL081s and MSCs

 Makefile.objs                            |   1 +
 hw/misc/Makefile.objs                    |   2 +
 hw/watchdog/Makefile.objs                |   1 +
 include/hw/arm/iotkit.h                  |  20 +-
 include/hw/dma/pl080.h                   |  71 +++++
 include/hw/misc/iotkit-secctl.h          |  14 +
 include/hw/misc/iotkit-sysctl.h          |  50 ++++
 include/hw/misc/tz-msc.h                 |  79 ++++++
 include/hw/watchdog/cmsdk-apb-watchdog.h |  59 ++++
 hw/arm/armv7m.c                          |   1 +
 hw/arm/iotkit.c                          |  99 ++++++-
 hw/arm/mps2-tz.c                         | 101 ++++++-
 hw/arm/realview.c                        |   8 +-
 hw/arm/versatilepb.c                     |   9 +-
 hw/dma/pl080.c                           | 113 ++++----
 hw/intc/armv7m_nvic.c                    |  19 ++
 hw/misc/iotkit-secctl.c                  |  73 ++++-
 hw/misc/iotkit-sysctl.c                  | 324 ++++++++++++++++++++++
 hw/misc/tz-msc.c                         | 308 +++++++++++++++++++++
 hw/watchdog/cmsdk-apb-watchdog.c         | 326 +++++++++++++++++++++++
 MAINTAINERS                              |   7 +
 default-configs/arm-softmmu.mak          |   3 +
 hw/intc/trace-events                     |   1 +
 hw/misc/trace-events                     |  16 ++
 hw/watchdog/trace-events                 |   6 +
 25 files changed, 1632 insertions(+), 79 deletions(-)
 create mode 100644 include/hw/dma/pl080.h
 create mode 100644 include/hw/misc/iotkit-sysctl.h
 create mode 100644 include/hw/misc/tz-msc.h
 create mode 100644 include/hw/watchdog/cmsdk-apb-watchdog.h
 create mode 100644 hw/misc/iotkit-sysctl.c
 create mode 100644 hw/misc/tz-msc.c
 create mode 100644 hw/watchdog/cmsdk-apb-watchdog.c
 create mode 100644 hw/watchdog/trace-events

-- 
2.17.1

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  1:27   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 02/16] nvic: Expose NMI line Peter Maydell
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The Arm Cortex-M System Design Kit includes a simple watchdog module
based on a 32-bit down-counter. Implement this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 Makefile.objs                            |   1 +
 hw/watchdog/Makefile.objs                |   1 +
 include/hw/watchdog/cmsdk-apb-watchdog.h |  59 ++++
 hw/watchdog/cmsdk-apb-watchdog.c         | 326 +++++++++++++++++++++++
 MAINTAINERS                              |   2 +
 default-configs/arm-softmmu.mak          |   1 +
 hw/watchdog/trace-events                 |   6 +
 7 files changed, 396 insertions(+)
 create mode 100644 include/hw/watchdog/cmsdk-apb-watchdog.h
 create mode 100644 hw/watchdog/cmsdk-apb-watchdog.c
 create mode 100644 hw/watchdog/trace-events

diff --git a/Makefile.objs b/Makefile.objs
index 7a9828da282..ce9c79235e6 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -240,6 +240,7 @@ trace-events-subdirs += hw/tpm
 trace-events-subdirs += hw/usb
 trace-events-subdirs += hw/vfio
 trace-events-subdirs += hw/virtio
+trace-events-subdirs += hw/watchdog
 trace-events-subdirs += hw/xen
 trace-events-subdirs += io
 trace-events-subdirs += linux-user
diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
index 9589bed63a3..3f536d1cad8 100644
--- a/hw/watchdog/Makefile.objs
+++ b/hw/watchdog/Makefile.objs
@@ -1,4 +1,5 @@
 common-obj-y += watchdog.o
+common-obj-$(CONFIG_CMSDK_APB_WATCHDOG) += cmsdk-apb-watchdog.o
 common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
 common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
 common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
diff --git a/include/hw/watchdog/cmsdk-apb-watchdog.h b/include/hw/watchdog/cmsdk-apb-watchdog.h
new file mode 100644
index 00000000000..ab8b5987a19
--- /dev/null
+++ b/include/hw/watchdog/cmsdk-apb-watchdog.h
@@ -0,0 +1,59 @@
+/*
+ * ARM CMSDK APB watchdog 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 "APB watchdog" which is part of the Cortex-M
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ *
+ * QEMU interface:
+ *  + QOM property "wdogclk-frq": frequency at which the watchdog is clocked
+ *  + sysbus MMIO region 0: the register bank
+ *  + sysbus IRQ 0: watchdog interrupt
+ *
+ * In real hardware the watchdog's reset output is just a GPIO line
+ * which can then be masked by the board or treated as a simple interrupt.
+ * (For instance the IoTKit does this with the non-secure watchdog, so that
+ * secure code can control whether non-secure code can perform a system
+ * reset via its watchdog.) In QEMU, we just wire up the watchdog reset
+ * to watchdog_perform_action(), at least for the moment.
+ */
+
+#ifndef CMSDK_APB_WATCHDOG_H
+#define CMSDK_APB_WATCHDOG_H
+
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+
+#define TYPE_CMSDK_APB_WATCHDOG "cmsdk-apb-watchdog"
+#define CMSDK_APB_WATCHDOG(obj) OBJECT_CHECK(CMSDKAPBWatchdog, (obj), \
+                                              TYPE_CMSDK_APB_WATCHDOG)
+
+typedef struct CMSDKAPBWatchdog {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion iomem;
+    qemu_irq wdogint;
+    uint32_t wdogclk_frq;
+    struct ptimer_state *timer;
+
+    uint32_t control;
+    uint32_t intstatus;
+    uint32_t lock;
+    uint32_t itcr;
+    uint32_t itop;
+    uint32_t resetstatus;
+} CMSDKAPBWatchdog;
+
+#endif
diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
new file mode 100644
index 00000000000..eb79a73fa6c
--- /dev/null
+++ b/hw/watchdog/cmsdk-apb-watchdog.c
@@ -0,0 +1,326 @@
+/*
+ * ARM CMSDK APB watchdog 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 "APB watchdog" which is part of the Cortex-M
+ * System Design Kit (CMSDK) and documented in the Cortex-M System
+ * Design Kit Technical Reference Manual (ARM DDI0479C):
+ * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "qemu/main-loop.h"
+#include "sysemu/watchdog.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/watchdog/cmsdk-apb-watchdog.h"
+
+REG32(WDOGLOAD, 0x0)
+REG32(WDOGVALUE, 0x4)
+REG32(WDOGCONTROL, 0x8)
+    FIELD(WDOGCONTROL, INTEN, 0, 1)
+    FIELD(WDOGCONTROL, RESEN, 1, 1)
+#define R_WDOGCONTROL_VALID_MASK (R_WDOGCONTROL_INTEN_MASK | \
+                                  R_WDOGCONTROL_RESEN_MASK)
+REG32(WDOGINTCLR, 0xc)
+REG32(WDOGRIS, 0x10)
+    FIELD(WDOGRIS, INT, 0, 1)
+REG32(WDOGMIS, 0x14)
+REG32(WDOGLOCK, 0xc00)
+#define WDOG_UNLOCK_VALUE 0x1ACCE551
+REG32(WDOGITCR, 0xf00)
+    FIELD(WDOGITCR, ENABLE, 0, 1)
+#define R_WDOGITCR_VALID_MASK R_WDOGITCR_ENABLE_MASK
+REG32(WDOGITOP, 0xf04)
+    FIELD(WDOGITOP, WDOGRES, 0, 1)
+    FIELD(WDOGITOP, WDOGINT, 1, 1)
+#define R_WDOGITOP_VALID_MASK (R_WDOGITOP_WDOGRES_MASK | \
+                               R_WDOGITOP_WDOGINT_MASK)
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* PID/CID values */
+static const int watchdog_id[] = {
+    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+    0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
+    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s)
+{
+    /* Return masked interrupt status */
+    return s->intstatus && (s->control & R_WDOGCONTROL_INTEN_MASK);
+}
+
+static bool cmsdk_apb_watchdog_resetstatus(CMSDKAPBWatchdog *s)
+{
+    /* Return masked reset status */
+    return s->resetstatus && (s->control & R_WDOGCONTROL_RESEN_MASK);
+}
+
+static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s)
+{
+    bool wdogint;
+    bool wdogres;
+
+    if (s->itcr) {
+        wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK;
+        wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK;
+    } else {
+        wdogint = cmsdk_apb_watchdog_intstatus(s);
+        wdogres = cmsdk_apb_watchdog_resetstatus(s);
+    }
+
+    qemu_set_irq(s->wdogint, wdogint);
+    if (wdogres) {
+        watchdog_perform_action();
+    }
+}
+
+static uint64_t cmsdk_apb_watchdog_read(void *opaque, hwaddr offset,
+                                        unsigned size)
+{
+    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
+    uint64_t r;
+
+    switch (offset) {
+    case A_WDOGLOAD:
+        r = ptimer_get_limit(s->timer);
+        break;
+    case A_WDOGVALUE:
+        r = ptimer_get_count(s->timer);
+        break;
+    case A_WDOGCONTROL:
+        r = s->control;
+        break;
+    case A_WDOGRIS:
+        r = s->intstatus;
+        break;
+    case A_WDOGMIS:
+        r = cmsdk_apb_watchdog_intstatus(s);
+        break;
+    case A_WDOGLOCK:
+        r = s->lock;
+        break;
+    case A_WDOGITCR:
+        r = s->itcr;
+        break;
+    case A_PID4 ... A_CID3:
+        r = watchdog_id[(offset - A_PID4) / 4];
+        break;
+    case A_WDOGINTCLR:
+    case A_WDOGITOP:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CMSDK APB watchdog read: read of WO offset %x\n",
+                      (int)offset);
+        r = 0;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CMSDK APB watchdog read: bad offset %x\n", (int)offset);
+        r = 0;
+        break;
+    }
+    trace_cmsdk_apb_watchdog_read(offset, r, size);
+    return r;
+}
+
+static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
+                                     uint64_t value, unsigned size)
+{
+    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
+
+    trace_cmsdk_apb_watchdog_write(offset, value, size);
+
+    if (s->lock && offset != A_WDOGLOCK) {
+        /* Write access is disabled via WDOGLOCK */
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CMSDK APB watchdog write: write to locked watchdog\n");
+        return;
+    }
+
+    switch (offset) {
+    case A_WDOGLOAD:
+        /*
+         * Reset the load value and the current count, and make sure
+         * we're counting.
+         */
+        ptimer_set_limit(s->timer, value, 1);
+        ptimer_run(s->timer, 0);
+        break;
+    case A_WDOGCONTROL:
+        s->control = value & R_WDOGCONTROL_VALID_MASK;
+        cmsdk_apb_watchdog_update(s);
+        break;
+    case A_WDOGINTCLR:
+        s->intstatus = 0;
+        ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
+        cmsdk_apb_watchdog_update(s);
+        break;
+    case A_WDOGLOCK:
+        s->lock = (value != WDOG_UNLOCK_VALUE);
+        break;
+    case A_WDOGITCR:
+        s->itcr = value & R_WDOGITCR_VALID_MASK;
+        cmsdk_apb_watchdog_update(s);
+        break;
+    case A_WDOGITOP:
+        s->itop = value & R_WDOGITOP_VALID_MASK;
+        cmsdk_apb_watchdog_update(s);
+        break;
+    case A_WDOGVALUE:
+    case A_WDOGRIS:
+    case A_WDOGMIS:
+    case A_PID4 ... A_CID3:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CMSDK APB watchdog write: write to RO offset 0x%x\n",
+                      (int)offset);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "CMSDK APB watchdog write: bad offset 0x%x\n",
+                      (int)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps cmsdk_apb_watchdog_ops = {
+    .read = cmsdk_apb_watchdog_read,
+    .write = cmsdk_apb_watchdog_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    /* byte/halfword accesses are just zero-padded on reads and writes */
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+};
+
+static void cmsdk_apb_watchdog_tick(void *opaque)
+{
+    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
+
+    if (!s->intstatus) {
+        /* Count expired for the first time: raise interrupt */
+        s->intstatus = R_WDOGRIS_INT_MASK;
+    } else {
+        /* Count expired for the second time: raise reset and stop clock */
+        s->resetstatus = 1;
+        ptimer_stop(s->timer);
+    }
+    cmsdk_apb_watchdog_update(s);
+}
+
+static void cmsdk_apb_watchdog_reset(DeviceState *dev)
+{
+    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
+
+    trace_cmsdk_apb_watchdog_reset();
+    s->control = 0;
+    s->intstatus = 0;
+    s->lock = 0;
+    s->itcr = 0;
+    s->itop = 0;
+    s->resetstatus = 0;
+    /* Set the limit and the count */
+    ptimer_set_limit(s->timer, 0xffffffff, 1);
+    ptimer_run(s->timer, 0);
+}
+
+static void cmsdk_apb_watchdog_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
+
+    memory_region_init_io(&s->iomem, obj, &cmsdk_apb_watchdog_ops,
+                          s, "cmsdk-apb-watchdog", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->wdogint);
+}
+
+static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
+{
+    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
+    QEMUBH *bh;
+
+    if (s->wdogclk_frq == 0) {
+        error_setg(errp,
+                   "CMSDK APB watchdog: wdogclk-frq property must be set");
+        return;
+    }
+
+    bh = qemu_bh_new(cmsdk_apb_watchdog_tick, s);
+    s->timer = ptimer_init(bh,
+                           PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
+                           PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
+                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
+                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
+
+    ptimer_set_freq(s->timer, s->wdogclk_frq);
+}
+
+static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
+    .name = "cmsdk-apb-watchdog",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(timer, CMSDKAPBWatchdog),
+        VMSTATE_UINT32(control, CMSDKAPBWatchdog),
+        VMSTATE_UINT32(intstatus, CMSDKAPBWatchdog),
+        VMSTATE_UINT32(lock, CMSDKAPBWatchdog),
+        VMSTATE_UINT32(itcr, CMSDKAPBWatchdog),
+        VMSTATE_UINT32(itop, CMSDKAPBWatchdog),
+        VMSTATE_UINT32(resetstatus, CMSDKAPBWatchdog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property cmsdk_apb_watchdog_properties[] = {
+    DEFINE_PROP_UINT32("wdogclk-frq", CMSDKAPBWatchdog, wdogclk_frq, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = cmsdk_apb_watchdog_realize;
+    dc->vmsd = &cmsdk_apb_watchdog_vmstate;
+    dc->reset = cmsdk_apb_watchdog_reset;
+    dc->props = cmsdk_apb_watchdog_properties;
+}
+
+static const TypeInfo cmsdk_apb_watchdog_info = {
+    .name = TYPE_CMSDK_APB_WATCHDOG,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(CMSDKAPBWatchdog),
+    .instance_init = cmsdk_apb_watchdog_init,
+    .class_init = cmsdk_apb_watchdog_class_init,
+};
+
+static void cmsdk_apb_watchdog_register_types(void)
+{
+    type_register_static(&cmsdk_apb_watchdog_info);
+}
+
+type_init(cmsdk_apb_watchdog_register_types);
diff --git a/MAINTAINERS b/MAINTAINERS
index 2c1a55ca207..7ea39c0176b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -457,6 +457,8 @@ F: hw/timer/cmsdk-apb-dualtimer.c
 F: include/hw/timer/cmsdk-apb-dualtimer.h
 F: hw/char/cmsdk-apb-uart.c
 F: include/hw/char/cmsdk-apb-uart.h
+F: hw/watchdog/cmsdk-apb-watchdog.c
+F: include/hw/watchdog/cmsdk-apb-watchdog.h
 F: hw/misc/tz-ppc.c
 F: include/hw/misc/tz-ppc.h
 F: hw/misc/tz-mpc.c
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 046e8903839..521c3d459fa 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -105,6 +105,7 @@ CONFIG_STM32F205_SOC=y
 CONFIG_CMSDK_APB_TIMER=y
 CONFIG_CMSDK_APB_DUALTIMER=y
 CONFIG_CMSDK_APB_UART=y
+CONFIG_CMSDK_APB_WATCHDOG=y
 
 CONFIG_MPS2_FPGAIO=y
 CONFIG_MPS2_SCC=y
diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
new file mode 100644
index 00000000000..fee95847df0
--- /dev/null
+++ b/hw/watchdog/trace-events
@@ -0,0 +1,6 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/char/cmsdk_apb_watchdog.c
+cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset"
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 02/16] nvic: Expose NMI line
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-10  5:05   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 03/16] hw/arm/iotkit: Wire up the watchdogs Peter Maydell
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

On real v7M hardware, the NMI line is an externally visible signal
that an SoC or board can toggle to assert an NMI. Expose it in
our QEMU NVIC and armv7m container objects so that a board model
can wire it up if it needs to.

In particular, the MPS2 watchdog is wired to NMI.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/armv7m.c       |  1 +
 hw/intc/armv7m_nvic.c | 19 +++++++++++++++++++
 hw/intc/trace-events  |  1 +
 3 files changed, 21 insertions(+)

diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 6b076660574..66217a6053a 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -202,6 +202,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
      */
     qdev_pass_gpios(DEVICE(&s->nvic), dev, NULL);
     qdev_pass_gpios(DEVICE(&s->nvic), dev, "SYSRESETREQ");
+    qdev_pass_gpios(DEVICE(&s->nvic), dev, "NMI");
 
     /* Wire the NVIC up to the CPU */
     sbd = SYS_BUS_DEVICE(&s->nvic);
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index cd1e7f17299..be7771e9d1f 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -772,6 +772,24 @@ static void set_irq_level(void *opaque, int n, int level)
     }
 }
 
+/* callback when external NMI line is changed */
+static void nvic_nmi_trigger(void *opaque, int n, int level)
+{
+    NVICState *s = opaque;
+
+    trace_nvic_set_nmi_level(level);
+
+    /*
+     * The architecture doesn't specify whether NMI should share
+     * the normal-interrupt behaviour of being resampled on
+     * exception handler return. We choose not to, so just
+     * set NMI pending here and don't track the current level.
+     */
+    if (level) {
+        armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI, false);
+    }
+}
+
 static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
 {
     ARMCPU *cpu = s->cpu;
@@ -2310,6 +2328,7 @@ static void armv7m_nvic_instance_init(Object *obj)
     qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
     qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger",
                             M_REG_NUM_BANKS);
+    qdev_init_gpio_in_named(dev, nvic_nmi_trigger, "NMI", 1);
 }
 
 static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 5fb18e65c97..33e932fb918 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -184,6 +184,7 @@ nvic_acknowledge_irq(int irq, int prio) "NVIC acknowledge IRQ: %d now active (pr
 nvic_get_pending_irq_info(int irq, bool secure) "NVIC next IRQ %d: targets_secure: %d"
 nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
 nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
+nvic_set_nmi_level(int level) "NVIC external NMI level set to %d"
 nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
 nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 03/16] hw/arm/iotkit: Wire up the watchdogs
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module Peter Maydell
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 02/16] nvic: Expose NMI line Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-17 23:47   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 04/16] hw/arm/iotkit: Wire up the S32KTIMER Peter Maydell
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The IoTKit includes three different instances of the
CMSDK APB watchdog; create and wire them up.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h |  6 +++++
 hw/arm/iotkit.c         | 58 ++++++++++++++++++++++++++++++++++++++---
 2 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index 3e6d806e352..776d0497087 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -57,6 +57,7 @@
 #include "hw/misc/tz-mpc.h"
 #include "hw/timer/cmsdk-apb-timer.h"
 #include "hw/timer/cmsdk-apb-dualtimer.h"
+#include "hw/watchdog/cmsdk-apb-watchdog.h"
 #include "hw/misc/unimp.h"
 #include "hw/or-irq.h"
 #include "hw/core/split-irq.h"
@@ -87,10 +88,15 @@ typedef struct IoTKit {
     SplitIRQ ppc_irq_splitter[NUM_PPCS];
     SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
     qemu_or_irq mpc_irq_orgate;
+    qemu_or_irq nmi_orgate;
 
     CMSDKAPBDualTimer dualtimer;
     UnimplementedDeviceState s32ktimer;
 
+    CMSDKAPBWatchdog s32kwatchdog;
+    CMSDKAPBWatchdog nswatchdog;
+    CMSDKAPBWatchdog swatchdog;
+
     MemoryRegion container;
     MemoryRegion alias1;
     MemoryRegion alias2;
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 130d013909e..5cedfa03570 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -19,6 +19,9 @@
 #include "hw/misc/unimp.h"
 #include "hw/arm/arm.h"
 
+/* Clock frequency in HZ of the 32KHz "slow clock" */
+#define S32KCLK (32 * 1000)
+
 /* Create an alias region of @size bytes starting at @base
  * which mirrors the memory starting at @orig.
  */
@@ -140,6 +143,15 @@ static void iotkit_init(Object *obj)
                           TYPE_CMSDK_APB_TIMER);
     sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
                           TYPE_CMSDK_APB_DUALTIMER);
+    sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
+                          sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG);
+    sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog,
+                          sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
+    sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
+                          sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
+    object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
+                            sizeof(s->nmi_orgate), TYPE_OR_IRQ,
+                            &error_abort, NULL);
     object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
                             sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
                             &error_abort, NULL);
@@ -510,12 +522,52 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
     create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
 
     create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
-    create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000);
+
+    /* This OR gate wires together outputs from the secure watchdogs to NMI */
+    object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
+                          qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
+
+    qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
+    object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
+                       qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
 
     /* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */
 
-    create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
-    create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
+    qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
+    object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
+                       qdev_get_gpio_in(DEVICE(&s->armv7m), 1));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
+
+    qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
+    object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
+                       qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
 
     for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
         Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 04/16] hw/arm/iotkit: Wire up the S32KTIMER
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (2 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 03/16] hw/arm/iotkit: Wire up the watchdogs Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-17 23:49   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element Peter Maydell
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The IoTKit has a CMSDK timer device that runs on the S32KCLK.
Create this and wire it up.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h | 2 +-
 hw/arm/iotkit.c         | 9 +++++----
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index 776d0497087..0f5c5101708 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -83,6 +83,7 @@ typedef struct IoTKit {
     TZMPC mpc;
     CMSDKAPBTIMER timer0;
     CMSDKAPBTIMER timer1;
+    CMSDKAPBTIMER s32ktimer;
     qemu_or_irq ppc_irq_orgate;
     SplitIRQ sec_resp_splitter;
     SplitIRQ ppc_irq_splitter[NUM_PPCS];
@@ -91,7 +92,6 @@ typedef struct IoTKit {
     qemu_or_irq nmi_orgate;
 
     CMSDKAPBDualTimer dualtimer;
-    UnimplementedDeviceState s32ktimer;
 
     CMSDKAPBWatchdog s32kwatchdog;
     CMSDKAPBWatchdog nswatchdog;
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 5cedfa03570..cb0ec456f39 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -141,6 +141,8 @@ static void iotkit_init(Object *obj)
                           TYPE_CMSDK_APB_TIMER);
     sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
                           TYPE_CMSDK_APB_TIMER);
+    sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
+                          TYPE_CMSDK_APB_TIMER);
     sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
                           TYPE_CMSDK_APB_DUALTIMER);
     sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
@@ -166,8 +168,6 @@ static void iotkit_init(Object *obj)
                                 TYPE_SPLIT_IRQ, &error_abort, NULL);
         g_free(name);
     }
-    sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
-                          TYPE_UNIMPLEMENTED_DEVICE);
 }
 
 static void iotkit_exp_irq(void *opaque, int n, int level)
@@ -476,13 +476,14 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
     /* Devices behind APB PPC1:
      *   0x4002f000: S32K timer
      */
-    qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER");
-    qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000);
+    qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
     object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
     if (err) {
         error_propagate(errp, err);
         return;
     }
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
+                       qdev_get_gpio_in(DEVICE(&s->armv7m), 2));
     mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
     object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
     if (err) {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (3 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 04/16] hw/arm/iotkit: Wire up the S32KTIMER Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  0:23   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 06/16] hw/misc/iotkit: Wire up the " Peter Maydell
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The Arm IoTKit includes a system control element which
provides a block of read-only ID registers and a block
of read-write control registers. Implement a minimal
version of this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/misc/Makefile.objs           |   1 +
 include/hw/misc/iotkit-sysctl.h |  50 +++++
 hw/misc/iotkit-sysctl.c         | 324 ++++++++++++++++++++++++++++++++
 MAINTAINERS                     |   2 +
 default-configs/arm-softmmu.mak |   1 +
 hw/misc/trace-events            |   7 +
 6 files changed, 385 insertions(+)
 create mode 100644 include/hw/misc/iotkit-sysctl.h
 create mode 100644 hw/misc/iotkit-sysctl.c

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 93509008451..dbadb41d57a 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -65,6 +65,7 @@ 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
+obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
 
 obj-$(CONFIG_PVPANIC) += pvpanic.o
 obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
new file mode 100644
index 00000000000..c3b14ccee4c
--- /dev/null
+++ b/include/hw/misc/iotkit-sysctl.h
@@ -0,0 +1,50 @@
+/*
+ * ARM IoTKit system control element
+ *
+ * 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 "system control element" which is part of the
+ * Arm IoTKit and documented in
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * Specifically, it implements the "system information block" and
+ * "system control register" blocks.
+ *
+ * QEMU interface:
+ *  + sysbus MMIO region 0: the system information register bank
+ *  + sysbus MMIO region 1: the system control register bank
+ */
+
+#ifndef HW_MISC_IOTKIT_SYSCTL_H
+#define HW_MISC_IOTKIT_SYSCTL_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_IOTKIT_SYSCTL "iotkit-sysctl"
+#define IOTKIT_SYSCTL(obj) OBJECT_CHECK(IoTKitSysCtl, (obj), \
+                                        TYPE_IOTKIT_SYSCTL)
+
+typedef struct IoTKitSysCtl {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    MemoryRegion sysinfo_iomem;
+    MemoryRegion sysctl_iomem;
+
+    uint32_t secure_debug;
+    uint32_t reset_syndrome;
+    uint32_t reset_mask;
+    uint32_t gretreg;
+    uint32_t initsvrtor0;
+    uint32_t cpuwait;
+    uint32_t wicctrl;
+} IoTKitSysCtl;
+
+#endif
diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
new file mode 100644
index 00000000000..9445500be76
--- /dev/null
+++ b/hw/misc/iotkit-sysctl.c
@@ -0,0 +1,324 @@
+/*
+ * ARM IoTKit system control element
+ *
+ * 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 "system control element" which is part of the
+ * Arm IoTKit and documented in
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
+ * Specifically, it implements the "system information block" and
+ * "system control register" blocks.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "trace.h"
+#include "qapi/error.h"
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "hw/registerfields.h"
+#include "hw/misc/iotkit-sysctl.h"
+
+/* sysinfo block registers */
+REG32(SYS_VERSION, 0x0)
+REG32(SYS_CONFIG, 0x4)
+
+/* sysctl block registers */
+REG32(SECDBGSTAT, 0x0)
+REG32(SECDBGSET, 0x4)
+REG32(SECDBGCLR, 0x8)
+REG32(RESET_SYNDROME, 0x100)
+REG32(RESET_MASK, 0x104)
+REG32(SWRESET, 0x108)
+    FIELD(SWRESET, SWRESETREQ, 9, 1)
+REG32(GRETREG, 0x10c)
+REG32(INITSVRTOR0, 0x110)
+REG32(CPUWAIT, 0x118)
+REG32(BUSWAIT, 0x11c)
+REG32(WICCTRL, 0x120)
+
+/* PID registers, same offset in both blocks */
+REG32(PID4, 0xfd0)
+REG32(PID5, 0xfd4)
+REG32(PID6, 0xfd8)
+REG32(PID7, 0xfdc)
+REG32(PID0, 0xfe0)
+REG32(PID1, 0xfe4)
+REG32(PID2, 0xfe8)
+REG32(PID3, 0xfec)
+REG32(CID0, 0xff0)
+REG32(CID1, 0xff4)
+REG32(CID2, 0xff8)
+REG32(CID3, 0xffc)
+
+/* PID/CID values */
+static const int sysinfo_id[] = {
+    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+    0x58, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
+    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static const int sysctl_id[] = {
+    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
+    0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
+    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
+};
+
+static uint64_t iotkit_sysinfo_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    uint64_t r;
+
+    switch (offset) {
+    case A_SYS_VERSION:
+        r = 0x41743;
+        break;
+
+    case A_SYS_CONFIG:
+        r = 0x31;
+        break;
+    case A_PID4 ... A_CID3:
+        r = sysinfo_id[(offset - A_PID4) / 4];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "IoTKit SysInfo read: bad offset %x\n", (int)offset);
+        r = 0;
+        break;
+    }
+    trace_iotkit_sysinfo_read(offset, r, size);
+    return r;
+}
+
+static void iotkit_sysinfo_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    trace_iotkit_sysinfo_write(offset, value, size);
+
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "IoTKit SysInfo: write to RO offset 0x%x\n", (int)offset);
+}
+
+static const MemoryRegionOps iotkit_sysinfo_ops = {
+    .read = iotkit_sysinfo_read,
+    .write = iotkit_sysinfo_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    /* byte/halfword accesses are just zero-padded on reads and writes */
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+};
+
+static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
+    uint64_t r;
+
+    switch (offset) {
+    case A_SECDBGSTAT:
+        r = s->secure_debug;
+        break;
+    case A_RESET_SYNDROME:
+        r = s->reset_syndrome;
+        break;
+    case A_RESET_MASK:
+        r = s->reset_mask;
+        break;
+    case A_GRETREG:
+        r = s->gretreg;
+        break;
+    case A_INITSVRTOR0:
+        r = s->initsvrtor0;
+        break;
+    case A_CPUWAIT:
+        r = s->cpuwait;
+        break;
+    case A_BUSWAIT:
+        /* In IoTKit BUSWAIT is reserved, R/O, zero */
+        r = 0;
+        break;
+    case A_WICCTRL:
+        r = s->wicctrl;
+        break;
+    case A_PID4 ... A_CID3:
+        r = sysctl_id[(offset - A_PID4) / 4];
+        break;
+    case A_SECDBGSET:
+    case A_SECDBGCLR:
+    case A_SWRESET:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "IoTKit SysCtl read: read of WO offset %x\n",
+                      (int)offset);
+        r = 0;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "IoTKit SysCtl read: bad offset %x\n", (int)offset);
+        r = 0;
+        break;
+    }
+    trace_iotkit_sysctl_read(offset, r, size);
+    return r;
+}
+
+static void iotkit_sysctl_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
+
+    trace_iotkit_sysctl_write(offset, value, size);
+
+    /*
+     * Most of the state here has to do with control of reset and
+     * similar kinds of power up -- for instance the guest can ask
+     * what the reason for the last reset was, or forbid reset for
+     * some causes (like the non-secure watchdog). Most of this is
+     * not relevant to QEMU, which doesn't really model anything other
+     * than a full power-on reset.
+     * We just model the registers as reads-as-written.
+     */
+
+    switch (offset) {
+    case A_RESET_SYNDROME:
+        qemu_log_mask(LOG_UNIMP,
+                      "IoTKit SysCtl RESET_SYNDROME unimplemented\n");
+        s->reset_syndrome = value;
+        break;
+    case A_RESET_MASK:
+        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n");
+        s->reset_mask = value;
+        break;
+    case A_GRETREG:
+        /*
+         * General retention register, which is only reset by a power-on
+         * reset. Technically this implementation is complete, since
+         * QEMU only supports power-on resets...
+         */
+        s->gretreg = value;
+        break;
+    case A_INITSVRTOR0:
+        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl INITSVRTOR0 unimplemented\n");
+        s->initsvrtor0 = value;
+        break;
+    case A_CPUWAIT:
+        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CPUWAIT unimplemented\n");
+        s->cpuwait = value;
+        break;
+    case A_WICCTRL:
+        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n");
+        s->wicctrl = value;
+        break;
+    case A_SECDBGSET:
+        /* write-1-to-set */
+        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n");
+        s->secure_debug |= value;
+        break;
+    case A_SECDBGCLR:
+        /* write-1-to-clear */
+        s->secure_debug &= ~value;
+        break;
+    case A_SWRESET:
+        /* One w/o bit to request a reset; all other bits reserved */
+        if (value & R_SWRESET_SWRESETREQ_MASK) {
+            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        }
+        break;
+    case A_BUSWAIT:        /* In IoTKit BUSWAIT is reserved, R/O, zero */
+    case A_SECDBGSTAT:
+    case A_PID4 ... A_CID3:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "IoTKit SysCtl write: write of RO offset %x\n",
+                      (int)offset);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "IoTKit SysCtl write: bad offset %x\n", (int)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps iotkit_sysctl_ops = {
+    .read = iotkit_sysctl_read,
+    .write = iotkit_sysctl_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    /* byte/halfword accesses are just zero-padded on reads and writes */
+    .impl.min_access_size = 4,
+    .impl.max_access_size = 4,
+    .valid.min_access_size = 1,
+    .valid.max_access_size = 4,
+};
+
+static void iotkit_sysctl_reset(DeviceState *dev)
+{
+    IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
+
+    trace_iotkit_sysctl_reset();
+    s->secure_debug = 0;
+    s->reset_syndrome = 1;
+    s->reset_mask = 0;
+    s->gretreg = 0;
+    s->initsvrtor0 = 0x10000000;
+    s->cpuwait = 0;
+    s->wicctrl = 0;
+}
+
+static void iotkit_sysctl_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    IoTKitSysCtl *s = IOTKIT_SYSCTL(obj);
+
+    memory_region_init_io(&s->sysinfo_iomem, obj, &iotkit_sysinfo_ops,
+                          s, "iotkit-sysinfo", 0x1000);
+    memory_region_init_io(&s->sysctl_iomem, obj, &iotkit_sysctl_ops,
+                          s, "iotkit-sysctl", 0x1000);
+    sysbus_init_mmio(sbd, &s->sysinfo_iomem);
+    sysbus_init_mmio(sbd, &s->sysctl_iomem);
+}
+
+static const VMStateDescription iotkit_sysctl_vmstate = {
+    .name = "iotkit-sysctl",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(secure_debug, IoTKitSysCtl),
+        VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl),
+        VMSTATE_UINT32(reset_mask, IoTKitSysCtl),
+        VMSTATE_UINT32(gretreg, IoTKitSysCtl),
+        VMSTATE_UINT32(initsvrtor0, IoTKitSysCtl),
+        VMSTATE_UINT32(cpuwait, IoTKitSysCtl),
+        VMSTATE_UINT32(wicctrl, IoTKitSysCtl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void iotkit_sysctl_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->vmsd = &iotkit_sysctl_vmstate;
+    dc->reset = iotkit_sysctl_reset;
+}
+
+static const TypeInfo iotkit_sysctl_info = {
+    .name = TYPE_IOTKIT_SYSCTL,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(IoTKitSysCtl),
+    .instance_init = iotkit_sysctl_init,
+    .class_init = iotkit_sysctl_class_init,
+};
+
+static void iotkit_sysctl_register_types(void)
+{
+    type_register_static(&iotkit_sysctl_info);
+}
+
+type_init(iotkit_sysctl_register_types);
diff --git a/MAINTAINERS b/MAINTAINERS
index 7ea39c0176b..96fe011e952 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -537,6 +537,8 @@ F: hw/misc/mps2-*.c
 F: include/hw/misc/mps2-*.h
 F: hw/arm/iotkit.c
 F: include/hw/arm/iotkit.h
+F: hw/misc/iotkit-sysctl.c
+F: include/hw/misc/iotkit-sysctl.h
 
 Musicpal
 M: Jan Kiszka <jan.kiszka@web.de>
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 521c3d459fa..da59b820a4f 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -114,6 +114,7 @@ CONFIG_TZ_MPC=y
 CONFIG_TZ_PPC=y
 CONFIG_IOTKIT=y
 CONFIG_IOTKIT_SECCTL=y
+CONFIG_IOTKIT_SYSCTL=y
 
 CONFIG_VERSATILE=y
 CONFIG_VERSATILE_PCI=y
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index c956e1419b7..83ab58c30f5 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -109,3 +109,10 @@ iotkit_secctl_s_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit Sec
 iotkit_secctl_ns_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs read: offset 0x%x data 0x%" PRIx64 " size %u"
 iotkit_secctl_ns_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs write: offset 0x%x data 0x%" PRIx64 " size %u"
 iotkit_secctl_reset(void) "IoTKit SecCtl: reset"
+
+# hw/misc/iotkit-sysctl.c
+iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysctl_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysctl_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+iotkit_sysctl_reset(void) "IoTKit SysCtl: reset"
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 06/16] hw/misc/iotkit: Wire up the system control element
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (4 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  0:00   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 07/16] hw/misc/tz-msc: Model TrustZone Master Security Controller Peter Maydell
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

Wire up the system control element's register banks.

This is the last of the previously completely unimplemented
components in the IoTKit.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h |  4 +++-
 hw/arm/iotkit.c         | 19 +++++++++++--------
 2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index 0f5c5101708..1ffa31d521b 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -58,7 +58,7 @@
 #include "hw/timer/cmsdk-apb-timer.h"
 #include "hw/timer/cmsdk-apb-dualtimer.h"
 #include "hw/watchdog/cmsdk-apb-watchdog.h"
-#include "hw/misc/unimp.h"
+#include "hw/misc/iotkit-sysctl.h"
 #include "hw/or-irq.h"
 #include "hw/core/split-irq.h"
 
@@ -97,6 +97,8 @@ typedef struct IoTKit {
     CMSDKAPBWatchdog nswatchdog;
     CMSDKAPBWatchdog swatchdog;
 
+    IoTKitSysCtl sysctl;
+
     MemoryRegion container;
     MemoryRegion alias1;
     MemoryRegion alias2;
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index cb0ec456f39..5d59ed5489f 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -16,7 +16,6 @@
 #include "hw/sysbus.h"
 #include "hw/registerfields.h"
 #include "hw/arm/iotkit.h"
-#include "hw/misc/unimp.h"
 #include "hw/arm/arm.h"
 
 /* Clock frequency in HZ of the 32KHz "slow clock" */
@@ -151,6 +150,8 @@ static void iotkit_init(Object *obj)
                           sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
     sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
                           sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
+    sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl, sizeof(s->sysctl),
+                          TYPE_IOTKIT_SYSCTL);
     object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
                             sizeof(s->nmi_orgate), TYPE_OR_IRQ,
                             &error_abort, NULL);
@@ -516,13 +517,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
                           qdev_get_gpio_in_named(dev_apb_ppc1,
                                                  "cfg_sec_resp", 0));
 
-    /* Using create_unimplemented_device() maps the stub into the
-     * system address space rather than into our container, but the
-     * overall effect to the guest is the same.
-     */
-    create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
-
-    create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
+    object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    /* System information registers */
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x40020000);
+    /* System control registers */
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 1, 0x50021000);
 
     /* This OR gate wires together outputs from the secure watchdogs to NMI */
     object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 07/16] hw/misc/tz-msc: Model TrustZone Master Security Controller
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (5 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 06/16] hw/misc/iotkit: Wire up the " Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  1:15   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs Peter Maydell
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

Implement a model of the TrustZone Master Securtiy Controller,
as documented in the Arm CoreLink SIE-200 System IP for
Embedded TRM  (DDI0571G):
  https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g

The MSC is intended to sit in front of a device which can
be a bus master (eg a DMA controller) and programmably gate
its transactions. This allows a bus-mastering device to be
controlled by non-secure code but still restricted from
making accesses to addresses which are secure-only.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/misc/Makefile.objs           |   1 +
 include/hw/misc/tz-msc.h        |  79 ++++++++
 hw/misc/tz-msc.c                | 308 ++++++++++++++++++++++++++++++++
 MAINTAINERS                     |   2 +
 default-configs/arm-softmmu.mak |   1 +
 hw/misc/trace-events            |   9 +
 6 files changed, 400 insertions(+)
 create mode 100644 include/hw/misc/tz-msc.h
 create mode 100644 hw/misc/tz-msc.c

diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index dbadb41d57a..d168f8ac304 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -63,6 +63,7 @@ obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
 obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
 
 obj-$(CONFIG_TZ_MPC) += tz-mpc.o
+obj-$(CONFIG_TZ_MSC) += tz-msc.o
 obj-$(CONFIG_TZ_PPC) += tz-ppc.o
 obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
 obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
diff --git a/include/hw/misc/tz-msc.h b/include/hw/misc/tz-msc.h
new file mode 100644
index 00000000000..116b96ae9b8
--- /dev/null
+++ b/include/hw/misc/tz-msc.h
@@ -0,0 +1,79 @@
+/*
+ * ARM TrustZone master security 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 master security controller (MSC).
+ * 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 MSC sits in front of a device which can be a bus master (such as
+ * a DMA controller) and allows secure software to configure it to either
+ * pass through or reject transactions made by that bus master.
+ * 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 MSC has no register interface -- it is configured purely by a
+ * collection of input signals from other hardware in the system. Typically
+ * they are either hardwired or exposed in an ad-hoc register interface by
+ * the SoC that uses the MSC.
+ *
+ * We don't currently implement the irq_enable GPIO input, because on
+ * the MPS2 FPGA images it is always tied high, which is awkward to
+ * implement in QEMU.
+ *
+ * QEMU interface:
+ * + Named GPIO input "cfg_nonsec": set to 1 if the bus master should be
+ *   treated as nonsecure, or 0 for secure
+ * + Named GPIO input "cfg_sec_resp": set to 1 if a rejected transaction should
+ *   result in a transaction error, or 0 for the transaction to RAZ/WI
+ * + Named GPIO input "irq_clear": set to 1 to clear a pending interrupt
+ * + Named GPIO output "irq": set for a transaction-failed interrupt
+ * + Property "downstream": MemoryRegion defining where bus master transactions
+ *   are made if they are not blocked
+ * + Property "idau": an object implementing IDAUInterface, which defines which
+ *   addresses should be treated as secure and which as non-secure.
+ *   This need not be the same IDAU as the one used by the CPU.
+ * + sysbus MMIO region 0: MemoryRegion defining the upstream end of the MSC;
+ *   this should be passed to the bus master device as the region it should
+ *   make memory transactions to
+ */
+
+#ifndef TZ_MSC_H
+#define TZ_MSC_H
+
+#include "hw/sysbus.h"
+#include "target/arm/idau.h"
+
+#define TYPE_TZ_MSC "tz-msc"
+#define TZ_MSC(obj) OBJECT_CHECK(TZMSC, (obj), TYPE_TZ_MSC)
+
+typedef struct TZMSC {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+
+    /* State: these just track the values of our input signals */
+    bool cfg_nonsec;
+    bool cfg_sec_resp;
+    bool irq_clear;
+    /* State: are we asserting irq ? */
+    bool irq_status;
+
+    qemu_irq irq;
+    MemoryRegion *downstream;
+    AddressSpace downstream_as;
+    MemoryRegion upstream;
+    IDAUInterface *idau;
+} TZMSC;
+
+#endif
diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
new file mode 100644
index 00000000000..9e352044ea5
--- /dev/null
+++ b/hw/misc/tz-msc.c
@@ -0,0 +1,308 @@
+/*
+ * ARM TrustZone master security 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-msc.h"
+
+static void tz_msc_update_irq(TZMSC *s)
+{
+    bool level = s->irq_status;
+
+    trace_tz_msc_update_irq(level);
+    qemu_set_irq(s->irq, level);
+}
+
+static void tz_msc_cfg_nonsec(void *opaque, int n, int level)
+{
+    TZMSC *s = TZ_MSC(opaque);
+
+    trace_tz_msc_cfg_nonsec(level);
+    s->cfg_nonsec = level;
+}
+
+static void tz_msc_cfg_sec_resp(void *opaque, int n, int level)
+{
+    TZMSC *s = TZ_MSC(opaque);
+
+    trace_tz_msc_cfg_sec_resp(level);
+    s->cfg_sec_resp = level;
+}
+
+static void tz_msc_irq_clear(void *opaque, int n, int level)
+{
+    TZMSC *s = TZ_MSC(opaque);
+
+    trace_tz_msc_irq_clear(level);
+
+    s->irq_clear = level;
+    if (level) {
+        s->irq_status = false;
+        tz_msc_update_irq(s);
+    }
+}
+
+/* The MSC may either block a transaction by aborting it, block a
+ * transaction by making it RAZ/WI, allow it through with
+ * MemTxAttrs indicating a secure transaction, or allow it with
+ * MemTxAttrs indicating a non-secure transaction.
+ */
+typedef enum MSCAction {
+    MSCBlockAbort,
+    MSCBlockRAZWI,
+    MSCAllowSecure,
+    MSCAllowNonSecure,
+} MSCAction;
+
+static MSCAction tz_msc_check(TZMSC *s, hwaddr addr)
+{
+    /*
+     * Check whether to allow an access from the bus master, returning
+     * an MSCAction indicating the required behaviour. If the transaction
+     * is blocked, the caller must check cfg_sec_resp to determine
+     * whether to abort or RAZ/WI the transaction.
+     */
+    IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(s->idau);
+    IDAUInterface *ii = IDAU_INTERFACE(s->idau);
+    bool idau_exempt = false, idau_ns = true, idau_nsc = true;
+    int idau_region = IREGION_NOTVALID;
+
+    iic->check(ii, addr, &idau_region, &idau_exempt, &idau_ns, &idau_nsc);
+
+    if (idau_exempt) {
+        /*
+         * Uncheck region -- OK, transaction type depends on
+         * whether bus master is configured as Secure or NonSecure
+         */
+        return s->cfg_nonsec ? MSCAllowNonSecure : MSCAllowSecure;
+    }
+
+    if (idau_ns) {
+        /* NonSecure region -- always forward as NS transaction */
+        return MSCAllowNonSecure;
+    }
+
+    if (!s->cfg_nonsec) {
+        /* Access to Secure region by Secure bus master: OK */
+        return MSCAllowSecure;
+    }
+
+    /* Attempted access to Secure region by NS bus master: block */
+    trace_tz_msc_access_blocked(addr);
+    if (!s->cfg_sec_resp) {
+        return MSCBlockRAZWI;
+    }
+
+    /*
+     * The TRM isn't clear on behaviour if irq_clear is high when a
+     * transaction is blocked. We assume that the MSC behaves like the
+     * PPC, where holding irq_clear high suppresses the interrupt.
+     */
+    if (!s->irq_clear) {
+        s->irq_status = true;
+        tz_msc_update_irq(s);
+    }
+    return MSCBlockAbort;
+}
+
+static MemTxResult tz_msc_read(void *opaque, hwaddr addr, uint64_t *pdata,
+                               unsigned size, MemTxAttrs attrs)
+{
+    TZMSC *s = opaque;
+    AddressSpace *as = &s->downstream_as;
+    uint64_t data;
+    MemTxResult res;
+
+    switch (tz_msc_check(s, addr)) {
+    case MSCBlockAbort:
+        return MEMTX_ERROR;
+    case MSCBlockRAZWI:
+        *pdata = 0;
+        return MEMTX_OK;
+    case MSCAllowSecure:
+        attrs.secure = 1;
+        attrs.unspecified = 0;
+        break;
+    case MSCAllowNonSecure:
+        attrs.secure = 0;
+        attrs.unspecified = 0;
+        break;
+    }
+
+    switch (size) {
+    case 1:
+        data = address_space_ldub(as, addr, attrs, &res);
+        break;
+    case 2:
+        data = address_space_lduw_le(as, addr, attrs, &res);
+        break;
+    case 4:
+        data = address_space_ldl_le(as, addr, attrs, &res);
+        break;
+    case 8:
+        data = address_space_ldq_le(as, addr, attrs, &res);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    *pdata = data;
+    return res;
+}
+
+static MemTxResult tz_msc_write(void *opaque, hwaddr addr, uint64_t val,
+                                unsigned size, MemTxAttrs attrs)
+{
+    TZMSC *s = opaque;
+    AddressSpace *as = &s->downstream_as;
+    MemTxResult res;
+
+    switch (tz_msc_check(s, addr)) {
+    case MSCBlockAbort:
+        return MEMTX_ERROR;
+    case MSCBlockRAZWI:
+        return MEMTX_OK;
+    case MSCAllowSecure:
+        attrs.secure = 1;
+        attrs.unspecified = 0;
+        break;
+    case MSCAllowNonSecure:
+        attrs.secure = 0;
+        attrs.unspecified = 0;
+        break;
+    }
+
+    switch (size) {
+    case 1:
+        address_space_stb(as, addr, val, attrs, &res);
+        break;
+    case 2:
+        address_space_stw_le(as, addr, val, attrs, &res);
+        break;
+    case 4:
+        address_space_stl_le(as, addr, val, attrs, &res);
+        break;
+    case 8:
+        address_space_stq_le(as, addr, val, attrs, &res);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    return res;
+}
+
+static const MemoryRegionOps tz_msc_ops = {
+    .read_with_attrs = tz_msc_read,
+    .write_with_attrs = tz_msc_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void tz_msc_reset(DeviceState *dev)
+{
+    TZMSC *s = TZ_MSC(dev);
+
+    trace_tz_msc_reset();
+    s->cfg_sec_resp = false;
+    s->cfg_nonsec = false;
+    s->irq_clear = 0;
+    s->irq_status = 0;
+}
+
+static void tz_msc_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    TZMSC *s = TZ_MSC(obj);
+
+    qdev_init_gpio_in_named(dev, tz_msc_cfg_nonsec, "cfg_nonsec", 1);
+    qdev_init_gpio_in_named(dev, tz_msc_cfg_sec_resp, "cfg_sec_resp", 1);
+    qdev_init_gpio_in_named(dev, tz_msc_irq_clear, "irq_clear", 1);
+    qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
+}
+
+static void tz_msc_realize(DeviceState *dev, Error **errp)
+{
+    Object *obj = OBJECT(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    TZMSC *s = TZ_MSC(dev);
+    const char *name = "tz-msc-downstream";
+    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, "MSC 'downstream' link not set");
+        return;
+    }
+    if (!s->idau) {
+        error_setg(errp, "MSC 'idau' link not set");
+        return;
+    }
+
+    size = memory_region_size(s->downstream);
+    address_space_init(&s->downstream_as, s->downstream, name);
+    memory_region_init_io(&s->upstream, obj, &tz_msc_ops, s, name, size);
+    sysbus_init_mmio(sbd, &s->upstream);
+}
+
+static const VMStateDescription tz_msc_vmstate = {
+    .name = "tz-msc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(cfg_nonsec, TZMSC),
+        VMSTATE_BOOL(cfg_sec_resp, TZMSC),
+        VMSTATE_BOOL(irq_clear, TZMSC),
+        VMSTATE_BOOL(irq_status, TZMSC),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property tz_msc_properties[] = {
+    DEFINE_PROP_LINK("downstream", TZMSC, downstream,
+                     TYPE_MEMORY_REGION, MemoryRegion *),
+    DEFINE_PROP_LINK("idau", TZMSC, idau,
+                     TYPE_IDAU_INTERFACE, IDAUInterface *),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tz_msc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = tz_msc_realize;
+    dc->vmsd = &tz_msc_vmstate;
+    dc->reset = tz_msc_reset;
+    dc->props = tz_msc_properties;
+}
+
+static const TypeInfo tz_msc_info = {
+    .name = TYPE_TZ_MSC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(TZMSC),
+    .instance_init = tz_msc_init,
+    .class_init = tz_msc_class_init,
+};
+
+static void tz_msc_register_types(void)
+{
+    type_register_static(&tz_msc_info);
+}
+
+type_init(tz_msc_register_types);
diff --git a/MAINTAINERS b/MAINTAINERS
index 96fe011e952..5d1a3645dd4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -463,6 +463,8 @@ 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
+F: hw/misc/tz-msc.c
+F: include/hw/misc/tz-msc.h
 
 ARM cores
 M: Peter Maydell <peter.maydell@linaro.org>
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index da59b820a4f..1f2ac3b1767 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -111,6 +111,7 @@ CONFIG_MPS2_FPGAIO=y
 CONFIG_MPS2_SCC=y
 
 CONFIG_TZ_MPC=y
+CONFIG_TZ_MSC=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 83ab58c30f5..f9be1b822e7 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -92,6 +92,15 @@ tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secur
 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-msc.c
+tz_msc_reset(void) "TZ MSC: reset"
+tz_msc_cfg_nonsec(int level) "TZ MSC: cfg_nonsec = %d"
+tz_msc_cfg_sec_resp(int level) "TZ MSC: cfg_sec_resp = %d"
+tz_msc_irq_enable(int level) "TZ MSC: int_enable = %d"
+tz_msc_irq_clear(int level) "TZ MSC: int_clear = %d"
+tz_msc_update_irq(int level) "TZ MSC: setting irq line to %d"
+tz_msc_access_blocked(uint64_t offset) "TZ MSC: offset 0x%" PRIx64 " access blocked"
+
 # 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"
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (6 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 07/16] hw/misc/tz-msc: Model TrustZone Master Security Controller Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  0:37   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 09/16] hw/arm/iotkit: Wire up the lines for MSCs Peter Maydell
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The IoTKit does not have any Master Security Contollers itself,
but it does provide registers in the secure privilege control
block which allow control of MSCs in the external system.
Add support for these registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/misc/iotkit-secctl.h | 14 +++++++
 hw/misc/iotkit-secctl.c         | 73 +++++++++++++++++++++++++++++----
 2 files changed, 79 insertions(+), 8 deletions(-)

diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h
index 082c14c925e..1a193b306f1 100644
--- a/include/hw/misc/iotkit-secctl.h
+++ b/include/hw/misc/iotkit-secctl.h
@@ -19,6 +19,7 @@
  *  + named GPIO output "sec_resp_cfg" indicating whether blocked accesses
  *    should RAZ/WI or bus error
  *  + named GPIO output "nsc_cfg" whose value tracks the NSCCFG register value
+ *  + named GPIO output "msc_irq" for the combined IRQ line from the MSCs
  * Controlling the 2 APB PPCs in the IoTKit:
  *  + named GPIO outputs apb_ppc0_nonsec[0..2] and apb_ppc1_nonsec
  *  + named GPIO outputs apb_ppc0_ap[0..2] and apb_ppc1_ap
@@ -44,6 +45,11 @@
  * Controlling each of the 16 expansion MPCs which a system using the IoTKit
  * might provide:
  *  + named GPIO inputs mpcexp_status[0..15]
+ * Controlling each of the 16 expansion MSCs which a system using the IoTKit
+ * might provide:
+ *  + named GPIO inputs mscexp_status[0..15]
+ *  + named GPIO outputs mscexp_clear[0..15]
+ *  + named GPIO outputs mscexp_ns[0..15]
  */
 
 #ifndef IOTKIT_SECCTL_H
@@ -62,6 +68,7 @@
 #define IOTS_NUM_AHB_EXP_PPC 4
 #define IOTS_NUM_EXP_MPC 16
 #define IOTS_NUM_MPC 1
+#define IOTS_NUM_EXP_MSC 16
 
 typedef struct IoTKitSecCtl IoTKitSecCtl;
 
@@ -103,6 +110,13 @@ struct IoTKitSecCtl {
     uint32_t brginten;
     uint32_t mpcintstatus;
 
+    uint32_t secmscintstat;
+    uint32_t secmscinten;
+    uint32_t nsmscexp;
+    qemu_irq mscexp_clear[IOTS_NUM_EXP_MSC];
+    qemu_irq mscexp_ns[IOTS_NUM_EXP_MSC];
+    qemu_irq msc_irq;
+
     IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC];
     IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC];
     IoTKitSecCtlPPC ahbexp[IOTS_NUM_APB_EXP_PPC];
diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
index de4fd8e36d2..2222b3e147d 100644
--- a/hw/misc/iotkit-secctl.c
+++ b/hw/misc/iotkit-secctl.c
@@ -190,12 +190,13 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
         r = s->apbexp[offset_to_ppc_idx(offset)].sp;
         break;
     case A_SECMSCINTSTAT:
+        r = s->secmscintstat;
+        break;
     case A_SECMSCINTEN:
+        r = s->secmscinten;
+        break;
     case A_NSMSCEXP:
-        qemu_log_mask(LOG_UNIMP,
-                      "IoTKit SecCtl S block read: "
-                      "unimplemented offset 0x%x\n", offset);
-        r = 0;
+        r = s->nsmscexp;
         break;
     case A_PID4:
     case A_PID5:
@@ -291,6 +292,23 @@ static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc)
     qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1));
 }
 
+static void iotkit_secctl_update_mscexp_irqs(qemu_irq *msc_irqs, uint32_t value)
+{
+    int i;
+
+    for (i = 0; i < IOTS_NUM_EXP_MSC; i++) {
+        qemu_set_irq(msc_irqs[i], extract32(value, i + 16, 1));
+    }
+}
+
+static void iotkit_secctl_update_msc_irq(IoTKitSecCtl *s)
+{
+    /* Update the combined MSC IRQ, based on S_MSCEXP_STATUS and S_MSCEXP_EN */
+    bool level = s->secmscintstat & s->secmscinten;
+
+    qemu_set_irq(s->msc_irq, level);
+}
+
 static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
                                          uint64_t value,
                                          unsigned size, MemTxAttrs attrs)
@@ -370,10 +388,15 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
         iotkit_secctl_ppc_sp_write(ppc, value);
         break;
     case A_SECMSCINTCLR:
+        iotkit_secctl_update_mscexp_irqs(s->mscexp_clear, value);
+        break;
     case A_SECMSCINTEN:
-        qemu_log_mask(LOG_UNIMP,
-                      "IoTKit SecCtl S block write: "
-                      "unimplemented offset 0x%x\n", offset);
+        s->secmscinten = value;
+        iotkit_secctl_update_msc_irq(s);
+        break;
+    case A_NSMSCEXP:
+        s->nsmscexp = value;
+        iotkit_secctl_update_mscexp_irqs(s->mscexp_ns, value);
         break;
     case A_SECMPCINTSTATUS:
     case A_SECPPCINTSTAT:
@@ -381,7 +404,6 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
     case A_BRGINTSTAT:
     case A_AHBNSPPC0:
     case A_AHBSPPPC0:
-    case A_NSMSCEXP:
     case A_PID4:
     case A_PID5:
     case A_PID6:
@@ -588,6 +610,14 @@ static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level)
     s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level);
 }
 
+static void iotkit_secctl_mscexp_status(void *opaque, int n, int level)
+{
+    IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
+
+    s->secmscintstat = deposit32(s->secmscintstat, n + 16, 1, !!level);
+    iotkit_secctl_update_msc_irq(s);
+}
+
 static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
 {
     IoTKitSecCtlPPC *ppc = opaque;
@@ -660,6 +690,14 @@ static void iotkit_secctl_init(Object *obj)
     qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status,
                             "mpcexp_status", IOTS_NUM_EXP_MPC);
 
+    qdev_init_gpio_in_named(dev, iotkit_secctl_mscexp_status,
+                            "mscexp_status", IOTS_NUM_EXP_MSC);
+    qdev_init_gpio_out_named(dev, s->mscexp_clear, "mscexp_clear",
+                             IOTS_NUM_EXP_MSC);
+    qdev_init_gpio_out_named(dev, s->mscexp_ns, "mscexp_ns",
+                             IOTS_NUM_EXP_MSC);
+    qdev_init_gpio_out_named(dev, &s->msc_irq, "msc_irq", 1);
+
     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,
@@ -690,6 +728,24 @@ static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = {
     }
 };
 
+static bool needed_always(void *opaque)
+{
+    return true;
+}
+
+static const VMStateDescription iotkit_secctl_msc_vmstate = {
+    .name = "iotkit-secctl/msc",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .needed = needed_always,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(secmscintstat, IoTKitSecCtl),
+        VMSTATE_UINT32(secmscinten, IoTKitSecCtl),
+        VMSTATE_UINT32(nsmscexp, IoTKitSecCtl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static const VMStateDescription iotkit_secctl_vmstate = {
     .name = "iotkit-secctl",
     .version_id = 1,
@@ -710,6 +766,7 @@ static const VMStateDescription iotkit_secctl_vmstate = {
     },
     .subsections = (const VMStateDescription*[]) {
         &iotkit_secctl_mpcintstatus_vmstate,
+        &iotkit_secctl_msc_vmstate,
         NULL
     },
 };
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 09/16] hw/arm/iotkit: Wire up the lines for MSCs
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (7 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  0:39   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device Peter Maydell
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The IoTKit doesn't have any MSCs itself but it does need
some wiring to connect the external signals from MSCs
in the outer board model up to the registers and the
NVIC IRQ line.

We also need to expose a MemoryRegion corresponding to
the AHB bus, so that MSCs in the outer board model can
use that as their downstream port. (In the FPGA this is
the "AHB Slave Expansion" ports shown in the block
diagram in the AN505 documentation.)

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/arm/iotkit.h |  8 ++++++++
 hw/arm/iotkit.c         | 15 +++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
index 1ffa31d521b..5bb66b10468 100644
--- a/include/hw/arm/iotkit.h
+++ b/include/hw/arm/iotkit.h
@@ -28,6 +28,9 @@
  *  + QOM property "EXP_NUMIRQ" sets the number of expansion interrupts
  *  + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts, which
  *    are wired to the NVIC lines 32 .. n+32
+ *  + sysbus MMIO region 0 is the "AHB Slave Expansion" which allows
+ *    bus master devices in the board model to make transactions into
+ *    all the devices and memory areas in the IoTKit
  * Controlling up to 4 AHB expansion PPBs which a system using the IoTKit
  * might provide:
  *  + named GPIO outputs apb_ppcexp{0,1,2,3}_nonsec[0..15]
@@ -45,6 +48,11 @@
  * Controlling each of the 16 expansion MPCs which a system using the IoTKit
  * might provide:
  *  + named GPIO inputs mpcexp_status[0..15]
+ * Controlling each of the 16 expansion MSCs which a system using the IoTKit
+ * might provide:
+ *  + named GPIO inputs mscexp_status[0..15]
+ *  + named GPIO outputs mscexp_clear[0..15]
+ *  + named GPIO outputs mscexp_ns[0..15]
  */
 
 #ifndef IOTKIT_H
diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
index 5d59ed5489f..8ae2a052517 100644
--- a/hw/arm/iotkit.c
+++ b/hw/arm/iotkit.c
@@ -660,6 +660,21 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
 
     iotkit_forward_sec_resp_cfg(s);
 
+    /* Forward the MSC related signals */
+    qdev_pass_gpios(dev_secctl, dev, "mscexp_status");
+    qdev_pass_gpios(dev_secctl, dev, "mscexp_clear");
+    qdev_pass_gpios(dev_secctl, dev, "mscexp_ns");
+    qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0,
+                                qdev_get_gpio_in(DEVICE(&s->armv7m), 11));
+
+    /*
+     * Expose our container region to the board model; this corresponds
+     * to the AHB Slave Expansion ports which allow bus master devices
+     * (eg DMA controllers) in the board model to make transactions into
+     * devices in the IoTKit.
+     */
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
+
     system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (8 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 09/16] hw/arm/iotkit: Wire up the lines for MSCs Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-10  5:18   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 11/16] hw/dma/pl080: Support all three interrupt lines Peter Maydell
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

Create a new include file for the pl081's device struct,
type macros, etc, so that it can be instantiated using
the "embedded struct" coding style.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/dma/pl080.h | 62 ++++++++++++++++++++++++++++++++++++++++++
 hw/dma/pl080.c         | 34 ++---------------------
 MAINTAINERS            |  1 +
 3 files changed, 65 insertions(+), 32 deletions(-)
 create mode 100644 include/hw/dma/pl080.h

diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h
new file mode 100644
index 00000000000..7deb46c8578
--- /dev/null
+++ b/include/hw/dma/pl080.h
@@ -0,0 +1,62 @@
+/*
+ * ARM PrimeCell PL080/PL081 DMA controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2018 Linaro Limited
+ * Written by Paul Brook, 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 Arm PrimeCell PL080/PL081 DMA controller:
+ * The PL080 TRM is:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0196g/DDI0196.pdf
+ * and the PL081 TRM is:
+ * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0218e/DDI0218.pdf
+ *
+ * QEMU interface:
+ * + sysbus IRQ: DMACINTR combined interrupt line
+ * + sysbus MMIO region 0: MemoryRegion for the device's registers
+ */
+
+#ifndef HW_DMA_PL080_H
+#define HW_DMA_PL080_H
+
+#include "hw/sysbus.h"
+
+#define PL080_MAX_CHANNELS 8
+
+typedef struct {
+    uint32_t src;
+    uint32_t dest;
+    uint32_t lli;
+    uint32_t ctrl;
+    uint32_t conf;
+} pl080_channel;
+
+#define TYPE_PL080 "pl080"
+#define TYPE_PL081 "pl081"
+#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
+
+typedef struct PL080State {
+    SysBusDevice parent_obj;
+
+    MemoryRegion iomem;
+    uint8_t tc_int;
+    uint8_t tc_mask;
+    uint8_t err_int;
+    uint8_t err_mask;
+    uint32_t conf;
+    uint32_t sync;
+    uint32_t req_single;
+    uint32_t req_burst;
+    pl080_channel chan[PL080_MAX_CHANNELS];
+    int nchannels;
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+    qemu_irq irq;
+} PL080State;
+
+#endif
diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 7724c93b8f2..0f79c2d8a6c 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -11,8 +11,8 @@
 #include "hw/sysbus.h"
 #include "exec/address-spaces.h"
 #include "qemu/log.h"
+#include "hw/dma/pl080.h"
 
-#define PL080_MAX_CHANNELS 8
 #define PL080_CONF_E    0x1
 #define PL080_CONF_M1   0x2
 #define PL080_CONF_M2   0x4
@@ -30,36 +30,6 @@
 #define PL080_CCTRL_D   0x02000000
 #define PL080_CCTRL_S   0x01000000
 
-typedef struct {
-    uint32_t src;
-    uint32_t dest;
-    uint32_t lli;
-    uint32_t ctrl;
-    uint32_t conf;
-} pl080_channel;
-
-#define TYPE_PL080 "pl080"
-#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
-
-typedef struct PL080State {
-    SysBusDevice parent_obj;
-
-    MemoryRegion iomem;
-    uint8_t tc_int;
-    uint8_t tc_mask;
-    uint8_t err_int;
-    uint8_t err_mask;
-    uint32_t conf;
-    uint32_t sync;
-    uint32_t req_single;
-    uint32_t req_burst;
-    pl080_channel chan[PL080_MAX_CHANNELS];
-    int nchannels;
-    /* Flag to avoid recursive DMA invocations.  */
-    int running;
-    qemu_irq irq;
-} PL080State;
-
 static const VMStateDescription vmstate_pl080_channel = {
     .name = "pl080_channel",
     .version_id = 1,
@@ -408,7 +378,7 @@ static const TypeInfo pl080_info = {
 };
 
 static const TypeInfo pl081_info = {
-    .name          = "pl081",
+    .name          = TYPE_PL081,
     .parent        = TYPE_PL080,
     .instance_init = pl081_init,
 };
diff --git a/MAINTAINERS b/MAINTAINERS
index 5d1a3645dd4..92ccca716c6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -444,6 +444,7 @@ F: hw/char/pl011.c
 F: include/hw/char/pl011.h
 F: hw/display/pl110*
 F: hw/dma/pl080.c
+F: include/hw/dma/pl080.h
 F: hw/dma/pl330.c
 F: hw/gpio/pl061.c
 F: hw/input/pl050.c
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 11/16] hw/dma/pl080: Support all three interrupt lines
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (9 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  0:43   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 12/16] hw/dma/pl080: Don't use CPU address space for DMA accesses Peter Maydell
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The PL080 and PL081 have three outgoing interrupt lines:
 * DMACINTERR signals DMA errors
 * DMACINTTC is the DMA count interrupt
 * DMACINTR is a combined interrupt, the logical OR of the other two

We currently only implement DMACINTR, because that's all the
realview and versatile boards needed, but the instances of the
PL081 in the MPS2 firmware images use all three interrupt lines.
Implement the missing DMACINTERR and DMACINTTC.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/dma/pl080.h |  6 +++++-
 hw/dma/pl080.c         | 13 ++++++++-----
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h
index 7deb46c8578..7c6a4184833 100644
--- a/include/hw/dma/pl080.h
+++ b/include/hw/dma/pl080.h
@@ -17,7 +17,9 @@
  * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0218e/DDI0218.pdf
  *
  * QEMU interface:
- * + sysbus IRQ: DMACINTR combined interrupt line
+ * + sysbus IRQ 0: DMACINTR combined interrupt line
+ * + sysbus IRQ 1: DMACINTERR error interrupt request
+ * + sysbus IRQ 2: DMACINTTC count interrupt request
  * + sysbus MMIO region 0: MemoryRegion for the device's registers
  */
 
@@ -57,6 +59,8 @@ typedef struct PL080State {
     /* Flag to avoid recursive DMA invocations.  */
     int running;
     qemu_irq irq;
+    qemu_irq interr;
+    qemu_irq inttc;
 } PL080State;
 
 #endif
diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 0f79c2d8a6c..301030dd118 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -75,11 +75,12 @@ static const unsigned char pl081_id[] =
 
 static void pl080_update(PL080State *s)
 {
-    if ((s->tc_int & s->tc_mask)
-            || (s->err_int & s->err_mask))
-        qemu_irq_raise(s->irq);
-    else
-        qemu_irq_lower(s->irq);
+    bool tclevel = (s->tc_int & s->tc_mask);
+    bool errlevel = (s->err_int & s->err_mask);
+
+    qemu_set_irq(s->interr, errlevel);
+    qemu_set_irq(s->inttc, tclevel);
+    qemu_set_irq(s->irq, errlevel || tclevel);
 }
 
 static void pl080_run(PL080State *s)
@@ -352,6 +353,8 @@ static void pl080_init(Object *obj)
     memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq);
+    sysbus_init_irq(sbd, &s->interr);
+    sysbus_init_irq(sbd, &s->inttc);
     s->nchannels = 8;
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 12/16] hw/dma/pl080: Don't use CPU address space for DMA accesses
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (10 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 11/16] hw/dma/pl080: Support all three interrupt lines Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-10  5:10   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 13/16] hw/dma/pl080: Provide device reset function Peter Maydell
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

Currently our PL080/PL081 model uses a combination of the CPU's
address space (via cpu_physical_memory_{read,write}()) and the
system address space for performing DMA accesses.

For the PL081s in the MPS FPGA images, their DMA accesses
must go via Master Security Controllers. Switch the
PL080/PL081 model to take a MemoryRegion property which
defines its downstream for making DMA accesses.

Since the PL08x are only used in two board models, we
make provision of the 'downstream' link mandatory and convert
both users at once, rather than having it be optional with
a default to the system address space.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/hw/dma/pl080.h |  5 +++++
 hw/arm/realview.c      |  8 +++++++-
 hw/arm/versatilepb.c   |  9 ++++++++-
 hw/dma/pl080.c         | 35 +++++++++++++++++++++++++++++------
 4 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h
index 7c6a4184833..9d4b3df143f 100644
--- a/include/hw/dma/pl080.h
+++ b/include/hw/dma/pl080.h
@@ -21,6 +21,8 @@
  * + sysbus IRQ 1: DMACINTERR error interrupt request
  * + sysbus IRQ 2: DMACINTTC count interrupt request
  * + sysbus MMIO region 0: MemoryRegion for the device's registers
+ * + QOM property "downstream": MemoryRegion defining where DMA
+ *   bus master transactions are made
  */
 
 #ifndef HW_DMA_PL080_H
@@ -61,6 +63,9 @@ typedef struct PL080State {
     qemu_irq irq;
     qemu_irq interr;
     qemu_irq inttc;
+
+    MemoryRegion *downstream;
+    AddressSpace downstream_as;
 } PL080State;
 
 #endif
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index cd585d94694..ab8c14fde38 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -201,7 +201,13 @@ static void realview_init(MachineState *machine,
     pl011_create(0x1000c000, pic[15], serial_hd(3));
 
     /* DMA controller is optional, apparently.  */
-    sysbus_create_simple("pl081", 0x10030000, pic[24]);
+    dev = qdev_create(NULL, "pl081");
+    object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream",
+                             &error_fatal);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0x10030000);
+    sysbus_connect_irq(busdev, 0, pic[24]);
 
     sysbus_create_simple("sp804", 0x10011000, pic[4]);
     sysbus_create_simple("sp804", 0x10012000, pic[5]);
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index a5a06b6d408..8b748570596 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -287,7 +287,14 @@ static void versatile_init(MachineState *machine, int board_id)
     pl011_create(0x101f3000, pic[14], serial_hd(2));
     pl011_create(0x10009000, sic[6], serial_hd(3));
 
-    sysbus_create_simple("pl080", 0x10130000, pic[17]);
+    dev = qdev_create(NULL, "pl080");
+    object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream",
+                             &error_fatal);
+    qdev_init_nofail(dev);
+    busdev = SYS_BUS_DEVICE(dev);
+    sysbus_mmio_map(busdev, 0, 0x10130000);
+    sysbus_connect_irq(busdev, 0, pic[17]);
+
     sysbus_create_simple("sp804", 0x101e2000, pic[4]);
     sysbus_create_simple("sp804", 0x101e3000, pic[5]);
 
diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 301030dd118..8f9f3e08d9a 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -12,6 +12,7 @@
 #include "exec/address-spaces.h"
 #include "qemu/log.h"
 #include "hw/dma/pl080.h"
+#include "qapi/error.h"
 
 #define PL080_CONF_E    0x1
 #define PL080_CONF_M1   0x2
@@ -161,14 +162,16 @@ again:
             swidth = 1 << ((ch->ctrl >> 18) & 7);
             dwidth = 1 << ((ch->ctrl >> 21) & 7);
             for (n = 0; n < dwidth; n+= swidth) {
-                cpu_physical_memory_read(ch->src, buff + n, swidth);
+                address_space_read(&s->downstream_as, ch->src,
+                                   MEMTXATTRS_UNSPECIFIED, buff + n, swidth);
                 if (ch->ctrl & PL080_CCTRL_SI)
                     ch->src += swidth;
             }
             xsize = (dwidth < swidth) ? swidth : dwidth;
             /* ??? This may pad the value incorrectly for dwidth < 32.  */
             for (n = 0; n < xsize; n += dwidth) {
-                cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
+                address_space_write(&s->downstream_as, ch->dest + n,
+                                    MEMTXATTRS_UNSPECIFIED, buff + n, dwidth);
                 if (ch->ctrl & PL080_CCTRL_DI)
                     ch->dest += swidth;
             }
@@ -178,19 +181,19 @@ again:
             if (size == 0) {
                 /* Transfer complete.  */
                 if (ch->lli) {
-                    ch->src = address_space_ldl_le(&address_space_memory,
+                    ch->src = address_space_ldl_le(&s->downstream_as,
                                                    ch->lli,
                                                    MEMTXATTRS_UNSPECIFIED,
                                                    NULL);
-                    ch->dest = address_space_ldl_le(&address_space_memory,
+                    ch->dest = address_space_ldl_le(&s->downstream_as,
                                                     ch->lli + 4,
                                                     MEMTXATTRS_UNSPECIFIED,
                                                     NULL);
-                    ch->ctrl = address_space_ldl_le(&address_space_memory,
+                    ch->ctrl = address_space_ldl_le(&s->downstream_as,
                                                     ch->lli + 12,
                                                     MEMTXATTRS_UNSPECIFIED,
                                                     NULL);
-                    ch->lli = address_space_ldl_le(&address_space_memory,
+                    ch->lli = address_space_ldl_le(&s->downstream_as,
                                                    ch->lli + 8,
                                                    MEMTXATTRS_UNSPECIFIED,
                                                    NULL);
@@ -358,6 +361,18 @@ static void pl080_init(Object *obj)
     s->nchannels = 8;
 }
 
+static void pl080_realize(DeviceState *dev, Error **errp)
+{
+    PL080State *s = PL080(dev);
+
+    if (!s->downstream) {
+        error_setg(errp, "PL080 'downstream' link not set");
+        return;
+    }
+
+    address_space_init(&s->downstream_as, s->downstream, "pl080-downstream");
+}
+
 static void pl081_init(Object *obj)
 {
     PL080State *s = PL080(obj);
@@ -365,11 +380,19 @@ static void pl081_init(Object *obj)
     s->nchannels = 2;
 }
 
+static Property pl080_properties[] = {
+    DEFINE_PROP_LINK("downstream", PL080State, downstream,
+                     TYPE_MEMORY_REGION, MemoryRegion *),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
 static void pl080_class_init(ObjectClass *oc, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(oc);
 
     dc->vmsd = &vmstate_pl080;
+    dc->realize = pl080_realize;
+    dc->props = pl080_properties;
 }
 
 static const TypeInfo pl080_info = {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 13/16] hw/dma/pl080: Provide device reset function
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (11 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 12/16] hw/dma/pl080: Don't use CPU address space for DMA accesses Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-10  5:11   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic Peter Maydell
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The PL080/PL081 model is missing a reset function; implement it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/pl080.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 8f9f3e08d9a..a7aacad74f0 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -348,6 +348,30 @@ static const MemoryRegionOps pl080_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
+static void pl080_reset(DeviceState *dev)
+{
+    PL080State *s = PL080(dev);
+    int i;
+
+    s->tc_int = 0;
+    s->tc_mask = 0;
+    s->err_int = 0;
+    s->err_mask = 0;
+    s->conf = 0;
+    s->sync = 0;
+    s->req_single = 0;
+    s->req_burst = 0;
+    s->running = 0;
+
+    for (i = 0; i < s->nchannels; i++) {
+        s->chan[i].src = 0;
+        s->chan[i].dest = 0;
+        s->chan[i].lli = 0;
+        s->chan[i].ctrl = 0;
+        s->chan[i].conf = 0;
+    }
+}
+
 static void pl080_init(Object *obj)
 {
     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
@@ -393,6 +417,7 @@ static void pl080_class_init(ObjectClass *oc, void *data)
     dc->vmsd = &vmstate_pl080;
     dc->realize = pl080_realize;
     dc->props = pl080_properties;
+    dc->reset = pl080_reset;
 }
 
 static const TypeInfo pl080_info = {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (12 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 13/16] hw/dma/pl080: Provide device reset function Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-15 14:39   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 15/16] hw/dma/pl080: Remove hw_error() if DMA is enabled Peter Maydell
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

A bug in the handling of the register address decode logic
for the PL08x meant that we were incorrectly treating
accesses to the DMA channel registers (DMACCxSrcAddr,
DMACCxDestaddr, DMACCxLLI, DMACCxControl, DMACCxConfiguration)
as bad offsets. Fix this long-standing bug.

Fixes: https://bugs.launchpad.net/qemu/+bug/1637974
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
This has been around for a long time, identified by code
inspection several years ago in the LP bug. Now I have
some guest code that actually tries to use the PL08x I
can test the fix...
---
 hw/dma/pl080.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index a7aacad74f0..8f92550392b 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -229,7 +229,7 @@ static uint64_t pl080_read(void *opaque, hwaddr offset,
         i = (offset & 0xe0) >> 5;
         if (i >= s->nchannels)
             goto bad_offset;
-        switch (offset >> 2) {
+        switch ((offset >> 2) & 7) {
         case 0: /* SrcAddr */
             return s->chan[i].src;
         case 1: /* DestAddr */
@@ -290,7 +290,7 @@ static void pl080_write(void *opaque, hwaddr offset,
         i = (offset & 0xe0) >> 5;
         if (i >= s->nchannels)
             goto bad_offset;
-        switch (offset >> 2) {
+        switch ((offset >> 2) & 7) {
         case 0: /* SrcAddr */
             s->chan[i].src = value;
             break;
@@ -308,6 +308,7 @@ static void pl080_write(void *opaque, hwaddr offset,
             pl080_run(s);
             break;
         }
+        return;
     }
     switch (offset >> 2) {
     case 2: /* IntTCClear */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 15/16] hw/dma/pl080: Remove hw_error() if DMA is enabled
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (13 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-10  5:12   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs Peter Maydell
  2018-08-16 18:02 ` [Qemu-devel] [Qemu-arm] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The PL08x model currently will unconditionally call hw_error()
if the DMA engine is enabled by the guest. This has been
present since the PL080 model was edded in 2006, and is
presumably either unintentional debug code left enabled,
or a guard against untested DMA engine code being used.

Remove the hw_error(), since we now have a guest which
will actually try to use the DMA engine (the self-test
binary for the AN505 MPS2 FPGA image).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/dma/pl080.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
index 8f92550392b..ef15d3e628d 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -110,7 +110,6 @@ static void pl080_run(PL080State *s)
     if ((s->conf & PL080_CONF_E) == 0)
         return;
 
-hw_error("DMA active\n");
     /* If we are already in the middle of a DMA operation then indicate that
        there may be new DMA requests and return immediately.  */
     if (s->running) {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [Qemu-devel] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (14 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 15/16] hw/dma/pl080: Remove hw_error() if DMA is enabled Peter Maydell
@ 2018-08-09 13:01 ` Peter Maydell
  2018-08-18  1:09   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
  2018-08-16 18:02 ` [Qemu-devel] [Qemu-arm] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-09 13:01 UTC (permalink / raw)
  To: qemu-arm, qemu-devel; +Cc: patches

The AN505 FPGA image includes four PL081 DMA controllers, each
of which is gated by a Master Security Controller that allows
the guest to prevent a non-secure DMA controller from accessing
memory that is used by secure guest code. Create and wire
up these devices.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/mps2-tz.c | 101 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 94 insertions(+), 7 deletions(-)

diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
index 22180c56fb7..7d92bc5fe1c 100644
--- a/hw/arm/mps2-tz.c
+++ b/hw/arm/mps2-tz.c
@@ -45,7 +45,9 @@
 #include "hw/misc/mps2-scc.h"
 #include "hw/misc/mps2-fpgaio.h"
 #include "hw/misc/tz-mpc.h"
+#include "hw/misc/tz-msc.h"
 #include "hw/arm/iotkit.h"
+#include "hw/dma/pl080.h"
 #include "hw/devices.h"
 #include "net/net.h"
 #include "hw/core/split-irq.h"
@@ -75,8 +77,9 @@ typedef struct {
     UnimplementedDeviceState i2c[4];
     UnimplementedDeviceState i2s_audio;
     UnimplementedDeviceState gpio[4];
-    UnimplementedDeviceState dma[4];
     UnimplementedDeviceState gfx;
+    PL080State dma[4];
+    TZMSC msc[4];
     CMSDKAPBUART uart[5];
     SplitIRQ sec_resp_splitter;
     qemu_or_irq uart_irq_orgate;
@@ -273,6 +276,65 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
     return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
 }
 
+static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
+                              const char *name, hwaddr size)
+{
+    PL080State *dma = opaque;
+    int i = dma - &mms->dma[0];
+    SysBusDevice *s;
+    char *mscname = g_strdup_printf("%s-msc", name);
+    TZMSC *msc = &mms->msc[i];
+    DeviceState *iotkitdev = DEVICE(&mms->iotkit);
+    MemoryRegion *msc_upstream;
+    MemoryRegion *msc_downstream;
+
+    /*
+     * Each DMA device is a PL081 whose transaction master interface
+     * is guarded by a Master Security Controller. The downstream end of
+     * the MSC connects to the IoTKit AHB Slave Expansion port, so the
+     * DMA devices can see all devices and memory that the CPU does.
+     */
+    init_sysbus_child(OBJECT(mms), mscname, msc, sizeof(mms->msc[0]),
+                      TYPE_TZ_MSC);
+    msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0);
+    object_property_set_link(OBJECT(msc), OBJECT(msc_downstream),
+                             "downstream", &error_fatal);
+    object_property_set_link(OBJECT(msc), OBJECT(mms),
+                             "idau", &error_fatal);
+    object_property_set_bool(OBJECT(msc), true, "realized", &error_fatal);
+
+    qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0,
+                                qdev_get_gpio_in_named(iotkitdev,
+                                                       "mscexp_status", i));
+    qdev_connect_gpio_out_named(iotkitdev, "mscexp_clear", i,
+                                qdev_get_gpio_in_named(DEVICE(msc),
+                                                       "irq_clear", 0));
+    qdev_connect_gpio_out_named(iotkitdev, "mscexp_ns", i,
+                                qdev_get_gpio_in_named(DEVICE(msc),
+                                                       "cfg_nonsec", 0));
+    qdev_connect_gpio_out(DEVICE(&mms->sec_resp_splitter),
+                          ARRAY_SIZE(mms->ppc) + i,
+                          qdev_get_gpio_in_named(DEVICE(msc),
+                                                 "cfg_sec_resp", 0));
+    msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0);
+
+    init_sysbus_child(OBJECT(mms), name, dma, sizeof(mms->dma[0]), TYPE_PL081);
+    object_property_set_link(OBJECT(dma), OBJECT(msc_upstream),
+                             "downstream", &error_fatal);
+    object_property_set_bool(OBJECT(dma), true, "realized", &error_fatal);
+
+    s = SYS_BUS_DEVICE(dma);
+    /* Wire up DMACINTR, DMACINTERR, DMACINTTC */
+    sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev,
+                                                    "EXP_IRQ", 58 + i * 3));
+    sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev,
+                                                    "EXP_IRQ", 56 + i * 3));
+    sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev,
+                                                    "EXP_IRQ", 57 + i * 3));
+
+    return sysbus_mmio_get_region(s, 0);
+}
+
 static void mps2tz_common_init(MachineState *machine)
 {
     MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
@@ -299,13 +361,14 @@ static void mps2tz_common_init(MachineState *machine)
                              &error_fatal);
 
     /* The sec_resp_cfg output from the IoTKit must be split into multiple
-     * lines, one for each of the PPCs we create here.
+     * lines, one for each of the PPCs we create here, plus one per MSC.
      */
     object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
                       TYPE_SPLIT_IRQ);
     object_property_add_child(OBJECT(machine), "sec-resp-splitter",
                               OBJECT(&mms->sec_resp_splitter), &error_abort);
-    object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5,
+    object_property_set_int(OBJECT(&mms->sec_resp_splitter),
+                            ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
                             "num-lines", &error_fatal);
     object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
                              "realized", &error_fatal);
@@ -406,10 +469,10 @@ static void mps2tz_common_init(MachineState *machine)
         }, {
             .name = "ahb_ppcexp1",
             .ports = {
-                { "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 },
-                { "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 },
-                { "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 },
-                { "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 },
+                { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000 },
+                { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000 },
+                { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000 },
+                { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000 },
             },
         },
     };
@@ -490,12 +553,32 @@ static void mps2tz_common_init(MachineState *machine)
     armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
 }
 
+static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
+                               int *iregion, bool *exempt, bool *ns, bool *nsc)
+{
+    /*
+     * The MPS2 TZ FPGA images have IDAUs in them which are connected to
+     * the Master Security Controllers. Thes have the same logic as
+     * is used by the IoTKit for the IDAU connected to the CPU, except
+     * that MSCs don't care about the NSC attribute.
+     */
+    int region = extract32(address, 28, 4);
+
+    *ns = !(region & 1);
+    *nsc = false;
+    /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */
+    *exempt = (address & 0xeff00000) == 0xe0000000;
+    *iregion = region;
+}
+
 static void mps2tz_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
+    IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
 
     mc->init = mps2tz_common_init;
     mc->max_cpus = 1;
+    iic->check = mps2_tz_idau_check;
 }
 
 static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
@@ -516,6 +599,10 @@ static const TypeInfo mps2tz_info = {
     .instance_size = sizeof(MPS2TZMachineState),
     .class_size = sizeof(MPS2TZMachineClass),
     .class_init = mps2tz_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_IDAU_INTERFACE },
+        { }
+    },
 };
 
 static const TypeInfo mps2tz_an505_info = {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 02/16] nvic: Expose NMI line
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 02/16] nvic: Expose NMI line Peter Maydell
@ 2018-08-10  5:05   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-10  5:05 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> On real v7M hardware, the NMI line is an externally visible signal
> that an SoC or board can toggle to assert an NMI. Expose it in
> our QEMU NVIC and armv7m container objects so that a board model
> can wire it up if it needs to.
> 
> In particular, the MPS2 watchdog is wired to NMI.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>  hw/arm/armv7m.c       |  1 +
>  hw/intc/armv7m_nvic.c | 19 +++++++++++++++++++
>  hw/intc/trace-events  |  1 +
>  3 files changed, 21 insertions(+)
> 
> diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
> index 6b076660574..66217a6053a 100644
> --- a/hw/arm/armv7m.c
> +++ b/hw/arm/armv7m.c
> @@ -202,6 +202,7 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
>       */
>      qdev_pass_gpios(DEVICE(&s->nvic), dev, NULL);
>      qdev_pass_gpios(DEVICE(&s->nvic), dev, "SYSRESETREQ");
> +    qdev_pass_gpios(DEVICE(&s->nvic), dev, "NMI");
>  
>      /* Wire the NVIC up to the CPU */
>      sbd = SYS_BUS_DEVICE(&s->nvic);
> diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
> index cd1e7f17299..be7771e9d1f 100644
> --- a/hw/intc/armv7m_nvic.c
> +++ b/hw/intc/armv7m_nvic.c
> @@ -772,6 +772,24 @@ static void set_irq_level(void *opaque, int n, int level)
>      }
>  }
>  
> +/* callback when external NMI line is changed */
> +static void nvic_nmi_trigger(void *opaque, int n, int level)
> +{
> +    NVICState *s = opaque;
> +
> +    trace_nvic_set_nmi_level(level);
> +
> +    /*
> +     * The architecture doesn't specify whether NMI should share
> +     * the normal-interrupt behaviour of being resampled on
> +     * exception handler return. We choose not to, so just
> +     * set NMI pending here and don't track the current level.
> +     */
> +    if (level) {
> +        armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI, false);
> +    }
> +}
> +
>  static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
>  {
>      ARMCPU *cpu = s->cpu;
> @@ -2310,6 +2328,7 @@ static void armv7m_nvic_instance_init(Object *obj)
>      qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
>      qdev_init_gpio_in_named(dev, nvic_systick_trigger, "systick-trigger",
>                              M_REG_NUM_BANKS);
> +    qdev_init_gpio_in_named(dev, nvic_nmi_trigger, "NMI", 1);
>  }
>  
>  static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 5fb18e65c97..33e932fb918 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -184,6 +184,7 @@ nvic_acknowledge_irq(int irq, int prio) "NVIC acknowledge IRQ: %d now active (pr
>  nvic_get_pending_irq_info(int irq, bool secure) "NVIC next IRQ %d: targets_secure: %d"
>  nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)"
>  nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to %d"
> +nvic_set_nmi_level(int level) "NVIC external NMI level set to %d"
>  nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
>  nvic_sysreg_write(uint64_t addr, uint32_t value, unsigned size) "NVIC sysreg write addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u"
>  
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 12/16] hw/dma/pl080: Don't use CPU address space for DMA accesses
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 12/16] hw/dma/pl080: Don't use CPU address space for DMA accesses Peter Maydell
@ 2018-08-10  5:10   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-10  5:10 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> Currently our PL080/PL081 model uses a combination of the CPU's
> address space (via cpu_physical_memory_{read,write}()) and the
> system address space for performing DMA accesses.
> 
> For the PL081s in the MPS FPGA images, their DMA accesses
> must go via Master Security Controllers. Switch the
> PL080/PL081 model to take a MemoryRegion property which
> defines its downstream for making DMA accesses.
> 
> Since the PL08x are only used in two board models, we
> make provision of the 'downstream' link mandatory and convert
> both users at once, rather than having it be optional with
> a default to the system address space.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/dma/pl080.h |  5 +++++
>  hw/arm/realview.c      |  8 +++++++-
>  hw/arm/versatilepb.c   |  9 ++++++++-
>  hw/dma/pl080.c         | 35 +++++++++++++++++++++++++++++------
>  4 files changed, 49 insertions(+), 8 deletions(-)
> 
> diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h
> index 7c6a4184833..9d4b3df143f 100644
> --- a/include/hw/dma/pl080.h
> +++ b/include/hw/dma/pl080.h
> @@ -21,6 +21,8 @@
>   * + sysbus IRQ 1: DMACINTERR error interrupt request
>   * + sysbus IRQ 2: DMACINTTC count interrupt request
>   * + sysbus MMIO region 0: MemoryRegion for the device's registers
> + * + QOM property "downstream": MemoryRegion defining where DMA
> + *   bus master transactions are made
>   */
>  
>  #ifndef HW_DMA_PL080_H
> @@ -61,6 +63,9 @@ typedef struct PL080State {
>      qemu_irq irq;
>      qemu_irq interr;
>      qemu_irq inttc;
> +
> +    MemoryRegion *downstream;
> +    AddressSpace downstream_as;
>  } PL080State;
>  
>  #endif
> diff --git a/hw/arm/realview.c b/hw/arm/realview.c
> index cd585d94694..ab8c14fde38 100644
> --- a/hw/arm/realview.c
> +++ b/hw/arm/realview.c
> @@ -201,7 +201,13 @@ static void realview_init(MachineState *machine,
>      pl011_create(0x1000c000, pic[15], serial_hd(3));
>  
>      /* DMA controller is optional, apparently.  */
> -    sysbus_create_simple("pl081", 0x10030000, pic[24]);
> +    dev = qdev_create(NULL, "pl081");
> +    object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream",
> +                             &error_fatal);

Nice!

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> +    qdev_init_nofail(dev);
> +    busdev = SYS_BUS_DEVICE(dev);
> +    sysbus_mmio_map(busdev, 0, 0x10030000);
> +    sysbus_connect_irq(busdev, 0, pic[24]);
>  
>      sysbus_create_simple("sp804", 0x10011000, pic[4]);
>      sysbus_create_simple("sp804", 0x10012000, pic[5]);
> diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
> index a5a06b6d408..8b748570596 100644
> --- a/hw/arm/versatilepb.c
> +++ b/hw/arm/versatilepb.c
> @@ -287,7 +287,14 @@ static void versatile_init(MachineState *machine, int board_id)
>      pl011_create(0x101f3000, pic[14], serial_hd(2));
>      pl011_create(0x10009000, sic[6], serial_hd(3));
>  
> -    sysbus_create_simple("pl080", 0x10130000, pic[17]);
> +    dev = qdev_create(NULL, "pl080");
> +    object_property_set_link(OBJECT(dev), OBJECT(sysmem), "downstream",
> +                             &error_fatal);
> +    qdev_init_nofail(dev);
> +    busdev = SYS_BUS_DEVICE(dev);
> +    sysbus_mmio_map(busdev, 0, 0x10130000);
> +    sysbus_connect_irq(busdev, 0, pic[17]);
> +
>      sysbus_create_simple("sp804", 0x101e2000, pic[4]);
>      sysbus_create_simple("sp804", 0x101e3000, pic[5]);
>  
> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
> index 301030dd118..8f9f3e08d9a 100644
> --- a/hw/dma/pl080.c
> +++ b/hw/dma/pl080.c
> @@ -12,6 +12,7 @@
>  #include "exec/address-spaces.h"
>  #include "qemu/log.h"
>  #include "hw/dma/pl080.h"
> +#include "qapi/error.h"
>  
>  #define PL080_CONF_E    0x1
>  #define PL080_CONF_M1   0x2
> @@ -161,14 +162,16 @@ again:
>              swidth = 1 << ((ch->ctrl >> 18) & 7);
>              dwidth = 1 << ((ch->ctrl >> 21) & 7);
>              for (n = 0; n < dwidth; n+= swidth) {
> -                cpu_physical_memory_read(ch->src, buff + n, swidth);
> +                address_space_read(&s->downstream_as, ch->src,
> +                                   MEMTXATTRS_UNSPECIFIED, buff + n, swidth);
>                  if (ch->ctrl & PL080_CCTRL_SI)
>                      ch->src += swidth;
>              }
>              xsize = (dwidth < swidth) ? swidth : dwidth;
>              /* ??? This may pad the value incorrectly for dwidth < 32.  */
>              for (n = 0; n < xsize; n += dwidth) {
> -                cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
> +                address_space_write(&s->downstream_as, ch->dest + n,
> +                                    MEMTXATTRS_UNSPECIFIED, buff + n, dwidth);
>                  if (ch->ctrl & PL080_CCTRL_DI)
>                      ch->dest += swidth;
>              }
> @@ -178,19 +181,19 @@ again:
>              if (size == 0) {
>                  /* Transfer complete.  */
>                  if (ch->lli) {
> -                    ch->src = address_space_ldl_le(&address_space_memory,
> +                    ch->src = address_space_ldl_le(&s->downstream_as,
>                                                     ch->lli,
>                                                     MEMTXATTRS_UNSPECIFIED,
>                                                     NULL);
> -                    ch->dest = address_space_ldl_le(&address_space_memory,
> +                    ch->dest = address_space_ldl_le(&s->downstream_as,
>                                                      ch->lli + 4,
>                                                      MEMTXATTRS_UNSPECIFIED,
>                                                      NULL);
> -                    ch->ctrl = address_space_ldl_le(&address_space_memory,
> +                    ch->ctrl = address_space_ldl_le(&s->downstream_as,
>                                                      ch->lli + 12,
>                                                      MEMTXATTRS_UNSPECIFIED,
>                                                      NULL);
> -                    ch->lli = address_space_ldl_le(&address_space_memory,
> +                    ch->lli = address_space_ldl_le(&s->downstream_as,
>                                                     ch->lli + 8,
>                                                     MEMTXATTRS_UNSPECIFIED,
>                                                     NULL);
> @@ -358,6 +361,18 @@ static void pl080_init(Object *obj)
>      s->nchannels = 8;
>  }
>  
> +static void pl080_realize(DeviceState *dev, Error **errp)
> +{
> +    PL080State *s = PL080(dev);
> +
> +    if (!s->downstream) {
> +        error_setg(errp, "PL080 'downstream' link not set");
> +        return;
> +    }
> +
> +    address_space_init(&s->downstream_as, s->downstream, "pl080-downstream");
> +}
> +
>  static void pl081_init(Object *obj)
>  {
>      PL080State *s = PL080(obj);
> @@ -365,11 +380,19 @@ static void pl081_init(Object *obj)
>      s->nchannels = 2;
>  }
>  
> +static Property pl080_properties[] = {
> +    DEFINE_PROP_LINK("downstream", PL080State, downstream,
> +                     TYPE_MEMORY_REGION, MemoryRegion *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
>  static void pl080_class_init(ObjectClass *oc, void *data)
>  {
>      DeviceClass *dc = DEVICE_CLASS(oc);
>  
>      dc->vmsd = &vmstate_pl080;
> +    dc->realize = pl080_realize;
> +    dc->props = pl080_properties;
>  }
>  
>  static const TypeInfo pl080_info = {
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 13/16] hw/dma/pl080: Provide device reset function
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 13/16] hw/dma/pl080: Provide device reset function Peter Maydell
@ 2018-08-10  5:11   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-10  5:11 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The PL080/PL081 model is missing a reset function; implement it.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>  hw/dma/pl080.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
> index 8f9f3e08d9a..a7aacad74f0 100644
> --- a/hw/dma/pl080.c
> +++ b/hw/dma/pl080.c
> @@ -348,6 +348,30 @@ static const MemoryRegionOps pl080_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>  
> +static void pl080_reset(DeviceState *dev)
> +{
> +    PL080State *s = PL080(dev);
> +    int i;
> +
> +    s->tc_int = 0;
> +    s->tc_mask = 0;
> +    s->err_int = 0;
> +    s->err_mask = 0;
> +    s->conf = 0;
> +    s->sync = 0;
> +    s->req_single = 0;
> +    s->req_burst = 0;
> +    s->running = 0;
> +
> +    for (i = 0; i < s->nchannels; i++) {
> +        s->chan[i].src = 0;
> +        s->chan[i].dest = 0;
> +        s->chan[i].lli = 0;
> +        s->chan[i].ctrl = 0;
> +        s->chan[i].conf = 0;
> +    }
> +}
> +
>  static void pl080_init(Object *obj)
>  {
>      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> @@ -393,6 +417,7 @@ static void pl080_class_init(ObjectClass *oc, void *data)
>      dc->vmsd = &vmstate_pl080;
>      dc->realize = pl080_realize;
>      dc->props = pl080_properties;
> +    dc->reset = pl080_reset;
>  }
>  
>  static const TypeInfo pl080_info = {
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 15/16] hw/dma/pl080: Remove hw_error() if DMA is enabled
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 15/16] hw/dma/pl080: Remove hw_error() if DMA is enabled Peter Maydell
@ 2018-08-10  5:12   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-10  5:12 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The PL08x model currently will unconditionally call hw_error()
> if the DMA engine is enabled by the guest. This has been
> present since the PL080 model was edded in 2006, and is
> presumably either unintentional debug code left enabled,
> or a guard against untested DMA engine code being used.
> 
> Remove the hw_error(), since we now have a guest which
> will actually try to use the DMA engine (the self-test
> binary for the AN505 MPS2 FPGA image).
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>  hw/dma/pl080.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
> index 8f92550392b..ef15d3e628d 100644
> --- a/hw/dma/pl080.c
> +++ b/hw/dma/pl080.c
> @@ -110,7 +110,6 @@ static void pl080_run(PL080State *s)
>      if ((s->conf & PL080_CONF_E) == 0)
>          return;
>  
> -hw_error("DMA active\n");
>      /* If we are already in the middle of a DMA operation then indicate that
>         there may be new DMA requests and return immediately.  */
>      if (s->running) {
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device Peter Maydell
@ 2018-08-10  5:18   ` Philippe Mathieu-Daudé
  2018-08-10  5:27     ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-10  5:18 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> Create a new include file for the pl081's device struct,
> type macros, etc, so that it can be instantiated using
> the "embedded struct" coding style.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/dma/pl080.h | 62 ++++++++++++++++++++++++++++++++++++++++++
>  hw/dma/pl080.c         | 34 ++---------------------
>  MAINTAINERS            |  1 +
>  3 files changed, 65 insertions(+), 32 deletions(-)
>  create mode 100644 include/hw/dma/pl080.h
> 
> diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h
> new file mode 100644
> index 00000000000..7deb46c8578
> --- /dev/null
> +++ b/include/hw/dma/pl080.h
> @@ -0,0 +1,62 @@
> +/*
> + * ARM PrimeCell PL080/PL081 DMA controller
> + *
> + * Copyright (c) 2006 CodeSourcery.
> + * Copyright (c) 2018 Linaro Limited
> + * Written by Paul Brook, 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 Arm PrimeCell PL080/PL081 DMA controller:
> + * The PL080 TRM is:
> + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0196g/DDI0196.pdf
> + * and the PL081 TRM is:
> + * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0218e/DDI0218.pdf
> + *
> + * QEMU interface:
> + * + sysbus IRQ: DMACINTR combined interrupt line
> + * + sysbus MMIO region 0: MemoryRegion for the device's registers
> + */
> +
> +#ifndef HW_DMA_PL080_H
> +#define HW_DMA_PL080_H
> +
> +#include "hw/sysbus.h"
> +
> +#define PL080_MAX_CHANNELS 8
> +
> +typedef struct {
> +    uint32_t src;
> +    uint32_t dest;
> +    uint32_t lli;
> +    uint32_t ctrl;
> +    uint32_t conf;
> +} pl080_channel;
> +
> +#define TYPE_PL080 "pl080"
> +#define TYPE_PL081 "pl081"
> +#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)

The PL080() macro can stay in the source.

Regardless:
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> +
> +typedef struct PL080State {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion iomem;
> +    uint8_t tc_int;
> +    uint8_t tc_mask;
> +    uint8_t err_int;
> +    uint8_t err_mask;
> +    uint32_t conf;
> +    uint32_t sync;
> +    uint32_t req_single;
> +    uint32_t req_burst;
> +    pl080_channel chan[PL080_MAX_CHANNELS];
> +    int nchannels;
> +    /* Flag to avoid recursive DMA invocations.  */
> +    int running;
> +    qemu_irq irq;
> +} PL080State;
> +
> +#endif
> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
> index 7724c93b8f2..0f79c2d8a6c 100644
> --- a/hw/dma/pl080.c
> +++ b/hw/dma/pl080.c
> @@ -11,8 +11,8 @@
>  #include "hw/sysbus.h"
>  #include "exec/address-spaces.h"
>  #include "qemu/log.h"
> +#include "hw/dma/pl080.h"
>  
> -#define PL080_MAX_CHANNELS 8
>  #define PL080_CONF_E    0x1
>  #define PL080_CONF_M1   0x2
>  #define PL080_CONF_M2   0x4
> @@ -30,36 +30,6 @@
>  #define PL080_CCTRL_D   0x02000000
>  #define PL080_CCTRL_S   0x01000000
>  
> -typedef struct {
> -    uint32_t src;
> -    uint32_t dest;
> -    uint32_t lli;
> -    uint32_t ctrl;
> -    uint32_t conf;
> -} pl080_channel;
> -
> -#define TYPE_PL080 "pl080"
> -#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
> -
> -typedef struct PL080State {
> -    SysBusDevice parent_obj;
> -
> -    MemoryRegion iomem;
> -    uint8_t tc_int;
> -    uint8_t tc_mask;
> -    uint8_t err_int;
> -    uint8_t err_mask;
> -    uint32_t conf;
> -    uint32_t sync;
> -    uint32_t req_single;
> -    uint32_t req_burst;
> -    pl080_channel chan[PL080_MAX_CHANNELS];
> -    int nchannels;
> -    /* Flag to avoid recursive DMA invocations.  */
> -    int running;
> -    qemu_irq irq;
> -} PL080State;
> -
>  static const VMStateDescription vmstate_pl080_channel = {
>      .name = "pl080_channel",
>      .version_id = 1,
> @@ -408,7 +378,7 @@ static const TypeInfo pl080_info = {
>  };
>  
>  static const TypeInfo pl081_info = {
> -    .name          = "pl081",
> +    .name          = TYPE_PL081,
>      .parent        = TYPE_PL080,
>      .instance_init = pl081_init,
>  };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5d1a3645dd4..92ccca716c6 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -444,6 +444,7 @@ F: hw/char/pl011.c
>  F: include/hw/char/pl011.h
>  F: hw/display/pl110*
>  F: hw/dma/pl080.c
> +F: include/hw/dma/pl080.h
>  F: hw/dma/pl330.c
>  F: hw/gpio/pl061.c
>  F: hw/input/pl050.c
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device
  2018-08-10  5:18   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
@ 2018-08-10  5:27     ` Philippe Mathieu-Daudé
  2018-08-10  9:03       ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-10  5:27 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/10/2018 02:18 AM, Philippe Mathieu-Daudé wrote:
> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>> Create a new include file for the pl081's device struct,
>> type macros, etc, so that it can be instantiated using
>> the "embedded struct" coding style.
[...]
>> +#ifndef HW_DMA_PL080_H
>> +#define HW_DMA_PL080_H
>> +
>> +#include "hw/sysbus.h"
>> +
>> +#define PL080_MAX_CHANNELS 8
>> +
>> +typedef struct {
>> +    uint32_t src;
>> +    uint32_t dest;
>> +    uint32_t lli;
>> +    uint32_t ctrl;
>> +    uint32_t conf;
>> +} pl080_channel;
>> +
>> +#define TYPE_PL080 "pl080"
>> +#define TYPE_PL081 "pl081"
>> +#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
> 
> The PL080() macro can stay in the source.

Oh this respect the "coding style" indeed.
Can you add the PL081() companion? Thanks.

> 
> Regardless:
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> 
>> +
>> +typedef struct PL080State {
>> +    SysBusDevice parent_obj;
>> +
>> +    MemoryRegion iomem;
>> +    uint8_t tc_int;
>> +    uint8_t tc_mask;
>> +    uint8_t err_int;
>> +    uint8_t err_mask;
>> +    uint32_t conf;
>> +    uint32_t sync;
>> +    uint32_t req_single;
>> +    uint32_t req_burst;
>> +    pl080_channel chan[PL080_MAX_CHANNELS];
>> +    int nchannels;
>> +    /* Flag to avoid recursive DMA invocations.  */
>> +    int running;
>> +    qemu_irq irq;
>> +} PL080State;
>> +
>> +#endif
>> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
>> index 7724c93b8f2..0f79c2d8a6c 100644
>> --- a/hw/dma/pl080.c
>> +++ b/hw/dma/pl080.c
>> @@ -11,8 +11,8 @@
>>  #include "hw/sysbus.h"
>>  #include "exec/address-spaces.h"
>>  #include "qemu/log.h"
>> +#include "hw/dma/pl080.h"
>>  
>> -#define PL080_MAX_CHANNELS 8
>>  #define PL080_CONF_E    0x1
>>  #define PL080_CONF_M1   0x2
>>  #define PL080_CONF_M2   0x4
>> @@ -30,36 +30,6 @@
>>  #define PL080_CCTRL_D   0x02000000
>>  #define PL080_CCTRL_S   0x01000000
>>  
>> -typedef struct {
>> -    uint32_t src;
>> -    uint32_t dest;
>> -    uint32_t lli;
>> -    uint32_t ctrl;
>> -    uint32_t conf;
>> -} pl080_channel;
>> -
>> -#define TYPE_PL080 "pl080"
>> -#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
>> -
>> -typedef struct PL080State {
>> -    SysBusDevice parent_obj;
>> -
>> -    MemoryRegion iomem;
>> -    uint8_t tc_int;
>> -    uint8_t tc_mask;
>> -    uint8_t err_int;
>> -    uint8_t err_mask;
>> -    uint32_t conf;
>> -    uint32_t sync;
>> -    uint32_t req_single;
>> -    uint32_t req_burst;
>> -    pl080_channel chan[PL080_MAX_CHANNELS];
>> -    int nchannels;
>> -    /* Flag to avoid recursive DMA invocations.  */
>> -    int running;
>> -    qemu_irq irq;
>> -} PL080State;
>> -
>>  static const VMStateDescription vmstate_pl080_channel = {
>>      .name = "pl080_channel",
>>      .version_id = 1,
>> @@ -408,7 +378,7 @@ static const TypeInfo pl080_info = {
>>  };
>>  
>>  static const TypeInfo pl081_info = {
>> -    .name          = "pl081",
>> +    .name          = TYPE_PL081,
>>      .parent        = TYPE_PL080,
>>      .instance_init = pl081_init,
>>  };
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 5d1a3645dd4..92ccca716c6 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -444,6 +444,7 @@ F: hw/char/pl011.c
>>  F: include/hw/char/pl011.h
>>  F: hw/display/pl110*
>>  F: hw/dma/pl080.c
>> +F: include/hw/dma/pl080.h
>>  F: hw/dma/pl330.c
>>  F: hw/gpio/pl061.c
>>  F: hw/input/pl050.c
>>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device
  2018-08-10  5:27     ` Philippe Mathieu-Daudé
@ 2018-08-10  9:03       ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2018-08-10  9:03 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: qemu-arm, QEMU Developers, patches

On 10 August 2018 at 06:27, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> On 08/10/2018 02:18 AM, Philippe Mathieu-Daudé wrote:
>> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>>> Create a new include file for the pl081's device struct,
>>> type macros, etc, so that it can be instantiated using
>>> the "embedded struct" coding style.
> [...]
>>> +#ifndef HW_DMA_PL080_H
>>> +#define HW_DMA_PL080_H
>>> +
>>> +#include "hw/sysbus.h"
>>> +
>>> +#define PL080_MAX_CHANNELS 8
>>> +
>>> +typedef struct {
>>> +    uint32_t src;
>>> +    uint32_t dest;
>>> +    uint32_t lli;
>>> +    uint32_t ctrl;
>>> +    uint32_t conf;
>>> +} pl080_channel;
>>> +
>>> +#define TYPE_PL080 "pl080"
>>> +#define TYPE_PL081 "pl081"
>>> +#define PL080(obj) OBJECT_CHECK(PL080State, (obj), TYPE_PL080)
>>
>> The PL080() macro can stay in the source.
>
> Oh this respect the "coding style" indeed.

Yes.

> Can you add the PL081() companion? Thanks.

No, because the PL081 has no separate data structure
and there is no PL081State* for a PL081() macro to
be casting to.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic Peter Maydell
@ 2018-08-15 14:39   ` Philippe Mathieu-Daudé
  2018-08-15 15:31     ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-15 14:39 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> A bug in the handling of the register address decode logic
> for the PL08x meant that we were incorrectly treating
> accesses to the DMA channel registers (DMACCxSrcAddr,
> DMACCxDestaddr, DMACCxLLI, DMACCxControl, DMACCxConfiguration)
> as bad offsets. Fix this long-standing bug.

Since this file's origin (cdbdb648b7c).

> 
> Fixes: https://bugs.launchpad.net/qemu/+bug/1637974
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> This has been around for a long time, identified by code
> inspection several years ago in the LP bug. Now I have
> some guest code that actually tries to use the PL08x I
> can test the fix...
> ---
>  hw/dma/pl080.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
> index a7aacad74f0..8f92550392b 100644
> --- a/hw/dma/pl080.c
> +++ b/hw/dma/pl080.c
> @@ -229,7 +229,7 @@ static uint64_t pl080_read(void *opaque, hwaddr offset,
>          i = (offset & 0xe0) >> 5;
>          if (i >= s->nchannels)
>              goto bad_offset;
> -        switch (offset >> 2) {
> +        switch ((offset >> 2) & 7) {

So only the first channel ever worked...

>          case 0: /* SrcAddr */
>              return s->chan[i].src;
>          case 1: /* DestAddr */
> @@ -290,7 +290,7 @@ static void pl080_write(void *opaque, hwaddr offset,
>          i = (offset & 0xe0) >> 5;
>          if (i >= s->nchannels)
>              goto bad_offset;
> -        switch (offset >> 2) {
> +        switch ((offset >> 2) & 7) {
>          case 0: /* SrcAddr */
>              s->chan[i].src = value;
>              break;
> @@ -308,6 +308,7 @@ static void pl080_write(void *opaque, hwaddr offset,
>              pl080_run(s);
>              break;
>          }
> +        return;
>      }
>      switch (offset >> 2) {

Eventually copy/pasted from here.

>      case 2: /* IntTCClear */
> 

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic
  2018-08-15 14:39   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
@ 2018-08-15 15:31     ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2018-08-15 15:31 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: qemu-arm, QEMU Developers, patches

On 15 August 2018 at 15:39, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
>> index a7aacad74f0..8f92550392b 100644
>> --- a/hw/dma/pl080.c
>> +++ b/hw/dma/pl080.c
>> @@ -229,7 +229,7 @@ static uint64_t pl080_read(void *opaque, hwaddr offset,
>>          i = (offset & 0xe0) >> 5;
>>          if (i >= s->nchannels)
>>              goto bad_offset;
>> -        switch (offset >> 2) {
>> +        switch ((offset >> 2) & 7) {
>
> So only the first channel ever worked...

Not even that -- the per-channel registers are in the
0x100..0x200 region, so channel 0's registers start at 0x100.


> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>


thanks
-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA
  2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
                   ` (15 preceding siblings ...)
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs Peter Maydell
@ 2018-08-16 18:02 ` Peter Maydell
  2018-08-18  1:29   ` Philippe Mathieu-Daudé
  16 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-16 18:02 UTC (permalink / raw)
  To: qemu-arm, QEMU Developers; +Cc: patches

Ping for code review, please?

(It's only been a week so this is a little bit eager, but
I have some more MPS patches which wire up the PL022 SPI
controllers, which I'm holding off on posting until this
and the preceding FPGAIO set get reviewed and committed, so
as not to have too many MPS patches in flight at once.)

thanks
-- PMM

On 9 August 2018 at 14:00, Peter Maydell <peter.maydell@linaro.org> wrote:
> This patchset adds some more missing devices to the MPS2 AN505
> board model:
>
> Patches 1-3 implement and wire up the CMSDK APB watchdog devices.
>
> Patch 4 adds a CMSDK timer device that had been forgotten.
>
> Ppatches 5-6 implement and wire up the "system control element",
> which is some simple control/ID registers in the IoTKit
>
> Patches 7-16 are the meat of the patchset, and add support
> for the DMA controllers and their associated Master Security
> Controllers. A TrustZone MSC sits in front of a device which
> can be a bus master (such as a DMA controller) and allows secure
> software to configure it to either pass through or reject transactions
> made by that bus master. 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 AN505 has four
> PL081 DMA controllers, each with its own MSC.
>
> Patches 10-15 are various minor cleanups and bugfixes in
> the PL081 model that are needed for its use in the AN505.
> In particular the PL081 was previously entirely broken as
> it would hw_error() as soon as the guest enabled the DMA
> engine. I assume this was either accidentally left-in debug code,
> or a deliberate choice to guard a never-tested implementation
> so as to be able to identify when we had guest code to test it
> with. (Linux for the realview/versatile boards never tries to
> use the PL08x there for DMA.)
>
> This patchset is sufficient for the "DMA" test in the AN505
> self-test binary to pass. (I suspect it is not giving the
> PL081 or MSC a very thorough workout, though.)
>
> Based-on: <20180730162458.23186-1-peter.maydell@linaro.org>
> ("[PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer")
>
> thanks
> -- PMM
>
> Peter Maydell (16):
>   hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module
>   nvic: Expose NMI line
>   hw/arm/iotkit: Wire up the watchdogs
>   hw/arm/iotkit: Wire up the S32KTIMER
>   hw/misc/iotkit-sysctl: Implement IoTKit system control element
>   hw/misc/iotkit: Wire up the system control element
>   hw/misc/tz-msc: Model TrustZone Master Security Controller
>   hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
>   hw/arm/iotkit: Wire up the lines for MSCs
>   hw/dma/pl080: Allow use as embedded-struct device
>   hw/dma/pl080: Support all three interrupt lines
>   hw/dma/pl080: Don't use CPU address space for DMA accesses
>   hw/dma/pl080: Provide device reset function
>   hw/dma/pl080: Correct bug in register address decode logic
>   hw/dma/pl080: Remove hw_error() if DMA is enabled
>   hw/arm/mps2-tz: Create PL081s and MSCs
>
>  Makefile.objs                            |   1 +
>  hw/misc/Makefile.objs                    |   2 +
>  hw/watchdog/Makefile.objs                |   1 +
>  include/hw/arm/iotkit.h                  |  20 +-
>  include/hw/dma/pl080.h                   |  71 +++++
>  include/hw/misc/iotkit-secctl.h          |  14 +
>  include/hw/misc/iotkit-sysctl.h          |  50 ++++
>  include/hw/misc/tz-msc.h                 |  79 ++++++
>  include/hw/watchdog/cmsdk-apb-watchdog.h |  59 ++++
>  hw/arm/armv7m.c                          |   1 +
>  hw/arm/iotkit.c                          |  99 ++++++-
>  hw/arm/mps2-tz.c                         | 101 ++++++-
>  hw/arm/realview.c                        |   8 +-
>  hw/arm/versatilepb.c                     |   9 +-
>  hw/dma/pl080.c                           | 113 ++++----
>  hw/intc/armv7m_nvic.c                    |  19 ++
>  hw/misc/iotkit-secctl.c                  |  73 ++++-
>  hw/misc/iotkit-sysctl.c                  | 324 ++++++++++++++++++++++
>  hw/misc/tz-msc.c                         | 308 +++++++++++++++++++++
>  hw/watchdog/cmsdk-apb-watchdog.c         | 326 +++++++++++++++++++++++
>  MAINTAINERS                              |   7 +
>  default-configs/arm-softmmu.mak          |   3 +
>  hw/intc/trace-events                     |   1 +
>  hw/misc/trace-events                     |  16 ++
>  hw/watchdog/trace-events                 |   6 +
>  25 files changed, 1632 insertions(+), 79 deletions(-)
>  create mode 100644 include/hw/dma/pl080.h
>  create mode 100644 include/hw/misc/iotkit-sysctl.h
>  create mode 100644 include/hw/misc/tz-msc.h
>  create mode 100644 include/hw/watchdog/cmsdk-apb-watchdog.h
>  create mode 100644 hw/misc/iotkit-sysctl.c
>  create mode 100644 hw/misc/tz-msc.c
>  create mode 100644 hw/watchdog/cmsdk-apb-watchdog.c
>  create mode 100644 hw/watchdog/trace-events
>
> --
> 2.17.1

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 03/16] hw/arm/iotkit: Wire up the watchdogs
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 03/16] hw/arm/iotkit: Wire up the watchdogs Peter Maydell
@ 2018-08-17 23:47   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-17 23:47 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

Hi Peter,

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The IoTKit includes three different instances of the
> CMSDK APB watchdog; create and wire them up.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/arm/iotkit.h |  6 +++++
>  hw/arm/iotkit.c         | 58 ++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 61 insertions(+), 3 deletions(-)
> 
> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
> index 3e6d806e352..776d0497087 100644
> --- a/include/hw/arm/iotkit.h
> +++ b/include/hw/arm/iotkit.h
> @@ -57,6 +57,7 @@
>  #include "hw/misc/tz-mpc.h"
>  #include "hw/timer/cmsdk-apb-timer.h"
>  #include "hw/timer/cmsdk-apb-dualtimer.h"
> +#include "hw/watchdog/cmsdk-apb-watchdog.h"
>  #include "hw/misc/unimp.h"
>  #include "hw/or-irq.h"
>  #include "hw/core/split-irq.h"
> @@ -87,10 +88,15 @@ typedef struct IoTKit {
>      SplitIRQ ppc_irq_splitter[NUM_PPCS];
>      SplitIRQ mpc_irq_splitter[IOTS_NUM_EXP_MPC + IOTS_NUM_MPC];
>      qemu_or_irq mpc_irq_orgate;
> +    qemu_or_irq nmi_orgate;
>  
>      CMSDKAPBDualTimer dualtimer;
>      UnimplementedDeviceState s32ktimer;
>  
> +    CMSDKAPBWatchdog s32kwatchdog;
> +    CMSDKAPBWatchdog nswatchdog;
> +    CMSDKAPBWatchdog swatchdog;
> +
>      MemoryRegion container;
>      MemoryRegion alias1;
>      MemoryRegion alias2;
> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
> index 130d013909e..5cedfa03570 100644
> --- a/hw/arm/iotkit.c
> +++ b/hw/arm/iotkit.c
> @@ -19,6 +19,9 @@
>  #include "hw/misc/unimp.h"
>  #include "hw/arm/arm.h"
>  
> +/* Clock frequency in HZ of the 32KHz "slow clock" */
> +#define S32KCLK (32 * 1000)
> +
>  /* Create an alias region of @size bytes starting at @base
>   * which mirrors the memory starting at @orig.
>   */
> @@ -140,6 +143,15 @@ static void iotkit_init(Object *obj)
>                            TYPE_CMSDK_APB_TIMER);
>      sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
>                            TYPE_CMSDK_APB_DUALTIMER);
> +    sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
> +                          sizeof(s->s32kwatchdog), TYPE_CMSDK_APB_WATCHDOG);
> +    sysbus_init_child_obj(obj, "nswatchdog", &s->nswatchdog,
> +                          sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
> +    sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
> +                          sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
> +    object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
> +                            sizeof(s->nmi_orgate), TYPE_OR_IRQ,
> +                            &error_abort, NULL);
>      object_initialize_child(obj, "ppc-irq-orgate", &s->ppc_irq_orgate,
>                              sizeof(s->ppc_irq_orgate), TYPE_OR_IRQ,
>                              &error_abort, NULL);
> @@ -510,12 +522,52 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>      create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
>  
>      create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
> -    create_unimplemented_device("S32KWATCHDOG", 0x5002e000, 0x1000);
> +
> +    /* This OR gate wires together outputs from the secure watchdogs to NMI */
> +    object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    object_property_set_bool(OBJECT(&s->nmi_orgate), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
> +                          qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
> +
> +    qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
> +    object_property_set_bool(OBJECT(&s->s32kwatchdog), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32kwatchdog), 0,
> +                       qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 0));
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->s32kwatchdog), 0, 0x5002e000);
>  
>      /* 0x40080000 .. 0x4008ffff : IoTKit second Base peripheral region */
>  
> -    create_unimplemented_device("NS watchdog", 0x40081000, 0x1000);
> -    create_unimplemented_device("S watchdog", 0x50081000, 0x1000);
> +    qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
> +    object_property_set_bool(OBJECT(&s->nswatchdog), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->nswatchdog), 0,
> +                       qdev_get_gpio_in(DEVICE(&s->armv7m), 1));

So a NS watchdog expiration will triggers
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET). This is fine for
now, we can eventually implement the proper behavior of IRQ#0 later
(flag the NSWD of the RESET_SYNDROME register and continue execution
from cpu reset if NSWD enabled in RESET_MASK, without shutting QEMU down).

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
> +
> +    qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
> +    object_property_set_bool(OBJECT(&s->swatchdog), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->swatchdog), 0,
> +                       qdev_get_gpio_in(DEVICE(&s->nmi_orgate), 1));
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->swatchdog), 0, 0x50081000);
>  
>      for (i = 0; i < ARRAY_SIZE(s->ppc_irq_splitter); i++) {
>          Object *splitter = OBJECT(&s->ppc_irq_splitter[i]);
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 04/16] hw/arm/iotkit: Wire up the S32KTIMER
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 04/16] hw/arm/iotkit: Wire up the S32KTIMER Peter Maydell
@ 2018-08-17 23:49   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-17 23:49 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The IoTKit has a CMSDK timer device that runs on the S32KCLK.
> Create this and wire it up.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>  include/hw/arm/iotkit.h | 2 +-
>  hw/arm/iotkit.c         | 9 +++++----
>  2 files changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
> index 776d0497087..0f5c5101708 100644
> --- a/include/hw/arm/iotkit.h
> +++ b/include/hw/arm/iotkit.h
> @@ -83,6 +83,7 @@ typedef struct IoTKit {
>      TZMPC mpc;
>      CMSDKAPBTIMER timer0;
>      CMSDKAPBTIMER timer1;
> +    CMSDKAPBTIMER s32ktimer;
>      qemu_or_irq ppc_irq_orgate;
>      SplitIRQ sec_resp_splitter;
>      SplitIRQ ppc_irq_splitter[NUM_PPCS];
> @@ -91,7 +92,6 @@ typedef struct IoTKit {
>      qemu_or_irq nmi_orgate;
>  
>      CMSDKAPBDualTimer dualtimer;
> -    UnimplementedDeviceState s32ktimer;
>  
>      CMSDKAPBWatchdog s32kwatchdog;
>      CMSDKAPBWatchdog nswatchdog;
> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
> index 5cedfa03570..cb0ec456f39 100644
> --- a/hw/arm/iotkit.c
> +++ b/hw/arm/iotkit.c
> @@ -141,6 +141,8 @@ static void iotkit_init(Object *obj)
>                            TYPE_CMSDK_APB_TIMER);
>      sysbus_init_child_obj(obj, "timer1", &s->timer1, sizeof(s->timer1),
>                            TYPE_CMSDK_APB_TIMER);
> +    sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
> +                          TYPE_CMSDK_APB_TIMER);
>      sysbus_init_child_obj(obj, "dualtimer", &s->dualtimer, sizeof(s->dualtimer),
>                            TYPE_CMSDK_APB_DUALTIMER);
>      sysbus_init_child_obj(obj, "s32kwatchdog", &s->s32kwatchdog,
> @@ -166,8 +168,6 @@ static void iotkit_init(Object *obj)
>                                  TYPE_SPLIT_IRQ, &error_abort, NULL);
>          g_free(name);
>      }
> -    sysbus_init_child_obj(obj, "s32ktimer", &s->s32ktimer, sizeof(s->s32ktimer),
> -                          TYPE_UNIMPLEMENTED_DEVICE);
>  }
>  
>  static void iotkit_exp_irq(void *opaque, int n, int level)
> @@ -476,13 +476,14 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>      /* Devices behind APB PPC1:
>       *   0x4002f000: S32K timer
>       */
> -    qdev_prop_set_string(DEVICE(&s->s32ktimer), "name", "S32KTIMER");
> -    qdev_prop_set_uint64(DEVICE(&s->s32ktimer), "size", 0x1000);
> +    qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
>      object_property_set_bool(OBJECT(&s->s32ktimer), true, "realized", &err);
>      if (err) {
>          error_propagate(errp, err);
>          return;
>      }
> +    sysbus_connect_irq(SYS_BUS_DEVICE(&s->s32ktimer), 0,
> +                       qdev_get_gpio_in(DEVICE(&s->armv7m), 2));
>      mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->s32ktimer), 0);
>      object_property_set_link(OBJECT(&s->apb_ppc1), OBJECT(mr), "port[0]", &err);
>      if (err) {
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 06/16] hw/misc/iotkit: Wire up the system control element
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 06/16] hw/misc/iotkit: Wire up the " Peter Maydell
@ 2018-08-18  0:00   ` Philippe Mathieu-Daudé
  2018-08-18  9:55     ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  0:00 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

Hi Peter,

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> Wire up the system control element's register banks.
> 
> This is the last of the previously completely unimplemented
> components in the IoTKit.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/arm/iotkit.h |  4 +++-
>  hw/arm/iotkit.c         | 19 +++++++++++--------
>  2 files changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
> index 0f5c5101708..1ffa31d521b 100644
> --- a/include/hw/arm/iotkit.h
> +++ b/include/hw/arm/iotkit.h
> @@ -58,7 +58,7 @@
>  #include "hw/timer/cmsdk-apb-timer.h"
>  #include "hw/timer/cmsdk-apb-dualtimer.h"
>  #include "hw/watchdog/cmsdk-apb-watchdog.h"
> -#include "hw/misc/unimp.h"
> +#include "hw/misc/iotkit-sysctl.h"
>  #include "hw/or-irq.h"
>  #include "hw/core/split-irq.h"
>  
> @@ -97,6 +97,8 @@ typedef struct IoTKit {
>      CMSDKAPBWatchdog nswatchdog;
>      CMSDKAPBWatchdog swatchdog;
>  
> +    IoTKitSysCtl sysctl;
> +
>      MemoryRegion container;
>      MemoryRegion alias1;
>      MemoryRegion alias2;
> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
> index cb0ec456f39..5d59ed5489f 100644
> --- a/hw/arm/iotkit.c
> +++ b/hw/arm/iotkit.c
> @@ -16,7 +16,6 @@
>  #include "hw/sysbus.h"
>  #include "hw/registerfields.h"
>  #include "hw/arm/iotkit.h"
> -#include "hw/misc/unimp.h"
>  #include "hw/arm/arm.h"
>  
>  /* Clock frequency in HZ of the 32KHz "slow clock" */
> @@ -151,6 +150,8 @@ static void iotkit_init(Object *obj)
>                            sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
>      sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
>                            sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
> +    sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl, sizeof(s->sysctl),
> +                          TYPE_IOTKIT_SYSCTL);
>      object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
>                              sizeof(s->nmi_orgate), TYPE_OR_IRQ,
>                              &error_abort, NULL);
> @@ -516,13 +517,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>                            qdev_get_gpio_in_named(dev_apb_ppc1,
>                                                   "cfg_sec_resp", 0));
>  
> -    /* Using create_unimplemented_device() maps the stub into the
> -     * system address space rather than into our container, but the
> -     * overall effect to the guest is the same.
> -     */
> -    create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
> -
> -    create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
> +    object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +    /* System information registers */
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x40020000);

What about the Secure access?

       sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50020000);

> +    /* System control registers */
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 1, 0x50021000);
>  
>      /* This OR gate wires together outputs from the secure watchdogs to NMI */
>      object_property_set_int(OBJECT(&s->nmi_orgate), 2, "num-lines", &err);
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element Peter Maydell
@ 2018-08-18  0:23   ` Philippe Mathieu-Daudé
  2018-08-18 10:04     ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  0:23 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

Hi Peter,

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The Arm IoTKit includes a system control element which
> provides a block of read-only ID registers and a block
> of read-write control registers. Implement a minimal
> version of this.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/misc/Makefile.objs           |   1 +
>  include/hw/misc/iotkit-sysctl.h |  50 +++++
>  hw/misc/iotkit-sysctl.c         | 324 ++++++++++++++++++++++++++++++++
>  MAINTAINERS                     |   2 +
>  default-configs/arm-softmmu.mak |   1 +
>  hw/misc/trace-events            |   7 +
>  6 files changed, 385 insertions(+)
>  create mode 100644 include/hw/misc/iotkit-sysctl.h
>  create mode 100644 hw/misc/iotkit-sysctl.c
> 
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 93509008451..dbadb41d57a 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -65,6 +65,7 @@ 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
> +obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
>  
>  obj-$(CONFIG_PVPANIC) += pvpanic.o
>  obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
> diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
> new file mode 100644
> index 00000000000..c3b14ccee4c
> --- /dev/null
> +++ b/include/hw/misc/iotkit-sysctl.h
> @@ -0,0 +1,50 @@
> +/*
> + * ARM IoTKit system control element
> + *
> + * 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 "system control element" which is part of the
> + * Arm IoTKit and documented in
> + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
> + * Specifically, it implements the "system information block" and
> + * "system control register" blocks.
> + *
> + * QEMU interface:
> + *  + sysbus MMIO region 0: the system information register bank
> + *  + sysbus MMIO region 1: the system control register bank
> + */
> +
> +#ifndef HW_MISC_IOTKIT_SYSCTL_H
> +#define HW_MISC_IOTKIT_SYSCTL_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_IOTKIT_SYSCTL "iotkit-sysctl"
> +#define IOTKIT_SYSCTL(obj) OBJECT_CHECK(IoTKitSysCtl, (obj), \
> +                                        TYPE_IOTKIT_SYSCTL)
> +
> +typedef struct IoTKitSysCtl {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion sysinfo_iomem;
> +    MemoryRegion sysctl_iomem;
> +
> +    uint32_t secure_debug;
> +    uint32_t reset_syndrome;
> +    uint32_t reset_mask;
> +    uint32_t gretreg;
> +    uint32_t initsvrtor0;
> +    uint32_t cpuwait;
> +    uint32_t wicctrl;
> +} IoTKitSysCtl;
> +
> +#endif
> diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
> new file mode 100644
> index 00000000000..9445500be76
> --- /dev/null
> +++ b/hw/misc/iotkit-sysctl.c
> @@ -0,0 +1,324 @@
> +/*
> + * ARM IoTKit system control element
> + *
> + * 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 "system control element" which is part of the
> + * Arm IoTKit and documented in
> + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
> + * Specifically, it implements the "system information block" and
> + * "system control register" blocks.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "trace.h"
> +#include "qapi/error.h"
> +#include "sysemu/sysemu.h"
> +#include "hw/sysbus.h"
> +#include "hw/registerfields.h"
> +#include "hw/misc/iotkit-sysctl.h"
> +
> +/* sysinfo block registers */
> +REG32(SYS_VERSION, 0x0)
> +REG32(SYS_CONFIG, 0x4)

I find it a bit confuse to have the both SYSINFO/SYSCONTROL in the same
"iotkit-sysctl" device. They share the same state but there is no
particular need for it, then you need connect them as 2 different
devices in iotkit_realize but they have the same name "iotkit-sysctl".

Why not declare 2 different TypeInfo? I am probably missing what state
they need to share.

> +
> +/* sysctl block registers */
> +REG32(SECDBGSTAT, 0x0)
> +REG32(SECDBGSET, 0x4)
> +REG32(SECDBGCLR, 0x8)
> +REG32(RESET_SYNDROME, 0x100)
> +REG32(RESET_MASK, 0x104)
> +REG32(SWRESET, 0x108)
> +    FIELD(SWRESET, SWRESETREQ, 9, 1)
> +REG32(GRETREG, 0x10c)
> +REG32(INITSVRTOR0, 0x110)
> +REG32(CPUWAIT, 0x118)
> +REG32(BUSWAIT, 0x11c)
> +REG32(WICCTRL, 0x120)
> +
> +/* PID registers, same offset in both blocks */
> +REG32(PID4, 0xfd0)
> +REG32(PID5, 0xfd4)
> +REG32(PID6, 0xfd8)
> +REG32(PID7, 0xfdc)
> +REG32(PID0, 0xfe0)
> +REG32(PID1, 0xfe4)
> +REG32(PID2, 0xfe8)
> +REG32(PID3, 0xfec)
> +REG32(CID0, 0xff0)
> +REG32(CID1, 0xff4)
> +REG32(CID2, 0xff8)
> +REG32(CID3, 0xffc)
> +
> +/* PID/CID values */
> +static const int sysinfo_id[] = {
> +    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
> +    0x58, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
> +    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
> +};
> +
> +static const int sysctl_id[] = {
> +    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
> +    0x54, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
> +    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
> +};
> +
> +static uint64_t iotkit_sysinfo_read(void *opaque, hwaddr offset,
> +                                    unsigned size)
> +{
> +    uint64_t r;
> +
> +    switch (offset) {
> +    case A_SYS_VERSION:
> +        r = 0x41743;
> +        break;
> +

(superfluous newline)

> +    case A_SYS_CONFIG:
> +        r = 0x31;
> +        break;
> +    case A_PID4 ... A_CID3:
> +        r = sysinfo_id[(offset - A_PID4) / 4];
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "IoTKit SysInfo read: bad offset %x\n", (int)offset);
> +        r = 0;
> +        break;
> +    }
> +    trace_iotkit_sysinfo_read(offset, r, size);
> +    return r;
> +}
> +
> +static void iotkit_sysinfo_write(void *opaque, hwaddr offset,
> +                                 uint64_t value, unsigned size)
> +{
> +    trace_iotkit_sysinfo_write(offset, value, size);
> +
> +    qemu_log_mask(LOG_GUEST_ERROR,
> +                  "IoTKit SysInfo: write to RO offset 0x%x\n", (int)offset);
> +}
> +
> +static const MemoryRegionOps iotkit_sysinfo_ops = {
> +    .read = iotkit_sysinfo_read,
> +    .write = iotkit_sysinfo_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    /* byte/halfword accesses are just zero-padded on reads and writes */
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 4,
> +};
> +
> +static uint64_t iotkit_sysctl_read(void *opaque, hwaddr offset,
> +                                    unsigned size)
> +{
> +    IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
> +    uint64_t r;
> +
> +    switch (offset) {
> +    case A_SECDBGSTAT:
> +        r = s->secure_debug;
> +        break;
> +    case A_RESET_SYNDROME:
> +        r = s->reset_syndrome;
> +        break;
> +    case A_RESET_MASK:
> +        r = s->reset_mask;
> +        break;
> +    case A_GRETREG:
> +        r = s->gretreg;
> +        break;
> +    case A_INITSVRTOR0:
> +        r = s->initsvrtor0;
> +        break;
> +    case A_CPUWAIT:
> +        r = s->cpuwait;
> +        break;
> +    case A_BUSWAIT:
> +        /* In IoTKit BUSWAIT is reserved, R/O, zero */
> +        r = 0;
> +        break;
> +    case A_WICCTRL:
> +        r = s->wicctrl;
> +        break;
> +    case A_PID4 ... A_CID3:
> +        r = sysctl_id[(offset - A_PID4) / 4];
> +        break;
> +    case A_SECDBGSET:
> +    case A_SECDBGCLR:
> +    case A_SWRESET:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "IoTKit SysCtl read: read of WO offset %x\n",
> +                      (int)offset);
> +        r = 0;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "IoTKit SysCtl read: bad offset %x\n", (int)offset);
> +        r = 0;
> +        break;
> +    }
> +    trace_iotkit_sysctl_read(offset, r, size);
> +    return r;
> +}
> +
> +static void iotkit_sysctl_write(void *opaque, hwaddr offset,
> +                                 uint64_t value, unsigned size)
> +{
> +    IoTKitSysCtl *s = IOTKIT_SYSCTL(opaque);
> +
> +    trace_iotkit_sysctl_write(offset, value, size);
> +
> +    /*
> +     * Most of the state here has to do with control of reset and
> +     * similar kinds of power up -- for instance the guest can ask
> +     * what the reason for the last reset was, or forbid reset for
> +     * some causes (like the non-secure watchdog). Most of this is
> +     * not relevant to QEMU, which doesn't really model anything other
> +     * than a full power-on reset.
> +     * We just model the registers as reads-as-written.
> +     */
> +
> +    switch (offset) {
> +    case A_RESET_SYNDROME:
> +        qemu_log_mask(LOG_UNIMP,
> +                      "IoTKit SysCtl RESET_SYNDROME unimplemented\n");

Maybe warn_report() or warn_once() is more appropriate than UNIMP?

> +        s->reset_syndrome = value;
> +        break;
> +    case A_RESET_MASK:
> +        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl RESET_MASK unimplemented\n");

Ditto.

> +        s->reset_mask = value;
> +        break;
> +    case A_GRETREG:
> +        /*
> +         * General retention register, which is only reset by a power-on
> +         * reset. Technically this implementation is complete, since
> +         * QEMU only supports power-on resets...
> +         */
> +        s->gretreg = value;
> +        break;
> +    case A_INITSVRTOR0:
> +        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl INITSVRTOR0 unimplemented\n");
> +        s->initsvrtor0 = value;
> +        break;
> +    case A_CPUWAIT:
> +        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl CPUWAIT unimplemented\n");
> +        s->cpuwait = value;
> +        break;
> +    case A_WICCTRL:
> +        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl WICCTRL unimplemented\n");
> +        s->wicctrl = value;
> +        break;
> +    case A_SECDBGSET:
> +        /* write-1-to-set */
> +        qemu_log_mask(LOG_UNIMP, "IoTKit SysCtl SECDBGSET unimplemented\n");
> +        s->secure_debug |= value;
> +        break;
> +    case A_SECDBGCLR:
> +        /* write-1-to-clear */
> +        s->secure_debug &= ~value;
> +        break;
> +    case A_SWRESET:
> +        /* One w/o bit to request a reset; all other bits reserved */
> +        if (value & R_SWRESET_SWRESETREQ_MASK) {
> +            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> +        }

Shouldn't this be:

           } else {
               cpu_reset(...);
           }

> +        break;
> +    case A_BUSWAIT:        /* In IoTKit BUSWAIT is reserved, R/O, zero */
> +    case A_SECDBGSTAT:
> +    case A_PID4 ... A_CID3:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "IoTKit SysCtl write: write of RO offset %x\n",
> +                      (int)offset);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "IoTKit SysCtl write: bad offset %x\n", (int)offset);
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps iotkit_sysctl_ops = {
> +    .read = iotkit_sysctl_read,
> +    .write = iotkit_sysctl_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    /* byte/halfword accesses are just zero-padded on reads and writes */
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 4,
> +};
> +
> +static void iotkit_sysctl_reset(DeviceState *dev)
> +{
> +    IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
> +
> +    trace_iotkit_sysctl_reset();
> +    s->secure_debug = 0;
> +    s->reset_syndrome = 1;
> +    s->reset_mask = 0;
> +    s->gretreg = 0;
> +    s->initsvrtor0 = 0x10000000;

This one could be a property (now now ;) ).

> +    s->cpuwait = 0;
> +    s->wicctrl = 0;
> +}
> +
> +static void iotkit_sysctl_init(Object *obj)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    IoTKitSysCtl *s = IOTKIT_SYSCTL(obj);
> +
> +    memory_region_init_io(&s->sysinfo_iomem, obj, &iotkit_sysinfo_ops,
> +                          s, "iotkit-sysinfo", 0x1000);
> +    memory_region_init_io(&s->sysctl_iomem, obj, &iotkit_sysctl_ops,
> +                          s, "iotkit-sysctl", 0x1000);
> +    sysbus_init_mmio(sbd, &s->sysinfo_iomem);
> +    sysbus_init_mmio(sbd, &s->sysctl_iomem);
> +}
> +
> +static const VMStateDescription iotkit_sysctl_vmstate = {
> +    .name = "iotkit-sysctl",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(secure_debug, IoTKitSysCtl),
> +        VMSTATE_UINT32(reset_syndrome, IoTKitSysCtl),
> +        VMSTATE_UINT32(reset_mask, IoTKitSysCtl),
> +        VMSTATE_UINT32(gretreg, IoTKitSysCtl),
> +        VMSTATE_UINT32(initsvrtor0, IoTKitSysCtl),
> +        VMSTATE_UINT32(cpuwait, IoTKitSysCtl),
> +        VMSTATE_UINT32(wicctrl, IoTKitSysCtl),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void iotkit_sysctl_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->vmsd = &iotkit_sysctl_vmstate;
> +    dc->reset = iotkit_sysctl_reset;
> +}
> +
> +static const TypeInfo iotkit_sysctl_info = {
> +    .name = TYPE_IOTKIT_SYSCTL,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(IoTKitSysCtl),
> +    .instance_init = iotkit_sysctl_init,
> +    .class_init = iotkit_sysctl_class_init,
> +};
> +
> +static void iotkit_sysctl_register_types(void)
> +{
> +    type_register_static(&iotkit_sysctl_info);
> +}
> +
> +type_init(iotkit_sysctl_register_types);
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7ea39c0176b..96fe011e952 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -537,6 +537,8 @@ F: hw/misc/mps2-*.c
>  F: include/hw/misc/mps2-*.h
>  F: hw/arm/iotkit.c
>  F: include/hw/arm/iotkit.h
> +F: hw/misc/iotkit-sysctl.c
> +F: include/hw/misc/iotkit-sysctl.h
>  
>  Musicpal
>  M: Jan Kiszka <jan.kiszka@web.de>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index 521c3d459fa..da59b820a4f 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -114,6 +114,7 @@ CONFIG_TZ_MPC=y
>  CONFIG_TZ_PPC=y
>  CONFIG_IOTKIT=y
>  CONFIG_IOTKIT_SECCTL=y
> +CONFIG_IOTKIT_SYSCTL=y
>  
>  CONFIG_VERSATILE=y
>  CONFIG_VERSATILE_PCI=y
> diff --git a/hw/misc/trace-events b/hw/misc/trace-events
> index c956e1419b7..83ab58c30f5 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -109,3 +109,10 @@ iotkit_secctl_s_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit Sec
>  iotkit_secctl_ns_read(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs read: offset 0x%x data 0x%" PRIx64 " size %u"
>  iotkit_secctl_ns_write(uint32_t offset, uint64_t data, unsigned size) "IoTKit SecCtl NS regs write: offset 0x%x data 0x%" PRIx64 " size %u"
>  iotkit_secctl_reset(void) "IoTKit SecCtl: reset"
> +
> +# hw/misc/iotkit-sysctl.c
> +iotkit_sysinfo_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
> +iotkit_sysinfo_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysInfo write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
> +iotkit_sysctl_read(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
> +iotkit_sysctl_write(uint64_t offset, uint64_t data, unsigned size) "IoTKit SysCtl write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
> +iotkit_sysctl_reset(void) "IoTKit SysCtl: reset"
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs Peter Maydell
@ 2018-08-18  0:37   ` Philippe Mathieu-Daudé
  2018-08-18 10:05     ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  0:37 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The IoTKit does not have any Master Security Contollers itself,
> but it does provide registers in the secure privilege control
> block which allow control of MSCs in the external system.
> Add support for these registers.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/misc/iotkit-secctl.h | 14 +++++++
>  hw/misc/iotkit-secctl.c         | 73 +++++++++++++++++++++++++++++----
>  2 files changed, 79 insertions(+), 8 deletions(-)
> 
> diff --git a/include/hw/misc/iotkit-secctl.h b/include/hw/misc/iotkit-secctl.h
> index 082c14c925e..1a193b306f1 100644
> --- a/include/hw/misc/iotkit-secctl.h
> +++ b/include/hw/misc/iotkit-secctl.h
> @@ -19,6 +19,7 @@
>   *  + named GPIO output "sec_resp_cfg" indicating whether blocked accesses
>   *    should RAZ/WI or bus error
>   *  + named GPIO output "nsc_cfg" whose value tracks the NSCCFG register value
> + *  + named GPIO output "msc_irq" for the combined IRQ line from the MSCs
>   * Controlling the 2 APB PPCs in the IoTKit:
>   *  + named GPIO outputs apb_ppc0_nonsec[0..2] and apb_ppc1_nonsec
>   *  + named GPIO outputs apb_ppc0_ap[0..2] and apb_ppc1_ap
> @@ -44,6 +45,11 @@
>   * Controlling each of the 16 expansion MPCs which a system using the IoTKit
>   * might provide:
>   *  + named GPIO inputs mpcexp_status[0..15]
> + * Controlling each of the 16 expansion MSCs which a system using the IoTKit
> + * might provide:
> + *  + named GPIO inputs mscexp_status[0..15]
> + *  + named GPIO outputs mscexp_clear[0..15]
> + *  + named GPIO outputs mscexp_ns[0..15]
>   */
>  
>  #ifndef IOTKIT_SECCTL_H
> @@ -62,6 +68,7 @@
>  #define IOTS_NUM_AHB_EXP_PPC 4
>  #define IOTS_NUM_EXP_MPC 16
>  #define IOTS_NUM_MPC 1
> +#define IOTS_NUM_EXP_MSC 16
>  
>  typedef struct IoTKitSecCtl IoTKitSecCtl;
>  
> @@ -103,6 +110,13 @@ struct IoTKitSecCtl {
>      uint32_t brginten;
>      uint32_t mpcintstatus;
>  
> +    uint32_t secmscintstat;
> +    uint32_t secmscinten;
> +    uint32_t nsmscexp;
> +    qemu_irq mscexp_clear[IOTS_NUM_EXP_MSC];
> +    qemu_irq mscexp_ns[IOTS_NUM_EXP_MSC];
> +    qemu_irq msc_irq;
> +
>      IoTKitSecCtlPPC apb[IOTS_NUM_APB_PPC];
>      IoTKitSecCtlPPC apbexp[IOTS_NUM_APB_EXP_PPC];
>      IoTKitSecCtlPPC ahbexp[IOTS_NUM_APB_EXP_PPC];
> diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c
> index de4fd8e36d2..2222b3e147d 100644
> --- a/hw/misc/iotkit-secctl.c
> +++ b/hw/misc/iotkit-secctl.c
> @@ -190,12 +190,13 @@ static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr,
>          r = s->apbexp[offset_to_ppc_idx(offset)].sp;
>          break;
>      case A_SECMSCINTSTAT:
> +        r = s->secmscintstat;
> +        break;
>      case A_SECMSCINTEN:
> +        r = s->secmscinten;
> +        break;
>      case A_NSMSCEXP:
> -        qemu_log_mask(LOG_UNIMP,
> -                      "IoTKit SecCtl S block read: "
> -                      "unimplemented offset 0x%x\n", offset);
> -        r = 0;
> +        r = s->nsmscexp;
>          break;
>      case A_PID4:
>      case A_PID5:
> @@ -291,6 +292,23 @@ static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc)
>      qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1));
>  }
>  
> +static void iotkit_secctl_update_mscexp_irqs(qemu_irq *msc_irqs, uint32_t value)
> +{
> +    int i;
> +
> +    for (i = 0; i < IOTS_NUM_EXP_MSC; i++) {
> +        qemu_set_irq(msc_irqs[i], extract32(value, i + 16, 1));
> +    }
> +}
> +
> +static void iotkit_secctl_update_msc_irq(IoTKitSecCtl *s)
> +{
> +    /* Update the combined MSC IRQ, based on S_MSCEXP_STATUS and S_MSCEXP_EN */
> +    bool level = s->secmscintstat & s->secmscinten;
> +
> +    qemu_set_irq(s->msc_irq, level);
> +}
> +
>  static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
>                                           uint64_t value,
>                                           unsigned size, MemTxAttrs attrs)
> @@ -370,10 +388,15 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
>          iotkit_secctl_ppc_sp_write(ppc, value);
>          break;
>      case A_SECMSCINTCLR:
> +        iotkit_secctl_update_mscexp_irqs(s->mscexp_clear, value);
> +        break;
>      case A_SECMSCINTEN:
> -        qemu_log_mask(LOG_UNIMP,
> -                      "IoTKit SecCtl S block write: "
> -                      "unimplemented offset 0x%x\n", offset);

Maybe:

           if (value & ~0xffff) {
               GUEST_ERROR(...)
           }

> +        s->secmscinten = value;
> +        iotkit_secctl_update_msc_irq(s);
> +        break;
> +    case A_NSMSCEXP:

Ditto.

> +        s->nsmscexp = value;
> +        iotkit_secctl_update_mscexp_irqs(s->mscexp_ns, value);
>          break;
>      case A_SECMPCINTSTATUS:
>      case A_SECPPCINTSTAT:
> @@ -381,7 +404,6 @@ static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr,
>      case A_BRGINTSTAT:
>      case A_AHBNSPPC0:
>      case A_AHBSPPPC0:
> -    case A_NSMSCEXP:
>      case A_PID4:
>      case A_PID5:
>      case A_PID6:
> @@ -588,6 +610,14 @@ static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level)
>      s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level);
>  }
>  
> +static void iotkit_secctl_mscexp_status(void *opaque, int n, int level)
> +{
> +    IoTKitSecCtl *s = IOTKIT_SECCTL(opaque);
> +
> +    s->secmscintstat = deposit32(s->secmscintstat, n + 16, 1, !!level);
> +    iotkit_secctl_update_msc_irq(s);
> +}
> +
>  static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level)
>  {
>      IoTKitSecCtlPPC *ppc = opaque;
> @@ -660,6 +690,14 @@ static void iotkit_secctl_init(Object *obj)
>      qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status,
>                              "mpcexp_status", IOTS_NUM_EXP_MPC);
>  
> +    qdev_init_gpio_in_named(dev, iotkit_secctl_mscexp_status,
> +                            "mscexp_status", IOTS_NUM_EXP_MSC);
> +    qdev_init_gpio_out_named(dev, s->mscexp_clear, "mscexp_clear",
> +                             IOTS_NUM_EXP_MSC);
> +    qdev_init_gpio_out_named(dev, s->mscexp_ns, "mscexp_ns",
> +                             IOTS_NUM_EXP_MSC);
> +    qdev_init_gpio_out_named(dev, &s->msc_irq, "msc_irq", 1);
> +
>      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,
> @@ -690,6 +728,24 @@ static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = {
>      }
>  };
>  
> +static bool needed_always(void *opaque)
> +{
> +    return true;
> +}
> +
> +static const VMStateDescription iotkit_secctl_msc_vmstate = {
> +    .name = "iotkit-secctl/msc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = needed_always,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(secmscintstat, IoTKitSecCtl),
> +        VMSTATE_UINT32(secmscinten, IoTKitSecCtl),
> +        VMSTATE_UINT32(nsmscexp, IoTKitSecCtl),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  static const VMStateDescription iotkit_secctl_vmstate = {
>      .name = "iotkit-secctl",
>      .version_id = 1,
> @@ -710,6 +766,7 @@ static const VMStateDescription iotkit_secctl_vmstate = {
>      },
>      .subsections = (const VMStateDescription*[]) {
>          &iotkit_secctl_mpcintstatus_vmstate,
> +        &iotkit_secctl_msc_vmstate,
>          NULL
>      },
>  };
> 

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 09/16] hw/arm/iotkit: Wire up the lines for MSCs
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 09/16] hw/arm/iotkit: Wire up the lines for MSCs Peter Maydell
@ 2018-08-18  0:39   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  0:39 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The IoTKit doesn't have any MSCs itself but it does need
> some wiring to connect the external signals from MSCs
> in the outer board model up to the registers and the
> NVIC IRQ line.
> 
> We also need to expose a MemoryRegion corresponding to
> the AHB bus, so that MSCs in the outer board model can
> use that as their downstream port. (In the FPGA this is
> the "AHB Slave Expansion" ports shown in the block
> diagram in the AN505 documentation.)
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  include/hw/arm/iotkit.h |  8 ++++++++
>  hw/arm/iotkit.c         | 15 +++++++++++++++
>  2 files changed, 23 insertions(+)
> 
> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
> index 1ffa31d521b..5bb66b10468 100644
> --- a/include/hw/arm/iotkit.h
> +++ b/include/hw/arm/iotkit.h
> @@ -28,6 +28,9 @@
>   *  + QOM property "EXP_NUMIRQ" sets the number of expansion interrupts
>   *  + Named GPIO inputs "EXP_IRQ" 0..n are the expansion interrupts, which
>   *    are wired to the NVIC lines 32 .. n+32
> + *  + sysbus MMIO region 0 is the "AHB Slave Expansion" which allows
> + *    bus master devices in the board model to make transactions into
> + *    all the devices and memory areas in the IoTKit
>   * Controlling up to 4 AHB expansion PPBs which a system using the IoTKit
>   * might provide:
>   *  + named GPIO outputs apb_ppcexp{0,1,2,3}_nonsec[0..15]
> @@ -45,6 +48,11 @@
>   * Controlling each of the 16 expansion MPCs which a system using the IoTKit
>   * might provide:
>   *  + named GPIO inputs mpcexp_status[0..15]
> + * Controlling each of the 16 expansion MSCs which a system using the IoTKit
> + * might provide:
> + *  + named GPIO inputs mscexp_status[0..15]
> + *  + named GPIO outputs mscexp_clear[0..15]
> + *  + named GPIO outputs mscexp_ns[0..15]
>   */
>  
>  #ifndef IOTKIT_H
> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
> index 5d59ed5489f..8ae2a052517 100644
> --- a/hw/arm/iotkit.c
> +++ b/hw/arm/iotkit.c
> @@ -660,6 +660,21 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>  
>      iotkit_forward_sec_resp_cfg(s);
>  
> +    /* Forward the MSC related signals */
> +    qdev_pass_gpios(dev_secctl, dev, "mscexp_status");
> +    qdev_pass_gpios(dev_secctl, dev, "mscexp_clear");
> +    qdev_pass_gpios(dev_secctl, dev, "mscexp_ns");
> +    qdev_connect_gpio_out_named(dev_secctl, "msc_irq", 0,
> +                                qdev_get_gpio_in(DEVICE(&s->armv7m), 11));
> +
> +    /*
> +     * Expose our container region to the board model; this corresponds
> +     * to the AHB Slave Expansion ports which allow bus master devices
> +     * (eg DMA controllers) in the board model to make transactions into
> +     * devices in the IoTKit.
> +     */
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
> +
>      system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
>  }
>  
> 

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 11/16] hw/dma/pl080: Support all three interrupt lines
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 11/16] hw/dma/pl080: Support all three interrupt lines Peter Maydell
@ 2018-08-18  0:43   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  0:43 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The PL080 and PL081 have three outgoing interrupt lines:
>  * DMACINTERR signals DMA errors
>  * DMACINTTC is the DMA count interrupt
>  * DMACINTR is a combined interrupt, the logical OR of the other two
> 
> We currently only implement DMACINTR, because that's all the
> realview and versatile boards needed, but the instances of the
> PL081 in the MPS2 firmware images use all three interrupt lines.
> Implement the missing DMACINTERR and DMACINTTC.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> ---
>  include/hw/dma/pl080.h |  6 +++++-
>  hw/dma/pl080.c         | 13 ++++++++-----
>  2 files changed, 13 insertions(+), 6 deletions(-)
> 
> diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h
> index 7deb46c8578..7c6a4184833 100644
> --- a/include/hw/dma/pl080.h
> +++ b/include/hw/dma/pl080.h
> @@ -17,7 +17,9 @@
>   * http://infocenter.arm.com/help/topic/com.arm.doc.ddi0218e/DDI0218.pdf
>   *
>   * QEMU interface:
> - * + sysbus IRQ: DMACINTR combined interrupt line
> + * + sysbus IRQ 0: DMACINTR combined interrupt line
> + * + sysbus IRQ 1: DMACINTERR error interrupt request
> + * + sysbus IRQ 2: DMACINTTC count interrupt request
>   * + sysbus MMIO region 0: MemoryRegion for the device's registers
>   */
>  
> @@ -57,6 +59,8 @@ typedef struct PL080State {
>      /* Flag to avoid recursive DMA invocations.  */
>      int running;
>      qemu_irq irq;
> +    qemu_irq interr;
> +    qemu_irq inttc;
>  } PL080State;
>  
>  #endif
> diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c
> index 0f79c2d8a6c..301030dd118 100644
> --- a/hw/dma/pl080.c
> +++ b/hw/dma/pl080.c
> @@ -75,11 +75,12 @@ static const unsigned char pl081_id[] =
>  
>  static void pl080_update(PL080State *s)
>  {
> -    if ((s->tc_int & s->tc_mask)
> -            || (s->err_int & s->err_mask))
> -        qemu_irq_raise(s->irq);
> -    else
> -        qemu_irq_lower(s->irq);
> +    bool tclevel = (s->tc_int & s->tc_mask);
> +    bool errlevel = (s->err_int & s->err_mask);
> +
> +    qemu_set_irq(s->interr, errlevel);
> +    qemu_set_irq(s->inttc, tclevel);
> +    qemu_set_irq(s->irq, errlevel || tclevel);
>  }
>  
>  static void pl080_run(PL080State *s)
> @@ -352,6 +353,8 @@ static void pl080_init(Object *obj)
>      memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000);
>      sysbus_init_mmio(sbd, &s->iomem);
>      sysbus_init_irq(sbd, &s->irq);
> +    sysbus_init_irq(sbd, &s->interr);
> +    sysbus_init_irq(sbd, &s->inttc);
>      s->nchannels = 8;
>  }
>  
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs Peter Maydell
@ 2018-08-18  1:09   ` Philippe Mathieu-Daudé
  2018-08-18 10:07     ` Peter Maydell
  0 siblings, 1 reply; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  1:09 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The AN505 FPGA image includes four PL081 DMA controllers, each
> of which is gated by a Master Security Controller that allows
> the guest to prevent a non-secure DMA controller from accessing
> memory that is used by secure guest code. Create and wire
> up these devices.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/arm/mps2-tz.c | 101 +++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 94 insertions(+), 7 deletions(-)
> 
> diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
> index 22180c56fb7..7d92bc5fe1c 100644
> --- a/hw/arm/mps2-tz.c
> +++ b/hw/arm/mps2-tz.c
> @@ -45,7 +45,9 @@
>  #include "hw/misc/mps2-scc.h"
>  #include "hw/misc/mps2-fpgaio.h"
>  #include "hw/misc/tz-mpc.h"
> +#include "hw/misc/tz-msc.h"
>  #include "hw/arm/iotkit.h"
> +#include "hw/dma/pl080.h"
>  #include "hw/devices.h"
>  #include "net/net.h"
>  #include "hw/core/split-irq.h"
> @@ -75,8 +77,9 @@ typedef struct {
>      UnimplementedDeviceState i2c[4];
>      UnimplementedDeviceState i2s_audio;
>      UnimplementedDeviceState gpio[4];
> -    UnimplementedDeviceState dma[4];
>      UnimplementedDeviceState gfx;
> +    PL080State dma[4];
> +    TZMSC msc[4];
>      CMSDKAPBUART uart[5];
>      SplitIRQ sec_resp_splitter;
>      qemu_or_irq uart_irq_orgate;
> @@ -273,6 +276,65 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
>      return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
>  }
>  
> +static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
> +                              const char *name, hwaddr size)
> +{
> +    PL080State *dma = opaque;
> +    int i = dma - &mms->dma[0];

This line is not trivial to read. I wondered "isn't this ptrdiff_t? why
not divide by sizeof(dma)...

> +    SysBusDevice *s;
> +    char *mscname = g_strdup_printf("%s-msc", name);
> +    TZMSC *msc = &mms->msc[i];
> +    DeviceState *iotkitdev = DEVICE(&mms->iotkit);
> +    MemoryRegion *msc_upstream;
> +    MemoryRegion *msc_downstream;
> +
> +    /*
> +     * Each DMA device is a PL081 whose transaction master interface
> +     * is guarded by a Master Security Controller. The downstream end of
> +     * the MSC connects to the IoTKit AHB Slave Expansion port, so the
> +     * DMA devices can see all devices and memory that the CPU does.
> +     */
> +    init_sysbus_child(OBJECT(mms), mscname, msc, sizeof(mms->msc[0]),

sizeof(*msc) easier to read?

> +                      TYPE_TZ_MSC);
> +    msc_downstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(&mms->iotkit), 0);
> +    object_property_set_link(OBJECT(msc), OBJECT(msc_downstream),
> +                             "downstream", &error_fatal);
> +    object_property_set_link(OBJECT(msc), OBJECT(mms),
> +                             "idau", &error_fatal);
> +    object_property_set_bool(OBJECT(msc), true, "realized", &error_fatal);
> +
> +    qdev_connect_gpio_out_named(DEVICE(msc), "irq", 0,
> +                                qdev_get_gpio_in_named(iotkitdev,
> +                                                       "mscexp_status", i));
> +    qdev_connect_gpio_out_named(iotkitdev, "mscexp_clear", i,
> +                                qdev_get_gpio_in_named(DEVICE(msc),
> +                                                       "irq_clear", 0));
> +    qdev_connect_gpio_out_named(iotkitdev, "mscexp_ns", i,
> +                                qdev_get_gpio_in_named(DEVICE(msc),
> +                                                       "cfg_nonsec", 0));
> +    qdev_connect_gpio_out(DEVICE(&mms->sec_resp_splitter),
> +                          ARRAY_SIZE(mms->ppc) + i,
> +                          qdev_get_gpio_in_named(DEVICE(msc),
> +                                                 "cfg_sec_resp", 0));
> +    msc_upstream = sysbus_mmio_get_region(SYS_BUS_DEVICE(msc), 0);
> +
> +    init_sysbus_child(OBJECT(mms), name, dma, sizeof(mms->dma[0]), TYPE_PL081);
> +    object_property_set_link(OBJECT(dma), OBJECT(msc_upstream),
> +                             "downstream", &error_fatal);
> +    object_property_set_bool(OBJECT(dma), true, "realized", &error_fatal);
> +
> +    s = SYS_BUS_DEVICE(dma);
> +    /* Wire up DMACINTR, DMACINTERR, DMACINTTC */
> +    sysbus_connect_irq(s, 0, qdev_get_gpio_in_named(iotkitdev,
> +                                                    "EXP_IRQ", 58 + i * 3));
> +    sysbus_connect_irq(s, 1, qdev_get_gpio_in_named(iotkitdev,
> +                                                    "EXP_IRQ", 56 + i * 3));
> +    sysbus_connect_irq(s, 2, qdev_get_gpio_in_named(iotkitdev,
> +                                                    "EXP_IRQ", 57 + i * 3));
> +
> +    return sysbus_mmio_get_region(s, 0);
> +}
> +
>  static void mps2tz_common_init(MachineState *machine)
>  {
>      MPS2TZMachineState *mms = MPS2TZ_MACHINE(machine);
> @@ -299,13 +361,14 @@ static void mps2tz_common_init(MachineState *machine)
>                               &error_fatal);
>  
>      /* The sec_resp_cfg output from the IoTKit must be split into multiple
> -     * lines, one for each of the PPCs we create here.
> +     * lines, one for each of the PPCs we create here, plus one per MSC.
>       */
>      object_initialize(&mms->sec_resp_splitter, sizeof(mms->sec_resp_splitter),
>                        TYPE_SPLIT_IRQ);
>      object_property_add_child(OBJECT(machine), "sec-resp-splitter",
>                                OBJECT(&mms->sec_resp_splitter), &error_abort);
> -    object_property_set_int(OBJECT(&mms->sec_resp_splitter), 5,
> +    object_property_set_int(OBJECT(&mms->sec_resp_splitter),
> +                            ARRAY_SIZE(mms->ppc) + ARRAY_SIZE(mms->msc),
>                              "num-lines", &error_fatal);
>      object_property_set_bool(OBJECT(&mms->sec_resp_splitter), true,
>                               "realized", &error_fatal);
> @@ -406,10 +469,10 @@ static void mps2tz_common_init(MachineState *machine)
>          }, {
>              .name = "ahb_ppcexp1",
>              .ports = {
> -                { "dma0", make_unimp_dev, &mms->dma[0], 0x40110000, 0x1000 },
> -                { "dma1", make_unimp_dev, &mms->dma[1], 0x40111000, 0x1000 },
> -                { "dma2", make_unimp_dev, &mms->dma[2], 0x40112000, 0x1000 },
> -                { "dma3", make_unimp_dev, &mms->dma[3], 0x40113000, 0x1000 },
> +                { "dma0", make_dma, &mms->dma[0], 0x40110000, 0x1000 },
> +                { "dma1", make_dma, &mms->dma[1], 0x40111000, 0x1000 },
> +                { "dma2", make_dma, &mms->dma[2], 0x40112000, 0x1000 },
> +                { "dma3", make_dma, &mms->dma[3], 0x40113000, 0x1000 },
>              },
>          },
>      };
> @@ -490,12 +553,32 @@ static void mps2tz_common_init(MachineState *machine)
>      armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename, 0x400000);
>  }
>  
> +static void mps2_tz_idau_check(IDAUInterface *ii, uint32_t address,
> +                               int *iregion, bool *exempt, bool *ns, bool *nsc)
> +{
> +    /*
> +     * The MPS2 TZ FPGA images have IDAUs in them which are connected to
> +     * the Master Security Controllers. Thes have the same logic as
> +     * is used by the IoTKit for the IDAU connected to the CPU, except
> +     * that MSCs don't care about the NSC attribute.
> +     */
> +    int region = extract32(address, 28, 4);
> +
> +    *ns = !(region & 1);
> +    *nsc = false;
> +    /* 0xe0000000..0xe00fffff and 0xf0000000..0xf00fffff are exempt */
> +    *exempt = (address & 0xeff00000) == 0xe0000000;
> +    *iregion = region;
> +}
> +
>  static void mps2tz_class_init(ObjectClass *oc, void *data)
>  {
>      MachineClass *mc = MACHINE_CLASS(oc);
> +    IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc);
>  
>      mc->init = mps2tz_common_init;
>      mc->max_cpus = 1;
> +    iic->check = mps2_tz_idau_check;
>  }
>  
>  static void mps2tz_an505_class_init(ObjectClass *oc, void *data)
> @@ -516,6 +599,10 @@ static const TypeInfo mps2tz_info = {
>      .instance_size = sizeof(MPS2TZMachineState),
>      .class_size = sizeof(MPS2TZMachineClass),
>      .class_init = mps2tz_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { TYPE_IDAU_INTERFACE },
> +        { }
> +    },
>  };
>  
>  static const TypeInfo mps2tz_an505_info = {
> 

mps2-tz is now a piece of art...

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 07/16] hw/misc/tz-msc: Model TrustZone Master Security Controller
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 07/16] hw/misc/tz-msc: Model TrustZone Master Security Controller Peter Maydell
@ 2018-08-18  1:15   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  1:15 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> Implement a model of the TrustZone Master Securtiy Controller,

Security

> as documented in the Arm CoreLink SIE-200 System IP for
> Embedded TRM  (DDI0571G):
>   https://developer.arm.com/products/architecture/m-profile/docs/ddi0571/g

Your link returns 404.

This one worked:

https://developer.arm.com/docs/ddi0571/e

> 
> The MSC is intended to sit in front of a device which can
> be a bus master (eg a DMA controller) and programmably gate
> its transactions. This allows a bus-mastering device to be
> controlled by non-secure code but still restricted from
> making accesses to addresses which are secure-only.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/misc/Makefile.objs           |   1 +
>  include/hw/misc/tz-msc.h        |  79 ++++++++
>  hw/misc/tz-msc.c                | 308 ++++++++++++++++++++++++++++++++
>  MAINTAINERS                     |   2 +
>  default-configs/arm-softmmu.mak |   1 +
>  hw/misc/trace-events            |   9 +
>  6 files changed, 400 insertions(+)
>  create mode 100644 include/hw/misc/tz-msc.h
>  create mode 100644 hw/misc/tz-msc.c
> 
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index dbadb41d57a..d168f8ac304 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -63,6 +63,7 @@ obj-$(CONFIG_MPS2_FPGAIO) += mps2-fpgaio.o
>  obj-$(CONFIG_MPS2_SCC) += mps2-scc.o
>  
>  obj-$(CONFIG_TZ_MPC) += tz-mpc.o
> +obj-$(CONFIG_TZ_MSC) += tz-msc.o
>  obj-$(CONFIG_TZ_PPC) += tz-ppc.o
>  obj-$(CONFIG_IOTKIT_SECCTL) += iotkit-secctl.o
>  obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
> diff --git a/include/hw/misc/tz-msc.h b/include/hw/misc/tz-msc.h
> new file mode 100644
> index 00000000000..116b96ae9b8
> --- /dev/null
> +++ b/include/hw/misc/tz-msc.h
> @@ -0,0 +1,79 @@
> +/*
> + * ARM TrustZone master security 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 master security controller (MSC).
> + * 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 MSC sits in front of a device which can be a bus master (such as
> + * a DMA controller) and allows secure software to configure it to either
> + * pass through or reject transactions made by that bus master.
> + * 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 MSC has no register interface -- it is configured purely by a
> + * collection of input signals from other hardware in the system. Typically
> + * they are either hardwired or exposed in an ad-hoc register interface by
> + * the SoC that uses the MSC.
> + *
> + * We don't currently implement the irq_enable GPIO input, because on
> + * the MPS2 FPGA images it is always tied high, which is awkward to
> + * implement in QEMU.
> + *
> + * QEMU interface:
> + * + Named GPIO input "cfg_nonsec": set to 1 if the bus master should be
> + *   treated as nonsecure, or 0 for secure
> + * + Named GPIO input "cfg_sec_resp": set to 1 if a rejected transaction should
> + *   result in a transaction error, or 0 for the transaction to RAZ/WI
> + * + Named GPIO input "irq_clear": set to 1 to clear a pending interrupt
> + * + Named GPIO output "irq": set for a transaction-failed interrupt
> + * + Property "downstream": MemoryRegion defining where bus master transactions
> + *   are made if they are not blocked
> + * + Property "idau": an object implementing IDAUInterface, which defines which
> + *   addresses should be treated as secure and which as non-secure.
> + *   This need not be the same IDAU as the one used by the CPU.
> + * + sysbus MMIO region 0: MemoryRegion defining the upstream end of the MSC;
> + *   this should be passed to the bus master device as the region it should
> + *   make memory transactions to
> + */
> +
> +#ifndef TZ_MSC_H
> +#define TZ_MSC_H
> +
> +#include "hw/sysbus.h"
> +#include "target/arm/idau.h"
> +
> +#define TYPE_TZ_MSC "tz-msc"
> +#define TZ_MSC(obj) OBJECT_CHECK(TZMSC, (obj), TYPE_TZ_MSC)
> +
> +typedef struct TZMSC {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +
> +    /* State: these just track the values of our input signals */
> +    bool cfg_nonsec;
> +    bool cfg_sec_resp;
> +    bool irq_clear;
> +    /* State: are we asserting irq ? */
> +    bool irq_status;
> +
> +    qemu_irq irq;
> +    MemoryRegion *downstream;
> +    AddressSpace downstream_as;
> +    MemoryRegion upstream;
> +    IDAUInterface *idau;
> +} TZMSC;
> +
> +#endif
> diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c
> new file mode 100644
> index 00000000000..9e352044ea5
> --- /dev/null
> +++ b/hw/misc/tz-msc.c
> @@ -0,0 +1,308 @@
> +/*
> + * ARM TrustZone master security 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-msc.h"
> +
> +static void tz_msc_update_irq(TZMSC *s)
> +{
> +    bool level = s->irq_status;
> +
> +    trace_tz_msc_update_irq(level);
> +    qemu_set_irq(s->irq, level);
> +}
> +
> +static void tz_msc_cfg_nonsec(void *opaque, int n, int level)
> +{
> +    TZMSC *s = TZ_MSC(opaque);
> +
> +    trace_tz_msc_cfg_nonsec(level);
> +    s->cfg_nonsec = level;
> +}
> +
> +static void tz_msc_cfg_sec_resp(void *opaque, int n, int level)
> +{
> +    TZMSC *s = TZ_MSC(opaque);
> +
> +    trace_tz_msc_cfg_sec_resp(level);
> +    s->cfg_sec_resp = level;
> +}
> +
> +static void tz_msc_irq_clear(void *opaque, int n, int level)
> +{
> +    TZMSC *s = TZ_MSC(opaque);
> +
> +    trace_tz_msc_irq_clear(level);
> +
> +    s->irq_clear = level;
> +    if (level) {
> +        s->irq_status = false;
> +        tz_msc_update_irq(s);
> +    }
> +}
> +
> +/* The MSC may either block a transaction by aborting it, block a
> + * transaction by making it RAZ/WI, allow it through with
> + * MemTxAttrs indicating a secure transaction, or allow it with
> + * MemTxAttrs indicating a non-secure transaction.
> + */
> +typedef enum MSCAction {
> +    MSCBlockAbort,
> +    MSCBlockRAZWI,
> +    MSCAllowSecure,
> +    MSCAllowNonSecure,
> +} MSCAction;
> +
> +static MSCAction tz_msc_check(TZMSC *s, hwaddr addr)
> +{
> +    /*
> +     * Check whether to allow an access from the bus master, returning
> +     * an MSCAction indicating the required behaviour. If the transaction
> +     * is blocked, the caller must check cfg_sec_resp to determine
> +     * whether to abort or RAZ/WI the transaction.
> +     */
> +    IDAUInterfaceClass *iic = IDAU_INTERFACE_GET_CLASS(s->idau);
> +    IDAUInterface *ii = IDAU_INTERFACE(s->idau);
> +    bool idau_exempt = false, idau_ns = true, idau_nsc = true;
> +    int idau_region = IREGION_NOTVALID;
> +
> +    iic->check(ii, addr, &idau_region, &idau_exempt, &idau_ns, &idau_nsc);
> +
> +    if (idau_exempt) {
> +        /*
> +         * Uncheck region -- OK, transaction type depends on
> +         * whether bus master is configured as Secure or NonSecure
> +         */
> +        return s->cfg_nonsec ? MSCAllowNonSecure : MSCAllowSecure;
> +    }
> +
> +    if (idau_ns) {
> +        /* NonSecure region -- always forward as NS transaction */
> +        return MSCAllowNonSecure;
> +    }
> +
> +    if (!s->cfg_nonsec) {
> +        /* Access to Secure region by Secure bus master: OK */
> +        return MSCAllowSecure;
> +    }
> +
> +    /* Attempted access to Secure region by NS bus master: block */
> +    trace_tz_msc_access_blocked(addr);
> +    if (!s->cfg_sec_resp) {
> +        return MSCBlockRAZWI;
> +    }
> +
> +    /*
> +     * The TRM isn't clear on behaviour if irq_clear is high when a
> +     * transaction is blocked. We assume that the MSC behaves like the
> +     * PPC, where holding irq_clear high suppresses the interrupt.
> +     */
> +    if (!s->irq_clear) {
> +        s->irq_status = true;
> +        tz_msc_update_irq(s);
> +    }
> +    return MSCBlockAbort;
> +}
> +
> +static MemTxResult tz_msc_read(void *opaque, hwaddr addr, uint64_t *pdata,
> +                               unsigned size, MemTxAttrs attrs)
> +{
> +    TZMSC *s = opaque;
> +    AddressSpace *as = &s->downstream_as;
> +    uint64_t data;
> +    MemTxResult res;
> +
> +    switch (tz_msc_check(s, addr)) {
> +    case MSCBlockAbort:
> +        return MEMTX_ERROR;
> +    case MSCBlockRAZWI:
> +        *pdata = 0;
> +        return MEMTX_OK;
> +    case MSCAllowSecure:
> +        attrs.secure = 1;
> +        attrs.unspecified = 0;
> +        break;
> +    case MSCAllowNonSecure:
> +        attrs.secure = 0;
> +        attrs.unspecified = 0;
> +        break;
> +    }
> +
> +    switch (size) {
> +    case 1:
> +        data = address_space_ldub(as, addr, attrs, &res);
> +        break;
> +    case 2:
> +        data = address_space_lduw_le(as, addr, attrs, &res);
> +        break;
> +    case 4:
> +        data = address_space_ldl_le(as, addr, attrs, &res);
> +        break;
> +    case 8:
> +        data = address_space_ldq_le(as, addr, attrs, &res);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +    *pdata = data;
> +    return res;
> +}
> +
> +static MemTxResult tz_msc_write(void *opaque, hwaddr addr, uint64_t val,
> +                                unsigned size, MemTxAttrs attrs)
> +{
> +    TZMSC *s = opaque;
> +    AddressSpace *as = &s->downstream_as;
> +    MemTxResult res;
> +
> +    switch (tz_msc_check(s, addr)) {
> +    case MSCBlockAbort:
> +        return MEMTX_ERROR;
> +    case MSCBlockRAZWI:
> +        return MEMTX_OK;
> +    case MSCAllowSecure:
> +        attrs.secure = 1;
> +        attrs.unspecified = 0;
> +        break;
> +    case MSCAllowNonSecure:
> +        attrs.secure = 0;
> +        attrs.unspecified = 0;
> +        break;
> +    }
> +
> +    switch (size) {
> +    case 1:
> +        address_space_stb(as, addr, val, attrs, &res);
> +        break;
> +    case 2:
> +        address_space_stw_le(as, addr, val, attrs, &res);
> +        break;
> +    case 4:
> +        address_space_stl_le(as, addr, val, attrs, &res);
> +        break;
> +    case 8:
> +        address_space_stq_le(as, addr, val, attrs, &res);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +    return res;
> +}
> +
> +static const MemoryRegionOps tz_msc_ops = {
> +    .read_with_attrs = tz_msc_read,
> +    .write_with_attrs = tz_msc_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void tz_msc_reset(DeviceState *dev)
> +{
> +    TZMSC *s = TZ_MSC(dev);
> +
> +    trace_tz_msc_reset();
> +    s->cfg_sec_resp = false;
> +    s->cfg_nonsec = false;
> +    s->irq_clear = 0;
> +    s->irq_status = 0;
> +}
> +
> +static void tz_msc_init(Object *obj)
> +{
> +    DeviceState *dev = DEVICE(obj);
> +    TZMSC *s = TZ_MSC(obj);
> +
> +    qdev_init_gpio_in_named(dev, tz_msc_cfg_nonsec, "cfg_nonsec", 1);
> +    qdev_init_gpio_in_named(dev, tz_msc_cfg_sec_resp, "cfg_sec_resp", 1);
> +    qdev_init_gpio_in_named(dev, tz_msc_irq_clear, "irq_clear", 1);
> +    qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
> +}
> +
> +static void tz_msc_realize(DeviceState *dev, Error **errp)
> +{
> +    Object *obj = OBJECT(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    TZMSC *s = TZ_MSC(dev);
> +    const char *name = "tz-msc-downstream";
> +    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, "MSC 'downstream' link not set");
> +        return;
> +    }
> +    if (!s->idau) {
> +        error_setg(errp, "MSC 'idau' link not set");
> +        return;
> +    }
> +
> +    size = memory_region_size(s->downstream);
> +    address_space_init(&s->downstream_as, s->downstream, name);
> +    memory_region_init_io(&s->upstream, obj, &tz_msc_ops, s, name, size);
> +    sysbus_init_mmio(sbd, &s->upstream);
> +}
> +
> +static const VMStateDescription tz_msc_vmstate = {
> +    .name = "tz-msc",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_BOOL(cfg_nonsec, TZMSC),
> +        VMSTATE_BOOL(cfg_sec_resp, TZMSC),
> +        VMSTATE_BOOL(irq_clear, TZMSC),
> +        VMSTATE_BOOL(irq_status, TZMSC),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property tz_msc_properties[] = {
> +    DEFINE_PROP_LINK("downstream", TZMSC, downstream,
> +                     TYPE_MEMORY_REGION, MemoryRegion *),
> +    DEFINE_PROP_LINK("idau", TZMSC, idau,
> +                     TYPE_IDAU_INTERFACE, IDAUInterface *),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void tz_msc_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = tz_msc_realize;
> +    dc->vmsd = &tz_msc_vmstate;
> +    dc->reset = tz_msc_reset;
> +    dc->props = tz_msc_properties;
> +}
> +
> +static const TypeInfo tz_msc_info = {
> +    .name = TYPE_TZ_MSC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(TZMSC),
> +    .instance_init = tz_msc_init,
> +    .class_init = tz_msc_class_init,
> +};
> +
> +static void tz_msc_register_types(void)
> +{
> +    type_register_static(&tz_msc_info);
> +}
> +
> +type_init(tz_msc_register_types);
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 96fe011e952..5d1a3645dd4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -463,6 +463,8 @@ 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
> +F: hw/misc/tz-msc.c
> +F: include/hw/misc/tz-msc.h
>  
>  ARM cores
>  M: Peter Maydell <peter.maydell@linaro.org>
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index da59b820a4f..1f2ac3b1767 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -111,6 +111,7 @@ CONFIG_MPS2_FPGAIO=y
>  CONFIG_MPS2_SCC=y
>  
>  CONFIG_TZ_MPC=y
> +CONFIG_TZ_MSC=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 83ab58c30f5..f9be1b822e7 100644
> --- a/hw/misc/trace-events
> +++ b/hw/misc/trace-events
> @@ -92,6 +92,15 @@ tz_mpc_mem_blocked_write(uint64_t addr, uint64_t data, unsigned size, bool secur
>  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-msc.c
> +tz_msc_reset(void) "TZ MSC: reset"
> +tz_msc_cfg_nonsec(int level) "TZ MSC: cfg_nonsec = %d"
> +tz_msc_cfg_sec_resp(int level) "TZ MSC: cfg_sec_resp = %d"
> +tz_msc_irq_enable(int level) "TZ MSC: int_enable = %d"
> +tz_msc_irq_clear(int level) "TZ MSC: int_clear = %d"
> +tz_msc_update_irq(int level) "TZ MSC: setting irq line to %d"
> +tz_msc_access_blocked(uint64_t offset) "TZ MSC: offset 0x%" PRIx64 " access blocked"
> +
>  # 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"
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module
  2018-08-09 13:01 ` [Qemu-devel] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module Peter Maydell
@ 2018-08-18  1:27   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  1:27 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, qemu-devel; +Cc: patches

On 08/09/2018 10:01 AM, Peter Maydell wrote:
> The Arm Cortex-M System Design Kit includes a simple watchdog module
> based on a 32-bit down-counter. Implement this.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  Makefile.objs                            |   1 +
>  hw/watchdog/Makefile.objs                |   1 +
>  include/hw/watchdog/cmsdk-apb-watchdog.h |  59 ++++
>  hw/watchdog/cmsdk-apb-watchdog.c         | 326 +++++++++++++++++++++++
>  MAINTAINERS                              |   2 +
>  default-configs/arm-softmmu.mak          |   1 +
>  hw/watchdog/trace-events                 |   6 +
>  7 files changed, 396 insertions(+)
>  create mode 100644 include/hw/watchdog/cmsdk-apb-watchdog.h
>  create mode 100644 hw/watchdog/cmsdk-apb-watchdog.c
>  create mode 100644 hw/watchdog/trace-events
> 
> diff --git a/Makefile.objs b/Makefile.objs
> index 7a9828da282..ce9c79235e6 100644
> --- a/Makefile.objs
> +++ b/Makefile.objs
> @@ -240,6 +240,7 @@ trace-events-subdirs += hw/tpm
>  trace-events-subdirs += hw/usb
>  trace-events-subdirs += hw/vfio
>  trace-events-subdirs += hw/virtio
> +trace-events-subdirs += hw/watchdog
>  trace-events-subdirs += hw/xen
>  trace-events-subdirs += io
>  trace-events-subdirs += linux-user
> diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs
> index 9589bed63a3..3f536d1cad8 100644
> --- a/hw/watchdog/Makefile.objs
> +++ b/hw/watchdog/Makefile.objs
> @@ -1,4 +1,5 @@
>  common-obj-y += watchdog.o
> +common-obj-$(CONFIG_CMSDK_APB_WATCHDOG) += cmsdk-apb-watchdog.o
>  common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
>  common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
>  common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
> diff --git a/include/hw/watchdog/cmsdk-apb-watchdog.h b/include/hw/watchdog/cmsdk-apb-watchdog.h
> new file mode 100644
> index 00000000000..ab8b5987a19
> --- /dev/null
> +++ b/include/hw/watchdog/cmsdk-apb-watchdog.h
> @@ -0,0 +1,59 @@
> +/*
> + * ARM CMSDK APB watchdog 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 "APB watchdog" which is part of the Cortex-M
> + * System Design Kit (CMSDK) and documented in the Cortex-M System
> + * Design Kit Technical Reference Manual (ARM DDI0479C):
> + * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
> + *
> + * QEMU interface:
> + *  + QOM property "wdogclk-frq": frequency at which the watchdog is clocked
> + *  + sysbus MMIO region 0: the register bank
> + *  + sysbus IRQ 0: watchdog interrupt
> + *
> + * In real hardware the watchdog's reset output is just a GPIO line
> + * which can then be masked by the board or treated as a simple interrupt.
> + * (For instance the IoTKit does this with the non-secure watchdog, so that
> + * secure code can control whether non-secure code can perform a system
> + * reset via its watchdog.) In QEMU, we just wire up the watchdog reset
> + * to watchdog_perform_action(), at least for the moment.
> + */
> +
> +#ifndef CMSDK_APB_WATCHDOG_H
> +#define CMSDK_APB_WATCHDOG_H
> +
> +#include "hw/sysbus.h"
> +#include "hw/ptimer.h"
> +
> +#define TYPE_CMSDK_APB_WATCHDOG "cmsdk-apb-watchdog"
> +#define CMSDK_APB_WATCHDOG(obj) OBJECT_CHECK(CMSDKAPBWatchdog, (obj), \
> +                                              TYPE_CMSDK_APB_WATCHDOG)
> +
> +typedef struct CMSDKAPBWatchdog {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    MemoryRegion iomem;
> +    qemu_irq wdogint;
> +    uint32_t wdogclk_frq;
> +    struct ptimer_state *timer;
> +
> +    uint32_t control;
> +    uint32_t intstatus;
> +    uint32_t lock;
> +    uint32_t itcr;
> +    uint32_t itop;
> +    uint32_t resetstatus;
> +} CMSDKAPBWatchdog;
> +
> +#endif
> diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c
> new file mode 100644
> index 00000000000..eb79a73fa6c
> --- /dev/null
> +++ b/hw/watchdog/cmsdk-apb-watchdog.c
> @@ -0,0 +1,326 @@
> +/*
> + * ARM CMSDK APB watchdog 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 "APB watchdog" which is part of the Cortex-M
> + * System Design Kit (CMSDK) and documented in the Cortex-M System
> + * Design Kit Technical Reference Manual (ARM DDI0479C):
> + * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "trace.h"
> +#include "qapi/error.h"
> +#include "qemu/main-loop.h"
> +#include "sysemu/watchdog.h"
> +#include "hw/sysbus.h"
> +#include "hw/registerfields.h"
> +#include "hw/watchdog/cmsdk-apb-watchdog.h"
> +
> +REG32(WDOGLOAD, 0x0)
> +REG32(WDOGVALUE, 0x4)
> +REG32(WDOGCONTROL, 0x8)
> +    FIELD(WDOGCONTROL, INTEN, 0, 1)
> +    FIELD(WDOGCONTROL, RESEN, 1, 1)
> +#define R_WDOGCONTROL_VALID_MASK (R_WDOGCONTROL_INTEN_MASK | \
> +                                  R_WDOGCONTROL_RESEN_MASK)

Or:

       FIELD(WDOGCONTROL, VALID, 0, 2)

> +REG32(WDOGINTCLR, 0xc)
> +REG32(WDOGRIS, 0x10)
> +    FIELD(WDOGRIS, INT, 0, 1)
> +REG32(WDOGMIS, 0x14)
> +REG32(WDOGLOCK, 0xc00)
> +#define WDOG_UNLOCK_VALUE 0x1ACCE551
> +REG32(WDOGITCR, 0xf00)
> +    FIELD(WDOGITCR, ENABLE, 0, 1)
> +#define R_WDOGITCR_VALID_MASK R_WDOGITCR_ENABLE_MASK
> +REG32(WDOGITOP, 0xf04)
> +    FIELD(WDOGITOP, WDOGRES, 0, 1)
> +    FIELD(WDOGITOP, WDOGINT, 1, 1)
> +#define R_WDOGITOP_VALID_MASK (R_WDOGITOP_WDOGRES_MASK | \
> +                               R_WDOGITOP_WDOGINT_MASK)
> +REG32(PID4, 0xfd0)
> +REG32(PID5, 0xfd4)
> +REG32(PID6, 0xfd8)
> +REG32(PID7, 0xfdc)
> +REG32(PID0, 0xfe0)
> +REG32(PID1, 0xfe4)
> +REG32(PID2, 0xfe8)
> +REG32(PID3, 0xfec)
> +REG32(CID0, 0xff0)
> +REG32(CID1, 0xff4)
> +REG32(CID2, 0xff8)
> +REG32(CID3, 0xffc)
> +
> +/* PID/CID values */
> +static const int watchdog_id[] = {
> +    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
> +    0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
> +    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
> +};
> +
> +static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s)
> +{
> +    /* Return masked interrupt status */
> +    return s->intstatus && (s->control & R_WDOGCONTROL_INTEN_MASK);
> +}
> +
> +static bool cmsdk_apb_watchdog_resetstatus(CMSDKAPBWatchdog *s)
> +{
> +    /* Return masked reset status */
> +    return s->resetstatus && (s->control & R_WDOGCONTROL_RESEN_MASK);
> +}
> +
> +static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s)
> +{
> +    bool wdogint;
> +    bool wdogres;
> +
> +    if (s->itcr) {
> +        wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK;
> +        wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK;
> +    } else {
> +        wdogint = cmsdk_apb_watchdog_intstatus(s);
> +        wdogres = cmsdk_apb_watchdog_resetstatus(s);
> +    }
> +
> +    qemu_set_irq(s->wdogint, wdogint);
> +    if (wdogres) {
> +        watchdog_perform_action();
> +    }
> +}
> +
> +static uint64_t cmsdk_apb_watchdog_read(void *opaque, hwaddr offset,
> +                                        unsigned size)
> +{
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
> +    uint64_t r;
> +
> +    switch (offset) {
> +    case A_WDOGLOAD:
> +        r = ptimer_get_limit(s->timer);
> +        break;
> +    case A_WDOGVALUE:
> +        r = ptimer_get_count(s->timer);
> +        break;
> +    case A_WDOGCONTROL:
> +        r = s->control;
> +        break;
> +    case A_WDOGRIS:
> +        r = s->intstatus;
> +        break;
> +    case A_WDOGMIS:
> +        r = cmsdk_apb_watchdog_intstatus(s);
> +        break;
> +    case A_WDOGLOCK:
> +        r = s->lock;
> +        break;
> +    case A_WDOGITCR:
> +        r = s->itcr;
> +        break;
> +    case A_PID4 ... A_CID3:
> +        r = watchdog_id[(offset - A_PID4) / 4];
> +        break;
> +    case A_WDOGINTCLR:
> +    case A_WDOGITOP:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "CMSDK APB watchdog read: read of WO offset %x\n",
> +                      (int)offset);
> +        r = 0;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "CMSDK APB watchdog read: bad offset %x\n", (int)offset);
> +        r = 0;
> +        break;
> +    }
> +    trace_cmsdk_apb_watchdog_read(offset, r, size);
> +    return r;
> +}
> +
> +static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
> +                                     uint64_t value, unsigned size)
> +{
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
> +
> +    trace_cmsdk_apb_watchdog_write(offset, value, size);
> +
> +    if (s->lock && offset != A_WDOGLOCK) {
> +        /* Write access is disabled via WDOGLOCK */
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "CMSDK APB watchdog write: write to locked watchdog\n");
> +        return;
> +    }
> +
> +    switch (offset) {
> +    case A_WDOGLOAD:
> +        /*
> +         * Reset the load value and the current count, and make sure
> +         * we're counting.
> +         */
> +        ptimer_set_limit(s->timer, value, 1);
> +        ptimer_run(s->timer, 0);
> +        break;
> +    case A_WDOGCONTROL:
> +        s->control = value & R_WDOGCONTROL_VALID_MASK;
> +        cmsdk_apb_watchdog_update(s);
> +        break;
> +    case A_WDOGINTCLR:
> +        s->intstatus = 0;
> +        ptimer_set_count(s->timer, ptimer_get_limit(s->timer));
> +        cmsdk_apb_watchdog_update(s);
> +        break;
> +    case A_WDOGLOCK:
> +        s->lock = (value != WDOG_UNLOCK_VALUE);
> +        break;
> +    case A_WDOGITCR:
> +        s->itcr = value & R_WDOGITCR_VALID_MASK;
> +        cmsdk_apb_watchdog_update(s);
> +        break;
> +    case A_WDOGITOP:
> +        s->itop = value & R_WDOGITOP_VALID_MASK;
> +        cmsdk_apb_watchdog_update(s);
> +        break;
> +    case A_WDOGVALUE:
> +    case A_WDOGRIS:
> +    case A_WDOGMIS:
> +    case A_PID4 ... A_CID3:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "CMSDK APB watchdog write: write to RO offset 0x%x\n",
> +                      (int)offset);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "CMSDK APB watchdog write: bad offset 0x%x\n",
> +                      (int)offset);
> +        break;
> +    }
> +}
> +
> +static const MemoryRegionOps cmsdk_apb_watchdog_ops = {
> +    .read = cmsdk_apb_watchdog_read,
> +    .write = cmsdk_apb_watchdog_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    /* byte/halfword accesses are just zero-padded on reads and writes */
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 4,
> +};
> +
> +static void cmsdk_apb_watchdog_tick(void *opaque)
> +{
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
> +
> +    if (!s->intstatus) {
> +        /* Count expired for the first time: raise interrupt */
> +        s->intstatus = R_WDOGRIS_INT_MASK;
> +    } else {
> +        /* Count expired for the second time: raise reset and stop clock */
> +        s->resetstatus = 1;
> +        ptimer_stop(s->timer);
> +    }
> +    cmsdk_apb_watchdog_update(s);
> +}
> +
> +static void cmsdk_apb_watchdog_reset(DeviceState *dev)
> +{
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
> +
> +    trace_cmsdk_apb_watchdog_reset();
> +    s->control = 0;
> +    s->intstatus = 0;
> +    s->lock = 0;
> +    s->itcr = 0;
> +    s->itop = 0;
> +    s->resetstatus = 0;
> +    /* Set the limit and the count */
> +    ptimer_set_limit(s->timer, 0xffffffff, 1);
> +    ptimer_run(s->timer, 0);
> +}
> +
> +static void cmsdk_apb_watchdog_init(Object *obj)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
> +
> +    memory_region_init_io(&s->iomem, obj, &cmsdk_apb_watchdog_ops,
> +                          s, "cmsdk-apb-watchdog", 0x1000);
> +    sysbus_init_mmio(sbd, &s->iomem);
> +    sysbus_init_irq(sbd, &s->wdogint);
> +}
> +
> +static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
> +{
> +    CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
> +    QEMUBH *bh;
> +
> +    if (s->wdogclk_frq == 0) {
> +        error_setg(errp,
> +                   "CMSDK APB watchdog: wdogclk-frq property must be set");
> +        return;
> +    }
> +
> +    bh = qemu_bh_new(cmsdk_apb_watchdog_tick, s);
> +    s->timer = ptimer_init(bh,
> +                           PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
> +                           PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
> +                           PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
> +                           PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
> +
> +    ptimer_set_freq(s->timer, s->wdogclk_frq);
> +}
> +
> +static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
> +    .name = "cmsdk-apb-watchdog",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PTIMER(timer, CMSDKAPBWatchdog),
> +        VMSTATE_UINT32(control, CMSDKAPBWatchdog),
> +        VMSTATE_UINT32(intstatus, CMSDKAPBWatchdog),
> +        VMSTATE_UINT32(lock, CMSDKAPBWatchdog),
> +        VMSTATE_UINT32(itcr, CMSDKAPBWatchdog),
> +        VMSTATE_UINT32(itop, CMSDKAPBWatchdog),
> +        VMSTATE_UINT32(resetstatus, CMSDKAPBWatchdog),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property cmsdk_apb_watchdog_properties[] = {
> +    DEFINE_PROP_UINT32("wdogclk-frq", CMSDKAPBWatchdog, wdogclk_frq, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = cmsdk_apb_watchdog_realize;
> +    dc->vmsd = &cmsdk_apb_watchdog_vmstate;
> +    dc->reset = cmsdk_apb_watchdog_reset;
> +    dc->props = cmsdk_apb_watchdog_properties;
> +}
> +
> +static const TypeInfo cmsdk_apb_watchdog_info = {
> +    .name = TYPE_CMSDK_APB_WATCHDOG,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(CMSDKAPBWatchdog),
> +    .instance_init = cmsdk_apb_watchdog_init,
> +    .class_init = cmsdk_apb_watchdog_class_init,
> +};
> +
> +static void cmsdk_apb_watchdog_register_types(void)
> +{
> +    type_register_static(&cmsdk_apb_watchdog_info);
> +}
> +
> +type_init(cmsdk_apb_watchdog_register_types);
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2c1a55ca207..7ea39c0176b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -457,6 +457,8 @@ F: hw/timer/cmsdk-apb-dualtimer.c
>  F: include/hw/timer/cmsdk-apb-dualtimer.h
>  F: hw/char/cmsdk-apb-uart.c
>  F: include/hw/char/cmsdk-apb-uart.h
> +F: hw/watchdog/cmsdk-apb-watchdog.c
> +F: include/hw/watchdog/cmsdk-apb-watchdog.h
>  F: hw/misc/tz-ppc.c
>  F: include/hw/misc/tz-ppc.h
>  F: hw/misc/tz-mpc.c
> diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
> index 046e8903839..521c3d459fa 100644
> --- a/default-configs/arm-softmmu.mak
> +++ b/default-configs/arm-softmmu.mak
> @@ -105,6 +105,7 @@ CONFIG_STM32F205_SOC=y
>  CONFIG_CMSDK_APB_TIMER=y
>  CONFIG_CMSDK_APB_DUALTIMER=y
>  CONFIG_CMSDK_APB_UART=y
> +CONFIG_CMSDK_APB_WATCHDOG=y
>  
>  CONFIG_MPS2_FPGAIO=y
>  CONFIG_MPS2_SCC=y
> diff --git a/hw/watchdog/trace-events b/hw/watchdog/trace-events
> new file mode 100644
> index 00000000000..fee95847df0
> --- /dev/null
> +++ b/hw/watchdog/trace-events
> @@ -0,0 +1,6 @@
> +# See docs/devel/tracing.txt for syntax documentation.
> +
> +# hw/char/cmsdk_apb_watchdog.c
> +cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
> +cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
> +cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset"
> 

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA
  2018-08-16 18:02 ` [Qemu-devel] [Qemu-arm] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
@ 2018-08-18  1:29   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18  1:29 UTC (permalink / raw)
  To: Peter Maydell, qemu-arm, QEMU Developers; +Cc: patches

On 08/16/2018 03:02 PM, Peter Maydell wrote:
> Ping for code review, please?

I let patch #7 for someone else (or later) and few comments before
adding R-b for the rest.

> 
> (It's only been a week so this is a little bit eager, but
> I have some more MPS patches which wire up the PL022 SPI
> controllers, which I'm holding off on posting until this
> and the preceding FPGAIO set get reviewed and committed, so
> as not to have too many MPS patches in flight at once.)
> 
> thanks
> -- PMM
> 
> On 9 August 2018 at 14:00, Peter Maydell <peter.maydell@linaro.org> wrote:
>> This patchset adds some more missing devices to the MPS2 AN505
>> board model:
>>
>> Patches 1-3 implement and wire up the CMSDK APB watchdog devices.
>>
>> Patch 4 adds a CMSDK timer device that had been forgotten.
>>
>> Ppatches 5-6 implement and wire up the "system control element",
>> which is some simple control/ID registers in the IoTKit
>>
>> Patches 7-16 are the meat of the patchset, and add support
>> for the DMA controllers and their associated Master Security
>> Controllers. A TrustZone MSC sits in front of a device which
>> can be a bus master (such as a DMA controller) and allows secure
>> software to configure it to either pass through or reject transactions
>> made by that bus master. 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 AN505 has four
>> PL081 DMA controllers, each with its own MSC.
>>
>> Patches 10-15 are various minor cleanups and bugfixes in
>> the PL081 model that are needed for its use in the AN505.
>> In particular the PL081 was previously entirely broken as
>> it would hw_error() as soon as the guest enabled the DMA
>> engine. I assume this was either accidentally left-in debug code,
>> or a deliberate choice to guard a never-tested implementation
>> so as to be able to identify when we had guest code to test it
>> with. (Linux for the realview/versatile boards never tries to
>> use the PL08x there for DMA.)
>>
>> This patchset is sufficient for the "DMA" test in the AN505
>> self-test binary to pass. (I suspect it is not giving the
>> PL081 or MSC a very thorough workout, though.)
>>
>> Based-on: <20180730162458.23186-1-peter.maydell@linaro.org>
>> ("[PATCH 0/5] mps2: Implement FPGAIO counters and dual-timer")
>>
>> thanks
>> -- PMM
>>
>> Peter Maydell (16):
>>   hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module
>>   nvic: Expose NMI line
>>   hw/arm/iotkit: Wire up the watchdogs
>>   hw/arm/iotkit: Wire up the S32KTIMER
>>   hw/misc/iotkit-sysctl: Implement IoTKit system control element
>>   hw/misc/iotkit: Wire up the system control element
>>   hw/misc/tz-msc: Model TrustZone Master Security Controller
>>   hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
>>   hw/arm/iotkit: Wire up the lines for MSCs
>>   hw/dma/pl080: Allow use as embedded-struct device
>>   hw/dma/pl080: Support all three interrupt lines
>>   hw/dma/pl080: Don't use CPU address space for DMA accesses
>>   hw/dma/pl080: Provide device reset function
>>   hw/dma/pl080: Correct bug in register address decode logic
>>   hw/dma/pl080: Remove hw_error() if DMA is enabled
>>   hw/arm/mps2-tz: Create PL081s and MSCs
>>
>>  Makefile.objs                            |   1 +
>>  hw/misc/Makefile.objs                    |   2 +
>>  hw/watchdog/Makefile.objs                |   1 +
>>  include/hw/arm/iotkit.h                  |  20 +-
>>  include/hw/dma/pl080.h                   |  71 +++++
>>  include/hw/misc/iotkit-secctl.h          |  14 +
>>  include/hw/misc/iotkit-sysctl.h          |  50 ++++
>>  include/hw/misc/tz-msc.h                 |  79 ++++++
>>  include/hw/watchdog/cmsdk-apb-watchdog.h |  59 ++++
>>  hw/arm/armv7m.c                          |   1 +
>>  hw/arm/iotkit.c                          |  99 ++++++-
>>  hw/arm/mps2-tz.c                         | 101 ++++++-
>>  hw/arm/realview.c                        |   8 +-
>>  hw/arm/versatilepb.c                     |   9 +-
>>  hw/dma/pl080.c                           | 113 ++++----
>>  hw/intc/armv7m_nvic.c                    |  19 ++
>>  hw/misc/iotkit-secctl.c                  |  73 ++++-
>>  hw/misc/iotkit-sysctl.c                  | 324 ++++++++++++++++++++++
>>  hw/misc/tz-msc.c                         | 308 +++++++++++++++++++++
>>  hw/watchdog/cmsdk-apb-watchdog.c         | 326 +++++++++++++++++++++++
>>  MAINTAINERS                              |   7 +
>>  default-configs/arm-softmmu.mak          |   3 +
>>  hw/intc/trace-events                     |   1 +
>>  hw/misc/trace-events                     |  16 ++
>>  hw/watchdog/trace-events                 |   6 +
>>  25 files changed, 1632 insertions(+), 79 deletions(-)
>>  create mode 100644 include/hw/dma/pl080.h
>>  create mode 100644 include/hw/misc/iotkit-sysctl.h
>>  create mode 100644 include/hw/misc/tz-msc.h
>>  create mode 100644 include/hw/watchdog/cmsdk-apb-watchdog.h
>>  create mode 100644 hw/misc/iotkit-sysctl.c
>>  create mode 100644 hw/misc/tz-msc.c
>>  create mode 100644 hw/watchdog/cmsdk-apb-watchdog.c
>>  create mode 100644 hw/watchdog/trace-events
>>
>> --
>> 2.17.1
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 06/16] hw/misc/iotkit: Wire up the system control element
  2018-08-18  0:00   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
@ 2018-08-18  9:55     ` Peter Maydell
  2018-08-18 15:06       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-18  9:55 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: qemu-arm, QEMU Developers, patches

On 18 August 2018 at 01:00, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> Hi Peter,
>
> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>> Wire up the system control element's register banks.
>>
>> This is the last of the previously completely unimplemented
>> components in the IoTKit.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  include/hw/arm/iotkit.h |  4 +++-
>>  hw/arm/iotkit.c         | 19 +++++++++++--------
>>  2 files changed, 14 insertions(+), 9 deletions(-)
>>
>> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
>> index 0f5c5101708..1ffa31d521b 100644
>> --- a/include/hw/arm/iotkit.h
>> +++ b/include/hw/arm/iotkit.h
>> @@ -58,7 +58,7 @@
>>  #include "hw/timer/cmsdk-apb-timer.h"
>>  #include "hw/timer/cmsdk-apb-dualtimer.h"
>>  #include "hw/watchdog/cmsdk-apb-watchdog.h"
>> -#include "hw/misc/unimp.h"
>> +#include "hw/misc/iotkit-sysctl.h"
>>  #include "hw/or-irq.h"
>>  #include "hw/core/split-irq.h"
>>
>> @@ -97,6 +97,8 @@ typedef struct IoTKit {
>>      CMSDKAPBWatchdog nswatchdog;
>>      CMSDKAPBWatchdog swatchdog;
>>
>> +    IoTKitSysCtl sysctl;
>> +
>>      MemoryRegion container;
>>      MemoryRegion alias1;
>>      MemoryRegion alias2;
>> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
>> index cb0ec456f39..5d59ed5489f 100644
>> --- a/hw/arm/iotkit.c
>> +++ b/hw/arm/iotkit.c
>> @@ -16,7 +16,6 @@
>>  #include "hw/sysbus.h"
>>  #include "hw/registerfields.h"
>>  #include "hw/arm/iotkit.h"
>> -#include "hw/misc/unimp.h"
>>  #include "hw/arm/arm.h"
>>
>>  /* Clock frequency in HZ of the 32KHz "slow clock" */
>> @@ -151,6 +150,8 @@ static void iotkit_init(Object *obj)
>>                            sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
>>      sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
>>                            sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
>> +    sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl, sizeof(s->sysctl),
>> +                          TYPE_IOTKIT_SYSCTL);
>>      object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
>>                              sizeof(s->nmi_orgate), TYPE_OR_IRQ,
>>                              &error_abort, NULL);
>> @@ -516,13 +517,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>>                            qdev_get_gpio_in_named(dev_apb_ppc1,
>>                                                   "cfg_sec_resp", 0));
>>
>> -    /* Using create_unimplemented_device() maps the stub into the
>> -     * system address space rather than into our container, but the
>> -     * overall effect to the guest is the same.
>> -     */
>> -    create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
>> -
>> -    create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
>> +    object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
>> +    if (err) {
>> +        error_propagate(errp, err);
>> +        return;
>> +    }
>> +    /* System information registers */
>> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x40020000);
>
> What about the Secure access?
>
>        sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50020000);

That should be handled by the general alias set up earlier
    make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
which maps all of the 0x5... space to 0x4... if there's nothing
higher priority mapped there.


thanks
-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element
  2018-08-18  0:23   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
@ 2018-08-18 10:04     ` Peter Maydell
  2018-08-18 19:54       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-18 10:04 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: qemu-arm, QEMU Developers, patches

On 18 August 2018 at 01:23, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> Hi Peter,
>
> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>> The Arm IoTKit includes a system control element which
>> provides a block of read-only ID registers and a block
>> of read-write control registers. Implement a minimal
>> version of this.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/misc/Makefile.objs           |   1 +
>>  include/hw/misc/iotkit-sysctl.h |  50 +++++
>>  hw/misc/iotkit-sysctl.c         | 324 ++++++++++++++++++++++++++++++++
>>  MAINTAINERS                     |   2 +
>>  default-configs/arm-softmmu.mak |   1 +
>>  hw/misc/trace-events            |   7 +
>>  6 files changed, 385 insertions(+)
>>  create mode 100644 include/hw/misc/iotkit-sysctl.h
>>  create mode 100644 hw/misc/iotkit-sysctl.c
>>
>> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
>> index 93509008451..dbadb41d57a 100644
>> --- a/hw/misc/Makefile.objs
>> +++ b/hw/misc/Makefile.objs
>> @@ -65,6 +65,7 @@ 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
>> +obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
>>
>>  obj-$(CONFIG_PVPANIC) += pvpanic.o
>>  obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
>> diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
>> new file mode 100644
>> index 00000000000..c3b14ccee4c
>> --- /dev/null
>> +++ b/include/hw/misc/iotkit-sysctl.h
>> @@ -0,0 +1,50 @@
>> +/*
>> + * ARM IoTKit system control element
>> + *
>> + * 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 "system control element" which is part of the
>> + * Arm IoTKit and documented in
>> + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
>> + * Specifically, it implements the "system information block" and
>> + * "system control register" blocks.
>> + *
>> + * QEMU interface:
>> + *  + sysbus MMIO region 0: the system information register bank
>> + *  + sysbus MMIO region 1: the system control register bank
>> + */
>> +
>> +#ifndef HW_MISC_IOTKIT_SYSCTL_H
>> +#define HW_MISC_IOTKIT_SYSCTL_H
>> +
>> +#include "hw/sysbus.h"
>> +
>> +#define TYPE_IOTKIT_SYSCTL "iotkit-sysctl"
>> +#define IOTKIT_SYSCTL(obj) OBJECT_CHECK(IoTKitSysCtl, (obj), \
>> +                                        TYPE_IOTKIT_SYSCTL)
>> +
>> +typedef struct IoTKitSysCtl {
>> +    /*< private >*/
>> +    SysBusDevice parent_obj;
>> +
>> +    /*< public >*/
>> +    MemoryRegion sysinfo_iomem;
>> +    MemoryRegion sysctl_iomem;
>> +
>> +    uint32_t secure_debug;
>> +    uint32_t reset_syndrome;
>> +    uint32_t reset_mask;
>> +    uint32_t gretreg;
>> +    uint32_t initsvrtor0;
>> +    uint32_t cpuwait;
>> +    uint32_t wicctrl;
>> +} IoTKitSysCtl;
>> +
>> +#endif
>> diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
>> new file mode 100644
>> index 00000000000..9445500be76
>> --- /dev/null
>> +++ b/hw/misc/iotkit-sysctl.c
>> @@ -0,0 +1,324 @@
>> +/*
>> + * ARM IoTKit system control element
>> + *
>> + * 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 "system control element" which is part of the
>> + * Arm IoTKit and documented in
>> + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
>> + * Specifically, it implements the "system information block" and
>> + * "system control register" blocks.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu/log.h"
>> +#include "trace.h"
>> +#include "qapi/error.h"
>> +#include "sysemu/sysemu.h"
>> +#include "hw/sysbus.h"
>> +#include "hw/registerfields.h"
>> +#include "hw/misc/iotkit-sysctl.h"
>> +
>> +/* sysinfo block registers */
>> +REG32(SYS_VERSION, 0x0)
>> +REG32(SYS_CONFIG, 0x4)
>
> I find it a bit confuse to have the both SYSINFO/SYSCONTROL in the same
> "iotkit-sysctl" device. They share the same state but there is no
> particular need for it, then you need connect them as 2 different
> devices in iotkit_realize but they have the same name "iotkit-sysctl".
>
> Why not declare 2 different TypeInfo? I am probably missing what state
> they need to share.

You're right, they don't share anything internally. It just
seemed a bit unnecessary to have a device that implements
2 read-only registers and nothing else. It probably is better
to split them up, though.

>> +    /*
>> +     * Most of the state here has to do with control of reset and
>> +     * similar kinds of power up -- for instance the guest can ask
>> +     * what the reason for the last reset was, or forbid reset for
>> +     * some causes (like the non-secure watchdog). Most of this is
>> +     * not relevant to QEMU, which doesn't really model anything other
>> +     * than a full power-on reset.
>> +     * We just model the registers as reads-as-written.
>> +     */
>> +
>> +    switch (offset) {
>> +    case A_RESET_SYNDROME:
>> +        qemu_log_mask(LOG_UNIMP,
>> +                      "IoTKit SysCtl RESET_SYNDROME unimplemented\n");
>
> Maybe warn_report() or warn_once() is more appropriate than UNIMP?

LOG_UNIMP is what we generally use for warning about accesses
to unimplemented registers.


>> +    case A_SWRESET:
>> +        /* One w/o bit to request a reset; all other bits reserved */
>> +        if (value & R_SWRESET_SWRESETREQ_MASK) {
>> +            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
>> +        }
>
> Shouldn't this be:
>
>            } else {
>                cpu_reset(...);
>            }

Why? The register function is "write 1 to request a system reset".
Writing a zero does nothing.


>> +        break;
>> +    case A_BUSWAIT:        /* In IoTKit BUSWAIT is reserved, R/O, zero */
>> +    case A_SECDBGSTAT:
>> +    case A_PID4 ... A_CID3:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "IoTKit SysCtl write: write of RO offset %x\n",
>> +                      (int)offset);
>> +        break;
>> +    default:
>> +        qemu_log_mask(LOG_GUEST_ERROR,
>> +                      "IoTKit SysCtl write: bad offset %x\n", (int)offset);
>> +        break;
>> +    }
>> +}
>> +
>> +static const MemoryRegionOps iotkit_sysctl_ops = {
>> +    .read = iotkit_sysctl_read,
>> +    .write = iotkit_sysctl_write,
>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>> +    /* byte/halfword accesses are just zero-padded on reads and writes */
>> +    .impl.min_access_size = 4,
>> +    .impl.max_access_size = 4,
>> +    .valid.min_access_size = 1,
>> +    .valid.max_access_size = 4,
>> +};
>> +
>> +static void iotkit_sysctl_reset(DeviceState *dev)
>> +{
>> +    IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
>> +
>> +    trace_iotkit_sysctl_reset();
>> +    s->secure_debug = 0;
>> +    s->reset_syndrome = 1;
>> +    s->reset_mask = 0;
>> +    s->gretreg = 0;
>> +    s->initsvrtor0 = 0x10000000;
>
> This one could be a property (now now ;) ).

It could be, but given that we don't actually support letting
the guest change the SVRTOR reset value on the CPU for the
next reset I think that would be overkill.

>> +    s->cpuwait = 0;
>> +    s->wicctrl = 0;
>> +}

thanks
-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
  2018-08-18  0:37   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
@ 2018-08-18 10:05     ` Peter Maydell
  2018-08-18 15:42       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 45+ messages in thread
From: Peter Maydell @ 2018-08-18 10:05 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: qemu-arm, QEMU Developers, patches

On 18 August 2018 at 01:37, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>> The IoTKit does not have any Master Security Contollers itself,
>> but it does provide registers in the secure privilege control
>> block which allow control of MSCs in the external system.
>> Add support for these registers.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---

>>      case A_SECMSCINTEN:
>> -        qemu_log_mask(LOG_UNIMP,
>> -                      "IoTKit SecCtl S block write: "
>> -                      "unimplemented offset 0x%x\n", offset);
>
> Maybe:
>
>            if (value & ~0xffff) {
>                GUEST_ERROR(...)
>            }

We don't generally bother to log writes of raz bits as errors.


thanks
-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs
  2018-08-18  1:09   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
@ 2018-08-18 10:07     ` Peter Maydell
  0 siblings, 0 replies; 45+ messages in thread
From: Peter Maydell @ 2018-08-18 10:07 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé; +Cc: qemu-arm, QEMU Developers, patches

On 18 August 2018 at 02:09, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>> The AN505 FPGA image includes four PL081 DMA controllers, each
>> of which is gated by a Master Security Controller that allows
>> the guest to prevent a non-secure DMA controller from accessing
>> memory that is used by secure guest code. Create and wire
>> up these devices.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/arm/mps2-tz.c | 101 +++++++++++++++++++++++++++++++++++++++++++----
>>  1 file changed, 94 insertions(+), 7 deletions(-)
>>
>> diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c
>> index 22180c56fb7..7d92bc5fe1c 100644
>> --- a/hw/arm/mps2-tz.c
>> +++ b/hw/arm/mps2-tz.c
>> @@ -45,7 +45,9 @@
>>  #include "hw/misc/mps2-scc.h"
>>  #include "hw/misc/mps2-fpgaio.h"
>>  #include "hw/misc/tz-mpc.h"
>> +#include "hw/misc/tz-msc.h"
>>  #include "hw/arm/iotkit.h"
>> +#include "hw/dma/pl080.h"
>>  #include "hw/devices.h"
>>  #include "net/net.h"
>>  #include "hw/core/split-irq.h"
>> @@ -75,8 +77,9 @@ typedef struct {
>>      UnimplementedDeviceState i2c[4];
>>      UnimplementedDeviceState i2s_audio;
>>      UnimplementedDeviceState gpio[4];
>> -    UnimplementedDeviceState dma[4];
>>      UnimplementedDeviceState gfx;
>> +    PL080State dma[4];
>> +    TZMSC msc[4];
>>      CMSDKAPBUART uart[5];
>>      SplitIRQ sec_resp_splitter;
>>      qemu_or_irq uart_irq_orgate;
>> @@ -273,6 +276,65 @@ static MemoryRegion *make_mpc(MPS2TZMachineState *mms, void *opaque,
>>      return sysbus_mmio_get_region(SYS_BUS_DEVICE(mpc), 0);
>>  }
>>
>> +static MemoryRegion *make_dma(MPS2TZMachineState *mms, void *opaque,
>> +                              const char *name, hwaddr size)
>> +{
>> +    PL080State *dma = opaque;
>> +    int i = dma - &mms->dma[0];
>
> This line is not trivial to read. I wondered "isn't this ptrdiff_t? why
> not divide by sizeof(dma)...

It's following the same approach as the other existing
make_*() functions in this file, though.


>> +    SysBusDevice *s;
>> +    char *mscname = g_strdup_printf("%s-msc", name);
>> +    TZMSC *msc = &mms->msc[i];
>> +    DeviceState *iotkitdev = DEVICE(&mms->iotkit);
>> +    MemoryRegion *msc_upstream;
>> +    MemoryRegion *msc_downstream;
>> +
>> +    /*
>> +     * Each DMA device is a PL081 whose transaction master interface
>> +     * is guarded by a Master Security Controller. The downstream end of
>> +     * the MSC connects to the IoTKit AHB Slave Expansion port, so the
>> +     * DMA devices can see all devices and memory that the CPU does.
>> +     */
>> +    init_sysbus_child(OBJECT(mms), mscname, msc, sizeof(mms->msc[0]),
>
> sizeof(*msc) easier to read?

That would work and probably is better; again I was just following
the same thing I'd done in other make_*() functions earlier.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 06/16] hw/misc/iotkit: Wire up the system control element
  2018-08-18  9:55     ` Peter Maydell
@ 2018-08-18 15:06       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18 15:06 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, QEMU Developers, patches

On 08/18/2018 06:55 AM, Peter Maydell wrote:
> On 18 August 2018 at 01:00, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>> Hi Peter,
>>
>> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>>> Wire up the system control element's register banks.
>>>
>>> This is the last of the previously completely unimplemented
>>> components in the IoTKit.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>>  include/hw/arm/iotkit.h |  4 +++-
>>>  hw/arm/iotkit.c         | 19 +++++++++++--------
>>>  2 files changed, 14 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/include/hw/arm/iotkit.h b/include/hw/arm/iotkit.h
>>> index 0f5c5101708..1ffa31d521b 100644
>>> --- a/include/hw/arm/iotkit.h
>>> +++ b/include/hw/arm/iotkit.h
>>> @@ -58,7 +58,7 @@
>>>  #include "hw/timer/cmsdk-apb-timer.h"
>>>  #include "hw/timer/cmsdk-apb-dualtimer.h"
>>>  #include "hw/watchdog/cmsdk-apb-watchdog.h"
>>> -#include "hw/misc/unimp.h"
>>> +#include "hw/misc/iotkit-sysctl.h"
>>>  #include "hw/or-irq.h"
>>>  #include "hw/core/split-irq.h"
>>>
>>> @@ -97,6 +97,8 @@ typedef struct IoTKit {
>>>      CMSDKAPBWatchdog nswatchdog;
>>>      CMSDKAPBWatchdog swatchdog;
>>>
>>> +    IoTKitSysCtl sysctl;
>>> +
>>>      MemoryRegion container;
>>>      MemoryRegion alias1;
>>>      MemoryRegion alias2;
>>> diff --git a/hw/arm/iotkit.c b/hw/arm/iotkit.c
>>> index cb0ec456f39..5d59ed5489f 100644
>>> --- a/hw/arm/iotkit.c
>>> +++ b/hw/arm/iotkit.c
>>> @@ -16,7 +16,6 @@
>>>  #include "hw/sysbus.h"
>>>  #include "hw/registerfields.h"
>>>  #include "hw/arm/iotkit.h"
>>> -#include "hw/misc/unimp.h"
>>>  #include "hw/arm/arm.h"
>>>
>>>  /* Clock frequency in HZ of the 32KHz "slow clock" */
>>> @@ -151,6 +150,8 @@ static void iotkit_init(Object *obj)
>>>                            sizeof(s->nswatchdog), TYPE_CMSDK_APB_WATCHDOG);
>>>      sysbus_init_child_obj(obj, "swatchdog", &s->swatchdog,
>>>                            sizeof(s->swatchdog), TYPE_CMSDK_APB_WATCHDOG);
>>> +    sysbus_init_child_obj(obj, "iotkit-sysctl", &s->sysctl, sizeof(s->sysctl),
>>> +                          TYPE_IOTKIT_SYSCTL);
>>>      object_initialize_child(obj, "nmi-orgate", &s->nmi_orgate,
>>>                              sizeof(s->nmi_orgate), TYPE_OR_IRQ,
>>>                              &error_abort, NULL);
>>> @@ -516,13 +517,15 @@ static void iotkit_realize(DeviceState *dev, Error **errp)
>>>                            qdev_get_gpio_in_named(dev_apb_ppc1,
>>>                                                   "cfg_sec_resp", 0));
>>>
>>> -    /* Using create_unimplemented_device() maps the stub into the
>>> -     * system address space rather than into our container, but the
>>> -     * overall effect to the guest is the same.
>>> -     */
>>> -    create_unimplemented_device("SYSINFO", 0x40020000, 0x1000);
>>> -
>>> -    create_unimplemented_device("SYSCONTROL", 0x50021000, 0x1000);
>>> +    object_property_set_bool(OBJECT(&s->sysctl), true, "realized", &err);
>>> +    if (err) {
>>> +        error_propagate(errp, err);
>>> +        return;
>>> +    }
>>> +    /* System information registers */
>>> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x40020000);
>>
>> What about the Secure access?
>>
>>        sysbus_mmio_map(SYS_BUS_DEVICE(&s->sysctl), 0, 0x50020000);
> 
> That should be handled by the general alias set up earlier
>     make_alias(s, &s->alias3, "alias 3", 0x50000000, 0x10000000, 0x40000000);
> which maps all of the 0x5... space to 0x4... if there's nothing
> higher priority mapped there.

Oh I missed that! Perfect then :)

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs
  2018-08-18 10:05     ` Peter Maydell
@ 2018-08-18 15:42       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18 15:42 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, QEMU Developers, patches

On 08/18/2018 07:05 AM, Peter Maydell wrote:
> On 18 August 2018 at 01:37, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>>> The IoTKit does not have any Master Security Contollers itself,
>>> but it does provide registers in the secure privilege control
>>> block which allow control of MSCs in the external system.
>>> Add support for these registers.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
> 
>>>      case A_SECMSCINTEN:
>>> -        qemu_log_mask(LOG_UNIMP,
>>> -                      "IoTKit SecCtl S block write: "
>>> -                      "unimplemented offset 0x%x\n", offset);
>>
>> Maybe:
>>
>>            if (value & ~0xffff) {
>>                GUEST_ERROR(...)
>>            }
> 
> We don't generally bother to log writes of raz bits as errors.

Yes I know, and this shouldn't make sens for an well publicly documented
device/board as this IoT Kit.

But you would be surprised by some proprietary firmwares or libraries
provided by some companies...
I have been surprised modeling the Hercules TMS570 series from TI, they
provide a datasheet with the register/bits for the embedded Flash
(F021), and a library/API to access this flash, however when I ran
firmwares linked with their flash library I noticed they access
undocumented bits to restrict^H^H^H^H^configure their flash, and I had
to model those undocumented bits to allow the firmware to continue
further and boot.

So not needed for this model, but it may be sometime useful ;)

Regards,

Phil.

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [Qemu-devel] [Qemu-arm] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element
  2018-08-18 10:04     ` Peter Maydell
@ 2018-08-18 19:54       ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 45+ messages in thread
From: Philippe Mathieu-Daudé @ 2018-08-18 19:54 UTC (permalink / raw)
  To: Peter Maydell; +Cc: qemu-arm, QEMU Developers, patches

On 08/18/2018 07:04 AM, Peter Maydell wrote:
> On 18 August 2018 at 01:23, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>> Hi Peter,
>>
>> On 08/09/2018 10:01 AM, Peter Maydell wrote:
>>> The Arm IoTKit includes a system control element which
>>> provides a block of read-only ID registers and a block
>>> of read-write control registers. Implement a minimal
>>> version of this.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>>  hw/misc/Makefile.objs           |   1 +
>>>  include/hw/misc/iotkit-sysctl.h |  50 +++++
>>>  hw/misc/iotkit-sysctl.c         | 324 ++++++++++++++++++++++++++++++++
>>>  MAINTAINERS                     |   2 +
>>>  default-configs/arm-softmmu.mak |   1 +
>>>  hw/misc/trace-events            |   7 +
>>>  6 files changed, 385 insertions(+)
>>>  create mode 100644 include/hw/misc/iotkit-sysctl.h
>>>  create mode 100644 hw/misc/iotkit-sysctl.c
>>>
>>> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
>>> index 93509008451..dbadb41d57a 100644
>>> --- a/hw/misc/Makefile.objs
>>> +++ b/hw/misc/Makefile.objs
>>> @@ -65,6 +65,7 @@ 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
>>> +obj-$(CONFIG_IOTKIT_SYSCTL) += iotkit-sysctl.o
>>>
>>>  obj-$(CONFIG_PVPANIC) += pvpanic.o
>>>  obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
>>> diff --git a/include/hw/misc/iotkit-sysctl.h b/include/hw/misc/iotkit-sysctl.h
>>> new file mode 100644
>>> index 00000000000..c3b14ccee4c
>>> --- /dev/null
>>> +++ b/include/hw/misc/iotkit-sysctl.h
>>> @@ -0,0 +1,50 @@
>>> +/*
>>> + * ARM IoTKit system control element
>>> + *
>>> + * 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 "system control element" which is part of the
>>> + * Arm IoTKit and documented in
>>> + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
>>> + * Specifically, it implements the "system information block" and
>>> + * "system control register" blocks.
>>> + *
>>> + * QEMU interface:
>>> + *  + sysbus MMIO region 0: the system information register bank
>>> + *  + sysbus MMIO region 1: the system control register bank
>>> + */
>>> +
>>> +#ifndef HW_MISC_IOTKIT_SYSCTL_H
>>> +#define HW_MISC_IOTKIT_SYSCTL_H
>>> +
>>> +#include "hw/sysbus.h"
>>> +
>>> +#define TYPE_IOTKIT_SYSCTL "iotkit-sysctl"
>>> +#define IOTKIT_SYSCTL(obj) OBJECT_CHECK(IoTKitSysCtl, (obj), \
>>> +                                        TYPE_IOTKIT_SYSCTL)
>>> +
>>> +typedef struct IoTKitSysCtl {
>>> +    /*< private >*/
>>> +    SysBusDevice parent_obj;
>>> +
>>> +    /*< public >*/
>>> +    MemoryRegion sysinfo_iomem;
>>> +    MemoryRegion sysctl_iomem;
>>> +
>>> +    uint32_t secure_debug;
>>> +    uint32_t reset_syndrome;
>>> +    uint32_t reset_mask;
>>> +    uint32_t gretreg;
>>> +    uint32_t initsvrtor0;
>>> +    uint32_t cpuwait;
>>> +    uint32_t wicctrl;
>>> +} IoTKitSysCtl;
>>> +
>>> +#endif
>>> diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c
>>> new file mode 100644
>>> index 00000000000..9445500be76
>>> --- /dev/null
>>> +++ b/hw/misc/iotkit-sysctl.c
>>> @@ -0,0 +1,324 @@
>>> +/*
>>> + * ARM IoTKit system control element
>>> + *
>>> + * 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 "system control element" which is part of the
>>> + * Arm IoTKit and documented in
>>> + * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ecm0601256/index.html
>>> + * Specifically, it implements the "system information block" and
>>> + * "system control register" blocks.
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "qemu/log.h"
>>> +#include "trace.h"
>>> +#include "qapi/error.h"
>>> +#include "sysemu/sysemu.h"
>>> +#include "hw/sysbus.h"
>>> +#include "hw/registerfields.h"
>>> +#include "hw/misc/iotkit-sysctl.h"
>>> +
>>> +/* sysinfo block registers */
>>> +REG32(SYS_VERSION, 0x0)
>>> +REG32(SYS_CONFIG, 0x4)
>>
>> I find it a bit confuse to have the both SYSINFO/SYSCONTROL in the same
>> "iotkit-sysctl" device. They share the same state but there is no
>> particular need for it, then you need connect them as 2 different
>> devices in iotkit_realize but they have the same name "iotkit-sysctl".
>>
>> Why not declare 2 different TypeInfo? I am probably missing what state
>> they need to share.
> 
> You're right, they don't share anything internally. It just
> seemed a bit unnecessary to have a device that implements
> 2 read-only registers and nothing else. It probably is better
> to split them up, though.

Whichever you prefer is fine by me.

>>> +    /*
>>> +     * Most of the state here has to do with control of reset and
>>> +     * similar kinds of power up -- for instance the guest can ask
>>> +     * what the reason for the last reset was, or forbid reset for
>>> +     * some causes (like the non-secure watchdog). Most of this is
>>> +     * not relevant to QEMU, which doesn't really model anything other
>>> +     * than a full power-on reset.
>>> +     * We just model the registers as reads-as-written.
>>> +     */
>>> +
>>> +    switch (offset) {
>>> +    case A_RESET_SYNDROME:
>>> +        qemu_log_mask(LOG_UNIMP,
>>> +                      "IoTKit SysCtl RESET_SYNDROME unimplemented\n");
>>
>> Maybe warn_report() or warn_once() is more appropriate than UNIMP?
> 
> LOG_UNIMP is what we generally use for warning about accesses
> to unimplemented registers.

Hmm yes, but I understand the warn* API as intended for generic user who
could report to the list if this code is hit, and the LOG_UNIMP for QEMU
developer. Often UNIMP logged registers can be ignored in normal flow,
but for this particular case I wonder if it is safe to silently continue
for generic user not using "-d unimp".

>>> +    case A_SWRESET:
>>> +        /* One w/o bit to request a reset; all other bits reserved */
>>> +        if (value & R_SWRESET_SWRESETREQ_MASK) {
>>> +            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
>>> +        }
>>
>> Shouldn't this be:
>>
>>            } else {
>>                cpu_reset(...);
>>            }
> 
> Why? The register function is "write 1 to request a system reset".
> Writing a zero does nothing.

Hmm OK, I misinterpreted the datasheet:

"Software Reset Request. Set to HIGH to request a system reset."
I understood as implicit "Set to LOW to request a software reset."

>>> +        break;
>>> +    case A_BUSWAIT:        /* In IoTKit BUSWAIT is reserved, R/O, zero */
>>> +    case A_SECDBGSTAT:
>>> +    case A_PID4 ... A_CID3:
>>> +        qemu_log_mask(LOG_GUEST_ERROR,
>>> +                      "IoTKit SysCtl write: write of RO offset %x\n",
>>> +                      (int)offset);
>>> +        break;
>>> +    default:
>>> +        qemu_log_mask(LOG_GUEST_ERROR,
>>> +                      "IoTKit SysCtl write: bad offset %x\n", (int)offset);
>>> +        break;
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps iotkit_sysctl_ops = {
>>> +    .read = iotkit_sysctl_read,
>>> +    .write = iotkit_sysctl_write,
>>> +    .endianness = DEVICE_LITTLE_ENDIAN,
>>> +    /* byte/halfword accesses are just zero-padded on reads and writes */
>>> +    .impl.min_access_size = 4,
>>> +    .impl.max_access_size = 4,
>>> +    .valid.min_access_size = 1,
>>> +    .valid.max_access_size = 4,
>>> +};
>>> +
>>> +static void iotkit_sysctl_reset(DeviceState *dev)
>>> +{
>>> +    IoTKitSysCtl *s = IOTKIT_SYSCTL(dev);
>>> +
>>> +    trace_iotkit_sysctl_reset();
>>> +    s->secure_debug = 0;
>>> +    s->reset_syndrome = 1;
>>> +    s->reset_mask = 0;
>>> +    s->gretreg = 0;
>>> +    s->initsvrtor0 = 0x10000000;
>>
>> This one could be a property (now now ;) ).
> 
> It could be, but given that we don't actually support letting
> the guest change the SVRTOR reset value on the CPU for the
> next reset I think that would be overkill.

Sure, not now.

>>> +    s->cpuwait = 0;
>>> +    s->wicctrl = 0;
>>> +}

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2018-08-18 19:55 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-09 13:00 [Qemu-devel] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
2018-08-09 13:01 ` [Qemu-devel] [PATCH 01/16] hw/watchdog/cmsdk_apb_watchdog: Implement CMSDK APB watchdog module Peter Maydell
2018-08-18  1:27   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 02/16] nvic: Expose NMI line Peter Maydell
2018-08-10  5:05   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 03/16] hw/arm/iotkit: Wire up the watchdogs Peter Maydell
2018-08-17 23:47   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 04/16] hw/arm/iotkit: Wire up the S32KTIMER Peter Maydell
2018-08-17 23:49   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 05/16] hw/misc/iotkit-sysctl: Implement IoTKit system control element Peter Maydell
2018-08-18  0:23   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-18 10:04     ` Peter Maydell
2018-08-18 19:54       ` Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 06/16] hw/misc/iotkit: Wire up the " Peter Maydell
2018-08-18  0:00   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-18  9:55     ` Peter Maydell
2018-08-18 15:06       ` Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 07/16] hw/misc/tz-msc: Model TrustZone Master Security Controller Peter Maydell
2018-08-18  1:15   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 08/16] hw/misc/iotkit-secctl: Wire up registers for controlling MSCs Peter Maydell
2018-08-18  0:37   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-18 10:05     ` Peter Maydell
2018-08-18 15:42       ` Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 09/16] hw/arm/iotkit: Wire up the lines for MSCs Peter Maydell
2018-08-18  0:39   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 10/16] hw/dma/pl080: Allow use as embedded-struct device Peter Maydell
2018-08-10  5:18   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-10  5:27     ` Philippe Mathieu-Daudé
2018-08-10  9:03       ` Peter Maydell
2018-08-09 13:01 ` [Qemu-devel] [PATCH 11/16] hw/dma/pl080: Support all three interrupt lines Peter Maydell
2018-08-18  0:43   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 12/16] hw/dma/pl080: Don't use CPU address space for DMA accesses Peter Maydell
2018-08-10  5:10   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 13/16] hw/dma/pl080: Provide device reset function Peter Maydell
2018-08-10  5:11   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 14/16] hw/dma/pl080: Correct bug in register address decode logic Peter Maydell
2018-08-15 14:39   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-15 15:31     ` Peter Maydell
2018-08-09 13:01 ` [Qemu-devel] [PATCH 15/16] hw/dma/pl080: Remove hw_error() if DMA is enabled Peter Maydell
2018-08-10  5:12   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-09 13:01 ` [Qemu-devel] [PATCH 16/16] hw/arm/mps2-tz: Create PL081s and MSCs Peter Maydell
2018-08-18  1:09   ` [Qemu-devel] [Qemu-arm] " Philippe Mathieu-Daudé
2018-08-18 10:07     ` Peter Maydell
2018-08-16 18:02 ` [Qemu-devel] [Qemu-arm] [PATCH 00/16] arm: Implement MPS2 watchdogs and DMA Peter Maydell
2018-08-18  1:29   ` Philippe Mathieu-Daudé

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.