armv7m: Check exception return consistency

Implement the exception return consistency checks
described in the v7M pseudocode ExceptionReturn().

Inspired by a patch from Michael Davidsaver's series, but
this is a reimplementation from scratch based on the
ARM ARM pseudocode.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 456480a..718b1a1 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -441,10 +441,11 @@
     nvic_irq_update(s);
 }
 
-void armv7m_nvic_complete_irq(void *opaque, int irq)
+int armv7m_nvic_complete_irq(void *opaque, int irq)
 {
     NVICState *s = (NVICState *)opaque;
     VecInfo *vec;
+    int ret;
 
     assert(irq > ARMV7M_EXCP_RESET && irq < s->num_irq);
 
@@ -452,6 +453,13 @@
 
     trace_nvic_complete_irq(irq);
 
+    if (!vec->active) {
+        /* Tell the caller this was an illegal exception return */
+        return -1;
+    }
+
+    ret = nvic_rettobase(s);
+
     vec->active = 0;
     if (vec->level) {
         /* Re-pend the exception if it's still held high; only
@@ -462,6 +470,8 @@
     }
 
     nvic_irq_update(s);
+
+    return ret;
 }
 
 /* callback when external interrupt line is changed */