From patchwork Mon Feb 27 18:04:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 94573 Delivered-To: patch@linaro.org Received: by 10.140.20.113 with SMTP id 104csp982292qgi; Mon, 27 Feb 2017 10:16:31 -0800 (PST) X-Received: by 10.237.36.53 with SMTP id r50mr18313550qtc.46.1488219391342; Mon, 27 Feb 2017 10:16:31 -0800 (PST) Return-Path: Received: from lists.gnu.org (lists.gnu.org. [2001:4830:134:3::11]) by mx.google.com with ESMTPS id f5si12393362qkb.239.2017.02.27.10.16.30 for (version=TLS1 cipher=AES128-SHA bits=128/128); Mon, 27 Feb 2017 10:16:31 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) client-ip=2001:4830:134:3::11; Authentication-Results: mx.google.com; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 2001:4830:134:3::11 as permitted sender) smtp.mailfrom=qemu-devel-bounces+patch=linaro.org@nongnu.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([::1]:55548 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciPqW-00039X-MN for patch@linaro.org; Mon, 27 Feb 2017 13:16:28 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52016) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ciPff-0002MP-LG for qemu-devel@nongnu.org; Mon, 27 Feb 2017 13:05:18 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ciPfe-0001te-1A for qemu-devel@nongnu.org; Mon, 27 Feb 2017 13:05:15 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:48677) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1ciPfd-0001lG-NV for qemu-devel@nongnu.org; Mon, 27 Feb 2017 13:05:13 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.84_2) (envelope-from ) id 1ciPfX-0002Nk-Se for qemu-devel@nongnu.org; Mon, 27 Feb 2017 18:05:07 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Date: Mon, 27 Feb 2017 18:04:44 +0000 Message-Id: <1488218699-31035-16-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1488218699-31035-1-git-send-email-peter.maydell@linaro.org> References: <1488218699-31035-1-git-send-email-peter.maydell@linaro.org> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PULL 15/30] armv7m: Fix condition check for taking exceptions 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: , Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" The M profile condition for when we can take a pending exception or interrupt is not the same as that for A/R profile. The code originally copied from the A/R profile version of the cpu_exec_interrupt function only worked by chance for the very simple case of exceptions being masked by PRIMASK. Replace it with a call to a function in the NVIC code that correctly compares the priority of the pending exception against the current execution priority of the CPU. [Michael Davidsaver's patchset had a patch to do something similar but the implementation ended up being a rewrite.] Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée --- target/arm/cpu.h | 8 ++++++++ hw/intc/armv7m_nvic.c | 7 +++++++ target/arm/cpu.c | 16 ++++++++-------- 3 files changed, 23 insertions(+), 8 deletions(-) -- 2.7.4 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 38a8e00..649f237 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1356,6 +1356,14 @@ uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx, uint32_t cur_el, bool secure); /* Interface between CPU and Interrupt controller. */ +#ifndef CONFIG_USER_ONLY +bool armv7m_nvic_can_take_pending_exception(void *opaque); +#else +static inline bool armv7m_nvic_can_take_pending_exception(void *opaque) +{ + return true; +} +#endif void armv7m_nvic_set_pending(void *opaque, int irq); int armv7m_nvic_acknowledge_irq(void *opaque); void armv7m_nvic_complete_irq(void *opaque, int irq); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index fb4c985..6a03e2c 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -286,6 +286,13 @@ static inline int nvic_exec_prio(NVICState *s) return MIN(running, s->exception_prio); } +bool armv7m_nvic_can_take_pending_exception(void *opaque) +{ + NVICState *s = opaque; + + return nvic_exec_prio(s) > nvic_pending_prio(s); +} + /* caller must call nvic_irq_update() after this */ static void set_prio(NVICState *s, unsigned irq, uint8_t prio) { diff --git a/target/arm/cpu.c b/target/arm/cpu.c index f7157dc..04b062c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -338,13 +338,6 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) CPUARMState *env = &cpu->env; bool ret = false; - - if (interrupt_request & CPU_INTERRUPT_FIQ - && !(env->daif & PSTATE_F)) { - cs->exception_index = EXCP_FIQ; - cc->do_interrupt(cs); - ret = true; - } /* ARMv7-M interrupt return works by loading a magic value * into the PC. On real hardware the load causes the * return to occur. The qemu implementation performs the @@ -354,9 +347,16 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) * the stack if an interrupt occurred at the wrong time. * We avoid this by disabling interrupts when * pc contains a magic address. + * + * ARMv7-M interrupt masking works differently than -A or -R. + * There is no FIQ/IRQ distinction. Instead of I and F bits + * masking FIQ and IRQ interrupts, an exception is taken only + * if it is higher priority than the current execution priority + * (which depends on state like BASEPRI, FAULTMASK and the + * currently active exception). */ if (interrupt_request & CPU_INTERRUPT_HARD - && !(env->daif & PSTATE_I) + && (armv7m_nvic_can_take_pending_exception(env->nvic)) && (env->regs[15] < 0xfffffff0)) { cs->exception_index = EXCP_IRQ; cc->do_interrupt(cs);