From nobody Sun May 19 00:42:46 2024 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 1517324900504809.4133336049313; Tue, 30 Jan 2018 07:08:20 -0800 (PST) Received: from localhost ([::1]:42103 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXWA-0004Mv-QM for importer@patchew.org; Tue, 30 Jan 2018 10:08:14 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49133) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXQq-0000Jo-Gv for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQp-0005dt-0S for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:44 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46114) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQd-0005Xp-Eq; Tue, 30 Jan 2018 10:02:31 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQW-0005sJ-CG; Tue, 30 Jan 2018 15:02:24 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:16 +0000 Message-Id: <1517324542-6607-2-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 1/7] target/arm: Add armv7m_nvic_set_pending_derived() 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" In order to support derived exceptions (exceptions generated in the course of trying to take an exception), we need to be able to handle prioritizing whether to take the original exception or the derived exception. We do this by introducing a new function armv7m_nvic_set_pending_derived() which the exception-taking code in helper.c will call when a derived exception occurs. Derived exceptions are dealt with mostly like normal pending exceptions, so we share the implementation with the armv7m_nvic_set_pending() function. Note that the way we structure this is significantly different from the v8M Arm ARM pseudocode: that does all the prioritization logic in the DerivedLateArrival() function, whereas we choose to let the existing "identify highest priority exception" logic do the prioritization for us. The effect is the same, though. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/cpu.h | 13 ++++++++++ hw/intc/armv7m_nvic.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++= ++-- hw/intc/trace-events | 2 +- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index d2bb59e..9ed03e6 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1506,6 +1506,19 @@ static inline bool armv7m_nvic_can_take_pending_exce= ption(void *opaque) */ void armv7m_nvic_set_pending(void *opaque, int irq, bool secure); /** + * armv7m_nvic_set_pending_derived: mark this derived exception as pending + * @opaque: the NVIC + * @irq: the exception number to mark pending + * @secure: false for non-banked exceptions or for the nonsecure + * version of a banked exception, true for the secure version of a banked + * exception. + * + * Similar to armv7m_nvic_set_pending(), but specifically for derived + * exceptions (exceptions generated in the course of trying to take + * a different exception). + */ +void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); +/** * armv7m_nvic_acknowledge_irq: make highest priority pending exception ac= tive * @opaque: the NVIC * diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 8ca6cee..b4a6e7c 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -503,8 +503,25 @@ static void armv7m_nvic_clear_pending(void *opaque, in= t irq, bool secure) } } =20 -void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) +static void do_armv7m_nvic_set_pending(void *opaque, int irq, bool secure, + bool derived) { + /* Pend an exception, including possibly escalating it to HardFault. + * + * This function handles both "normal" pending of interrupts and + * exceptions, and also derived exceptions (ones which occur as + * a result of trying to take some other exception). + * + * If derived =3D=3D true, the caller guarantees that we are part way = through + * trying to take an exception (but have not yet called + * armv7m_nvic_acknowledge_irq() to make it active), and so: + * - s->vectpending is the "original exception" we were trying to take + * - irq is the "derived exception" + * - nvic_exec_prio(s) gives the priority before exception entry + * Here we handle the prioritization logic which the pseudocode puts + * in the DerivedLateArrival() function. + */ + NVICState *s =3D (NVICState *)opaque; bool banked =3D exc_is_banked(irq); VecInfo *vec; @@ -514,7 +531,44 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bo= ol secure) =20 vec =3D (banked && secure) ? &s->sec_vectors[irq] : &s->vectors[irq]; =20 - trace_nvic_set_pending(irq, secure, vec->enabled, vec->prio); + trace_nvic_set_pending(irq, secure, derived, vec->enabled, vec->prio); + + if (derived) { + /* Derived exceptions are always synchronous. */ + assert(irq >=3D ARMV7M_EXCP_HARD && irq < ARMV7M_EXCP_PENDSV); + + if (irq =3D=3D ARMV7M_EXCP_DEBUG && + exc_group_prio(s, vec->prio, secure) >=3D nvic_exec_prio(s)) { + /* DebugMonitorFault, but its priority is lower than the + * preempted exception priority: just ignore it. + */ + return; + } + + if (irq =3D=3D ARMV7M_EXCP_HARD && vec->prio >=3D s->vectpending_p= rio) { + /* If this is a terminal exception (one which means we cannot + * take the original exception, like a failure to read its + * vector table entry), then we must take the derived exceptio= n. + * If the derived exception can't take priority over the + * original exception, then we go into Lockup. + * + * For QEMU, we rely on the fact that a derived exception is + * terminal if and only if it's reported to us as HardFault, + * which saves having to have an extra argument is_terminal + * that we'd only use in one place. + */ + cpu_abort(&s->cpu->parent_obj, + "Lockup: can't take terminal derived exception " + "(original exception priority %d)\n", + s->vectpending_prio); + } + /* We now continue with the same code as for a normal pending + * exception, which will cause us to pend the derived exception. + * We'll then take either the original or the derived exception + * based on which is higher priority by the usual mechanism + * for selecting the highest priority pending interrupt. + */ + } =20 if (irq >=3D ARMV7M_EXCP_HARD && irq < ARMV7M_EXCP_PENDSV) { /* If a synchronous exception is pending then it may be @@ -585,6 +639,16 @@ void armv7m_nvic_set_pending(void *opaque, int irq, bo= ol secure) } } =20 +void armv7m_nvic_set_pending(void *opaque, int irq, bool secure) +{ + do_armv7m_nvic_set_pending(opaque, irq, secure, false); +} + +void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure) +{ + do_armv7m_nvic_set_pending(opaque, irq, secure, true); +} + /* Make pending IRQ active. */ bool armv7m_nvic_acknowledge_irq(void *opaque) { diff --git a/hw/intc/trace-events b/hw/intc/trace-events index be76918..09e87d1 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -177,7 +177,7 @@ nvic_set_prio(int irq, bool secure, uint8_t prio) "NVIC= set irq %d secure-bank % 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" nvic_escalate_disabled(int irq) "NVIC escalating irq %d to HardFault: disa= bled" -nvic_set_pending(int irq, bool secure, int en, int prio) "NVIC set pending= irq %d secure-bank %d (enabled: %d priority %d)" +nvic_set_pending(int irq, bool secure, bool derived, int en, int prio) "NV= IC set pending irq %d secure-bank %d derived %d (enabled: %d priority %d)" nvic_clear_pending(int irq, bool secure, int en, int prio) "NVIC clear pen= ding irq %d secure-bank %d (enabled: %d priority %d)" nvic_set_pending_level(int irq) "NVIC set pending: irq %d higher prio than= vectpending: setting irq line to 1" nvic_acknowledge_irq(int irq, int prio, bool targets_secure) "NVIC acknowl= edge IRQ: %d now active (prio %d targets_secure %d)" --=20 2.7.4 From nobody Sun May 19 00:42:46 2024 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 1517324735788654.6011309265177; Tue, 30 Jan 2018 07:05:35 -0800 (PST) Received: from localhost ([::1]:42080 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXTa-0002Gp-VP for importer@patchew.org; Tue, 30 Jan 2018 10:05:34 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49159) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXQv-0000Ob-A9 for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:55 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQk-0005cW-Vg for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:49 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46094) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQY-0005SC-SW; Tue, 30 Jan 2018 10:02:27 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQX-0005sa-57; Tue, 30 Jan 2018 15:02:25 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:17 +0000 Message-Id: <1517324542-6607-3-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 2/7] target/arm: Split "get pending exception info" from "acknowledge it" 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" Currently armv7m_nvic_acknowledge_irq() does three things: * make the current highest priority pending interrupt active * return a bool indicating whether that interrupt is targeting Secure or NonSecure state * implicitly tell the caller which is the highest priority pending interrupt by setting env->v7m.exception We need to split these jobs, because v7m_exception_taken() needs to know whether the pending interrupt targets Secure so it can choose to stack callee-saves registers or not, but it must not make the interrupt active until after it has done that stacking, in case the stacking causes a derived exception. Similarly, it needs to know the number of the pending interrupt so it can read the correct vector table entry before the interrupt is made active, because vector table reads might also cause a derived exception. Create a new armv7m_nvic_get_pending_irq_info() function which simply returns information about the highest priority pending interrupt, and use it to rearrange the v7m_exception_taken() code so we don't acknowledge the exception until we've done all the things which could possibly cause a derived exception. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daud=C3=A9 Reviewed-by: Richard Henderson --- target/arm/cpu.h | 19 ++++++++++++++++--- hw/intc/armv7m_nvic.c | 30 +++++++++++++++++++++++------- target/arm/helper.c | 16 ++++++++++++---- hw/intc/trace-events | 3 ++- 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 9ed03e6..f21f68e 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1519,16 +1519,29 @@ void armv7m_nvic_set_pending(void *opaque, int irq,= bool secure); */ void armv7m_nvic_set_pending_derived(void *opaque, int irq, bool secure); /** + * armv7m_nvic_get_pending_irq_info: return highest priority pending + * exception, and whether it targets Secure state + * @opaque: the NVIC + * @pirq: set to pending exception number + * @ptargets_secure: set to whether pending exception targets Secure + * + * This function writes the number of the highest priority pending + * exception (the one which would be made active by + * armv7m_nvic_acknowledge_irq()) to @pirq, and sets @ptargets_secure + * to true if the current highest priority pending exception should + * be taken to Secure state, false for NS. + */ +void armv7m_nvic_get_pending_irq_info(void *opaque, int *pirq, + bool *ptargets_secure); +/** * armv7m_nvic_acknowledge_irq: make highest priority pending exception ac= tive * @opaque: the NVIC * * Move the current highest priority pending exception from the pending * state to the active state, and update v7m.exception to indicate that * it is the exception currently being handled. - * - * Returns: true if exception should be taken to Secure state, false for NS */ -bool armv7m_nvic_acknowledge_irq(void *opaque); +void armv7m_nvic_acknowledge_irq(void *opaque); /** * armv7m_nvic_complete_irq: complete specified interrupt or exception * @opaque: the NVIC diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index b4a6e7c..360889d 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -650,24 +650,20 @@ void armv7m_nvic_set_pending_derived(void *opaque, in= t irq, bool secure) } =20 /* Make pending IRQ active. */ -bool armv7m_nvic_acknowledge_irq(void *opaque) +void armv7m_nvic_acknowledge_irq(void *opaque) { NVICState *s =3D (NVICState *)opaque; CPUARMState *env =3D &s->cpu->env; const int pending =3D s->vectpending; const int running =3D nvic_exec_prio(s); VecInfo *vec; - bool targets_secure; =20 assert(pending > ARMV7M_EXCP_RESET && pending < s->num_irq); =20 if (s->vectpending_is_s_banked) { vec =3D &s->sec_vectors[pending]; - targets_secure =3D true; } else { vec =3D &s->vectors[pending]; - targets_secure =3D !exc_is_banked(s->vectpending) && - exc_targets_secure(s, s->vectpending); } =20 assert(vec->enabled); @@ -675,7 +671,7 @@ bool armv7m_nvic_acknowledge_irq(void *opaque) =20 assert(s->vectpending_prio < running); =20 - trace_nvic_acknowledge_irq(pending, s->vectpending_prio, targets_secur= e); + trace_nvic_acknowledge_irq(pending, s->vectpending_prio); =20 vec->active =3D 1; vec->pending =3D 0; @@ -683,8 +679,28 @@ bool armv7m_nvic_acknowledge_irq(void *opaque) write_v7m_exception(env, s->vectpending); =20 nvic_irq_update(s); +} + +void armv7m_nvic_get_pending_irq_info(void *opaque, + int *pirq, bool *ptargets_secure) +{ + NVICState *s =3D (NVICState *)opaque; + const int pending =3D s->vectpending; + bool targets_secure; + + assert(pending > ARMV7M_EXCP_RESET && pending < s->num_irq); + + if (s->vectpending_is_s_banked) { + targets_secure =3D true; + } else { + targets_secure =3D !exc_is_banked(pending) && + exc_targets_secure(s, pending); + } + + trace_nvic_get_pending_irq_info(pending, targets_secure); =20 - return targets_secure; + *ptargets_secure =3D targets_secure; + *pirq =3D pending; } =20 int armv7m_nvic_complete_irq(void *opaque, int irq, bool secure) diff --git a/target/arm/helper.c b/target/arm/helper.c index bfce096..6062f38 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6395,12 +6395,12 @@ static uint32_t *get_v7m_sp_ptr(CPUARMState *env, b= ool secure, bool threadmode, } } =20 -static uint32_t arm_v7m_load_vector(ARMCPU *cpu, bool targets_secure) +static uint32_t arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_sec= ure) { CPUState *cs =3D CPU(cpu); CPUARMState *env =3D &cpu->env; MemTxResult result; - hwaddr vec =3D env->v7m.vecbase[targets_secure] + env->v7m.exception *= 4; + hwaddr vec =3D env->v7m.vecbase[targets_secure] + exc * 4; uint32_t addr; =20 addr =3D address_space_ldl(cs->as, vec, @@ -6462,8 +6462,9 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t= lr, bool dotailchain) CPUARMState *env =3D &cpu->env; uint32_t addr; bool targets_secure; + int exc; =20 - targets_secure =3D armv7m_nvic_acknowledge_irq(env->nvic); + armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure); =20 if (arm_feature(env, ARM_FEATURE_V8)) { if (arm_feature(env, ARM_FEATURE_M_SECURITY) && @@ -6531,6 +6532,14 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_= t lr, bool dotailchain) } } =20 + addr =3D arm_v7m_load_vector(cpu, exc, targets_secure); + + /* Now we've done everything that might cause a derived exception + * we can go ahead and activate whichever exception we're going to + * take (which might now be the derived exception). + */ + armv7m_nvic_acknowledge_irq(env->nvic); + /* Switch to target security state -- must do this before writing SPSE= L */ switch_v7m_security_state(env, targets_secure); write_v7m_control_spsel(env, 0); @@ -6538,7 +6547,6 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t= lr, bool dotailchain) /* Clear IT bits */ env->condexec_bits =3D 0; env->regs[14] =3D lr; - addr =3D arm_v7m_load_vector(cpu, targets_secure); env->regs[15] =3D addr & 0xfffffffe; env->thumb =3D addr & 1; } diff --git a/hw/intc/trace-events b/hw/intc/trace-events index 09e87d1..4092d28 100644 --- a/hw/intc/trace-events +++ b/hw/intc/trace-events @@ -180,7 +180,8 @@ nvic_escalate_disabled(int irq) "NVIC escalating irq %d= to HardFault: disabled" nvic_set_pending(int irq, bool secure, bool derived, int en, int prio) "NV= IC set pending irq %d secure-bank %d derived %d (enabled: %d priority %d)" nvic_clear_pending(int irq, bool secure, int en, int prio) "NVIC clear pen= ding irq %d secure-bank %d (enabled: %d priority %d)" nvic_set_pending_level(int irq) "NVIC set pending: irq %d higher prio than= vectpending: setting irq line to 1" -nvic_acknowledge_irq(int irq, int prio, bool targets_secure) "NVIC acknowl= edge IRQ: %d now active (prio %d targets_secure %d)" +nvic_acknowledge_irq(int irq, int prio) "NVIC acknowledge IRQ: %d now acti= ve (prio %d)" +nvic_get_pending_irq_info(int irq, bool secure) "NVIC next IRQ %d: targets= _secure: %d" nvic_complete_irq(int irq, bool secure) "NVIC complete IRQ %d (secure %d)" nvic_set_irq_level(int irq, int level) "NVIC external irq %d level set to = %d" nvic_sysreg_read(uint64_t addr, uint32_t value, unsigned size) "NVIC sysre= g read addr 0x%" PRIx64 " data 0x%" PRIx32 " size %u" --=20 2.7.4 From nobody Sun May 19 00:42:46 2024 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 1517324726009291.2800070740717; Tue, 30 Jan 2018 07:05:26 -0800 (PST) Received: from localhost ([::1]:42079 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXTP-00025m-0B for importer@patchew.org; Tue, 30 Jan 2018 10:05:23 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49153) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXQu-0000O5-OR for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:54 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQo-0005dV-EY for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:48 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46104) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQZ-0005Tn-5O; Tue, 30 Jan 2018 10:02:27 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQX-0005sp-VE; Tue, 30 Jan 2018 15:02:25 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:18 +0000 Message-Id: <1517324542-6607-4-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 3/7] target/arm: Add ignore_stackfaults argument to v7m_exception_taken() 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" In the v8M architecture, if the process of taking an exception results in a further exception this is called a derived exception (for example, an MPU exception when writing the exception frame to memory). If the derived exception happens while pushing the initial stack frame, we must ignore any subsequent possible exception pushing the callee-saves registers. In preparation for making the stack writes check for exceptions, add a return value from v7m_push_stack() and a new parameter to v7m_exception_taken(), so that the former can tell the latter that it needs to ignore failures to write to the stack. We also plumb the argument through to v7m_push_callee_stack(), which is where the code to ignore the failures will be. (Note that the v8M ARM pseudocode structures this slightly differently: derived exceptions cause the attempt to process the original exception to be abandoned; then at the top level it calls DerivedLateArrival to prioritize the derived exception and call TakeException from there. We choose to let the NVIC do the prioritization and continue forward with a call to TakeException which will then take either the original or the derived exception. The effect is the same, but this structure works better for QEMU because we don't have a convenient top level place to do the abandon-and-retry logic.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6062f38..c713eea 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6419,7 +6419,8 @@ static uint32_t arm_v7m_load_vector(ARMCPU *cpu, int = exc, bool targets_secure) return addr; } =20 -static void v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in) +static void v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in, + bool ignore_faults) { /* For v8M, push the callee-saves register part of the stack frame. * Compare the v8M pseudocode PushCalleeStack(). @@ -6453,7 +6454,8 @@ static void v7m_push_callee_stack(ARMCPU *cpu, uint32= _t lr, bool dotailchain) *frame_sp_p =3D frameptr; } =20 -static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain) +static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, + bool ignore_stackfaults) { /* Do the "take the exception" parts of exception entry, * but not the pushing of state to the stack. This is @@ -6490,7 +6492,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t= lr, bool dotailchain) */ if (lr & R_V7M_EXCRET_DCRS_MASK && !(dotailchain && (lr & R_V7M_EXCRET_ES_MASK))) { - v7m_push_callee_stack(cpu, lr, dotailchain); + v7m_push_callee_stack(cpu, lr, dotailchain, + ignore_stackfaults); } lr |=3D R_V7M_EXCRET_DCRS_MASK; } @@ -6551,10 +6554,13 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32= _t lr, bool dotailchain) env->thumb =3D addr & 1; } =20 -static void v7m_push_stack(ARMCPU *cpu) +static bool v7m_push_stack(ARMCPU *cpu) { /* Do the "set up stack frame" part of exception entry, * similar to pseudocode PushStack(). + * Return true if we generate a derived exception (and so + * should ignore further stack faults trying to process + * that derived exception.) */ CPUARMState *env =3D &cpu->env; uint32_t xpsr =3D xpsr_read(env); @@ -6574,6 +6580,8 @@ static void v7m_push_stack(ARMCPU *cpu) v7m_push(env, env->regs[2]); v7m_push(env, env->regs[1]); v7m_push(env, env->regs[0]); + + return false; } =20 static void do_v7m_exception_exit(ARMCPU *cpu) @@ -6719,7 +6727,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) if (sfault) { env->v7m.sfsr |=3D R_V7M_SFSR_INVER_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, false); - v7m_exception_taken(cpu, excret, true); + v7m_exception_taken(cpu, excret, true, false); qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on existing " "stackframe: failed EXC_RETURN.ES validity check\n"); return; @@ -6731,7 +6739,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) */ env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.sec= ure); - v7m_exception_taken(cpu, excret, true); + v7m_exception_taken(cpu, excret, true, false); qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existing " "stackframe: failed exception return integrity check= \n"); return; @@ -6779,7 +6787,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) /* Take a SecureFault on the current stack */ env->v7m.sfsr |=3D R_V7M_SFSR_INVIS_MASK; armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_SECURE, fal= se); - v7m_exception_taken(cpu, excret, true); + v7m_exception_taken(cpu, excret, true, false); qemu_log_mask(CPU_LOG_INT, "...taking SecureFault on exist= ing " "stackframe: failed exception return integri= ty " "signature check\n"); @@ -6844,7 +6852,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, env->v7m.secure); env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; - v7m_exception_taken(cpu, excret, true); + v7m_exception_taken(cpu, excret, true, false); qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on existi= ng " "stackframe: failed exception return integri= ty " "check\n"); @@ -6877,11 +6885,13 @@ static void do_v7m_exception_exit(ARMCPU *cpu) /* Take an INVPC UsageFault by pushing the stack again; * we know we're v7M so this is never a Secure UsageFault. */ + bool ignore_stackfaults; + assert(!arm_feature(env, ARM_FEATURE_V8)); armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_USAGE, false); env->v7m.cfsr[env->v7m.secure] |=3D R_V7M_CFSR_INVPC_MASK; - v7m_push_stack(cpu); - v7m_exception_taken(cpu, excret, false); + ignore_stackfaults =3D v7m_push_stack(cpu); + v7m_exception_taken(cpu, excret, false, ignore_stackfaults); qemu_log_mask(CPU_LOG_INT, "...taking UsageFault on new stackframe= : " "failed exception return integrity check\n"); return; @@ -7122,6 +7132,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) ARMCPU *cpu =3D ARM_CPU(cs); CPUARMState *env =3D &cpu->env; uint32_t lr; + bool ignore_stackfaults; =20 arm_log_exception(cs->exception_index); =20 @@ -7296,8 +7307,8 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) lr |=3D R_V7M_EXCRET_MODE_MASK; } =20 - v7m_push_stack(cpu); - v7m_exception_taken(cpu, lr, false); + ignore_stackfaults =3D v7m_push_stack(cpu); + v7m_exception_taken(cpu, lr, false, ignore_stackfaults); qemu_log_mask(CPU_LOG_INT, "... as %d\n", env->v7m.exception); } =20 --=20 2.7.4 From nobody Sun May 19 00:42:46 2024 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 (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1517325066486491.83052479430864; Tue, 30 Jan 2018 07:11:06 -0800 (PST) Received: from localhost ([::1]:42249 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXYq-0006kr-Jo for importer@patchew.org; Tue, 30 Jan 2018 10:11:00 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49187) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXR0-0000UM-F3 for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:03:02 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQu-0005gr-55 for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:54 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46108) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQb-0005Uz-Qp; Tue, 30 Jan 2018 10:02:30 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQY-0005t7-QJ; Tue, 30 Jan 2018 15:02:26 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:19 +0000 Message-Id: <1517324542-6607-5-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 4/7] target/arm: Make v7M exception entry stack push check MPU 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" The memory writes done to push registers on the stack on exception entry in M profile CPUs are supposed to go via MPU permissions checks, which may cause us to take a derived exception instead of the original one of the MPU lookup fails. We were implementing these as always-succeeds direct writes to physical memory. Rewrite v7m_push_stack() to do the necessary checks. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 103 ++++++++++++++++++++++++++++++++++++++++++++----= ---- 1 file changed, 87 insertions(+), 16 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index c713eea..007e760 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6161,12 +6161,66 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint= 32_t excp_idx, return target_el; } =20 -static void v7m_push(CPUARMState *env, uint32_t val) +static bool v7m_stack_write(ARMCPU *cpu, uint32_t addr, uint32_t value, + ARMMMUIdx mmu_idx, bool ignfault) { - CPUState *cs =3D CPU(arm_env_get_cpu(env)); + CPUState *cs =3D CPU(cpu); + CPUARMState *env =3D &cpu->env; + MemTxAttrs attrs =3D {}; + MemTxResult txres; + target_ulong page_size; + hwaddr physaddr; + int prot; + ARMMMUFaultInfo fi; + bool secure =3D mmu_idx & ARM_MMU_IDX_M_S; + int exc; + bool exc_secure; =20 - env->regs[13] -=3D 4; - stl_phys(cs->as, env->regs[13], val); + if (get_phys_addr(env, addr, MMU_DATA_STORE, mmu_idx, &physaddr, + &attrs, &prot, &page_size, &fi, NULL)) { + /* MPU/SAU lookup failed */ + if (fi.type =3D=3D ARMFault_QEMU_SFault) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.AUVIOL during stacking= \n"); + env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVAL= ID_MASK; + env->v7m.sfar =3D addr; + exc =3D ARMV7M_EXCP_SECURE; + exc_secure =3D true; + } else { + qemu_log_mask(CPU_LOG_INT, "...MemManageFault with CFSR.MSTKER= R\n"); + env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MSTKERR_MASK; + exc =3D ARMV7M_EXCP_MEM; + exc_secure =3D secure; + } + goto pend_fault; + } + address_space_stl_le(arm_addressspace(cs, attrs), physaddr, value, + attrs, &txres); + if (txres !=3D MEMTX_OK) { + /* BusFault trying to write the data */ + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.STKERR\n"); + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_STKERR_MASK; + exc =3D ARMV7M_EXCP_BUS; + exc_secure =3D false; + goto pend_fault; + } + return true; + +pend_fault: + /* By pending the exception at this point we are making + * the IMPDEF choice "overridden exceptions pended" (see the + * MergeExcInfo() pseudocode). The other choice would be to not + * pend them now and then make a choice about which to throw away + * later if we have two derived exceptions. + * The only case when we must not pend the exception but instead + * throw it away is if we are doing the push of the callee registers + * and we've already generated a derived exception. Even in this + * case we will still update the fault status registers. + */ + if (!ignfault) { + armv7m_nvic_set_pending_derived(env->nvic, exc, exc_secure); + } + return false; } =20 /* Return true if we're using the process stack pointer (not the MSP) */ @@ -6562,26 +6616,43 @@ static bool v7m_push_stack(ARMCPU *cpu) * should ignore further stack faults trying to process * that derived exception.) */ + bool stacked_ok; CPUARMState *env =3D &cpu->env; uint32_t xpsr =3D xpsr_read(env); + uint32_t frameptr =3D env->regs[13]; + ARMMMUIdx mmu_idx =3D core_to_arm_mmu_idx(env, cpu_mmu_index(env, fals= e)); =20 /* Align stack pointer if the guest wants that */ - if ((env->regs[13] & 4) && + if ((frameptr & 4) && (env->v7m.ccr[env->v7m.secure] & R_V7M_CCR_STKALIGN_MASK)) { - env->regs[13] -=3D 4; + frameptr -=3D 4; xpsr |=3D XPSR_SPREALIGN; } - /* Switch to the handler mode. */ - v7m_push(env, xpsr); - v7m_push(env, env->regs[15]); - v7m_push(env, env->regs[14]); - v7m_push(env, env->regs[12]); - v7m_push(env, env->regs[3]); - v7m_push(env, env->regs[2]); - v7m_push(env, env->regs[1]); - v7m_push(env, env->regs[0]); =20 - return false; + frameptr -=3D 0x20; + + /* Write as much of the stack frame as we can. If we fail a stack + * write this will result in a derived exception being pended + * (which may be taken in preference to the one we started with + * if it has higher priority). + */ + stacked_ok =3D + v7m_stack_write(cpu, frameptr, env->regs[0], mmu_idx, false) && + v7m_stack_write(cpu, frameptr + 4, env->regs[1], mmu_idx, false) && + v7m_stack_write(cpu, frameptr + 8, env->regs[2], mmu_idx, false) && + v7m_stack_write(cpu, frameptr + 12, env->regs[3], mmu_idx, false) = && + v7m_stack_write(cpu, frameptr + 16, env->regs[12], mmu_idx, false)= && + v7m_stack_write(cpu, frameptr + 20, env->regs[14], mmu_idx, false)= && + v7m_stack_write(cpu, frameptr + 24, env->regs[15], mmu_idx, false)= && + v7m_stack_write(cpu, frameptr + 28, xpsr, mmu_idx, false); + + /* Update SP regardless of whether any of the stack accesses failed. + * When we implement v8M stack limit checking then this attempt to + * update SP might also fail and result in a derived exception. + */ + env->regs[13] =3D frameptr; + + return !stacked_ok; } =20 static void do_v7m_exception_exit(ARMCPU *cpu) --=20 2.7.4 From nobody Sun May 19 00:42:46 2024 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 1517324920385356.5321516676445; Tue, 30 Jan 2018 07:08:40 -0800 (PST) Received: from localhost ([::1]:42106 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXWZ-0004i1-Hr for importer@patchew.org; Tue, 30 Jan 2018 10:08:39 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49177) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXQx-0000QZ-4a for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:57 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQn-0005d6-CE for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:51 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46108) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQa-0005Uz-Qm; Tue, 30 Jan 2018 10:02:28 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQZ-0005tN-Mu; Tue, 30 Jan 2018 15:02:27 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:20 +0000 Message-Id: <1517324542-6607-6-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 5/7] target/arm: Make v7m_push_callee_stack() honour MPU 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" Make v7m_push_callee_stack() honour the MPU by using the new v7m_stack_write() function. We return a flag to indicate whether the pushes failed, which we can then use in v7m_exception_taken() to cause us to handle the derived exception correctly. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daud=C3=A9 Reviewed-by: Richard Henderson --- target/arm/helper.c | 64 ++++++++++++++++++++++++++++++++++++++++---------= ---- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 007e760..de0031b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6473,7 +6473,7 @@ static uint32_t arm_v7m_load_vector(ARMCPU *cpu, int = exc, bool targets_secure) return addr; } =20 -static void v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in, +static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in, bool ignore_faults) { /* For v8M, push the callee-saves register part of the stack frame. @@ -6481,31 +6481,55 @@ static void v7m_push_callee_stack(ARMCPU *cpu, uint= 32_t lr, bool dotailchain, * In the tailchaining case this may not be the current stack. */ CPUARMState *env =3D &cpu->env; - CPUState *cs =3D CPU(cpu); uint32_t *frame_sp_p; uint32_t frameptr; + ARMMMUIdx mmu_idx; + bool stacked_ok; =20 if (dotailchain) { - frame_sp_p =3D get_v7m_sp_ptr(env, true, - lr & R_V7M_EXCRET_MODE_MASK, + bool mode =3D lr & R_V7M_EXCRET_MODE_MASK; + bool priv =3D !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_NPRIV_MA= SK) || + !mode; + + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, M_REG_S, pr= iv); + frame_sp_p =3D get_v7m_sp_ptr(env, M_REG_S, mode, lr & R_V7M_EXCRET_SPSEL_MASK); } else { + mmu_idx =3D core_to_arm_mmu_idx(env, cpu_mmu_index(env, false)); frame_sp_p =3D &env->regs[13]; } =20 frameptr =3D *frame_sp_p - 0x28; =20 - stl_phys(cs->as, frameptr, 0xfefa125b); - stl_phys(cs->as, frameptr + 0x8, env->regs[4]); - stl_phys(cs->as, frameptr + 0xc, env->regs[5]); - stl_phys(cs->as, frameptr + 0x10, env->regs[6]); - stl_phys(cs->as, frameptr + 0x14, env->regs[7]); - stl_phys(cs->as, frameptr + 0x18, env->regs[8]); - stl_phys(cs->as, frameptr + 0x1c, env->regs[9]); - stl_phys(cs->as, frameptr + 0x20, env->regs[10]); - stl_phys(cs->as, frameptr + 0x24, env->regs[11]); + /* Write as much of the stack frame as we can. A write failure may + * cause us to pend a derived exception. + */ + stacked_ok =3D + v7m_stack_write(cpu, frameptr, 0xfefa125b, mmu_idx, ignore_faults)= && + v7m_stack_write(cpu, frameptr + 0x8, env->regs[4], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0xc, env->regs[5], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0x10, env->regs[6], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0x14, env->regs[7], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0x18, env->regs[8], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0x1c, env->regs[9], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0x20, env->regs[10], mmu_idx, + ignore_faults) && + v7m_stack_write(cpu, frameptr + 0x24, env->regs[11], mmu_idx, + ignore_faults); =20 + /* Update SP regardless of whether any of the stack accesses failed. + * When we implement v8M stack limit checking then this attempt to + * update SP might also fail and result in a derived exception. + */ *frame_sp_p =3D frameptr; + + return !stacked_ok; } =20 static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr, bool dotailchain, @@ -6519,6 +6543,7 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t= lr, bool dotailchain, uint32_t addr; bool targets_secure; int exc; + bool push_failed =3D false; =20 armv7m_nvic_get_pending_irq_info(env->nvic, &exc, &targets_secure); =20 @@ -6546,8 +6571,8 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_t= lr, bool dotailchain, */ if (lr & R_V7M_EXCRET_DCRS_MASK && !(dotailchain && (lr & R_V7M_EXCRET_ES_MASK))) { - v7m_push_callee_stack(cpu, lr, dotailchain, - ignore_stackfaults); + push_failed =3D v7m_push_callee_stack(cpu, lr, dotailc= hain, + ignore_stackfaults= ); } lr |=3D R_V7M_EXCRET_DCRS_MASK; } @@ -6589,6 +6614,15 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_= t lr, bool dotailchain, } } =20 + if (push_failed && !ignore_stackfaults) { + /* Derived exception on callee-saves register stacking: + * we might now want to take a different exception which + * targets a different security state, so try again from the top. + */ + v7m_exception_taken(cpu, lr, true, true); + return; + } + addr =3D arm_v7m_load_vector(cpu, exc, targets_secure); =20 /* Now we've done everything that might cause a derived exception --=20 2.7.4 From nobody Sun May 19 00:42:46 2024 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 1517324921484963.5002864638769; Tue, 30 Jan 2018 07:08:41 -0800 (PST) Received: from localhost ([::1]:42107 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXWa-0004jl-MG for importer@patchew.org; Tue, 30 Jan 2018 10:08:40 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49175) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXQw-0000QF-R8 for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:52 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQn-0005d1-Ax for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:50 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46108) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQc-0005Uz-Rr; Tue, 30 Jan 2018 10:02:31 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQa-0005tc-Fs; Tue, 30 Jan 2018 15:02:28 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:21 +0000 Message-Id: <1517324542-6607-7-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 6/7] target/arm: Make exception vector loads honour the SAU 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" Make the load of the exception vector from the vector table honour the SAU and any bus error on the load (possibly provoking a derived exception), rather than simply aborting if the load fails. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 71 +++++++++++++++++++++++++++++++++++++++++--------= ---- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index de0031b..6931a9d 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6449,28 +6449,63 @@ static uint32_t *get_v7m_sp_ptr(CPUARMState *env, b= ool secure, bool threadmode, } } =20 -static uint32_t arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_sec= ure) +static bool arm_v7m_load_vector(ARMCPU *cpu, int exc, bool targets_secure, + uint32_t *pvec) { CPUState *cs =3D CPU(cpu); CPUARMState *env =3D &cpu->env; MemTxResult result; - hwaddr vec =3D env->v7m.vecbase[targets_secure] + exc * 4; - uint32_t addr; + uint32_t addr =3D env->v7m.vecbase[targets_secure] + exc * 4; + uint32_t vector_entry; + MemTxAttrs attrs =3D {}; + ARMMMUIdx mmu_idx; + bool exc_secure; + + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, targets_secure,= true); =20 - addr =3D address_space_ldl(cs->as, vec, - MEMTXATTRS_UNSPECIFIED, &result); + /* We don't do a get_phys_addr() here because the rules for vector + * loads are special: they always use the default memory map, and + * the default memory map permits reads from all addresses. + * Since there's no easy way to pass through to pmsav8_mpu_lookup() + * that we want this special case which would always say "yes", + * we just do the SAU lookup here followed by a direct physical load. + */ + attrs.secure =3D targets_secure; + attrs.user =3D false; + + if (arm_feature(env, ARM_FEATURE_M_SECURITY)) { + V8M_SAttributes sattrs =3D {}; + + v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs); + if (sattrs.ns) { + attrs.secure =3D false; + } else if (!targets_secure) { + /* NS access to S memory */ + goto load_fail; + } + } + + vector_entry =3D address_space_ldl(arm_addressspace(cs, attrs), addr, + attrs, &result); if (result !=3D MEMTX_OK) { - /* Architecturally this should cause a HardFault setting HSFR.VECT= TBL, - * which would then be immediately followed by our failing to load - * the entry vector for that HardFault, which is a Lockup case. - * Since we don't model Lockup, we just report this guest error - * via cpu_abort(). - */ - cpu_abort(cs, "Failed to read from %s exception vector table " - "entry %08x\n", targets_secure ? "secure" : "nonsecure", - (unsigned)vec); + goto load_fail; } - return addr; + *pvec =3D vector_entry; + return true; + +load_fail: + /* All vector table fetch fails are reported as HardFault, with + * HFSR.VECTTBL and .FORCED set. (FORCED is set because + * technically the underlying exception is a MemManage or BusFault + * that is escalated to HardFault.) This is a terminal exception, + * so we will either take the HardFault immediately or else enter + * lockup (the latter case is handled in armv7m_nvic_set_pending_deriv= ed()). + */ + exc_secure =3D targets_secure || + !(cpu->env.v7m.aircr & R_V7M_AIRCR_BFHFNMINS_MASK); + env->v7m.hfsr |=3D R_V7M_HFSR_VECTTBL_MASK | R_V7M_HFSR_FORCED_MASK; + armv7m_nvic_set_pending_derived(env->nvic, ARMV7M_EXCP_HARD, exc_secur= e); + return false; } =20 static bool v7m_push_callee_stack(ARMCPU *cpu, uint32_t lr, bool dotailcha= in, @@ -6623,7 +6658,11 @@ static void v7m_exception_taken(ARMCPU *cpu, uint32_= t lr, bool dotailchain, return; } =20 - addr =3D arm_v7m_load_vector(cpu, exc, targets_secure); + if (!arm_v7m_load_vector(cpu, exc, targets_secure, &addr)) { + /* Vector load failed: derived exception */ + v7m_exception_taken(cpu, lr, true, true); + return; + } =20 /* Now we've done everything that might cause a derived exception * we can go ahead and activate whichever exception we're going to --=20 2.7.4 From nobody Sun May 19 00:42:46 2024 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 1517324735205497.63166565459017; Tue, 30 Jan 2018 07:05:35 -0800 (PST) Received: from localhost ([::1]:42081 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXTa-0002HV-D6 for importer@patchew.org; Tue, 30 Jan 2018 10:05:34 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49151) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1egXQu-0000O0-Mg for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1egXQp-0005ee-Qc for qemu-devel@nongnu.org; Tue, 30 Jan 2018 10:02:48 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46114) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1egXQc-0005Xp-ER; Tue, 30 Jan 2018 10:02:30 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1egXQb-0005tt-Ac; Tue, 30 Jan 2018 15:02:29 +0000 From: Peter Maydell To: qemu-arm@nongnu.org, qemu-devel@nongnu.org Date: Tue, 30 Jan 2018 15:02:22 +0000 Message-Id: <1517324542-6607-8-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1517324542-6607-1-git-send-email-peter.maydell@linaro.org> References: <1517324542-6607-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 7/7] target/arm: Handle exceptions during exception stack pop 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" Handle possible MPU faults, SAU faults or bus errors when popping register state off the stack during exception return. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- target/arm/helper.c | 115 ++++++++++++++++++++++++++++++++++++++++++------= ---- 1 file changed, 94 insertions(+), 21 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6931a9d..3332565 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6223,6 +6223,67 @@ pend_fault: return false; } =20 +static bool v7m_stack_read(ARMCPU *cpu, uint32_t *dest, uint32_t addr, + ARMMMUIdx mmu_idx) +{ + CPUState *cs =3D CPU(cpu); + CPUARMState *env =3D &cpu->env; + MemTxAttrs attrs =3D {}; + MemTxResult txres; + target_ulong page_size; + hwaddr physaddr; + int prot; + ARMMMUFaultInfo fi; + bool secure =3D mmu_idx & ARM_MMU_IDX_M_S; + int exc; + bool exc_secure; + uint32_t value; + + if (get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &physaddr, + &attrs, &prot, &page_size, &fi, NULL)) { + /* MPU/SAU lookup failed */ + if (fi.type =3D=3D ARMFault_QEMU_SFault) { + qemu_log_mask(CPU_LOG_INT, + "...SecureFault with SFSR.AUVIOL during unstack\= n"); + env->v7m.sfsr |=3D R_V7M_SFSR_AUVIOL_MASK | R_V7M_SFSR_SFARVAL= ID_MASK; + env->v7m.sfar =3D addr; + exc =3D ARMV7M_EXCP_SECURE; + exc_secure =3D true; + } else { + qemu_log_mask(CPU_LOG_INT, + "...MemManageFault with CFSR.MUNSTKERR\n"); + env->v7m.cfsr[secure] |=3D R_V7M_CFSR_MUNSTKERR_MASK; + exc =3D ARMV7M_EXCP_MEM; + exc_secure =3D secure; + } + goto pend_fault; + } + + value =3D address_space_ldl(arm_addressspace(cs, attrs), physaddr, + attrs, &txres); + if (txres !=3D MEMTX_OK) { + /* BusFault trying to read the data */ + qemu_log_mask(CPU_LOG_INT, "...BusFault with BFSR.UNSTKERR\n"); + env->v7m.cfsr[M_REG_NS] |=3D R_V7M_CFSR_UNSTKERR_MASK; + exc =3D ARMV7M_EXCP_BUS; + exc_secure =3D false; + goto pend_fault; + } + + *dest =3D value; + return true; + +pend_fault: + /* By pending the exception at this point we are making + * the IMPDEF choice "overridden exceptions pended" (see the + * MergeExcInfo() pseudocode). The other choice would be to not + * pend them now and then make a choice about which to throw away + * later if we have two derived exceptions. + */ + armv7m_nvic_set_pending(env->nvic, exc, exc_secure); + return false; +} + /* Return true if we're using the process stack pointer (not the MSP) */ static bool v7m_using_psp(CPUARMState *env) { @@ -6912,6 +6973,11 @@ static void do_v7m_exception_exit(ARMCPU *cpu) !return_to_handler, return_to_sp_process); uint32_t frameptr =3D *frame_sp_p; + bool pop_ok =3D true; + ARMMMUIdx mmu_idx; + + mmu_idx =3D arm_v7m_mmu_idx_for_secstate_and_priv(env, return_to_s= ecure, + !return_to_handler= ); =20 if (!QEMU_IS_ALIGNED(frameptr, 8) && arm_feature(env, ARM_FEATURE_V8)) { @@ -6938,29 +7004,38 @@ static void do_v7m_exception_exit(ARMCPU *cpu) return; } =20 - env->regs[4] =3D ldl_phys(cs->as, frameptr + 0x8); - env->regs[5] =3D ldl_phys(cs->as, frameptr + 0xc); - env->regs[6] =3D ldl_phys(cs->as, frameptr + 0x10); - env->regs[7] =3D ldl_phys(cs->as, frameptr + 0x14); - env->regs[8] =3D ldl_phys(cs->as, frameptr + 0x18); - env->regs[9] =3D ldl_phys(cs->as, frameptr + 0x1c); - env->regs[10] =3D ldl_phys(cs->as, frameptr + 0x20); - env->regs[11] =3D ldl_phys(cs->as, frameptr + 0x24); + pop_ok =3D + v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx= ) && + v7m_stack_read(cpu, &env->regs[4], frameptr + 0x8, mmu_idx= ) && + v7m_stack_read(cpu, &env->regs[5], frameptr + 0xc, mmu_idx= ) && + v7m_stack_read(cpu, &env->regs[6], frameptr + 0x10, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[7], frameptr + 0x14, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[8], frameptr + 0x18, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[9], frameptr + 0x1c, mmu_id= x) && + v7m_stack_read(cpu, &env->regs[10], frameptr + 0x20, mmu_i= dx) && + v7m_stack_read(cpu, &env->regs[11], frameptr + 0x24, mmu_i= dx); =20 frameptr +=3D 0x28; } =20 - /* Pop registers. TODO: make these accesses use the correct - * attributes and address space (S/NS, priv/unpriv) and handle - * memory transaction failures. - */ - env->regs[0] =3D ldl_phys(cs->as, frameptr); - env->regs[1] =3D ldl_phys(cs->as, frameptr + 0x4); - env->regs[2] =3D ldl_phys(cs->as, frameptr + 0x8); - env->regs[3] =3D ldl_phys(cs->as, frameptr + 0xc); - env->regs[12] =3D ldl_phys(cs->as, frameptr + 0x10); - env->regs[14] =3D ldl_phys(cs->as, frameptr + 0x14); - env->regs[15] =3D ldl_phys(cs->as, frameptr + 0x18); + /* Pop registers */ + pop_ok =3D pop_ok && + v7m_stack_read(cpu, &env->regs[0], frameptr, mmu_idx) && + v7m_stack_read(cpu, &env->regs[1], frameptr + 0x4, mmu_idx) && + v7m_stack_read(cpu, &env->regs[2], frameptr + 0x8, mmu_idx) && + v7m_stack_read(cpu, &env->regs[3], frameptr + 0xc, mmu_idx) && + v7m_stack_read(cpu, &env->regs[12], frameptr + 0x10, mmu_idx) = && + v7m_stack_read(cpu, &env->regs[14], frameptr + 0x14, mmu_idx) = && + v7m_stack_read(cpu, &env->regs[15], frameptr + 0x18, mmu_idx) = && + v7m_stack_read(cpu, &xpsr, frameptr + 0x1c, mmu_idx); + + if (!pop_ok) { + /* v7m_stack_read() pended a fault, so take it (as a tail + * chained exception on the same stack frame) + */ + v7m_exception_taken(cpu, excret, true, false); + return; + } =20 /* Returning from an exception with a PC with bit 0 set is defined * behaviour on v8M (bit 0 is ignored), but for v7M it was specifi= ed @@ -6979,8 +7054,6 @@ static void do_v7m_exception_exit(ARMCPU *cpu) } } =20 - xpsr =3D ldl_phys(cs->as, frameptr + 0x1c); - if (arm_feature(env, ARM_FEATURE_V8)) { /* For v8M we have to check whether the xPSR exception field * matches the EXCRET value for return to handler/thread --=20 2.7.4