[v7,13/42] target/arm: Define arm_cpu_do_unaligned_access for user-only

Message ID 20200603011317.473934-14-richard.henderson@linaro.org
State New
Headers show
Series
  • [v7,01/42] target/arm: Add isar tests for mte
Related show

Commit Message

Richard Henderson June 3, 2020, 1:12 a.m.
We need this to raise unaligned exceptions from user mode.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

---
v6: Use EXCP_UNALIGNED for user-only and update cpu_loop.c.
---
 linux-user/aarch64/cpu_loop.c |  7 ++++++
 linux-user/arm/cpu_loop.c     |  7 ++++++
 target/arm/cpu.c              |  2 +-
 target/arm/tlb_helper.c       | 41 ++++++++++++++++++++++-------------
 4 files changed, 41 insertions(+), 16 deletions(-)

-- 
2.25.1

Comments

Peter Maydell June 18, 2020, 1:31 p.m. | #1
On Wed, 3 Jun 2020 at 02:13, Richard Henderson
<richard.henderson@linaro.org> wrote:
>

> We need this to raise unaligned exceptions from user mode.

>

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> ---

> v6: Use EXCP_UNALIGNED for user-only and update cpu_loop.c.


Could you update the comment in cpu.h, maybe something like:
#define EXCP_UNALIGNED      22   /* v7M UNALIGNED UsageFault; also linux-user */

and also update the string printed by arm_log_exception():
#ifdef CONFIG_USER_ONLY
            [EXCP_UNALIGNED] = "linux-user unaligned access fault",
#else
            [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",
#endif

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>


thanks
-- PMM
Richard Henderson June 18, 2020, 5:03 p.m. | #2
On 6/18/20 6:31 AM, Peter Maydell wrote:
> On Wed, 3 Jun 2020 at 02:13, Richard Henderson

> <richard.henderson@linaro.org> wrote:

>>

>> We need this to raise unaligned exceptions from user mode.

>>

>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

>> ---

>> v6: Use EXCP_UNALIGNED for user-only and update cpu_loop.c.

> 

> Could you update the comment in cpu.h, maybe something like:

> #define EXCP_UNALIGNED      22   /* v7M UNALIGNED UsageFault; also linux-user */

> 

> and also update the string printed by arm_log_exception():

> #ifdef CONFIG_USER_ONLY

>             [EXCP_UNALIGNED] = "linux-user unaligned access fault",

> #else

>             [EXCP_UNALIGNED] = "v7M UNALIGNED UsageFault",

> #endif

> 

> Otherwise

> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>


First, this could definitely be delayed to the follow-on linux-user patch set.

Second, in the linux-user patch set, I decode the syndrome data to determine
what kind of segv to deliver for MTE synchronous faults.  It would be easy to
extend that just a little to notice the usual syndrome for unaligned accesses.
 Which may be less confusing than abusing the v7m exception code?


r~
Peter Maydell June 18, 2020, 5:45 p.m. | #3
On Thu, 18 Jun 2020 at 18:04, Richard Henderson
<richard.henderson@linaro.org> wrote:
> First, this could definitely be delayed to the follow-on linux-user patch set.

>

> Second, in the linux-user patch set, I decode the syndrome data to determine

> what kind of segv to deliver for MTE synchronous faults.  It would be easy to

> extend that just a little to notice the usual syndrome for unaligned accesses.

>  Which may be less confusing than abusing the v7m exception code?


Yeah, if we're going to look at syndrome data anyway that might
be clearer.

The other thing that really it would be nice if we were able
to feed through (via syndrome info or otherwise) is the difference
between SIGSEGV with si_code == SEGV_ACCERR vs SEGV_MAPERR.
At the moment handle_cpu_signal() knows the difference, but it
doesn't have a way to pass this through to tlb_fill, and then
cpu_loop() has to make up a si_code when it gets the EXCP_DATA_ABORT.
I mention this mostly in case it affects how you want to design
how you treat alignment and MTE faults -- it might be that the
si_code stuff is better dealt with entirely differently.

thanks
-- PMM
Richard Henderson June 18, 2020, 9:01 p.m. | #4
On 6/18/20 10:03 AM, Richard Henderson wrote:
> First, this could definitely be delayed to the follow-on linux-user patch set.


Bah, no, I need the function to be defined at least,
even if it isn't reachable yet.


r~

Patch

diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c
index bbe9fefca8..3cca637bb9 100644
--- a/linux-user/aarch64/cpu_loop.c
+++ b/linux-user/aarch64/cpu_loop.c
@@ -121,6 +121,13 @@  void cpu_loop(CPUARMState *env)
             info._sifields._sigfault._addr = env->exception.vaddress;
             queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
             break;
+        case EXCP_UNALIGNED:
+            info.si_signo = TARGET_SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_BUS_ADRALN;
+            info._sifields._sigfault._addr = env->exception.vaddress;
+            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+            break;
         case EXCP_DEBUG:
         case EXCP_BKPT:
             info.si_signo = TARGET_SIGTRAP;
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index 13629ee1f6..0d568d2d69 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -411,6 +411,13 @@  void cpu_loop(CPUARMState *env)
                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
             }
             break;
