From 09d69209a0a4288e87a0db73e5081f6136bfaae2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 2 Mar 2018 19:28:18 -0500 Subject: [PATCH] armv7m: Classify faults as MemManage or BusFault General logic is that operations stopped by the MPU are MemManage, and those which go through the MPU and are caught by the unassigned handle are BusFault. Distinguish these by looking at the exception.fsr values, and set the CFSR bits and (if appropriate) fill in the BFAR or MMFAR with the exception address. Backports commit 5dd0641d234e355597be62e5279d8a519c831625 from qemu --- qemu/target/arm/helper.c | 47 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 003d1880..19a081cb 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -5468,10 +5468,51 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) return; case EXCP_PREFETCH_ABORT: case EXCP_DATA_ABORT: - /* TODO: if we implemented the MPU registers, this is where we - * should set the MMFAR, etc from exception.fsr and exception.vaddress. + /* Note that for M profile we don't have a guest facing FSR, but + * the env->exception.fsr will be populated by the code that + * raises the fault, in the A profile short-descriptor format. */ - //armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); + switch (env->exception.fsr & 0xf) { + case 0x8: /* External Abort */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + env->v7m.cfsr |= R_V7M_CFSR_PRECISERR_MASK; + qemu_log_mask(CPU_LOG_INT, "...with CFSR.PRECISERR\n"); + break; + case EXCP_DATA_ABORT: + env->v7m.cfsr |= + (R_V7M_CFSR_IBUSERR_MASK | R_V7M_CFSR_BFARVALID_MASK); + env->v7m.bfar = env->exception.vaddress; + qemu_log_mask(CPU_LOG_INT, + "...with CFSR.IBUSERR and BFAR 0x%x\n", + env->v7m.bfar); + break; + } + // Unicorn: commented out + //armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_BUS); + break; + default: + /* All other FSR values are either MPU faults or "can't happen + * for M profile" cases. + */ + switch (cs->exception_index) { + case EXCP_PREFETCH_ABORT: + env->v7m.cfsr |= R_V7M_CFSR_IACCVIOL_MASK; + qemu_log_mask(CPU_LOG_INT, "...with CFSR.IACCVIOL\n"); + break; + case EXCP_DATA_ABORT: + env->v7m.cfsr |= + (R_V7M_CFSR_DACCVIOL_MASK | R_V7M_CFSR_MMARVALID_MASK); + env->v7m.mmfar = env->exception.vaddress; + qemu_log_mask(CPU_LOG_INT, + "...with CFSR.DACCVIOL and MMFAR 0x%x\n", + env->v7m.mmfar); + break; + } + // Unicorn: commented out + //armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM); + break; + } return; case EXCP_BKPT: #if 0