qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-arm@nongnu.org, qemu-devel@nongnu.org
Cc: patches@linaro.org
Subject: [Qemu-devel] [PATCH 08/19] nvic: Handle banked exceptions in nvic_recompute_state()
Date: Tue, 12 Sep 2017 19:13:55 +0100	[thread overview]
Message-ID: <1505240046-11454-9-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1505240046-11454-1-git-send-email-peter.maydell@linaro.org>

Update the nvic_recompute_state() code to handle the security
extension and its associated banked registers.

Code that uses the resulting cached state (ie the irq
acknowledge and complete code) will be updated in a later
commit.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/intc/armv7m_nvic.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++--
 hw/intc/trace-events  |   1 +
 2 files changed, 147 insertions(+), 5 deletions(-)

diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index b97dbe3..fb824e6 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -54,6 +54,8 @@
  * (higher than the highest possible priority value)
  */
 #define NVIC_NOEXC_PRIO 0x100
+/* Maximum priority of non-secure exceptions when AIRCR.PRIS is set */
+#define NVIC_NS_PRIO_LIMIT 0x80
 
 static const uint8_t nvic_id[] = {
     0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
@@ -126,13 +128,139 @@ static bool nvic_isrpending(NVICState *s)
     return false;
 }
 
+static bool exc_is_banked(int exc)
+{
+    /* Return true if this is one of the limited set of exceptions which
+     * are banked (and thus have state in sec_vectors[])
+     */
+    return exc == ARMV7M_EXCP_HARD ||
+        exc == ARMV7M_EXCP_MEM ||
+        exc == ARMV7M_EXCP_USAGE ||
+        exc == ARMV7M_EXCP_SVC ||
+        exc == ARMV7M_EXCP_PENDSV ||
+        exc == ARMV7M_EXCP_SYSTICK;
+}
+
 /* Return a mask word which clears the subpriority bits from
  * a priority value for an M-profile exception, leaving only
  * the group priority.
  */
