@@ -137,6 +137,10 @@ void cpu_loop(CPUARMState *env)
case 0x11: /* Synchronous Tag Check Fault */
info.si_code = TARGET_SEGV_MTESERR;
break;
+ case 0x21: /* Alignment fault */
+ info.si_signo = TARGET_SIGBUS;
+ info.si_code = TARGET_BUS_ADRALN;
+ break;
default:
g_assert_not_reached();
}
@@ -23,6 +23,7 @@
#include "elf.h"
#include "cpu_loop-common.h"
#include "semihosting/common-semi.h"
+#include "target/arm/syndrome.h"
#define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \
@@ -286,9 +287,8 @@ void cpu_loop(CPUARMState *env)
{
CPUState *cs = env_cpu(env);
int trapnr;
- unsigned int n, insn;
+ unsigned int n, insn, ec, fsc;
target_siginfo_t info;
- uint32_t addr;
abi_ulong ret;
for(;;) {
@@ -437,15 +437,40 @@ void cpu_loop(CPUARMState *env)
break;
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
- addr = env->exception.vaddress;
- {
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info._sifields._sigfault._addr = env->exception.vaddress;
+ /*
+ * We should only arrive here with EC in {DATAABORT, INSNABORT},
+ * and short-form FSC, which then tells us to look at the FSR.
+ * ??? arm_cpu_reset never sets TTBCR_EAE, so we always get
+ * short-form FSC.
+ */
+ ec = syn_get_ec(env->exception.syndrome);
+ assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
+ fsc = extract32(env->exception.syndrome, 0, 6);
+ assert(fsc == 0x3f);
+ switch (env->exception.fsr & 0x1f) {
+ case 0x1: /* Alignment */
+ info.si_signo = TARGET_SIGBUS;
+ info.si_code = TARGET_BUS_ADRALN;
+ break;
+ case 0x3: /* Access flag fault, level 1 */
+ case 0x6: /* Access flag fault, level 2 */
+ case 0x9: /* Domain fault, level 1 */
+ case 0xb: /* Domain fault, level 2 */
+ case 0xd: /* Permision fault, level 1 */
+ case 0xf: /* Permision fault, level 2 */
+ info.si_code = TARGET_SEGV_ACCERR;
+ break;
+ case 0x5: /* Translation fault, level 1 */
+ case 0x7: /* Translation fault, level 2 */
info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = addr;
- queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+ break;
+ default:
+ g_assert_not_reached();
}
+ queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break;
case EXCP_DEBUG:
case EXCP_BKPT:
@@ -1987,11 +1987,11 @@ static const struct TCGCPUOps arm_tcg_ops = {
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
.tlb_fill = arm_cpu_tlb_fill,
.debug_excp_handler = arm_debug_excp_handler,
+ .do_unaligned_access = arm_cpu_do_unaligned_access,
#if !defined(CONFIG_USER_ONLY)
.do_interrupt = arm_cpu_do_interrupt,
.do_transaction_failed = arm_cpu_do_transaction_failed,
- .do_unaligned_access = arm_cpu_do_unaligned_access,
.adjust_watchpoint_address = arm_adjust_watchpoint_address,
.debug_check_watchpoint = arm_debug_check_watchpoint,
.debug_check_breakpoint = arm_debug_check_breakpoint,
@@ -904,11 +904,11 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = {
.cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
.tlb_fill = arm_cpu_tlb_fill,
.debug_excp_handler = arm_debug_excp_handler,
+ .do_unaligned_access = arm_cpu_do_unaligned_access,
#if !defined(CONFIG_USER_ONLY)
.do_interrupt = arm_v7m_cpu_do_interrupt,
.do_transaction_failed = arm_cpu_do_transaction_failed,
- .do_unaligned_access = arm_cpu_do_unaligned_access,
.adjust_watchpoint_address = arm_adjust_watchpoint_address,
.debug_check_watchpoint = arm_debug_check_watchpoint,
.debug_check_breakpoint = arm_debug_check_breakpoint,