diff mbox series

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

Message ID 20211015041053.2769193-47-richard.henderson@linaro.org
State New
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(-)

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