From nobody Tue Nov 4 06:39:10 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1505240705310782.8750291181383; Tue, 12 Sep 2017 11:25:05 -0700 (PDT) Received: from localhost ([::1]:38004 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1drprs-0005eN-GD for importer@patchew.org; Tue, 12 Sep 2017 14:25:04 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:43478) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1drph4-0003Tz-3N for qemu-devel@nongnu.org; Tue, 12 Sep 2017 14:13:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1drph1-0006S0-Uj for qemu-devel@nongnu.org; Tue, 12 Sep 2017 14:13:54 -0400 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:37298) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1drpgw-0006Mo-0k; Tue, 12 Sep 2017 14:13:46 -0400 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1drpgv-000162-0H; Tue, 12 Sep 2017 19:13:45 +0100 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 12 Sep 2017 19:13:55 +0100 Message-Id: <1505240046-11454-9-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1505240046-11454-1-git-send-email-peter.maydell@linaro.org> References: <1505240046-11454-1-git-send-email-peter.maydell@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PATCH 08/19] nvic: Handle banked exceptions in nvic_recompute_state() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: patches@linaro.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Richard Henderson --- 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 =20 static const uint8_t nvic_id[] =3D { 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 @@ -126,13 +128,139 @@ static bool nvic_isrpending(NVICState *s) return false; } =20 +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 =3D=3D ARMV7M_EXCP_HARD || + exc =3D=3D ARMV7M_EXCP_MEM || + exc =3D=3D ARMV7M_EXCP_USAGE || + exc =3D=3D ARMV7M_EXCP_SVC || + exc =3D=3D ARMV7M_EXCP_PENDSV || + exc =3D=3D 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 >=3D 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 &=3D 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 =3D (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 =3D NVIC_NOEXC_PRIO; + int active_prio =3D NVIC_NOEXC_PRIO; + int pend_irq =3D 0; + bool pending_is_s_banked =3D 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 =3D 1; i < s->num_irq; i++) { + for (bank =3D M_REG_S; bank >=3D M_REG_NS; bank--) { + VecInfo *vec; + int prio; + bool targets_secure; + + if (bank =3D=3D M_REG_S) { + if (!exc_is_banked(i)) { + continue; + } + vec =3D &s->sec_vectors[i]; + targets_secure =3D true; + } else { + vec =3D &s->vectors[i]; + targets_secure =3D !exc_is_banked(i) && exc_targets_secure= (s, i); + } + + prio =3D exc_group_prio(s, vec->prio, targets_secure); + if (vec->enabled && vec->pending && prio < pend_prio) { + pend_prio =3D prio; + pend_irq =3D i; + pending_is_s_banked =3D (bank =3D=3D M_REG_S); + } + if (vec->active && prio < active_prio) { + active_prio =3D prio; + } + } + } + + s->vectpending_is_s_banked =3D pending_is_s_banked; + s->vectpending =3D pend_irq; + s->vectpending_prio =3D pend_prio; + s->exception_prio =3D active_prio; + + trace_nvic_recompute_state_secure(s->vectpending, + s->vectpending_is_s_banked, + s->vectpending_prio, + s->exception_prio); } =20 /* Recompute vectpending and exception_prio */ @@ -143,6 +271,18 @@ static void nvic_recompute_state(NVICState *s) int active_prio =3D NVIC_NOEXC_PRIO; int pend_irq =3D 0; =20 + /* 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 =3D 1; i < s->num_irq; i++) { VecInfo *vec =3D &s->vectors[i]; =20 @@ -156,11 +296,11 @@ static void nvic_recompute_state(NVICState *s) } =20 if (active_prio > 0) { - active_prio &=3D nvic_gprio_mask(s); + active_prio &=3D nvic_gprio_mask(s, false); } =20 if (pend_prio > 0) { - pend_prio &=3D nvic_gprio_mask(s); + pend_prio &=3D nvic_gprio_mask(s, false); } =20 s->vectpending =3D pend_irq; @@ -186,7 +326,8 @@ static inline int nvic_exec_prio(NVICState *s) } else if (env->v7m.primask[env->v7m.secure]) { running =3D 0; } else if (env->v7m.basepri[env->v7m.secure] > 0) { - running =3D env->v7m.basepri[env->v7m.secure] & nvic_gprio_mask(s); + running =3D env->v7m.basepri[env->v7m.secure] & + nvic_gprio_mask(s, env->v7m.secure); } else { running =3D 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 red= istributor 0x%x pending S =20 # 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: vectpend= ing %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 lev= el) "NVIC vectpending %d pending prio %d exception_prio %d: setting irq lin= e to %d" nvic_escalate_prio(int irq, int irqprio, int runprio) "NVIC escalating irq= %d to HardFault: insufficient priority %d >=3D %d" --=20 2.7.4