[PATCH v2 6/7] target/arm: Introduce EXCP_NWFPE

Richard Henderson posted 7 patches 2 days, 13 hours ago
Maintainers: Laurent Vivier <laurent@vivier.eu>, Pierrick Bouvier <pierrick.bouvier@linaro.org>, Peter Maydell <peter.maydell@linaro.org>
[PATCH v2 6/7] target/arm: Introduce EXCP_NWFPE
Posted by Richard Henderson 2 days, 13 hours ago
We don't normally emulate any coprocessor {1,2} insns, but
linux-user would like to emulate these fpa11 insns.

Filter these, raise a special exception, and store the
instruction in CPUARMState.syscall_info rather than reload
the instruction in the linux-user cpu_loop.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/cpu.h           |  1 +
 linux-user/arm/cpu_loop.c  | 34 ++++++----------------------------
 target/arm/tcg/translate.c | 27 +++++++++++++++++++++++++++
 3 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 5b564c7113..8f1afca2ae 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -64,6 +64,7 @@
 #define EXCP_VINMI          27
 #define EXCP_VFNMI          28
 #define EXCP_MON_TRAP       29   /* AArch32 trap to Monitor mode */
+#define EXCP_NWFPE          30   /* linux-user fpa11 emulation */
 /* NB: add new EXCP_ defines to the array in arm_log_exception() too */
 
 #define ARMV7M_EXCP_RESET   1
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index 4f7c5dab9c..ae941ba9af 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -29,19 +29,6 @@
 #include "user/page-protection.h"
 #include "target/arm/syndrome.h"
 
-#define get_user_code_u32(x, gaddr, env)                \
-    ({ abi_long __r = get_user_u32((x), (gaddr));       \
-        if (!__r && bswap_code(arm_sctlr_b(env))) {     \
-            (x) = bswap32(x);                           \
-        }                                               \
-        __r;                                            \
-    })
-
-/*
- * Note that if we need to do data accesses here, they should do a
- * bswap if arm_cpu_bswap_data() returns true.
- */
-
 /*
  * Similar to code in accel/tcg/user-exec.c, but outside the execution loop.
  * Must be called with mmap_lock.
@@ -262,24 +249,15 @@ void cpu_loop(CPUARMState *env)
         qemu_process_cpu_events(cs);
 
         switch(trapnr) {
+        case EXCP_NWFPE:
+            if (emulate_arm_fpa11(env, env->syscall_info)) {
+                break;
+            }
+            /* fall through */
         case EXCP_UDEF:
         case EXCP_NOCP:
         case EXCP_INVSTATE:
-            {
-                uint32_t opcode;
-
-                /* we handle the FPU emulation here, as Linux */
-                /* we get the opcode */
-                /* FIXME - what to do if get_user() fails? */
-                get_user_code_u32(opcode, env->regs[15], env);
-
-                if (!env->thumb && emulate_arm_fpa11(env, opcode)) {
-                    break;
-                }
-
-                force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN,
-                                env->regs[15]);
-            }
+            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->regs[15]);
             break;
         case EXCP_SWI:
             {
diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c
index 0447be0907..d910a007db 100644
--- a/target/arm/tcg/translate.c
+++ b/target/arm/tcg/translate.c
@@ -2358,8 +2358,26 @@ static bool valid_cp(DisasContext *s, int cp)
     return cp < 8 || cp >= 14;
 }
 
+static bool maybe_nwfpe(DisasContext *s, int cp)
+{
+#ifdef CONFIG_USER_ONLY
+# if defined(CONFIG_LINUX) && !defined(TARGET_AARCH64)
+    if (!s->thumb && (cp == 1 || cp == 2)) {
+        tcg_gen_st_i32(tcg_constant_i32(s->insn), tcg_env,
+                       offsetof(CPUARMState, syscall_info));
+        gen_exception_insn(s, 0, EXCP_NWFPE, syn_uncategorized());
+        return true;
+    }
+# endif
+#endif
+    return false;
+}
+
 static bool trans_MCR(DisasContext *s, arg_MCR *a)
 {
+    if (maybe_nwfpe(s, a->cp)) {
+        return true;
+    }
     if (!valid_cp(s, a->cp)) {
         return false;
     }
@@ -2370,6 +2388,9 @@ static bool trans_MCR(DisasContext *s, arg_MCR *a)
 
 static bool trans_MRC(DisasContext *s, arg_MRC *a)
 {
+    if (maybe_nwfpe(s, a->cp)) {
+        return true;
+    }
     if (!valid_cp(s, a->cp)) {
         return false;
     }
@@ -2380,6 +2401,9 @@ static bool trans_MRC(DisasContext *s, arg_MRC *a)
 
 static bool trans_MCRR(DisasContext *s, arg_MCRR *a)
 {
+    if (maybe_nwfpe(s, a->cp)) {
+        return true;
+    }
     if (!valid_cp(s, a->cp)) {
         return false;
     }
@@ -2390,6 +2414,9 @@ static bool trans_MCRR(DisasContext *s, arg_MCRR *a)
 
 static bool trans_MRRC(DisasContext *s, arg_MRRC *a)
 {
+    if (maybe_nwfpe(s, a->cp)) {
+        return true;
+    }
     if (!valid_cp(s, a->cp)) {
         return false;
     }
-- 
2.43.0