On Thu, Oct 14, 2021 at 10:14 PM Richard Henderson < [email protected]> wrote:
> Because of the complexity of setting ESR, re-use the existing > arm_cpu_do_unaligned_access function. This means we have to > handle the exception ourselves in cpu_loop, transforming it > to the appropriate signal. > > Signed-off-by: Richard Henderson <[email protected]> > --- > target/arm/internals.h | 2 ++ > linux-user/aarch64/cpu_loop.c | 12 +++++++++--- > linux-user/arm/cpu_loop.c | 30 ++++++++++++++++++++++++++---- > target/arm/cpu.c | 1 + > target/arm/cpu_tcg.c | 1 + > target/arm/tlb_helper.c | 6 ++++++ > 6 files changed, 45 insertions(+), 7 deletions(-) > Reviewed-by: Warner Losh <[email protected]> This will definitely have an impact on the bsd-user fork, and my plans to add arm and aarch64 to upstream before 6.2, but I believe most of the changes will port over so I'm not too worried. > diff --git a/target/arm/internals.h b/target/arm/internals.h > index 5a7aaf0f51..89f7610ebc 100644 > --- a/target/arm/internals.h > +++ b/target/arm/internals.h > @@ -548,6 +548,8 @@ static inline bool arm_extabort_type(MemTxResult > result) > void arm_cpu_record_sigsegv(CPUState *cpu, vaddr addr, > MMUAccessType access_type, > bool maperr, uintptr_t ra); > +void arm_cpu_record_sigbus(CPUState *cpu, vaddr addr, > + MMUAccessType access_type, uintptr_t ra); > #else > bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, > MMUAccessType access_type, int mmu_idx, > diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c > index 034b737435..97e0728b67 100644 > --- a/linux-user/aarch64/cpu_loop.c > +++ b/linux-user/aarch64/cpu_loop.c > @@ -79,7 +79,7 @@ > void cpu_loop(CPUARMState *env) > { > CPUState *cs = env_cpu(env); > - int trapnr, ec, fsc, si_code; > + int trapnr, ec, fsc, si_code, si_signo; > abi_long ret; > > for (;;) { > @@ -121,20 +121,26 @@ void cpu_loop(CPUARMState *env) > fsc = extract32(env->exception.syndrome, 0, 6); > switch (fsc) { > case 0x04 ... 0x07: /* Translation fault, level {0-3} */ > + si_signo = TARGET_SIGSEGV; > si_code = TARGET_SEGV_MAPERR; > break; > case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ > case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ > + si_signo = TARGET_SIGSEGV; > si_code = TARGET_SEGV_ACCERR; > break; > case 0x11: /* Synchronous Tag Check Fault */ > + si_signo = TARGET_SIGSEGV; > si_code = TARGET_SEGV_MTESERR; > break; > + case 0x21: /* Alignment fault */ > + si_signo = TARGET_SIGBUS; > + si_code = TARGET_BUS_ADRALN; > + break; > default: > g_assert_not_reached(); > } > - > - force_sig_fault(TARGET_SIGSEGV, si_code, > env->exception.vaddress); > + force_sig_fault(si_signo, si_code, env->exception.vaddress); > break; > case EXCP_DEBUG: > case EXCP_BKPT: > diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c > index ae09adcb95..01cb6eb534 100644 > --- a/linux-user/arm/cpu_loop.c > +++ b/linux-user/arm/cpu_loop.c > @@ -25,6 +25,7 @@ > #include "cpu_loop-common.h" > #include "signal-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)); \ > @@ -280,7 +281,7 @@ static bool emulate_arm_fpa11(CPUARMState *env, > uint32_t opcode) > void cpu_loop(CPUARMState *env) > { > CPUState *cs = env_cpu(env); > - int trapnr; > + int trapnr, si_signo, si_code; > unsigned int n, insn; > abi_ulong ret; > > @@ -423,9 +424,30 @@ void cpu_loop(CPUARMState *env) > break; > case EXCP_PREFETCH_ABORT: > case EXCP_DATA_ABORT: > - /* XXX: check env->error_code */ > - force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR, > - env->exception.vaddress); > + /* For user-only we don't set TTBCR_EAE, so look at the FSR. > */ > + switch (env->exception.fsr & 0x1f) { > + case 0x1: /* Alignment */ > + si_signo = TARGET_SIGBUS; > + 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 */ > + si_signo = TARGET_SIGSEGV; > + si_code = TARGET_SEGV_ACCERR; > + break; > + case 0x5: /* Translation fault, level 1 */ > + case 0x7: /* Translation fault, level 2 */ > + si_signo = TARGET_SIGSEGV; > + si_code = TARGET_SEGV_MAPERR; > + break; > + default: > + g_assert_not_reached(); > + } > + force_sig_fault(si_signo, si_code, env->exception.vaddress); > break; > case EXCP_DEBUG: > case EXCP_BKPT: > diff --git a/target/arm/cpu.c b/target/arm/cpu.c > index 7a18a58ca0..a211804fd3 100644 > --- a/target/arm/cpu.c > +++ b/target/arm/cpu.c > @@ -2035,6 +2035,7 @@ static const struct TCGCPUOps arm_tcg_ops = { > > #ifdef CONFIG_USER_ONLY > .record_sigsegv = arm_cpu_record_sigsegv, > + .record_sigbus = arm_cpu_record_sigbus, > #else > .tlb_fill = arm_cpu_tlb_fill, > .cpu_exec_interrupt = arm_cpu_exec_interrupt, > diff --git a/target/arm/cpu_tcg.c b/target/arm/cpu_tcg.c > index 7b3bea2fbb..13d0e9b195 100644 > --- a/target/arm/cpu_tcg.c > +++ b/target/arm/cpu_tcg.c > @@ -902,6 +902,7 @@ static const struct TCGCPUOps arm_v7m_tcg_ops = { > > #ifdef CONFIG_USER_ONLY > .record_sigsegv = arm_cpu_record_sigsegv, > + .record_sigbus = arm_cpu_record_sigbus, > #else > .tlb_fill = arm_cpu_tlb_fill, > .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt, > diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c > index dc5860180f..12a934e924 100644 > --- a/target/arm/tlb_helper.c > +++ b/target/arm/tlb_helper.c > @@ -213,4 +213,10 @@ void arm_cpu_record_sigsegv(CPUState *cs, vaddr addr, > cpu_restore_state(cs, ra, true); > arm_deliver_fault(cpu, addr, access_type, MMU_USER_IDX, &fi); > } > + > +void arm_cpu_record_sigbus(CPUState *cs, vaddr addr, > + MMUAccessType access_type, uintptr_t ra) > +{ > + arm_cpu_do_unaligned_access(cs, addr, access_type, MMU_USER_IDX, ra); > +} > #endif /* !defined(CONFIG_USER_ONLY) */ > -- > 2.25.1 > >
