From c1438d6c02eae03cc387dbdf2f30c11f45894954 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:10 -0700 Subject: linux-user/arm: Split out emulate_arm_fpa11 Pull out the fpa11 emulation to a helper function. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-2-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 153 ++++++++++++++++++++++++++++------------------ 1 file changed, 94 insertions(+), 59 deletions(-) (limited to 'linux-user/arm/cpu_loop.c') diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 989d03cd89..106909c7d8 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -224,6 +224,92 @@ static bool insn_is_linux_bkpt(uint32_t opcode, bool is_thumb) } } +static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) +{ + TaskState *ts = env_cpu(env)->opaque; + int rc = EmulateAll(opcode, &ts->fpa, env); + + if (rc == 0) { + /* Illegal instruction */ + return false; + } + if (rc > 0) { + /* Everything ok. */ + env->regs[15] += 4; + return true; + } + + /* FP exception */ + int arm_fpe = 0; + + /* Translate softfloat flags to FPSR flags */ + if (-rc & float_flag_invalid) { + arm_fpe |= BIT_IOC; + } + if (-rc & float_flag_divbyzero) { + arm_fpe |= BIT_DZC; + } + if (-rc & float_flag_overflow) { + arm_fpe |= BIT_OFC; + } + if (-rc & float_flag_underflow) { + arm_fpe |= BIT_UFC; + } + if (-rc & float_flag_inexact) { + arm_fpe |= BIT_IXC; + } + + /* Exception enabled? */ + FPSR fpsr = ts->fpa.fpsr; + if (fpsr & (arm_fpe << 16)) { + target_siginfo_t info; + + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + + /* ordered by priority, least first */ + if (arm_fpe & BIT_IXC) { + info.si_code = TARGET_FPE_FLTRES; + } + if (arm_fpe & BIT_UFC) { + info.si_code = TARGET_FPE_FLTUND; + } + if (arm_fpe & BIT_OFC) { + info.si_code = TARGET_FPE_FLTOVF; + } + if (arm_fpe & BIT_DZC) { + info.si_code = TARGET_FPE_FLTDIV; + } + if (arm_fpe & BIT_IOC) { + info.si_code = TARGET_FPE_FLTINV; + } + + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + } else { + env->regs[15] += 4; + } + + /* Accumulate unenabled exceptions */ + if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) { + fpsr |= BIT_IXC; + } + if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) { + fpsr |= BIT_UFC; + } + if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) { + fpsr |= BIT_OFC; + } + if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) { + fpsr |= BIT_DZC; + } + if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) { + fpsr |= BIT_IOC; + } + ts->fpa.fpsr = fpsr; + return true; +} + void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); @@ -244,9 +330,7 @@ void cpu_loop(CPUARMState *env) case EXCP_NOCP: case EXCP_INVSTATE: { - TaskState *ts = cs->opaque; uint32_t opcode; - int rc; /* we handle the FPU emulation here, as Linux */ /* we get the opcode */ @@ -263,64 +347,15 @@ void cpu_loop(CPUARMState *env) goto excp_debug; } - rc = EmulateAll(opcode, &ts->fpa, env); - if (rc == 0) { /* illegal instruction */ - info.si_signo = TARGET_SIGILL; - info.si_errno = 0; - info.si_code = TARGET_ILL_ILLOPN; - info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - } else if (rc < 0) { /* FP exception */ - int arm_fpe=0; - - /* translate softfloat flags to FPSR flags */ - if (-rc & float_flag_invalid) - arm_fpe |= BIT_IOC; - if (-rc & float_flag_divbyzero) - arm_fpe |= BIT_DZC; - if (-rc & float_flag_overflow) - arm_fpe |= BIT_OFC; - if (-rc & float_flag_underflow) - arm_fpe |= BIT_UFC; - if (-rc & float_flag_inexact) - arm_fpe |= BIT_IXC; - - FPSR fpsr = ts->fpa.fpsr; - //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); - - if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ - info.si_signo = TARGET_SIGFPE; - info.si_errno = 0; - - /* ordered by priority, least first */ - if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; - if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; - if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; - if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; - if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; - - info._sifields._sigfault._addr = env->regs[15]; - queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); - } else { - env->regs[15] += 4; - } - - /* accumulate unenabled exceptions */ - if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) - fpsr |= BIT_IXC; - if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) - fpsr |= BIT_UFC; - if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) - fpsr |= BIT_OFC; - if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) - fpsr |= BIT_DZC; - if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) - fpsr |= BIT_IOC; - ts->fpa.fpsr=fpsr; - } else { /* everything OK */ - /* increment PC */ - env->regs[15] += 4; + if (emulate_arm_fpa11(env, opcode)) { + break; } + + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPN; + info._sifields._sigfault._addr = env->regs[15]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } break; case EXCP_SWI: -- cgit 1.4.1 From d827f6d5fdb0826e17c80f63547c5c2dee3f0fac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:11 -0700 Subject: linux-user/arm: Do not emulate fpa11 in thumb mode These antiquated instructions are arm-mode only. Buglink: https://bugs.launchpad.net/bugs/1925512 Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-user/arm/cpu_loop.c') diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 106909c7d8..e2a1496b9f 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -347,7 +347,7 @@ void cpu_loop(CPUARMState *env) goto excp_debug; } - if (emulate_arm_fpa11(env, opcode)) { + if (!env->thumb && emulate_arm_fpa11(env, opcode)) { break; } -- cgit 1.4.1 From 0a50285ee8bf471936325f5ccd870752d2a038cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:12 -0700 Subject: linux-user/arm: Do not fill in si_code for fpa11 exceptions There is no such decoding in linux/arch/arm/nwfpe/fpmodule.c. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'linux-user/arm/cpu_loop.c') diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index e2a1496b9f..5f61d25717 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -262,29 +262,15 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) /* Exception enabled? */ FPSR fpsr = ts->fpa.fpsr; if (fpsr & (arm_fpe << 16)) { - target_siginfo_t info; + target_siginfo_t info = { }; + /* + * The kernel's nwfpe emulator does not pass a real si_code. + * It merely uses send_sig(SIGFPE, current, 1). + */ info.si_signo = TARGET_SIGFPE; - info.si_errno = 0; - - /* ordered by priority, least first */ - if (arm_fpe & BIT_IXC) { - info.si_code = TARGET_FPE_FLTRES; - } - if (arm_fpe & BIT_UFC) { - info.si_code = TARGET_FPE_FLTUND; - } - if (arm_fpe & BIT_OFC) { - info.si_code = TARGET_FPE_FLTOVF; - } - if (arm_fpe & BIT_DZC) { - info.si_code = TARGET_FPE_FLTDIV; - } - if (arm_fpe & BIT_IOC) { - info.si_code = TARGET_FPE_FLTINV; - } + info.si_code = TARGET_SI_KERNEL; - info._sifields._sigfault._addr = env->regs[15]; queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); } else { env->regs[15] += 4; -- cgit 1.4.1 From 74081ae0ff4aea6ad0db0427ed31ac5250a58b3f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 23 Apr 2021 09:54:13 -0700 Subject: linux-user/arm: Simplify accumulating and raising fpa11 exceptions Use bit masking instead of an if tree. Signed-off-by: Richard Henderson Reviewed-by: Peter Maydell Message-Id: <20210423165413.338259-5-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier --- linux-user/arm/cpu_loop.c | 50 +++++++++++++++++------------------------------ 1 file changed, 18 insertions(+), 32 deletions(-) (limited to 'linux-user/arm/cpu_loop.c') diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 5f61d25717..69632d15be 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -228,6 +228,7 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) { TaskState *ts = env_cpu(env)->opaque; int rc = EmulateAll(opcode, &ts->fpa, env); + int raise, enabled; if (rc == 0) { /* Illegal instruction */ @@ -240,28 +241,31 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) } /* FP exception */ - int arm_fpe = 0; + rc = -rc; + raise = 0; /* Translate softfloat flags to FPSR flags */ - if (-rc & float_flag_invalid) { - arm_fpe |= BIT_IOC; + if (rc & float_flag_invalid) { + raise |= BIT_IOC; } - if (-rc & float_flag_divbyzero) { - arm_fpe |= BIT_DZC; + if (rc & float_flag_divbyzero) { + raise |= BIT_DZC; } - if (-rc & float_flag_overflow) { - arm_fpe |= BIT_OFC; + if (rc & float_flag_overflow) { + raise |= BIT_OFC; } - if (-rc & float_flag_underflow) { - arm_fpe |= BIT_UFC; + if (rc & float_flag_underflow) { + raise |= BIT_UFC; } - if (-rc & float_flag_inexact) { - arm_fpe |= BIT_IXC; + if (rc & float_flag_inexact) { + raise |= BIT_IXC; } - /* Exception enabled? */ - FPSR fpsr = ts->fpa.fpsr; - if (fpsr & (arm_fpe << 16)) { + /* Accumulate unenabled exceptions */ + enabled = ts->fpa.fpsr >> 16; + ts->fpa.fpsr |= raise & ~enabled; + + if (raise & enabled) { target_siginfo_t info = { }; /* @@ -275,24 +279,6 @@ static bool emulate_arm_fpa11(CPUARMState *env, uint32_t opcode) } else { env->regs[15] += 4; } - - /* Accumulate unenabled exceptions */ - if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) { - fpsr |= BIT_IXC; - } - if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) { - fpsr |= BIT_UFC; - } - if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) { - fpsr |= BIT_OFC; - } - if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) { - fpsr |= BIT_DZC; - } - if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) { - fpsr |= BIT_IOC; - } - ts->fpa.fpsr = fpsr; return true; } -- cgit 1.4.1