Message ID | 20211015041053.2769193-47-richard.henderson@linaro.org |
---|---|
State | New |
Headers | show |
Series | user-only: Cleanup SIGSEGV and SIGBUS handling | expand |
On Thu, Oct 14, 2021 at 10:14 PM Richard Henderson < richard.henderson@linaro.org> 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 <richard.henderson@linaro.org> > --- > 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 <imp@bsdimp.com> 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 > >
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) */
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 <richard.henderson@linaro.org> --- 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(-)