summaryrefslogtreecommitdiffstats
path: root/hw/intc/armv7m_nvic.c
diff options
context:
space:
mode:
authorPeter Maydell2020-11-19 22:55:50 +0100
committerPeter Maydell2020-12-10 12:44:55 +0100
commita724377a11a436e711cd91c817ff6428d7ccb829 (patch)
tree0ed0e634db2fb50daa1fcad15e8c5b069029ebba /hw/intc/armv7m_nvic.c
parenti.MX6ul: Fix bad printf format specifiers (diff)
downloadqemu-a724377a11a436e711cd91c817ff6428d7ccb829.tar.gz
qemu-a724377a11a436e711cd91c817ff6428d7ccb829.tar.xz
qemu-a724377a11a436e711cd91c817ff6428d7ccb829.zip
hw/intc/armv7m_nvic: Make all of system PPB range be RAZWI/BusFault
For M-profile CPUs, the range from 0xe0000000 to 0xe00fffff is the Private Peripheral Bus range, which includes all of the memory mapped devices and registers that are part of the CPU itself, including the NVIC, systick timer, and debug and trace components like the Data Watchpoint and Trace unit (DWT). Within this large region, the range 0xe000e000 to 0xe000efff is the System Control Space (NVIC, system registers, systick) and 0xe002e000 to 0exe002efff is its Non-secure alias. The architecture is clear that within the SCS unimplemented registers should be RES0 for privileged accesses and generate BusFault for unprivileged accesses, and we currently implement this. It is less clear about how to handle accesses to unimplemented regions of the wider PPB. Unprivileged accesses should definitely cause BusFaults (R_DQQS), but the behaviour of privileged accesses is not given as a general rule. However, the register definitions of individual registers for components like the DWT all state that they are RES0 if the relevant component is not implemented, so the simplest way to provide that is to provide RAZ/WI for the whole range for privileged accesses. (The v7M Arm ARM does say that reserved registers should be UNK/SBZP.) Expand the container MemoryRegion that the NVIC exposes so that it covers the whole PPB space. This means: * moving the address that the ARMV7M device maps it to down by 0xe000 bytes * moving the off and the offsets within the container of all the subregions forward by 0xe000 bytes * adding a new default MemoryRegion that covers the whole container at a lower priority than anything else and which provides the RAZWI/BusFault behaviour Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20201119215617.29887-2-peter.maydell@linaro.org
Diffstat (limited to 'hw/intc/armv7m_nvic.c')
-rw-r--r--hw/intc/armv7m_nvic.c78
1 files changed, 67 insertions, 11 deletions
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 42b1ad59e6..9628ce876e 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -2479,6 +2479,43 @@ static const MemoryRegionOps nvic_systick_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
+/*
+ * Unassigned portions of the PPB space are RAZ/WI for privileged
+ * accesses, and fault for non-privileged accesses.
+ */
+static MemTxResult ppb_default_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ qemu_log_mask(LOG_UNIMP, "Read of unassigned area of PPB: offset 0x%x\n",
+ (uint32_t)addr);
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ *data = 0;
+ return MEMTX_OK;
+}
+
+static MemTxResult ppb_default_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ qemu_log_mask(LOG_UNIMP, "Write of unassigned area of PPB: offset 0x%x\n",
+ (uint32_t)addr);
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ return MEMTX_OK;
+}
+
+static const MemoryRegionOps ppb_default_ops = {
+ .read_with_attrs = ppb_default_read,
+ .write_with_attrs = ppb_default_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+};
+
static int nvic_post_load(void *opaque, int version_id)
{
NVICState *s = opaque;
@@ -2675,7 +2712,6 @@ static void nvic_systick_trigger(void *opaque, int n, int level)
static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
{
NVICState *s = NVIC(dev);
- int regionlen;
/* The armv7m container object will have set our CPU pointer */
if (!s->cpu || !arm_feature(&s->cpu->env, ARM_FEATURE_M)) {
@@ -2718,7 +2754,20 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
M_REG_S));
}
- /* The NVIC and System Control Space (SCS) starts at 0xe000e000
+ /*
+ * This device provides a single sysbus memory region which
+ * represents the whole of the "System PPB" space. This is the
+ * range from 0xe0000000 to 0xe00fffff and includes the NVIC,
+ * the System Control Space (system registers), the systick timer,
+ * and for CPUs with the Security extension an NS banked version
+ * of all of these.
+ *
+ * The default behaviour for unimplemented registers/ranges
+ * (for instance the Data Watchpoint and Trace unit at 0xe0001000)
+ * is to RAZ/WI for privileged access and BusFault for non-privileged
+ * access.
+ *
+ * The NVIC and System Control Space (SCS) starts at 0xe000e000
* and looks like this:
* 0x004 - ICTR
* 0x010 - 0xff - systick
@@ -2741,32 +2790,39 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
* generally code determining which banked register to use should
* use attrs.secure; code determining actual behaviour of the system
* should use env->v7m.secure.
+ *
+ * The container covers the whole PPB space. Within it the priority
+ * of overlapping regions is:
+ * - default region (for RAZ/WI and BusFault) : -1
+ * - system register regions : 0
+ * - systick : 1
+ * This is because the systick device is a small block of registers
+ * in the middle of the other system control registers.
*/
- regionlen = arm_feature(&s->cpu->env, ARM_FEATURE_V8) ? 0x21000 : 0x1000;
- memory_region_init(&s->container, OBJECT(s), "nvic", regionlen);
- /* The system register region goes at the bottom of the priority
- * stack as it covers the whole page.
- */
+ memory_region_init(&s->container, OBJECT(s), "nvic", 0x100000);
+ memory_region_init_io(&s->defaultmem, OBJECT(s), &ppb_default_ops, s,
+ "nvic-default", 0x100000);
+ memory_region_add_subregion_overlap(&s->container, 0, &s->defaultmem, -1);
memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s,
"nvic_sysregs", 0x1000);
- memory_region_add_subregion(&s->container, 0, &s->sysregmem);
+ memory_region_add_subregion(&s->container, 0xe000, &s->sysregmem);
memory_region_init_io(&s->systickmem, OBJECT(s),
&nvic_systick_ops, s,
"nvic_systick", 0xe0);
- memory_region_add_subregion_overlap(&s->container, 0x10,
+ memory_region_add_subregion_overlap(&s->container, 0xe010,
&s->systickmem, 1);
if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s),
&nvic_sysreg_ns_ops, &s->sysregmem,
"nvic_sysregs_ns", 0x1000);
- memory_region_add_subregion(&s->container, 0x20000, &s->sysreg_ns_mem);
+ memory_region_add_subregion(&s->container, 0x2e000, &s->sysreg_ns_mem);
memory_region_init_io(&s->systick_ns_mem, OBJECT(s),
&nvic_sysreg_ns_ops, &s->systickmem,
"nvic_systick_ns", 0xe0);
- memory_region_add_subregion_overlap(&s->container, 0x20010,
+ memory_region_add_subregion_overlap(&s->container, 0x2e010,
&s->systick_ns_mem, 1);
}