From 0736054d6d4188081c815e6b25c686152798646b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Fri, 2 Mar 2018 19:54:43 -0500 Subject: [PATCH] armv7m: Extract "exception taken" code into functions Extract the code from the tail end of arm_v7m_do_interrupt() which enters the exception handler into a pair of utility functions v7m_exception_taken() and v7m_push_stack(), which correspond roughly to the pseudocode PushStack() and ExceptionTaken(). This also requires us to move the arm_v7m_load_vector() utility routine up so we can call it. Handling illegal exception returns has some cases where we want to take a UsageFault either on an existing stack frame or with a new stack frame but with a specific LR value, so we want to be able to call these without having to go via arm_v7m_cpu_do_interrupt(). Backports commit 39ae2474e337247e5930e8be783b689adc9f6215 from qemu --- qemu/target/arm/helper.c | 120 ++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 1f53d686..705b063c 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -5327,6 +5327,73 @@ static void switch_v7m_sp(CPUARMState *env, bool new_spsel) } } +static uint32_t arm_v7m_load_vector(ARMCPU *cpu) +{ + CPUState *cs = CPU(cpu); + CPUARMState *env = &cpu->env; + MemTxResult result; + hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4; + uint32_t addr; + + addr = address_space_ldl(cs->as, vec, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { + /* Architecturally this should cause a HardFault setting HSFR.VECTTBL, + * 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 exception vector table " + "entry %08x\n", (unsigned)vec); + } + return addr; +} + +static void v7m_exception_taken(ARMCPU *cpu, uint32_t lr) +{ + /* Do the "take the exception" parts of exception entry, + * but not the pushing of state to the stack. This is + * similar to the pseudocode ExceptionTaken() function. + */ + CPUARMState *env = &cpu->env; + uint32_t addr; + + // Unicorn: commented out + //armv7m_nvic_acknowledge_irq(env->nvic); + switch_v7m_sp(env, 0); + /* Clear IT bits */ + env->condexec_bits = 0; + env->regs[14] = lr; + addr = arm_v7m_load_vector(cpu); + env->regs[15] = addr & 0xfffffffe; + env->thumb = addr & 1; +} + +static void v7m_push_stack(ARMCPU *cpu) +{ + /* Do the "set up stack frame" part of exception entry, + * similar to pseudocode PushStack(). + */ + CPUARMState *env = &cpu->env; + uint32_t xpsr = xpsr_read(env); + + /* Align stack pointer if the guest wants that */ + if ((env->regs[13] & 4) && (env->v7m.ccr & R_V7M_CCR_STKALIGN_MASK)) { + env->regs[13] -= 4; + xpsr |= 0x200; + } + /* 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]); +} + static void do_v7m_exception_exit(CPUARMState *env) { uint32_t type; @@ -5410,37 +5477,11 @@ static void arm_log_exception(int idx) } } -static uint32_t arm_v7m_load_vector(ARMCPU *cpu) - -{ - CPUState *cs = CPU(cpu); - CPUARMState *env = &cpu->env; - MemTxResult result; - hwaddr vec = env->v7m.vecbase + env->v7m.exception * 4; - uint32_t addr; - - addr = address_space_ldl(cs->as, vec, - MEMTXATTRS_UNSPECIFIED, &result); - if (result != MEMTX_OK) { - /* Architecturally this should cause a HardFault setting HSFR.VECTTBL, - * 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 exception vector table " - "entry %08x\n", (unsigned)vec); - } - return addr; -} - void arm_v7m_cpu_do_interrupt(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs->uc, cs); CPUARMState *env = cs->env_ptr; - uint32_t xpsr = xpsr_read(env); uint32_t lr; - uint32_t addr; arm_log_exception(cs->exception_index); @@ -5541,32 +5582,9 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) return; /* Never happens. Keep compiler happy. */ } - // Unicorn: commented out - //armv7m_nvic_acknowledge_irq(env->nvic); - + v7m_push_stack(cpu); + v7m_exception_taken(cpu, lr); qemu_log_mask(CPU_LOG_INT, "... as %d\n", env->v7m.exception); - - /* Align stack pointer if the guest wants that */ - if ((env->regs[13] & 4) && (env->v7m.ccr & R_V7M_CCR_STKALIGN_MASK)) { - env->regs[13] -= 4; - xpsr |= 0x200; - } - /* 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]); - switch_v7m_sp(env, 0); - /* Clear IT bits */ - env->condexec_bits = 0; - env->regs[14] = lr; - addr = arm_v7m_load_vector(cpu); - env->regs[15] = addr & 0xfffffffe; - env->thumb = addr & 1; } /* Function used to synchronize QEMU's AArch64 register set with AArch32