diff options
Diffstat (limited to 'hw/intc/armv7m_nvic.c')
| -rw-r--r-- | hw/intc/armv7m_nvic.c | 101 |
1 files changed, 96 insertions, 5 deletions
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index cd1e7f1729..0d816fdd2c 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -420,6 +420,8 @@ static void set_prio(NVICState *s, unsigned irq, bool secure, uint8_t prio) assert(irq > ARMV7M_EXCP_NMI); /* only use for configurable prios */ assert(irq < s->num_irq); + prio &= MAKE_64BIT_MASK(8 - s->num_prio_bits, s->num_prio_bits); + if (secure) { assert(exc_is_banked(irq)); s->sec_vectors[irq].prio = prio; @@ -772,6 +774,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; @@ -779,6 +799,9 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) switch (offset) { case 4: /* Interrupt Control Type. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) { + goto bad_offset; + } return ((s->num_irq - NVIC_FIRST_IRQ) / 32) - 1; case 0xc: /* CPPWR */ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) { @@ -867,6 +890,9 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) } return val; case 0xd10: /* System Control. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) { + goto bad_offset; + } return cpu->env.v7m.scr[attrs.secure]; case 0xd14: /* Configuration Control. */ /* The BFHFNMIGN bit is the only non-banked bit; we @@ -876,6 +902,9 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK; return val; case 0xd24: /* System Handler Control and State (SHCSR) */ + if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) { + goto bad_offset; + } val = 0; if (attrs.secure) { if (s->sec_vectors[ARMV7M_EXCP_MEM].active) { @@ -988,12 +1017,21 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs) } return val; case 0xd2c: /* Hard Fault Status. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } return cpu->env.v7m.hfsr; case 0xd30: /* Debug Fault Status. */ return cpu->env.v7m.dfsr; case 0xd34: /* MMFAR MemManage Fault Address */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } return cpu->env.v7m.mmfar[attrs.secure]; case 0xd38: /* Bus Fault Address. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } return cpu->env.v7m.bfar; case 0xd3c: /* Aux Fault Status. */ /* TODO: Implement fault status registers. */ @@ -1263,9 +1301,12 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, "Setting VECTRESET when not in DEBUG mode " "is UNPREDICTABLE\n"); } - s->prigroup[attrs.secure] = extract32(value, - R_V7M_AIRCR_PRIGROUP_SHIFT, - R_V7M_AIRCR_PRIGROUP_LENGTH); + if (arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + s->prigroup[attrs.secure] = + extract32(value, + R_V7M_AIRCR_PRIGROUP_SHIFT, + R_V7M_AIRCR_PRIGROUP_LENGTH); + } if (attrs.secure) { /* These bits are only writable by secure */ cpu->env.v7m.aircr = value & @@ -1288,6 +1329,9 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, } break; case 0xd10: /* System Control. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_V7)) { + goto bad_offset; + } /* We don't implement deep-sleep so these bits are RAZ/WI. * The other bits in the register are banked. * QEMU's implementation ignores SEVONPEND and SLEEPONEXIT, which @@ -1297,6 +1341,10 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, cpu->env.v7m.scr[attrs.secure] = value; break; case 0xd14: /* Configuration Control. */ + 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 | @@ -1321,6 +1369,9 @@ 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; + } if (attrs.secure) { s->sec_vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0; /* Secure HardFault active bit cannot be written */ @@ -1389,15 +1440,24 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, nvic_irq_update(s); break; case 0xd2c: /* Hard Fault Status. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } cpu->env.v7m.hfsr &= ~value; /* W1C */ break; case 0xd30: /* Debug Fault Status. */ cpu->env.v7m.dfsr &= ~value; /* W1C */ break; case 0xd34: /* Mem Manage Address. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } cpu->env.v7m.mmfar[attrs.secure] = value; return; case 0xd38: /* Bus Fault Address. */ + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } cpu->env.v7m.bfar = value; return; case 0xd3c: /* Aux Fault Status. */ @@ -1627,6 +1687,11 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value, case 0xf00: /* Software Triggered Interrupt Register */ { int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ; + + if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) { + goto bad_offset; + } + if (excnum < s->num_irq) { armv7m_nvic_set_pending(s, excnum, false); } @@ -1752,6 +1817,11 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, break; case 0x300 ... 0x33f: /* NVIC Active */ val = 0; + + if (!arm_feature(&s->cpu->env, ARM_FEATURE_V7)) { + break; + } + startvec = 8 * (offset - 0x300) + NVIC_FIRST_IRQ; /* vector # */ for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++) { @@ -1771,7 +1841,13 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, } } break; - case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */ + case 0xd18: /* System Handler Priority (SHPR1) */ + if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) { + val = 0; + break; + } + /* fall through */ + case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */ val = 0; for (i = 0; i < size; i++) { unsigned hdlidx = (offset - 0xd14) + i; @@ -1784,6 +1860,10 @@ static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, } break; case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ + if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) { + val = 0; + break; + }; /* The BFSR bits [15:8] are shared between security states * and we store them in the NS copy */ @@ -1876,7 +1956,12 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, } nvic_irq_update(s); return MEMTX_OK; - case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */ + case 0xd18: /* System Handler Priority (SHPR1) */ + if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) { + return MEMTX_OK; + } + /* fall through */ + case 0xd1c ... 0xd23: /* System Handler Priority (SHPR2, SHPR3) */ for (i = 0; i < size; i++) { unsigned hdlidx = (offset - 0xd14) + i; int newprio = extract32(value, i * 8, 8); @@ -1890,6 +1975,9 @@ static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, nvic_irq_update(s); return MEMTX_OK; case 0xd28 ... 0xd2b: /* Configurable Fault Status (CFSR) */ + if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_MAIN)) { + return MEMTX_OK; + } /* All bits are W1C, so construct 32 bit value with 0s in * the parts not written by the access size */ @@ -2203,6 +2291,8 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) /* include space for internal exception vectors */ s->num_irq += NVIC_FIRST_IRQ; + s->num_prio_bits = arm_feature(&s->cpu->env, ARM_FEATURE_V7) ? 8 : 2; + object_property_set_bool(OBJECT(&s->systick[M_REG_NS]), true, "realized", &err); if (err != NULL) { @@ -2310,6 +2400,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) |