diff mbox series

[v5,46/67] target/arm: Implement arm_cpu_record_sigbus

Message ID 20211015041053.2769193-47-richard.henderson@linaro.org
State Superseded
Headers show
Series user-only: Cleanup SIGSEGV and SIGBUS handling | expand

Commit Message

Richard Henderson Oct. 15, 2021, 4:10 a.m. UTC
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

Comments

Warner Losh Oct. 15, 2021, 7:05 p.m. UTC | #1
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 &lt;<a href="mailto:richard.henderson@linaro.org">richard.henderson@linaro.org</a>&gt; 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 &lt;<a href="mailto:richard.henderson@linaro.org" target="_blank">richard.henderson@linaro.org</a>&gt;<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 &lt;<a href="mailto:imp@bsdimp.com">imp@bsdimp.com</a>&gt;</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&#39;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-&gt;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-&gt;exception.vaddress);<br>
+            force_sig_fault(si_signo, si_code, env-&gt;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 &quot;cpu_loop-common.h&quot;<br>
 #include &quot;signal-common.h&quot;<br>
 #include &quot;semihosting/common-semi.h&quot;<br>
+#include &quot;target/arm/syndrome.h&quot;<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-&gt;error_code */<br>
-            force_sig_fault(TARGET_SIGSEGV, TARGET_SEGV_MAPERR,<br>
-                            env-&gt;exception.vaddress);<br>
+            /* For user-only we don&#39;t set TTBCR_EAE, so look at the FSR. */<br>
+            switch (env-&gt;exception.fsr &amp; 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-&gt;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, &amp;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 mbox series

Patch

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) */