qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-arm] [PATCH 11/18] armv7m: fix I and F flag handling


From: Michael Davidsaver
Subject: [Qemu-arm] [PATCH 11/18] armv7m: fix I and F flag handling
Date: Sun, 8 Nov 2015 20:11:38 -0500

Despite having the same notation, these bits
have completely different meaning than -AR.

Add armv7m_excp_unmasked()
to calculate the currently runable exception priority
taking into account masks and active handlers.
Use this in conjunction with the pending exception
priority to determine if the pending exception
can interrupt execution.

Signed-off-by: Michael Davidsaver <address@hidden>
---
 target-arm/cpu.c | 26 +++++++-------------------
 target-arm/cpu.h | 27 ++++++++++++++++++++++++++-
 2 files changed, 33 insertions(+), 20 deletions(-)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index be026bc..5d03117 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -173,6 +173,8 @@ static void arm_cpu_reset(CPUState *s)
         uint32_t initial_pc; /* Loaded from 0x4 */
         uint8_t *rom;
 
+        env->v7m.exception_prio = env->v7m.pending_prio = 0x100;
+
         env->daif &= ~PSTATE_I;
         rom = rom_ptr(0);
         if (rom) {
@@ -301,29 +303,15 @@ static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int 
interrupt_request)
 {
     CPUClass *cc = CPU_GET_CLASS(cs);
     ARMCPU *cpu = ARM_CPU(cs);
-    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
-     * jump normally, then does the exception return when the
-     * CPU tries to execute code at the magic address.
-     * This will cause the magic PC value to be pushed to
-     * 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 masking interrupt sources, the I and F bits
+     * (along with basepri) mask certain exception priority levels.
      */
     if (interrupt_request & CPU_INTERRUPT_HARD
-        && !(env->daif & PSTATE_I)
-        && (env->regs[15] < 0xfffffff0)) {
+            && (armv7m_excp_unmasked(cpu) >= cpu->env.v7m.pending_prio)) {
         cs->exception_index = EXCP_IRQ;
         cc->do_interrupt(cs);
         ret = true;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index c193fbb..29d89ce 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1033,9 +1033,34 @@ void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 uint32_t arm_phys_excp_target_el(CPUState *cs, uint32_t excp_idx,
                                  uint32_t cur_el, bool secure);
 
+/* @returns highest (numerically lowest) unmasked exception priority
+ */
+static inline
+int armv7m_excp_unmasked(ARMCPU *cpu)
+{
+    CPUARMState *env = &cpu->env;
+    int runnable;
+
+    /* find highest (numerically lowest) priority which could
+     * run based on masks
+     */
+    if (env->daif&PSTATE_F) { /* FAULTMASK */
+        runnable = -2;
+    } else if (env->daif&PSTATE_I) { /* PRIMASK */
+        runnable = -1;
+    } else if (env->v7m.basepri > 0) {
+        /* BASEPRI==1 -> runnable==-1 (same as PRIMASK==1) */
+        runnable = env->v7m.basepri-2;
+    } else {
+        runnable = 0x100; /* lower than any possible priority */
+    }
+    /* consider priority of active handler */
+    return MIN(runnable, env->v7m.exception_prio-1);
+}
+
 /* Interface between CPU and Interrupt controller.  */
 void armv7m_nvic_set_pending(void *opaque, int irq);
-int armv7m_nvic_acknowledge_irq(void *opaque);
+void armv7m_nvic_acknowledge_irq(void *opaque);
 void armv7m_nvic_complete_irq(void *opaque, int irq);
 
 /* Interface for defining coprocessor registers.
-- 
2.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]