summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Maydell2019-07-04 18:14:43 +0200
committerPeter Maydell2019-07-04 18:25:30 +0200
commit077d7449100d824a4e9230e349099399bde3b20f (patch)
treea560730cd75dc853b3380e7d89d1022ade5486c9
parenttarget/arm/helper: Move M profile routines to m_helper.c (diff)
downloadqemu-077d7449100d824a4e9230e349099399bde3b20f.tar.gz
qemu-077d7449100d824a4e9230e349099399bde3b20f.tar.xz
qemu-077d7449100d824a4e9230e349099399bde3b20f.zip
arm v8M: Forcibly clear negative-priority exceptions on deactivate
To prevent execution priority remaining negative if the guest returns from an NMI or HardFault with a corrupted IPSR, the v8M interrupt deactivation process forces the HardFault and NMI to inactive based on the current raw execution priority, even if the interrupt the guest is trying to deactivate is something else. In the pseudocode this is done in the Deactivate() function. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20190617175317.27557-3-peter.maydell@linaro.org
-rw-r--r--hw/intc/armv7m_nvic.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index b8ede30b3c..330eb728dd 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -812,15 +812,45 @@ void armv7m_nvic_get_pending_irq_info(void *opaque,
int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure)
{
NVICState *s = (NVICState *)opaque;
- VecInfo *vec;
+ VecInfo *vec = NULL;
int ret;
assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
- if (secure && exc_is_banked(irq)) {
- vec = &s->sec_vectors[irq];
- } else {
- vec = &s->vectors[irq];
+ /*
+ * For negative priorities, v8M will forcibly deactivate the appropriate
+ * NMI or HardFault regardless of what interrupt we're being asked to
+ * deactivate (compare the DeActivate() pseudocode). This is a guard
+ * against software returning from NMI or HardFault with a corrupted
+ * IPSR and leaving the CPU in a negative-priority state.
+ * v7M does not do this, but simply deactivates the requested interrupt.
+ */
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
+ switch (armv7m_nvic_raw_execution_priority(s)) {
+ case -1:
+ if (s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) {
+ vec = &s->vectors[ARMV7M_EXCP_HARD];
+ } else {
+ vec = &s->sec_vectors[ARMV7M_EXCP_HARD];
+ }
+ break;
+ case -2:
+ vec = &s->vectors[ARMV7M_EXCP_NMI];
+ break;
+ case -3:
+ vec = &s->sec_vectors[ARMV7M_EXCP_HARD];
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!vec) {
+ if (secure && exc_is_banked(irq)) {
+ vec = &s->sec_vectors[irq];
+ } else {
+ vec = &s->vectors[irq];
+ }
}
trace_nvic_complete_irq(irq, secure);