diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/armv7m.c | 100 | ||||
-rw-r--r-- | hw/intc/armv7m_nvic.c | 145 |
2 files changed, 103 insertions, 142 deletions
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 364ac06970..899159f70b 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -18,6 +18,7 @@ #include "sysemu/reset.h" #include "qemu/error-report.h" #include "qemu/module.h" +#include "qemu/log.h" #include "target/arm/idau.h" /* Bitbanded IO. Each word corresponds to a single bit. */ @@ -203,6 +204,43 @@ static const MemoryRegionOps v7m_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 void armv7m_instance_init(Object *obj) { ARMv7MState *s = ARMV7M(obj); @@ -309,13 +347,73 @@ static void armv7m_realize(DeviceState *dev, Error **errp) qdev_pass_gpios(DEVICE(&s->nvic), dev, "SYSRESETREQ"); qdev_pass_gpios(DEVICE(&s->nvic), dev, "NMI"); + /* + * We map various devices into the container MR at their architected + * addresses. In particular, we map everything corresponding to 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 + * 0x100..0x7ec - NVIC + * 0x7f0..0xcff - Reserved + * 0xd00..0xd3c - SCS registers + * 0xd40..0xeff - Reserved or Not implemented + * 0xf00 - STIR + * + * Some registers within this space are banked between security states. + * In v8M there is a second range 0xe002e000..0xe002efff which is the + * NonSecure alias SCS; secure accesses to this behave like NS accesses + * to the main SCS range, and non-secure accesses (including when + * the security extension is not implemented) are RAZ/WI. + * Note that both the main SCS range and the alias range are defined + * to be exempt from memory attribution (R_BLJT) and so the memory + * transaction attribute always matches the current CPU security + * state (attrs.secure == env->v7m.secure). In the v7m_sysreg_ns_ops + * wrappers we change attrs.secure to indicate the NS access; so + * generally code determining which banked register to use should + * use attrs.secure; code determining actual behaviour of the system + * should use env->v7m.secure. + * + * Within the PPB space, some MRs overlap, and the priority + * of overlapping regions is: + * - default region (for RAZ/WI and BusFault) : -1 + * - system register regions (provided by the NVIC) : 0 + * - systick : 1 + * This is because the systick device is a small block of registers + * in the middle of the other system control registers. + */ + + memory_region_init_io(&s->defaultmem, OBJECT(s), &ppb_default_ops, s, + "nvic-default", 0x100000); + memory_region_add_subregion_overlap(&s->container, 0xe0000000, + &s->defaultmem, -1); + /* Wire the NVIC up to the CPU */ sbd = SYS_BUS_DEVICE(&s->nvic); sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); - memory_region_add_subregion(&s->container, 0xe0000000, + memory_region_add_subregion(&s->container, 0xe000e000, sysbus_mmio_get_region(sbd, 0)); + if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) { + /* Create the NS alias region for the NVIC sysregs */ + memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s), + &v7m_sysreg_ns_ops, + sysbus_mmio_get_region(sbd, 0), + "nvic_sysregs_ns", 0x1000); + memory_region_add_subregion(&s->container, 0xe002e000, + &s->sysreg_ns_mem); + } /* Create and map the systick devices */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), errp)) { diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 2b3e79a3da..13df002ce4 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2470,90 +2470,6 @@ static const MemoryRegionOps nvic_sysreg_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static MemTxResult nvic_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 nvic_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 nvic_sysreg_ns_ops = { - .read_with_attrs = nvic_sysreg_ns_read, - .write_with_attrs = nvic_sysreg_ns_write, - .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; @@ -2770,66 +2686,13 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; /* - * 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 - * 0x100..0x7ec - NVIC - * 0x7f0..0xcff - Reserved - * 0xd00..0xd3c - SCS registers - * 0xd40..0xeff - Reserved or Not implemented - * 0xf00 - STIR - * - * Some registers within this space are banked between security states. - * In v8M there is a second range 0xe002e000..0xe002efff which is the - * NonSecure alias SCS; secure accesses to this behave like NS accesses - * to the main SCS range, and non-secure accesses (including when - * the security extension is not implemented) are RAZ/WI. - * Note that both the main SCS range and the alias range are defined - * to be exempt from memory attribution (R_BLJT) and so the memory - * transaction attribute always matches the current CPU security - * state (attrs.secure == env->v7m.secure). In the nvic_sysreg_ns_ops - * wrappers we change attrs.secure to indicate the NS access; so - * 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. + * This device provides a single memory region which covers the + * sysreg/NVIC registers from 0xE000E000 .. 0xE000EFFF, with the + * exception of the systick timer registers 0xE000E010 .. 0xE000E0FF. */ - 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, 0xe000, &s->sysregmem); - - 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, 0x2e000, &s->sysreg_ns_mem); - } - - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sysregmem); } static void armv7m_nvic_instance_init(Object *obj) |