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;
NVICState *s = (NVICState *)opaque;
bool banked = exc_is_banked(irq);
VecInfo *vec;
+ bool targets_secure;
assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
assert(!secure || banked);
vec = (banked && secure) ? &s->sec_vectors[irq] : &s->vectors[irq];
- trace_nvic_set_pending(irq, secure, derived, vec->enabled, vec->prio);
+ targets_secure = banked ? secure : exc_targets_secure(s, irq);
+
+ trace_nvic_set_pending(irq, secure, targets_secure,
+ derived, vec->enabled, vec->prio);
if (derived) {
/* Derived exceptions are always synchronous. */
*/
irq = ARMV7M_EXCP_HARD;
if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY) &&
- (secure ||
+ (targets_secure ||
!(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK))) {
vec = &s->sec_vectors[irq];
} else {
}
}
+/* 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;
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)) {
+ goto bad_offset;
+ }
+ /* We make the IMPDEF choice that nothing can ever go into a
+ * non-retentive power state, which allows us to RAZ/WI this.
+ */
+ return 0;
case 0x380 ... 0x3bf: /* NVIC_ITNS<n> */
{
int startvec = 8 * (offset - 0x380) + NVIC_FIRST_IRQ;
}
}
/* NMIPENDSET */
- if ((cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) &&
- s->vectors[ARMV7M_EXCP_NMI].pending) {
+ if ((attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK))
+ && s->vectors[ARMV7M_EXCP_NMI].pending) {
val |= (1 << 31);
}
/* ISRPREEMPT: RES0 when halting debug not implemented */
}
return val;
case 0xd10: /* System Control. */
- /* TODO: Implement SLEEPONEXIT. */
- return 0;
+ 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
* keep it in the non-secure copy of the register.
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) {
}
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. */
case 0xd5c: /* MMFR3. */
return cpu->id_mmfr3;
case 0xd60: /* ISAR0. */
- return cpu->id_isar0;
+ return cpu->isar.id_isar0;
case 0xd64: /* ISAR1. */
- return cpu->id_isar1;
+ return cpu->isar.id_isar1;
case 0xd68: /* ISAR2. */
- return cpu->id_isar2;
+ return cpu->isar.id_isar2;
case 0xd6c: /* ISAR3. */
- return cpu->id_isar3;
+ return cpu->isar.id_isar3;
case 0xd70: /* ISAR4. */
- return cpu->id_isar4;
+ return cpu->isar.id_isar4;
case 0xd74: /* ISAR5. */
- return cpu->id_isar5;
+ return cpu->isar.id_isar5;
+ case 0xd78: /* CLIDR */
+ return cpu->clidr;
+ case 0xd7c: /* CTR */
+ return cpu->ctr;
+ case 0xd80: /* CSSIDR */
+ {
+ int idx = cpu->env.v7m.csselr[attrs.secure] & R_V7M_CSSELR_INDEX_MASK;
+ return cpu->ccsidr[idx];
+ }
+ case 0xd84: /* CSSELR */
+ return cpu->env.v7m.csselr[attrs.secure];
/* TODO: Implement debug registers. */
case 0xd90: /* MPU_TYPE */
/* Unified MPU; if the MPU is not present this value is zero */
return 0;
}
return cpu->env.v7m.sfar;
+ case 0xf40: /* MVFR0 */
+ return cpu->isar.mvfr0;
+ case 0xf44: /* MVFR1 */
+ return cpu->isar.mvfr1;
+ case 0xf48: /* MVFR2 */
+ return cpu->isar.mvfr2;
default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
ARMCPU *cpu = s->cpu;
switch (offset) {
+ case 0xc: /* CPPWR */
+ if (!arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+ goto bad_offset;
+ }
+ /* Make the IMPDEF choice to RAZ/WI this. */
+ break;
case 0x380 ... 0x3bf: /* NVIC_ITNS<n> */
{
int startvec = 8 * (offset - 0x380) + NVIC_FIRST_IRQ;
break;
}
case 0xd04: /* Interrupt Control State (ICSR) */
- if (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
+ if (attrs.secure || cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
if (value & (1 << 31)) {
armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI, false);
} else if (value & (1 << 30) &&
"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 &
}
break;
case 0xd10: /* System Control. */
- /* TODO: Implement control registers. */
- qemu_log_mask(LOG_UNIMP, "NVIC: SCR unimplemented\n");
+ 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
+ * is architecturally permitted.
+ */
+ value &= ~(R_V7M_SCR_SLEEPDEEP_MASK | R_V7M_SCR_SLEEPDEEPS_MASK);
+ 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 |
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 */
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. */
qemu_log_mask(LOG_UNIMP,
"NVIC: Aux fault status registers unimplemented\n");
break;
+ case 0xd84: /* CSSELR */
+ if (!arm_v7m_csselr_razwi(cpu)) {
+ cpu->env.v7m.csselr[attrs.secure] = value & R_V7M_CSSELR_INDEX_MASK;
+ }
+ break;
case 0xd90: /* MPU_TYPE */
return; /* RO */
case 0xd94: /* MPU_CTRL */
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);
}
break;
}
+ case 0xf50: /* ICIALLU */
+ case 0xf58: /* ICIMVAU */
+ case 0xf5c: /* DCIMVAC */
+ case 0xf60: /* DCISW */
+ case 0xf64: /* DCCMVAU */
+ case 0xf68: /* DCCMVAC */
+ case 0xf6c: /* DCCSW */
+ case 0xf70: /* DCCIMVAC */
+ case 0xf74: /* DCCISW */
+ case 0xf78: /* BPIALL */
+ /* Cache and branch predictor maintenance: for QEMU these always NOP */
+ break;
default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
/* fall through */
case 0x180 ... 0x1bf: /* NVIC Clear enable */
val = 0;
- startvec = offset - 0x180 + NVIC_FIRST_IRQ; /* vector # */
+ startvec = 8 * (offset - 0x180) + NVIC_FIRST_IRQ; /* vector # */
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++) {
if (s->vectors[startvec + i].enabled &&
/* fall through */
case 0x280 ... 0x2bf: /* NVIC Clear pend */
val = 0;
- startvec = offset - 0x280 + NVIC_FIRST_IRQ; /* vector # */
+ startvec = 8 * (offset - 0x280) + NVIC_FIRST_IRQ; /* vector # */
for (i = 0, end = size * 8; i < end && startvec + i < s->num_irq; i++) {
if (s->vectors[startvec + i].pending &&
(attrs.secure || s->itns[startvec + i])) {
break;
case 0x300 ... 0x33f: /* NVIC Active */
val = 0;
- startvec = offset - 0x300 + NVIC_FIRST_IRQ; /* vector # */
+
+ 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++) {
if (s->vectors[startvec + i].active &&
}
}
break;
- case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
+ case 0xd18 ... 0xd1b: /* 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;
}
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
*/
case 0x300 ... 0x33f: /* NVIC Active */
return MEMTX_OK; /* R/O */
case 0x400 ... 0x5ef: /* NVIC Priority */
- startvec = 8 * (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */
+ startvec = (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */
for (i = 0; i < size && startvec + i < s->num_irq; i++) {
if (attrs.secure || s->itns[startvec + i]) {
}
nvic_irq_update(s);
return MEMTX_OK;
- case 0xd18 ... 0xd23: /* System Handler Priority (SHPR1, SHPR2, SHPR3) */
+ case 0xd18 ... 0xd1b: /* 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);
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
*/
}
static const VMStateDescription vmstate_nvic_security = {
- .name = "nvic/m-security",
+ .name = "armv7m_nvic/m-security",
.version_id = 1,
.minimum_version_id = 1,
.needed = nvic_security_needed,
Error *err = NULL;
int regionlen;
- s->cpu = ARM_CPU(qemu_get_cpu(0));
- assert(s->cpu);
+ /* The armv7m container object will have set our CPU pointer */
+ if (!s->cpu || !arm_feature(&s->cpu->env, ARM_FEATURE_M)) {
+ error_setg(errp, "The NVIC can only be used with a Cortex-M CPU");
+ return;
+ }
if (s->num_irq > NVIC_MAX_IRQ) {
error_setg(errp, "num-irq %d exceeds NVIC maximum", s->num_irq);
/* 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) {
NVICState *nvic = NVIC(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
- object_initialize(&nvic->systick[M_REG_NS],
- sizeof(nvic->systick[M_REG_NS]), TYPE_SYSTICK);
- qdev_set_parent_bus(DEVICE(&nvic->systick[M_REG_NS]), sysbus_get_default());
+ sysbus_init_child_obj(obj, "systick-reg-ns", &nvic->systick[M_REG_NS],
+ sizeof(nvic->systick[M_REG_NS]), TYPE_SYSTICK);
/* We can't initialize the secure systick here, as we don't know
* yet if we need it.
*/
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)