[18/19] nvic: Make SHCSR banked for v8M

Message ID 1505240046-11454-19-git-send-email-peter.maydell@linaro.org
State Superseded
Headers show
Series
  • ARMv8M: support security extn in the NVIC
Related show

Commit Message

Peter Maydell Sept. 12, 2017, 6:14 p.m.
Handle banking of SHCSR: some register bits are banked between
Secure and Non-Secure, and some are only accessible to Secure.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

---
 hw/intc/armv7m_nvic.c | 221 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 169 insertions(+), 52 deletions(-)

-- 
2.7.4

Comments

Richard Henderson Sept. 20, 2017, 6:37 p.m. | #1
On 09/12/2017 01:14 PM, Peter Maydell wrote:
> Handle banking of SHCSR: some register bits are banked between

> Secure and Non-Secure, and some are only accessible to Secure.

> 

> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

> ---

>  hw/intc/armv7m_nvic.c | 221 ++++++++++++++++++++++++++++++++++++++------------

>  1 file changed, 169 insertions(+), 52 deletions(-)


Reviewed-by: Richard Henderson <richard.henderson@linaro.org>


r~

Patch

diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 21fd199..9613990 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -770,50 +770,117 @@  static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
         val = cpu->env.v7m.ccr[attrs.secure];
         val |= cpu->env.v7m.ccr[M_REG_NS] & R_V7M_CCR_BFHFNMIGN_MASK;
         return val;
-    case 0xd24: /* System Handler Status.  */
+    case 0xd24: /* System Handler Control and State (SHCSR) */
         val = 0;
-        if (s->vectors[ARMV7M_EXCP_MEM].active) {
-            val |= (1 << 0);
-        }
-        if (s->vectors[ARMV7M_EXCP_BUS].active) {
-            val |= (1 << 1);
-        }
-        if (s->vectors[ARMV7M_EXCP_USAGE].active) {
-            val |= (1 << 3);
+        if (attrs.secure) {
+            if (s->sec_vectors[ARMV7M_EXCP_MEM].active) {
+                val |= (1 << 0);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_HARD].active) {
+                val |= (1 << 2);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_USAGE].active) {
+                val |= (1 << 3);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_SVC].active) {
+                val |= (1 << 7);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_PENDSV].active) {
+                val |= (1 << 10);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_SYSTICK].active) {
+                val |= (1 << 11);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_USAGE].pending) {
+                val |= (1 << 12);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_MEM].pending) {
+                val |= (1 << 13);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_SVC].pending) {
+                val |= (1 << 15);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_MEM].enabled) {
+                val |= (1 << 16);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_USAGE].enabled) {
+                val |= (1 << 18);
+            }
+            if (s->sec_vectors[ARMV7M_EXCP_HARD].pending) {
+                val |= (1 << 21);
+            }
+            /* SecureFault is not banked but is always RAZ/WI to NS */
+            if (s->vectors[ARMV7M_EXCP_SECURE].active) {
+                val |= (1 << 4);
+            }
+            if (s->vectors[ARMV7M_EXCP_SECURE].enabled) {
+                val |= (1 << 19);
+            }
+            if (s->vectors[ARMV7M_EXCP_SECURE].pending) {
+                val |= (1 << 20);
+            }
+        } else {
+            if (s->vectors[ARMV7M_EXCP_MEM].active) {
+                val |= (1 << 0);
+            }
+            if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+                /* HARDFAULTACT, HARDFAULTPENDED not present in v7M */
+                if (s->vectors[ARMV7M_EXCP_HARD].active) {
+                    val |= (1 << 2);
+                }
+                if (s->vectors[ARMV7M_EXCP_HARD].pending) {
+                    val |= (1 << 21);
+                }
+            }
+            if (s->vectors[ARMV7M_EXCP_USAGE].active) {
+                val |= (1 << 3);
+            }
+            if (s->vectors[ARMV7M_EXCP_SVC].active) {
+                val |= (1 << 7);
+            }
+            if (s->vectors[ARMV7M_EXCP_PENDSV].active) {
+                val |= (1 << 10);
+            }
+            if (s->vectors[ARMV7M_EXCP_SYSTICK].active) {
+                val |= (1 << 11);
+            }
+            if (s->vectors[ARMV7M_EXCP_USAGE].pending) {
+                val |= (1 << 12);
+            }
+            if (s->vectors[ARMV7M_EXCP_MEM].pending) {
+                val |= (1 << 13);
+            }
+            if (s->vectors[ARMV7M_EXCP_SVC].pending) {
+                val |= (1 << 15);
+            }
+            if (s->vectors[ARMV7M_EXCP_MEM].enabled) {
+                val |= (1 << 16);
+            }
+            if (s->vectors[ARMV7M_EXCP_USAGE].enabled) {
+                val |= (1 << 18);
+            }
         }