-static inline uint32_t nvic_gprio_mask(NVICState *s)
+static inline uint32_t nvic_gprio_mask(NVICState *s, bool secure)
+{
+    return ~0U << (s->prigroup[secure] + 1);
+}
+
+static bool exc_targets_secure(NVICState *s, int exc)
+{
+    /* Return true if this non-banked exception targets Secure state. */
+    if (!arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
+        return false;
+    }
+
+    if (exc >= NVIC_FIRST_IRQ) {
+        return !s->itns[exc];
+    }
+
+    /* Function shouldn't be called for banked exceptions. */
+    assert(!exc_is_banked(exc));
+
+    switch (exc) {
+    case ARMV7M_EXCP_NMI:
+    case ARMV7M_EXCP_BUS:
+        return !(s->cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK);
+    case ARMV7M_EXCP_SECURE:
+        return true;
+    case ARMV7M_EXCP_DEBUG:
+        /* TODO: controlled by DEMCR.SDME, which we don't yet implement */
+        return false;
+    default:
+        /* reset, and reserved (unused) low exception numbers.
+         * We'll get called by code that loops through all the exception
+         * numbers, but it doesn't matter what we return here as these
+         * non-existent exceptions will never be pended or active.
+         */
+        return true;
+    }
+}
+
+static int exc_group_prio(NVICState *s, int rawprio, bool targets_secure)
+{
+    /* Return the group priority for this exception, given its raw
+     * (group-and-subgroup) priority value and whether it is targeting
+     * secure state or not.
+     */
+    if (rawprio < 0) {
+        return rawprio;
+    }
+    rawprio &= nvic_gprio_mask(s, targets_secure);
+    /* AIRCR.PRIS causes us to squash all NS priorities into the
+     * lower half of the total range
+     */
+    if (!targets_secure &&
+        (s->cpu->env.v7m.aircr & R_V7M_AIRCR_PRIS_MASK)) {
+        rawprio = (rawprio >> 1) + NVIC_NS_PRIO_LIMIT;
+    }
+    return rawprio;
+}
+
+/* Recompute vectpending and exception_prio for a CPU which implements
+ * the Security extension
+ */
+static void nvic_recompute_state_secure(NVICState *s)
 {
-    return ~0U << (s->prigroup[M_REG_NS] + 1);
+    int i, bank;
+    int pend_prio = NVIC_NOEXC_PRIO;
+    int active_prio = NVIC_NOEXC_PRIO;
+    int pend_irq = 0;
+    bool pending_is_s_banked = false;
+
+    /* R_CQRV: precedence is by:
+     *  - lowest group priority; if both the same then
+     *  - lowest subpriority; if both the same then
+     *  - lowest exception number; if both the same (ie banked) then
+     *  - secure exception takes precedence
+     * Compare pseudocode RawExecutionPriority.
+     * Annoyingly, now we have two prigroup values (for S and NS)
+     * we can't do the loop comparison on raw priority values.
+     */
+    for (i = 1; i < s->num_irq; i++) {
+        for (bank = M_REG_S; bank >= M_REG_NS; bank--) {
+            VecInfo *vec;
+            int prio;
+            bool targets_secure;
+
+            if (bank == M_REG_S) {
+                if (!exc_is_banked(i)) {
+                    continue;
+                }
+                vec = &s->sec_vectors[i];
+                targets_secure = true;
+            } else {
+                vec = &s->vectors[i];
+                targets_secure = !exc_is_banked(i) && exc_targets_secure(s, i);
+            }
+
+            prio = exc_group_prio(s, vec->prio, targets_secure);
+            if (vec->enabled && vec->pending && prio < pend_prio) {
+                pend_prio = prio;
+                pend_irq = i;
+                pending_is_s_banked = (bank == M_REG_S);
+            }
+            if (vec->active && prio < active_prio) {
+                active_prio = prio;
+            }
+        }
+    }
+
+    s->vectpending_is_s_banked = pending_is_s_banked;
+    s->vectpending = pend_irq;
+    s->vectpending_prio = pend_prio;
+    s->exception_prio = active_prio;
+
+    trace_nvic_recompute_state_secure(s->vectpending,
+                                      s->vectpending_is_s_banked,
+                                      s->vectpending_prio,
+                                      s->exception_prio);
 }
 
 /* Recompute vectpending and exception_prio */
@@ -143,6 +271,18 @@ static void nvic_recompute_state(NVICState *s)
     int active_prio = NVIC_NOEXC_PRIO;
     int pend_irq = 0;
 
+    /* In theory we could write one function that handled both
+     * the "security extension present" and "not present"; however
+     * the security related changes significantly complicate the
+     * recomputation just by themselves and mixing both cases together
+     * would be even worse, so we retain a separate non-secure-only
+     * version for CPUs which don't implement the security extension.
+     */
+    if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
+        nvic_recompute_state_secure(s);
+        return;
+    }
+
     for (i = 1; i < s->num_irq; i++) {
         VecInfo *vec = &s->vectors[i];
 
@@ -156,11 +296,11 @@ static void nvic_recompute_state(NVICState *s)
     }
 
     if (active_prio > 0) {
-        active_prio &= nvic_gprio_mask(s);
+        active_prio &= nvic_gprio_mask(s, false);
     }
 
     if (pend_prio > 0) {
-        pend_prio &= nvic_gprio_mask(s);
+        pend_prio &= nvic_gprio_mask(s, false);
     }
 
     s->vectpending = pend_irq;