+        case EXCP_UNALIGNED:
+            info.si_signo = TARGET_SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_BUS_ADRALN;
+            info._sifields._sigfault._addr = env->exception.vaddress;
+            queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+            break;
         case EXCP_DEBUG:
         case EXCP_BKPT:
         excp_debug:
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 32bec156f2..0f1a46f531 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2166,8 +2166,8 @@  static void arm_cpu_class_init(ObjectClass *oc, void *data)
     cc->tlb_fill = arm_cpu_tlb_fill;
     cc->debug_excp_handler = arm_debug_excp_handler;
     cc->debug_check_watchpoint = arm_debug_check_watchpoint;
-#if !defined(CONFIG_USER_ONLY)
     cc->do_unaligned_access = arm_cpu_do_unaligned_access;
+#if !defined(CONFIG_USER_ONLY)
     cc->do_transaction_failed = arm_cpu_do_transaction_failed;
     cc->adjust_watchpoint_address = arm_adjust_watchpoint_address;
 #endif /* CONFIG_TCG && !CONFIG_USER_ONLY */
diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
index 7388494a55..d4e6d37f4f 100644
--- a/target/arm/tlb_helper.c
+++ b/target/arm/tlb_helper.c
@@ -107,21 +107,6 @@  static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr,
     raise_exception(env, exc, syn, target_el);
 }
 
-/* Raise a data fault alignment exception for the specified virtual address */
-void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
-                                 MMUAccessType access_type,
-                                 int mmu_idx, uintptr_t retaddr)
-{
-    ARMCPU *cpu = ARM_CPU(cs);
-    ARMMMUFaultInfo fi = {};
-
-    /* now we have a real cpu fault */
-    cpu_restore_state(cs, retaddr, true);
-
-    fi.type = ARMFault_Alignment;
-    arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
-}
-
 /*
  * arm_cpu_do_transaction_failed: handle a memory system error response
  * (eg "no device/memory present at address") by raising an external abort
@@ -198,3 +183,29 @@  bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     }
 #endif
 }
+
+/* Raise a data fault alignment exception for the specified virtual address */
+void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,
+                                 MMUAccessType access_type,
+                                 int mmu_idx, uintptr_t retaddr)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+
+#ifdef CONFIG_USER_ONLY
+    cpu->env.exception.vaddress = vaddr;
+    /*
+     * For HW, this is EXCP_DATA_ABORT with a proper syndrome.
+     * Make it easier for ourselves in linux-user/arm/cpu_loop.c.
+     */
+    cs->exception_index = EXCP_UNALIGNED;
+    cpu_loop_exit_restore(cs, retaddr);
+#else
+    ARMMMUFaultInfo fi = {};
+
+    /* now we have a real cpu fault */
+    cpu_restore_state(cs, retaddr, true);
+
+    fi.type = ARMFault_Alignment;
+    arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi);
+#endif
+}