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