diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2020-12-10 11:48:25 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2020-12-10 11:48:25 +0000 |
commit | 180834dcb8277a687b62f035b477abfd5a1ff978 (patch) | |
tree | 435634a8ba46ac2177b86a5d1c12b23a467a7974 /hw/intc | |
parent | 5e7b204dbfae9a562fc73684986f936b97f63877 (diff) | |
parent | 71f916be1c7e9ede0e37d9cabc781b5a9e8638ff (diff) | |
download | qemu-180834dcb8277a687b62f035b477abfd5a1ff978.zip qemu-180834dcb8277a687b62f035b477abfd5a1ff978.tar.gz qemu-180834dcb8277a687b62f035b477abfd5a1ff978.tar.bz2 |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20201210' into staging
target-arm queue:
* hw/arm/smmuv3: Fix up L1STD_SPAN decoding
* xlnx-zynqmp: Support Xilinx ZynqMP CAN controllers
* sbsa-ref: allow to use Cortex-A53/57/72 cpus
* Various minor code cleanups
* hw/intc/armv7m_nvic: Make all of system PPB range be RAZWI/BusFault
* Implement more pieces of ARMv8.1M support
# gpg: Signature made Thu 10 Dec 2020 11:46:43 GMT
# gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg: issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20201210: (36 commits)
hw/arm/armv7m: Correct typo in QOM object name
hw/intc/armv7m_nvic: Implement read/write for RAS register block
target/arm: Implement M-profile "minimal RAS implementation"
hw/intc/armv7m_nvic: Fix "return from inactive handler" check
target/arm: Implement CCR_S.TRD behaviour for SG insns
hw/intc/armv7m_nvic: Support v8.1M CCR.TRD bit
target/arm: Implement new v8.1M VLLDM and VLSTM encodings
target/arm: Implement new v8.1M NOCP check for exception return
target/arm: Implement v8.1M REVIDR register
target/arm: In v8.1M, don't set HFSR.FORCED on vector table fetch failures
target/arm: For v8.1M, always clear R0-R3, R12, APSR, EPSR on exception entry
hw/intc/armv7m_nvic: Update FPDSCR masking for v8.1M
target/arm: Implement FPCXT_S fp system register
target/arm: Factor out preserve-fp-state from full_vfp_access_check()
target/arm: Use new FPCR_NZCV_MASK constant
target/arm: Implement M-profile FPSCR_nzcvqc
target/arm: Implement VLDR/VSTR system register
target/arm: Move general-use constant expanders up in translate.c
target/arm: Refactor M-profile VMSR/VMRS handling
target/arm: Enforce M-profile VMRS/VMSR register restrictions
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/intc')
-rw-r--r-- | hw/intc/armv7m_nvic.c | 246 |
1 files changed, 199 insertions, 47 deletions
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 42b1ad5..f63aa2d 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -832,10 +832,40 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) { NVICState *s = (NVICState *)opaque; VecInfo *vec = NULL; - int ret; + int ret = 0; assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq); + trace_nvic_complete_irq(irq, secure); + + if (secure && exc_is_banked(irq)) { + vec = &s->sec_vectors[irq]; + } else { + vec = &s->vectors[irq]; + } + + /* + * Identify illegal exception return cases. We can't immediately + * return at this point because we still need to deactivate + * (either this exception or NMI/HardFault) first. + */ + if (!exc_is_banked(irq) && exc_targets_secure(s, irq) != secure) { + /* + * Return from a configurable exception targeting the opposite + * security state from the one we're trying to complete it for. + * Clear vec because it's not really the VecInfo for this + * (irq, secstate) so we mustn't deactivate it. + */ + ret = -1; + vec = NULL; + } else if (!vec->active) { + /* Return from an inactive interrupt */ + ret = -1; + } else { + /* Legal return, we will return the RETTOBASE bit value to the caller */ + ret = nvic_rettobase(s); + } + /* * For negative priorities, v8M will forcibly deactivate the appropriate * NMI or HardFault regardless of what interrupt we're being asked to @@ -865,32 +895,7 @@ int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) } if (!vec) { - if (secure && exc_is_banked(irq)) { - vec = &s->sec_vectors[irq]; - } else { - vec = &s->vectors[irq]; - } - } - - trace_nvic_complete_irq(irq, secure); - - if (!vec->active) { - /* Tell the caller this was an illegal exception return */ - return -1; - } - - /* - * If this is a configurable exception and it is currently - * targeting the opposite security state from the one we're trying - * to complete it for, this counts as an illegal exception return. - * We still need to deactivate whatever vector the logic above has - * selected, though, as it might not be the same as the one for the - * requested exception number. - */ - if (!exc_is_banked(irq) && exc_targets_secure(s, irq) != secure) { - ret = -1; - } else { - ret = nvic_rettobase(s); + return ret; } vec->active = 0; @@ -1025,6 +1030,11 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) } return val; } + case 0xcfc: + if (!arm_feature(&cpu->env, ARM_FEATURE_V8_1M)) { + goto bad_offset; + } + return cpu->revidr; case 0xd00: /* CPUID Base. */ return cpu->midr; case 0xd04: /* Interrupt Control State (ICSR) */ @@ -1090,8 +1100,9 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) } return cpu->env.v7m.scr[attrs.secure]; case 0xd14: /* Configuration Control. */ - /* The BFHFNMIGN bit is the only non-banked bit; we - * keep it in the non-secure copy of the register. + /* + * Non-banked bits: BFHFNMIGN (stored in the NS copy of the register) + * and TRD (stored in the S copy of the register) */ val = cpu->env.v7m.ccr[attrs.secure]; val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK; @@ -1472,6 +1483,12 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) return 0; } return cpu->env.v7m.sfar; + case 0xf04: /* RFSR */ + if (!cpu_isar_feature(aa32_ras, cpu)) { + goto bad_offset; + } + /* We provide minimal-RAS only: RFSR is RAZ/WI */ + return 0; case 0xf34: /* FPCCR */ if (!cpu_isar_feature(aa32_vfp_simd, cpu)) { return 0; @@ -1600,6 +1617,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, R_V7M_AIRCR_PRIGROUP_SHIFT, R_V7M_AIRCR_PRIGROUP_LENGTH); } + /* AIRCR.IESB is RAZ/WI because we implement only minimal RAS */ if (attrs.secure) { /* These bits are only writable by secure */ cpu->env.v7m.aircr = value & @@ -1634,17 +1652,25 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, cpu->env.v7m.scr[attrs.secure] = value; break; case 0xd14: /* Configuration Control. */ + { + uint32_t mask; + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { goto bad_offset; } /* Enforce RAZ/WI on reserved and must-RAZ/WI bits */ - value &= (R_V7M_CCR_STKALIGN_MASK | - R_V7M_CCR_BFHFNMIGN_MASK | - R_V7M_CCR_DIV_0_TRP_MASK | - R_V7M_CCR_UNALIGN_TRP_MASK | - R_V7M_CCR_USERSETMPEND_MASK | - R_V7M_CCR_NONBASETHRDENA_MASK); + mask = R_V7M_CCR_STKALIGN_MASK | + R_V7M_CCR_BFHFNMIGN_MASK | + R_V7M_CCR_DIV_0_TRP_MASK | + R_V7M_CCR_UNALIGN_TRP_MASK | + R_V7M_CCR_USERSETMPEND_MASK | + R_V7M_CCR_NONBASETHRDENA_MASK; + if (arm_feature(&cpu->env, ARM_FEATURE_V8_1M) && attrs.secure) { + /* TRD is always RAZ/WI from NS */ + mask |= R_V7M_CCR_TRD_MASK; + } + value &= mask; if (arm_feature(&cpu->env, ARM_FEATURE_V8)) { /* v8M makes NONBASETHRDENA and STKALIGN be RES1 */ @@ -1661,6 +1687,7 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, cpu->env.v7m.ccr[attrs.secure] = value; break; + } case 0xd24: /* System Handler Control and State (SHCSR) */ if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) { goto bad_offset; @@ -2006,6 +2033,12 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, } break; } + case 0xf04: /* RFSR */ + if (!cpu_isar_feature(aa32_ras, cpu)) { + goto bad_offset; + } + /* We provide minimal-RAS only: RFSR is RAZ/WI */ + break; case 0xf34: /* FPCCR */ if (cpu_isar_feature(aa32_vfp_simd, cpu)) { /* Not all bits here are banked. */ @@ -2068,7 +2101,14 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, break; case 0xf3c: /* FPDSCR */ if (cpu_isar_feature(aa32_vfp_simd, cpu)) { - value &= 0x07c00000; + uint32_t mask = FPCR_AHP | FPCR_DN | FPCR_FZ | FPCR_RMODE_MASK; + if (cpu_isar_feature(any_fp16, cpu)) { + mask |= FPCR_FZ16; + } + value &= mask; + if (cpu_isar_feature(aa32_lob, cpu)) { + value |= 4 << FPCR_LTPSIZE_SHIFT; + } cpu->env.v7m.fpdscr[attrs.secure] = value; } break; @@ -2479,6 +2519,93 @@ static const MemoryRegionOps nvic_systick_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; + +static MemTxResult ras_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) +{ + if (attrs.user) { + return MEMTX_ERROR; + } + + switch (addr) { + case 0xe10: /* ERRIIDR */ + /* architect field = Arm; product/variant/revision 0 */ + *data = 0x43b; + break; + case 0xfc8: /* ERRDEVID */ + /* Minimal RAS: we implement 0 error record indexes */ + *data = 0; + break; + default: + qemu_log_mask(LOG_UNIMP, "Read RAS register offset 0x%x\n", + (uint32_t)addr); + *data = 0; + break; + } + return MEMTX_OK; +} + +static MemTxResult ras_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + if (attrs.user) { + return MEMTX_ERROR; + } + + switch (addr) { + default: + qemu_log_mask(LOG_UNIMP, "Write to RAS register offset 0x%x\n", + (uint32_t)addr); + break; + } + return MEMTX_OK; +} + +static const MemoryRegionOps ras_ops = { + .read_with_attrs = ras_read, + .write_with_attrs = ras_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; @@ -2675,7 +2802,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 +2844,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,35 +2880,48 @@ 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); } + if (cpu_isar_feature(aa32_ras, s->cpu)) { + memory_region_init_io(&s->ras_mem, OBJECT(s), + &ras_ops, s, "nvic_ras", 0x1000); + memory_region_add_subregion(&s->container, 0x5000, &s->ras_mem); + } + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->container); } |