-        if (s->vectors[ARMV7M_EXCP_SVC].active) {
-            val |= (1 << 7);
+        if (attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+            if (s->vectors[ARMV7M_EXCP_BUS].active) {
+                val |= (1 << 1);
+            }
+            if (s->vectors[ARMV7M_EXCP_BUS].pending) {
+                val |= (1 << 14);
+            }
+            if (s->vectors[ARMV7M_EXCP_BUS].enabled) {
+                val |= (1 << 17);
+            }
+            if (arm_feature(&cpu->env, ARM_FEATURE_V8) &&
+                s->vectors[ARMV7M_EXCP_NMI].active) {
+                /* NMIACT is not present in v7M */
+                val |= (1 << 5);
+            }
         }
+
+        /* TODO: this is RAZ/WI from NS if DEMCR.SDME is set */
         if (s->vectors[ARMV7M_EXCP_DEBUG].active) {
             val |= (1 << 8);
         }
-        if (s->vectors[ARMV7M_EXCP_PENDSV].active) {
-            val |= (1 << 10);
-        }
-        if (s->vectors[ARMV7M_EXCP_SYSTICK].active) {
-            val |= (1 << 11);
-        }
-        if (s->vectors[ARMV7M_EXCP_USAGE].pending) {
-            val |= (1 << 12);
-        }
-        if (s->vectors[ARMV7M_EXCP_MEM].pending) {
-            val |= (1 << 13);
-        }
-        if (s->vectors[ARMV7M_EXCP_BUS].pending) {
-            val |= (1 << 14);
-        }
-        if (s->vectors[ARMV7M_EXCP_SVC].pending) {
-            val |= (1 << 15);
-        }
-        if (s->vectors[ARMV7M_EXCP_MEM].enabled) {
-            val |= (1 << 16);
-        }
-        if (s->vectors[ARMV7M_EXCP_BUS].enabled) {
-            val |= (1 << 17);
-        }
-        if (s->vectors[ARMV7M_EXCP_USAGE].enabled) {
-            val |= (1 << 18);
-        }
         return val;
     case 0xd28: /* Configurable Fault Status.  */
         /* The BFSR bits [15:8] are shared between security states
@@ -1061,21 +1128,71 @@  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.  */
-        s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
-        s->vectors[ARMV7M_EXCP_BUS].active = (value & (1 << 1)) != 0;
-        s->vectors[ARMV7M_EXCP_USAGE].active = (value & (1 << 3)) != 0;
-        s->vectors[ARMV7M_EXCP_SVC].active = (value & (1 << 7)) != 0;
+    case 0xd24: /* System Handler Control and State (SHCSR) */
+        if (attrs.secure) {
+            s->sec_vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
+            /* Secure HardFault active bit cannot be written */
+            s->sec_vectors[ARMV7M_EXCP_USAGE].active = (value & (1 << 3)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_SVC].active = (value & (1 << 7)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_PENDSV].active =
+                (value & (1 << 10)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_SYSTICK].active =
+                (value & (1 << 11)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_USAGE].pending =
+                (value & (1 << 12)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_MEM].pending = (value & (1 << 13)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_SVC].pending = (value & (1 << 15)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+            s->sec_vectors[ARMV7M_EXCP_USAGE].enabled =
+                (value & (1 << 18)) != 0;
+            /* SecureFault not banked, but RAZ/WI to NS */
+            s->vectors[ARMV7M_EXCP_SECURE].active = (value & (1 << 4)) != 0;
+            s->vectors[ARMV7M_EXCP_SECURE].enabled = (value & (1 << 19)) != 0;
+            s->vectors[ARMV7M_EXCP_SECURE].pending = (value & (1 << 20)) != 0;
+        } else {
+            s->vectors[ARMV7M_EXCP_MEM].active = (value & (1 << 0)) != 0;
+            if (arm_feature(&cpu->env, ARM_FEATURE_V8)) {
+                /* HARDFAULTPENDED is not present in v7M */
+                s->vectors[ARMV7M_EXCP_HARD].pending = (value & (1 << 21)) != 0;
+            }
+            s->vectors[ARMV7M_EXCP_USAGE].active = (value & (1 << 3)) != 0;
+            s->vectors[ARMV7M_EXCP_SVC].active = (value & (1 << 7)) != 0;
+            s->vectors[ARMV7M_EXCP_PENDSV].active = (value & (1 << 10)) != 0;
+            s->vectors[ARMV7M_EXCP_SYSTICK].active = (value & (1 << 11)) != 0;
+            s->vectors[ARMV7M_EXCP_USAGE].pending = (value & (1 << 12)) != 0;
+            s->vectors[ARMV7M_EXCP_MEM].pending = (value & (1 << 13)) != 0;
+            s->vectors[ARMV7M_EXCP_SVC].pending = (value & (1 << 15)) != 0;
+            s->vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
+            s->vectors[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
+        }
+        if (attrs.secure || (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK)) {
+            s->vectors[ARMV7M_EXCP_BUS].active = (value & (1 << 1)) != 0;
+            s->vectors[ARMV7M_EXCP_BUS].pending = (value & (1 << 14)) != 0;
+            s->vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
+        }
+        /* NMIACT can only be written if the write is of a zero, with
+         * BFHFNMINS 1, and by the CPU in secure state via the NS alias.
+         */
+        if (!attrs.secure && cpu->env.v7m.secure &&
+            (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) &&
+            (value & (1 << 5)) == 0) {
+            s->vectors[ARMV7M_EXCP_NMI].active = 0;
+        }
+        /* HARDFAULTACT can only be written if the write is of a zero
+         * to the non-secure HardFault state by the CPU in secure state.
+         * The only case where we can be targeting the non-secure HF state
+         * when in secure state is if this is a write via the NS alias
+         * and BFHFNMINS is 1.
+         */
+        if (!attrs.secure && cpu->env.v7m.secure &&
+            (cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK) &&
+            (value & (1 << 2)) == 0) {
+            s->vectors[ARMV7M_EXCP_HARD].active = 0;
+        }
+
+        /* TODO: this is RAZ/WI from NS if DEMCR.SDME is set */
         s->vectors[ARMV7M_EXCP_DEBUG].active = (value & (1 << 8)) != 0;
-        s->vectors[ARMV7M_EXCP_PENDSV].active = (value & (1 << 10)) != 0;
-        s->vectors[ARMV7M_EXCP_SYSTICK].active = (value & (1 << 11)) != 0;
-        s->vectors[ARMV7M_EXCP_USAGE].pending = (value & (1 << 12)) != 0;
-        s->vectors[ARMV7M_EXCP_MEM].pending = (value & (1 << 13)) != 0;
-        s->vectors[ARMV7M_EXCP_BUS].pending = (value & (1 << 14)) != 0;
-        s->vectors[ARMV7M_EXCP_SVC].pending = (value & (1 << 15)) != 0;
-        s->vectors[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
-        s->vectors[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
-        s->vectors[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
         nvic_irq_update(s);
         break;
     case 0xd28: /* Configurable Fault Status.  */