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