@@ -186,7 +326,8 @@ static inline int nvic_exec_prio(NVICState *s)
     } else if (env->v7m.primask[env->v7m.secure]) {
         running = 0;
     } else if (env->v7m.basepri[env->v7m.secure] > 0) {
-        running = env->v7m.basepri[env->v7m.secure] & nvic_gprio_mask(s);
+        running = env->v7m.basepri[env->v7m.secure] &
+            nvic_gprio_mask(s, env->v7m.secure);
     } else {
         running = NVIC_NOEXC_PRIO; /* lower than any possible priority */
     }
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 5635a5f..0b1fba3 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -168,6 +168,7 @@ gicv3_redist_send_sgi(uint32_t cpu, int irq) "GICv3 redistributor 0x%x pending S
 
 # hw/intc/armv7m_nvic.c
 nvic_recompute_state(int vectpending, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d vectpending_prio %d exception_prio %d"
+nvic_recompute_state_secure(int vectpending, bool vectpending_is_s_banked, int vectpending_prio, int exception_prio) "NVIC state recomputed: vectpending %d is_s_banked %d vectpending_prio %d exception_prio %d"
 nvic_set_prio(int irq, uint8_t prio) "NVIC set irq %d priority %d"
 nvic_irq_update(int vectpending, int pendprio, int exception_prio, int level) "NVIC vectpending %d pending prio %d exception_prio %d: setting irq line to %d"
 nvic_escalate_prio(int irq, int irqprio, int runprio) "NVIC escalating irq %d to HardFault: insufficient priority %d >= %d"
-- 
2.7.4

  parent reply	other threads:[~2017-09-12 18:13 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-12 18:13 [Qemu-devel] [PATCH 00/19] ARMv8M: support security extn in the NVIC Peter Maydell
2017-09-12 18:13 ` [Qemu-devel] [PATCH 01/19] target/arm: Implement MSR/MRS access to NS banked registers Peter Maydell
2017-09-13 22:58   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 02/19] nvic: Add banked exception states Peter Maydell
2017-09-13 23:08   ` Richard Henderson
2017-09-19 18:31   ` [Qemu-devel] [Qemu-arm] " Peter Maydell
2017-09-12 18:13 ` [Qemu-devel] [PATCH 03/19] nvic: Add cached vectpending_is_s_banked state Peter Maydell
2017-09-12 18:13 ` [Qemu-devel] [PATCH 04/19] nvic: Add cached vectpending_prio state Peter Maydell
2017-09-13 23:25   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 05/19] nvic: Implement AIRCR changes for v8M Peter Maydell
2017-09-13 23:35   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 06/19] nvic: Make ICSR.RETTOBASE handle banked exceptions Peter Maydell
2017-09-19 18:04   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 07/19] nvic: Implement NVIC_ITNS<n> registers Peter Maydell
2017-09-19 18:19   ` Richard Henderson
2017-09-12 18:13 ` Peter Maydell [this message]
2017-09-19 18:32   ` [Qemu-devel] [PATCH 08/19] nvic: Handle banked exceptions in nvic_recompute_state() Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 09/19] nvic: Make set_pending and clear_pending take a secure parameter Peter Maydell
2017-09-19 18:41   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 10/19] nvic: Make SHPR registers banked Peter Maydell
2017-09-19 18:47   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 11/19] nvic: Compare group priority for escalation to HF Peter Maydell
2017-09-19 18:48   ` Richard Henderson
2017-09-12 18:13 ` [Qemu-devel] [PATCH 12/19] nvic: In escalation to HardFault, support HF not being priority -1 Peter Maydell
2017-09-19 18:50   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 13/19] nvic: Implement v8M changes to fixed priority exceptions Peter Maydell
2017-09-19 18:54   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 14/19] nvic: Disable the non-secure HardFault if AIRCR.BFHFNMINS is clear Peter Maydell
2017-09-19 18:59   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 15/19] nvic: Handle v8M changes in nvic_exec_prio() Peter Maydell
2017-09-20 17:21   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 16/19] target/arm: Handle banking in negative-execution-priority check in cpu_mmu_index() Peter Maydell
2017-09-20 17:35   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 17/19] nvic: Make ICSR banked for v8M Peter Maydell
2017-09-20 17:43   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 18/19] nvic: Make SHCSR " Peter Maydell
2017-09-20 18:37   ` Richard Henderson
2017-09-12 18:14 ` [Qemu-devel] [PATCH 19/19] nvic: Support banked exceptions in acknowledge and complete Peter Maydell
2017-09-20 18:39   ` Richard Henderson
2017-09-19 18:12 ` [Qemu-devel] [PATCH 00/19] ARMv8M: support security extn in the NVIC no-reply
2017-09-19 18:29   ` Peter Maydell
2017-09-19 18:22 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1505240046-11454-9-git-send-email-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=patches@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).