:p
atchew
Login
Lots of missing trap code for cpu_loop(). r~ Richard Henderson (14): linux-user/sparc: Raise SIGILL for all unhandled software traps linux-user/sparc: Tidy syscall trap linux-user/sparc: Use TT_TRAP for flush windows linux-user/sparc: Tidy window spill/fill traps linux-user/sparc: Fix sparc64_{get,set}_context traps linux-user/sparc: Handle software breakpoint trap linux-user/sparc: Handle division by zero traps linux-user/sparc: Handle getcc, setcc, getpsr traps linux-user/sparc: Handle priviledged opcode trap linux-user/sparc: Handle privilidged action trap linux-user/sparc: Handle coprocessor disabled trap linux-user/sparc: Handle unimplemented flush trap linux-user/sparc: Handle floating-point exceptions linux-user/sparc: Handle tag overflow traps linux-user/sparc/target_signal.h | 2 +- linux-user/syscall_defs.h | 5 + target/sparc/cpu.h | 3 +- linux-user/sparc/cpu_loop.c | 170 +++++++++++++++++++++++++------ linux-user/sparc/signal.c | 36 +++---- 5 files changed, 167 insertions(+), 49 deletions(-) -- 2.34.1
The linux kernel's trap tables vector all unassigned trap numbers to BAD_TRAP, which then raises SIGILL. Reported-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) cpu_exec_step_atomic(cs); break; default: + /* + * Most software trap numbers vector to BAD_TRAP. + * Handle anything not explicitly matched above. + */ + if (trapnr >= TT_TRAP && trapnr <= TT_TRAP + 0x7f) { + force_sig_fault(TARGET_SIGILL, ILL_ILLTRP, env->pc); + break; + } fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); exit(EXIT_FAILURE); -- 2.34.1
Use TT_TRAP. For sparc32, 0x88 is the "Slowaris" system call, currently BAD_TRAP in the kernel's ttable_32.S. For sparc64, 0x110 is tl0_linux32, the sparc32 trap, as also seen in the adjacent code. We do not implement multiple abis, so treat this as !defined(CONFIG_COMPAT), which vectors this case to BTRAP. This was presumably a typo for 0x111, which is the "old" linux64 syscall number. Both old and new linux64 syscalls traps vector to LINUX_64BIT_SYSCALL_TRAP. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) } switch (trapnr) { -#ifndef TARGET_SPARC64 - case 0x88: - case 0x90: +#ifdef TARGET_SPARC64 + case TT_TRAP + 0x11: /* tl0_oldlinux64 */ + case TT_TRAP + 0x6d: /* tl0_linux64 */ #else - case 0x110: - case 0x16d: + case TT_TRAP + 0x10: /* t_linux */ #endif ret = do_syscall (env, env->gregs[1], env->regwptr[0], env->regwptr[1], -- 2.34.1
The v9 and pre-v9 code can be unified with this macro. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->pc = env->npc; env->npc = env->npc + 4; break; - case 0x83: /* flush windows */ -#ifdef TARGET_ABI32 - case 0x103: -#endif + + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ env->pc = env->npc; env->npc = env->npc + 4; break; + #ifndef TARGET_SPARC64 case TT_WIN_OVF: /* window overflow */ save_window(env); -- 2.34.1
Add some macros to localize the hw difference between v9 and pre-v9. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static void flush_windows(CPUSPARCState *env) #endif } +/* Avoid ifdefs below for the v9 and pre-v9 hw traps. */ +#ifdef TARGET_SPARC64 +#define TARGET_TT_SPILL TT_SPILL +#define TARGET_TT_FILL TT_FILL +#else +#define TARGET_TT_SPILL TT_WIN_OVF +#define TARGET_TT_FILL TT_WIN_UNF +#endif + void cpu_loop (CPUSPARCState *env) { CPUState *cs = env_cpu(env); @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; -#ifndef TARGET_SPARC64 - case TT_WIN_OVF: /* window overflow */ + case TARGET_TT_SPILL: /* window overflow */ save_window(env); break; - case TT_WIN_UNF: /* window underflow */ - restore_window(env); - break; -#else - case TT_SPILL: /* window overflow */ - save_window(env); - break; - case TT_FILL: /* window underflow */ + case TARGET_TT_FILL: /* window underflow */ restore_window(env); break; + +#ifdef TARGET_SPARC64 #ifndef TARGET_ABI32 case 0x16e: flush_windows(env); -- 2.34.1
These traps are present for sparc64 with ilp32, aka sparc32plus. Enabling them means adjusting the defines over in signal.c, and fixing an incorrect usage of abi_ulong when we really meant the full register, target_ulong. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 23 +++++++++++------------ linux-user/sparc/signal.c | 36 +++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; +#ifdef TARGET_SPARC64 + case TT_TRAP + 0x6e: + flush_windows(env); + sparc64_get_context(env); + break; + case TT_TRAP + 0x6f: + flush_windows(env); + sparc64_set_context(env); + break; +#endif + case TARGET_TT_SPILL: /* window overflow */ save_window(env); break; @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) restore_window(env); break; -#ifdef TARGET_SPARC64 -#ifndef TARGET_ABI32 - case 0x16e: - flush_windows(env); - sparc64_get_context(env); - break; - case 0x16f: - flush_windows(env); - sparc64_set_context(env); - break; -#endif -#endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -XXX,XX +XXX,XX @@ long do_rt_sigreturn(CPUSPARCState *env) return -QEMU_ESIGRETURN; } -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) +#ifdef TARGET_ABI32 +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0); + assert(tramp != NULL); + + default_sigreturn = sigtramp_page; + install_sigtramp(tramp, TARGET_NR_sigreturn); + + default_rt_sigreturn = sigtramp_page + 8; + install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn); + + unlock_user(tramp, sigtramp_page, 2 * 8); +} +#endif + +#ifdef TARGET_SPARC64 #define SPARC_MC_TSTATE 0 #define SPARC_MC_PC 1 #define SPARC_MC_NPC 2 @@ -XXX,XX +XXX,XX @@ void sparc64_set_context(CPUSPARCState *env) struct target_ucontext *ucp; target_mc_gregset_t *grp; target_mc_fpu_t *fpup; - abi_ulong pc, npc, tstate; + target_ulong pc, npc, tstate; unsigned int i; unsigned char fenab; @@ -XXX,XX +XXX,XX @@ do_sigsegv: unlock_user_struct(ucp, ucp_addr, 1); force_sig(TARGET_SIGSEGV); } -#else -void setup_sigtramp(abi_ulong sigtramp_page) -{ - uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0); - assert(tramp != NULL); - - default_sigreturn = sigtramp_page; - install_sigtramp(tramp, TARGET_NR_sigreturn); - - default_rt_sigreturn = sigtramp_page + 8; - install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn); - - unlock_user(tramp, sigtramp_page, 2 * 8); -} -#endif +#endif /* TARGET_SPARC64 */ -- 2.34.1
This is 'ta 1' for both v9 and pre-v9. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; + case TT_TRAP + 0x01: /* breakpoint */ + case EXCP_DEBUG: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + break; + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_ILL_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); break; - case EXCP_DEBUG: - force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); - break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- 2.34.1
In addition to the hw trap vector, there is a software trap assigned for older sparc without hw division instructions. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; + case TT_TRAP + 0x02: /* div0 */ + case TT_DIV_ZERO: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + break; + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ -- 2.34.1
These are really only meaningful for sparc32, but they're still present for backward compatibility for sparc64. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 62 +++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static void flush_windows(CPUSPARCState *env) #endif } +static void next_instruction(CPUSPARCState *env) +{ + env->pc = env->npc; + env->npc = env->npc + 4; +} + +static uint32_t do_getcc(CPUSPARCState *env) +{ +#ifdef TARGET_SPARC64 + return cpu_get_ccr(env) & 0xf; +#else + return extract32(cpu_get_psr(env), 20, 4); +#endif +} + +static void do_setcc(CPUSPARCState *env, uint32_t icc) +{ +#ifdef TARGET_SPARC64 + cpu_put_ccr(env, (cpu_get_ccr(env) & 0xf0) | (icc & 0xf)); +#else + cpu_put_psr(env, deposit32(cpu_get_psr(env), 20, 4, icc)); +#endif +} + +static uint32_t do_getpsr(CPUSPARCState *env) +{ +#ifdef TARGET_SPARC64 + const uint64_t TSTATE_CWP = 0x1f; + const uint64_t TSTATE_ICC = 0xfull << 32; + const uint64_t TSTATE_XCC = 0xfull << 36; + const uint32_t PSR_S = 0x00000080u; + const uint32_t PSR_V8PLUS = 0xff000000u; + uint64_t tstate = sparc64_tstate(env); + + /* See <asm/psrcompat.h>, tstate_to_psr. */ + return ((tstate & TSTATE_CWP) | + PSR_S | + ((tstate & TSTATE_ICC) >> 12) | + ((tstate & TSTATE_XCC) >> 20) | + PSR_V8PLUS); +#else + return (cpu_get_psr(env) & (PSR_ICC | PSR_CWP)) | PSR_S; +#endif +} + /* Avoid ifdefs below for the v9 and pre-v9 hw traps. */ #ifdef TARGET_SPARC64 #define TARGET_TT_SPILL TT_SPILL @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); - /* next instruction */ - env->pc = env->npc; - env->npc = env->npc + 4; + next_instruction(env); + break; + + case TT_TRAP + 0x20: /* getcc */ + env->gregs[1] = do_getcc(env); + next_instruction(env); + break; + case TT_TRAP + 0x21: /* setcc */ + do_setcc(env, env->gregs[1]); + next_instruction(env); + break; + case TT_TRAP + 0x22: /* getpsr */ + env->gregs[1] = do_getpsr(env); + next_instruction(env); break; #ifdef TARGET_SPARC64 -- 2.34.1
For the most part priviledged opcodes are ifdefed out of the user-only sparc translator, which will then incorrectly produce illegal opcode traps. But there are some code paths that properly raise TT_PRIV_INSN, so we must handle it. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_ILL_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); break; + case TT_PRIV_INSN: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- 2.34.1
This is raised by using an %asi < 0x80 in user-mode. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_PRIV_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; +#ifdef TARGET_SPARC64 + case TT_PRIV_ACT: + /* Note do_privact defers to do_privop. */ + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; +#endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- 2.34.1
Since qemu does not implement a sparc coprocessor, all such instructions raise this trap. Because of that, we never raise the coprocessor exception trap, which would be vector 0x28. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) /* Note do_privact defers to do_privop. */ force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; +#else + case TT_NCP_INSN: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); + break; #endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); -- 2.34.1
For sparc64, TT_UNIMP_FLUSH == TT_ILL_INSN, so this is already handled. For sparc32, the kernel uses SKIP_TRAP. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_NCP_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); break; + case TT_UNIMP_FLUSH: + next_instruction(env); + break; #endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); -- 2.34.1
Raise SIGFPE for ieee exceptions. The other types, such as FSR_FTT_UNIMPFPOP, should not appear, because we enable normal emulation of missing insns at the start of sparc_cpu_realizefn(). Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/sparc/cpu.h | 3 +-- linux-user/sparc/cpu_loop.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -XXX,XX +XXX,XX @@ enum { #define FSR_FTT2 (1ULL << 16) #define FSR_FTT1 (1ULL << 15) #define FSR_FTT0 (1ULL << 14) -//gcc warns about constant overflow for ~FSR_FTT_MASK -//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) +#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) #ifdef TARGET_SPARC64 #define FSR_FTT_NMASK 0xfffffffffffe3fffULL #define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) restore_window(env); break; + case TT_FP_EXCP: + { + int code = TARGET_FPE_FLTUNK; + target_ulong fsr = env->fsr; + + if ((fsr & FSR_FTT_MASK) == FSR_FTT_IEEE_EXCP) { + if (fsr & FSR_NVC) { + code = TARGET_FPE_FLTINV; + } else if (fsr & FSR_OFC) { + code = TARGET_FPE_FLTOVF; + } else if (fsr & FSR_UFC) { + code = TARGET_FPE_FLTUND; + } else if (fsr & FSR_DZC) { + code = TARGET_FPE_FLTDIV; + } else if (fsr & FSR_NXC) { + code = TARGET_FPE_FLTRES; + } + } + force_sig_fault(TARGET_SIGFPE, code, env->pc); + } + break; + case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; -- 2.34.1
This trap is raised by taddcctv and tsubcctv insns. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/target_signal.h | 2 +- linux-user/syscall_defs.h | 5 +++++ linux-user/sparc/cpu_loop.c | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -XXX,XX +XXX,XX @@ #define TARGET_SIGTRAP 5 #define TARGET_SIGABRT 6 #define TARGET_SIGIOT 6 -#define TARGET_SIGSTKFLT 7 /* actually EMT */ +#define TARGET_SIGEMT 7 #define TARGET_SIGFPE 8 #define TARGET_SIGKILL 9 #define TARGET_SIGBUS 10 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ typedef struct target_siginfo { #define TARGET_TRAP_HWBKPT (4) /* hardware breakpoint/watchpoint */ #define TARGET_TRAP_UNK (5) /* undiagnosed trap */ +/* + * SIGEMT si_codes + */ +#define TARGET_EMT_TAGOVF 1 /* tag overflow */ + #include "target_resource.h" struct target_pollfd { diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_PRIV_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; + case TT_TOVF: + force_sig_fault(TARGET_SIGEMT, TARGET_EMT_TAGOVF, env->pc); + break; #ifdef TARGET_SPARC64 case TT_PRIV_ACT: /* Note do_privact defers to do_privop. */ -- 2.34.1
Lots of missing trap codes for cpu_loop(). Changes for v2: - Fix v8plus syscall trap. - New patch to unify syscall error return via C flag. r~ Richard Henderson (15): linux-user/sparc: Raise SIGILL for all unhandled software traps linux-user/sparc: Tidy syscall trap linux-user/sparc: Tidy syscall error return linux-user/sparc: Use TT_TRAP for flush windows linux-user/sparc: Tidy window spill/fill traps linux-user/sparc: Fix sparc64_{get,set}_context traps linux-user/sparc: Handle software breakpoint trap linux-user/sparc: Handle division by zero traps linux-user/sparc: Handle getcc, setcc, getpsr traps linux-user/sparc: Handle priviledged opcode trap linux-user/sparc: Handle privilidged action trap linux-user/sparc: Handle coprocessor disabled trap linux-user/sparc: Handle unimplemented flush trap linux-user/sparc: Handle floating-point exceptions linux-user/sparc: Handle tag overflow traps linux-user/sparc/target_signal.h | 2 +- linux-user/syscall_defs.h | 5 + target/sparc/cpu.h | 3 +- linux-user/sparc/cpu_loop.c | 190 ++++++++++++++++++++++++------- linux-user/sparc/signal.c | 36 +++--- 5 files changed, 175 insertions(+), 61 deletions(-) -- 2.34.1
The linux kernel's trap tables vector all unassigned trap numbers to BAD_TRAP, which then raises SIGILL. Tested-by: Ilya Leoshkevich <iii@linux.ibm.com> Reported-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) cpu_exec_step_atomic(cs); break; default: + /* + * Most software trap numbers vector to BAD_TRAP. + * Handle anything not explicitly matched above. + */ + if (trapnr >= TT_TRAP && trapnr <= TT_TRAP + 0x7f) { + force_sig_fault(TARGET_SIGILL, ILL_ILLTRP, env->pc); + break; + } fprintf(stderr, "Unhandled trap: 0x%x\n", trapnr); cpu_dump_state(cs, stderr, 0); exit(EXIT_FAILURE); -- 2.34.1
Use TT_TRAP. For sparc32, 0x88 is the "Slowaris" system call, currently BAD_TRAP in the kernel's ttable_32.S. For sparc64, 0x110 is tl0_linux32, the sparc32 trap, now folded into the TARGET_ABI32 case via TT_TRAP. For sparc64, there does still exist trap 0x111 as tl0_oldlinux64, which was replaced by 0x16d as tl0_linux64 in 1998. Since no one has noticed, don't bother implementing it now. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static void flush_windows(CPUSPARCState *env) #endif } +#ifdef TARGET_ABI32 +#define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ +#else +#define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */ +#endif + void cpu_loop (CPUSPARCState *env) { CPUState *cs = env_cpu(env); @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) } switch (trapnr) { -#ifndef TARGET_SPARC64 - case 0x88: - case 0x90: -#else - case 0x110: - case 0x16d: -#endif + case TARGET_TT_SYSCALL: ret = do_syscall (env, env->gregs[1], env->regwptr[0], env->regwptr[1], env->regwptr[2], env->regwptr[3], -- 2.34.1
Reduce ifdefs with #define syscall_cc. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static void flush_windows(CPUSPARCState *env) #endif } +/* Avoid ifdefs below for the abi32 and abi64 paths. */ #ifdef TARGET_ABI32 #define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ +#define syscall_cc psr #else #define TARGET_TT_SYSCALL (TT_TRAP + 0x6d) /* tl0_linux64 */ +#define syscall_cc xcc #endif void cpu_loop (CPUSPARCState *env) @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) break; } if ((abi_ulong)ret >= (abi_ulong)(-515)) { -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc |= PSR_CARRY; -#else - env->psr |= PSR_CARRY; -#endif + env->syscall_cc |= PSR_CARRY; ret = -ret; } else { -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) - env->xcc &= ~PSR_CARRY; -#else - env->psr &= ~PSR_CARRY; -#endif + env->syscall_cc &= ~PSR_CARRY; } env->regwptr[0] = ret; /* next instruction */ -- 2.34.1
The v9 and pre-v9 code can be unified with this macro. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->pc = env->npc; env->npc = env->npc + 4; break; - case 0x83: /* flush windows */ -#ifdef TARGET_ABI32 - case 0x103: -#endif + + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ env->pc = env->npc; env->npc = env->npc + 4; break; + #ifndef TARGET_SPARC64 case TT_WIN_OVF: /* window overflow */ save_window(env); -- 2.34.1
Add some macros to localize the hw difference between v9 and pre-v9. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static void flush_windows(CPUSPARCState *env) #define syscall_cc xcc #endif +/* Avoid ifdefs below for the v9 and pre-v9 hw traps. */ +#ifdef TARGET_SPARC64 +#define TARGET_TT_SPILL TT_SPILL +#define TARGET_TT_FILL TT_FILL +#else +#define TARGET_TT_SPILL TT_WIN_OVF +#define TARGET_TT_FILL TT_WIN_UNF +#endif + void cpu_loop (CPUSPARCState *env) { CPUState *cs = env_cpu(env); @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; -#ifndef TARGET_SPARC64 - case TT_WIN_OVF: /* window overflow */ + case TARGET_TT_SPILL: /* window overflow */ save_window(env); break; - case TT_WIN_UNF: /* window underflow */ - restore_window(env); - break; -#else - case TT_SPILL: /* window overflow */ - save_window(env); - break; - case TT_FILL: /* window underflow */ + case TARGET_TT_FILL: /* window underflow */ restore_window(env); break; + +#ifdef TARGET_SPARC64 #ifndef TARGET_ABI32 case 0x16e: flush_windows(env); -- 2.34.1
These traps are present for sparc64 with ilp32, aka sparc32plus. Enabling them means adjusting the defines over in signal.c, and fixing an incorrect usage of abi_ulong when we really meant the full register, target_ulong. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 23 +++++++++++------------ linux-user/sparc/signal.c | 36 +++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; +#ifdef TARGET_SPARC64 + case TT_TRAP + 0x6e: + flush_windows(env); + sparc64_get_context(env); + break; + case TT_TRAP + 0x6f: + flush_windows(env); + sparc64_set_context(env); + break; +#endif + case TARGET_TT_SPILL: /* window overflow */ save_window(env); break; @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) restore_window(env); break; -#ifdef TARGET_SPARC64 -#ifndef TARGET_ABI32 - case 0x16e: - flush_windows(env); - sparc64_get_context(env); - break; - case 0x16f: - flush_windows(env); - sparc64_set_context(env); - break; -#endif -#endif case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; diff --git a/linux-user/sparc/signal.c b/linux-user/sparc/signal.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/signal.c +++ b/linux-user/sparc/signal.c @@ -XXX,XX +XXX,XX @@ long do_rt_sigreturn(CPUSPARCState *env) return -QEMU_ESIGRETURN; } -#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) +#ifdef TARGET_ABI32 +void setup_sigtramp(abi_ulong sigtramp_page) +{ + uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0); + assert(tramp != NULL); + + default_sigreturn = sigtramp_page; + install_sigtramp(tramp, TARGET_NR_sigreturn); + + default_rt_sigreturn = sigtramp_page + 8; + install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn); + + unlock_user(tramp, sigtramp_page, 2 * 8); +} +#endif + +#ifdef TARGET_SPARC64 #define SPARC_MC_TSTATE 0 #define SPARC_MC_PC 1 #define SPARC_MC_NPC 2 @@ -XXX,XX +XXX,XX @@ void sparc64_set_context(CPUSPARCState *env) struct target_ucontext *ucp; target_mc_gregset_t *grp; target_mc_fpu_t *fpup; - abi_ulong pc, npc, tstate; + target_ulong pc, npc, tstate; unsigned int i; unsigned char fenab; @@ -XXX,XX +XXX,XX @@ do_sigsegv: unlock_user_struct(ucp, ucp_addr, 1); force_sig(TARGET_SIGSEGV); } -#else -void setup_sigtramp(abi_ulong sigtramp_page) -{ - uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 2 * 8, 0); - assert(tramp != NULL); - - default_sigreturn = sigtramp_page; - install_sigtramp(tramp, TARGET_NR_sigreturn); - - default_rt_sigreturn = sigtramp_page + 8; - install_sigtramp(tramp + 2, TARGET_NR_rt_sigreturn); - - unlock_user(tramp, sigtramp_page, 2 * 8); -} -#endif +#endif /* TARGET_SPARC64 */ -- 2.34.1
This is 'ta 1' for both v9 and pre-v9. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) env->npc = env->npc + 4; break; + case TT_TRAP + 0x01: /* breakpoint */ + case EXCP_DEBUG: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + break; + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_ILL_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); break; - case EXCP_DEBUG: - force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); - break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- 2.34.1
In addition to the hw trap vector, there is a software trap assigned for older sparc without hw division instructions. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; + case TT_TRAP + 0x02: /* div0 */ + case TT_DIV_ZERO: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + break; + case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); /* next instruction */ -- 2.34.1
These are really only meaningful for sparc32, but they're still present for backward compatibility for sparc64. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 62 +++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ static void flush_windows(CPUSPARCState *env) #endif } +static void next_instruction(CPUSPARCState *env) +{ + env->pc = env->npc; + env->npc = env->npc + 4; +} + +static uint32_t do_getcc(CPUSPARCState *env) +{ +#ifdef TARGET_SPARC64 + return cpu_get_ccr(env) & 0xf; +#else + return extract32(cpu_get_psr(env), 20, 4); +#endif +} + +static void do_setcc(CPUSPARCState *env, uint32_t icc) +{ +#ifdef TARGET_SPARC64 + cpu_put_ccr(env, (cpu_get_ccr(env) & 0xf0) | (icc & 0xf)); +#else + cpu_put_psr(env, deposit32(cpu_get_psr(env), 20, 4, icc)); +#endif +} + +static uint32_t do_getpsr(CPUSPARCState *env) +{ +#ifdef TARGET_SPARC64 + const uint64_t TSTATE_CWP = 0x1f; + const uint64_t TSTATE_ICC = 0xfull << 32; + const uint64_t TSTATE_XCC = 0xfull << 36; + const uint32_t PSR_S = 0x00000080u; + const uint32_t PSR_V8PLUS = 0xff000000u; + uint64_t tstate = sparc64_tstate(env); + + /* See <asm/psrcompat.h>, tstate_to_psr. */ + return ((tstate & TSTATE_CWP) | + PSR_S | + ((tstate & TSTATE_ICC) >> 12) | + ((tstate & TSTATE_XCC) >> 20) | + PSR_V8PLUS); +#else + return (cpu_get_psr(env) & (PSR_ICC | PSR_CWP)) | PSR_S; +#endif +} + /* Avoid ifdefs below for the abi32 and abi64 paths. */ #ifdef TARGET_ABI32 #define TARGET_TT_SYSCALL (TT_TRAP + 0x10) /* t_linux */ @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_TRAP + 0x03: /* flush windows */ flush_windows(env); - /* next instruction */ - env->pc = env->npc; - env->npc = env->npc + 4; + next_instruction(env); + break; + + case TT_TRAP + 0x20: /* getcc */ + env->gregs[1] = do_getcc(env); + next_instruction(env); + break; + case TT_TRAP + 0x21: /* setcc */ + do_setcc(env, env->gregs[1]); + next_instruction(env); + break; + case TT_TRAP + 0x22: /* getpsr */ + env->gregs[1] = do_getpsr(env); + next_instruction(env); break; #ifdef TARGET_SPARC64 -- 2.34.1
For the most part priviledged opcodes are ifdefed out of the user-only sparc translator, which will then incorrectly produce illegal opcode traps. But there are some code paths that properly raise TT_PRIV_INSN, so we must handle it. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_ILL_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPC, env->pc); break; + case TT_PRIV_INSN: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- 2.34.1
This is raised by using an %asi < 0x80 in user-mode. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_PRIV_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; +#ifdef TARGET_SPARC64 + case TT_PRIV_ACT: + /* Note do_privact defers to do_privop. */ + force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); + break; +#endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); break; -- 2.34.1
Since qemu does not implement a sparc coprocessor, all such instructions raise this trap. Because of that, we never raise the coprocessor exception trap, which would be vector 0x28. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) /* Note do_privact defers to do_privop. */ force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; +#else + case TT_NCP_INSN: + force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); + break; #endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); -- 2.34.1
For sparc64, TT_UNIMP_FLUSH == TT_ILL_INSN, so this is already handled. For sparc32, the kernel uses SKIP_TRAP. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/cpu_loop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_NCP_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_COPROC, env->pc); break; + case TT_UNIMP_FLUSH: + next_instruction(env); + break; #endif case EXCP_ATOMIC: cpu_exec_step_atomic(cs); -- 2.34.1
Raise SIGFPE for ieee exceptions. The other types, such as FSR_FTT_UNIMPFPOP, should not appear, because we enable normal emulation of missing insns at the start of sparc_cpu_realizefn(). Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- target/sparc/cpu.h | 3 +-- linux-user/sparc/cpu_loop.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -XXX,XX +XXX,XX @@ enum { #define FSR_FTT2 (1ULL << 16) #define FSR_FTT1 (1ULL << 15) #define FSR_FTT0 (1ULL << 14) -//gcc warns about constant overflow for ~FSR_FTT_MASK -//#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) +#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0) #ifdef TARGET_SPARC64 #define FSR_FTT_NMASK 0xfffffffffffe3fffULL #define FSR_FTT_CEXC_NMASK 0xfffffffffffe3fe0ULL diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) restore_window(env); break; + case TT_FP_EXCP: + { + int code = TARGET_FPE_FLTUNK; + target_ulong fsr = env->fsr; + + if ((fsr & FSR_FTT_MASK) == FSR_FTT_IEEE_EXCP) { + if (fsr & FSR_NVC) { + code = TARGET_FPE_FLTINV; + } else if (fsr & FSR_OFC) { + code = TARGET_FPE_FLTOVF; + } else if (fsr & FSR_UFC) { + code = TARGET_FPE_FLTUND; + } else if (fsr & FSR_DZC) { + code = TARGET_FPE_FLTDIV; + } else if (fsr & FSR_NXC) { + code = TARGET_FPE_FLTRES; + } + } + force_sig_fault(TARGET_SIGFPE, code, env->pc); + } + break; + case EXCP_INTERRUPT: /* just indicate that signals should be handled asap */ break; -- 2.34.1
This trap is raised by taddcctv and tsubcctv insns. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- linux-user/sparc/target_signal.h | 2 +- linux-user/syscall_defs.h | 5 +++++ linux-user/sparc/cpu_loop.c | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/target_signal.h +++ b/linux-user/sparc/target_signal.h @@ -XXX,XX +XXX,XX @@ #define TARGET_SIGTRAP 5 #define TARGET_SIGABRT 6 #define TARGET_SIGIOT 6 -#define TARGET_SIGSTKFLT 7 /* actually EMT */ +#define TARGET_SIGEMT 7 #define TARGET_SIGFPE 8 #define TARGET_SIGKILL 9 #define TARGET_SIGBUS 10 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -XXX,XX +XXX,XX @@ typedef struct target_siginfo { #define TARGET_TRAP_HWBKPT (4) /* hardware breakpoint/watchpoint */ #define TARGET_TRAP_UNK (5) /* undiagnosed trap */ +/* + * SIGEMT si_codes + */ +#define TARGET_EMT_TAGOVF 1 /* tag overflow */ + #include "target_resource.h" struct target_pollfd { diff --git a/linux-user/sparc/cpu_loop.c b/linux-user/sparc/cpu_loop.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/sparc/cpu_loop.c +++ b/linux-user/sparc/cpu_loop.c @@ -XXX,XX +XXX,XX @@ void cpu_loop (CPUSPARCState *env) case TT_PRIV_INSN: force_sig_fault(TARGET_SIGILL, TARGET_ILL_PRVOPC, env->pc); break; + case TT_TOVF: + force_sig_fault(TARGET_SIGEMT, TARGET_EMT_TAGOVF, env->pc); + break; #ifdef TARGET_SPARC64 case TT_PRIV_ACT: /* Note do_privact defers to do_privop. */ -- 2.34.1