summaryrefslogtreecommitdiffstats
path: root/hw/arm/armv7m.c
diff options
context:
space:
mode:
authorPeter Maydell2021-08-12 11:33:33 +0200
committerPeter Maydell2021-09-01 12:08:18 +0200
commite36a25cb4759b9cfc122650a720e5a968b370a46 (patch)
tree37a0fe2eb4b71e4751d410c033520f51909a6e09 /hw/arm/armv7m.c
parentarm: Move M-profile RAS register block into its own device (diff)
downloadqemu-e36a25cb4759b9cfc122650a720e5a968b370a46.tar.gz
qemu-e36a25cb4759b9cfc122650a720e5a968b370a46.tar.xz
qemu-e36a25cb4759b9cfc122650a720e5a968b370a46.zip
arm: Move systick device creation from NVIC to ARMv7M object
There's no particular reason why the NVIC should be owning the SysTick device objects; move them into the ARMv7M container object instead, as part of consolidating the "create the devices which are built into an M-profile CPU and map them into their architected locations in the address space" work into one place. This involves temporarily creating a duplicate copy of the nvic_sysreg_ns_ops struct and its read/write functions (renamed as v7m_sysreg_ns_*), but we will delete the NVIC's copy of this code in a subsequent patch. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Acked-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Luc Michel <luc@lmichel.fr> Message-id: 20210812093356.1946-3-peter.maydell@linaro.org
Diffstat (limited to 'hw/arm/armv7m.c')
-rw-r--r--hw/arm/armv7m.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 8964730d15..364ac06970 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -124,6 +124,85 @@ static const hwaddr bitband_output_addr[ARMV7M_NUM_BITBANDS] = {
0x22000000, 0x42000000
};
+static MemTxResult v7m_sysreg_ns_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ MemoryRegion *mr = opaque;
+
+ if (attrs.secure) {
+ /* S accesses to the alias act like NS accesses to the real region */
+ attrs.secure = 0;
+ return memory_region_dispatch_write(mr, addr, value,
+ size_memop(size) | MO_TE, attrs);
+ } else {
+ /* NS attrs are RAZ/WI for privileged, and BusFault for user */
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ return MEMTX_OK;
+ }
+}
+
+static MemTxResult v7m_sysreg_ns_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ MemoryRegion *mr = opaque;
+
+ if (attrs.secure) {
+ /* S accesses to the alias act like NS accesses to the real region */
+ attrs.secure = 0;
+ return memory_region_dispatch_read(mr, addr, data,
+ size_memop(size) | MO_TE, attrs);
+ } else {
+ /* NS attrs are RAZ/WI for privileged, and BusFault for user */
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ *data = 0;
+ return MEMTX_OK;
+ }
+}
+
+static const MemoryRegionOps v7m_sysreg_ns_ops = {
+ .read_with_attrs = v7m_sysreg_ns_read,
+ .write_with_attrs = v7m_sysreg_ns_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static MemTxResult v7m_systick_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ ARMv7MState *s = opaque;
+ MemoryRegion *mr;
+
+ /* Direct the access to the correct systick */
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
+ return memory_region_dispatch_write(mr, addr, value,
+ size_memop(size) | MO_TE, attrs);
+}
+
+static MemTxResult v7m_systick_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ ARMv7MState *s = opaque;
+ MemoryRegion *mr;
+
+ /* Direct the access to the correct systick */
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
+ return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE,
+ attrs);
+}
+
+static const MemoryRegionOps v7m_systick_ops = {
+ .read_with_attrs = v7m_systick_read,
+ .write_with_attrs = v7m_systick_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
static void armv7m_instance_init(Object *obj)
{
ARMv7MState *s = ARMV7M(obj);
@@ -137,6 +216,13 @@ static void armv7m_instance_init(Object *obj)
object_property_add_alias(obj, "num-irq",
OBJECT(&s->nvic), "num-irq");
+ object_initialize_child(obj, "systick-reg-ns", &s->systick[M_REG_NS],
+ TYPE_SYSTICK);
+ /*
+ * We can't initialize the secure systick here, as we don't know
+ * yet if we need it.
+ */
+
for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
object_initialize_child(obj, "bitband[*]", &s->bitband[i],
TYPE_BITBAND);
@@ -231,6 +317,45 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->container, 0xe0000000,
sysbus_mmio_get_region(sbd, 0));
+ /* Create and map the systick devices */
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), errp)) {
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->nvic),
+ "systick-trigger", M_REG_NS));
+
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
+ /*
+ * We couldn't init the secure systick device in instance_init
+ * as we didn't know then if the CPU had the security extensions;
+ * so we have to do it here.
+ */
+ object_initialize_child(OBJECT(dev), "systick-reg-s",
+ &s->systick[M_REG_S], TYPE_SYSTICK);
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), errp)) {
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_S]), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->nvic),
+ "systick-trigger", M_REG_S));
+ }
+
+ memory_region_init_io(&s->systickmem, OBJECT(s),
+ &v7m_systick_ops, s,
+ "v7m_systick", 0xe0);
+
+ memory_region_add_subregion_overlap(&s->container, 0xe000e010,
+ &s->systickmem, 1);
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
+ memory_region_init_io(&s->systick_ns_mem, OBJECT(s),
+ &v7m_sysreg_ns_ops, &s->systickmem,
+ "v7m_systick_ns", 0xe0);
+ memory_region_add_subregion_overlap(&s->container, 0xe002e010,
+ &s->systick_ns_mem, 1);
+ }
+
/* If the CPU has RAS support, create the RAS register block */
if (cpu_isar_feature(aa32_ras, s->cpu)) {
object_initialize_child(OBJECT(dev), "armv7m-ras",