diff options
author | Richard Henderson <rth@twiddle.net> | 2009-12-27 18:30:03 -0800 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2010-02-28 17:54:52 +0100 |
commit | 6049f4f831c6f409031dfa09282b38d0cbaecad8 (patch) | |
tree | be945d7b3470317887ebebcaf3dfbcae008a5520 /linux-user/main.c | |
parent | f24518b502802a128ca627a746a8bcb8d9e306af (diff) |
alpha-linux-user: Implement signals.
Move userland PALcode handling into linux-user main loop so that
we can send signals from there. This also makes alpha_palcode.c
system-level only, so don't build it for userland. Add defines
for GENTRAP PALcall mapping to signals.
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'linux-user/main.c')
-rw-r--r-- | linux-user/main.c | 137 |
1 files changed, 112 insertions, 25 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index 88cd4a0f51..eeae22e2bf 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2351,6 +2351,7 @@ void cpu_loop (CPUState *env) { int trapnr; target_siginfo_t info; + abi_long sysret; while (1) { trapnr = cpu_alpha_exec (env); @@ -2365,16 +2366,22 @@ void cpu_loop (CPUState *env) exit(1); break; case EXCP_ARITH: - fprintf(stderr, "Arithmetic trap.\n"); - exit(1); + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_FLTINV; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_HW_INTERRUPT: fprintf(stderr, "External interrupt. Exit\n"); exit(1); break; case EXCP_DFAULT: - fprintf(stderr, "MMU data fault\n"); - exit(1); + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = 0; /* ??? SEGV_MAPERR vs SEGV_ACCERR. */ + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_DTB_MISS_PAL: fprintf(stderr, "MMU data TLB miss in PALcode\n"); @@ -2393,36 +2400,116 @@ void cpu_loop (CPUState *env) exit(1); break; case EXCP_UNALIGN: - fprintf(stderr, "Unaligned access\n"); - exit(1); + info.si_signo = TARGET_SIGBUS; + info.si_errno = 0; + info.si_code = TARGET_BUS_ADRALN; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_OPCDEC: - fprintf(stderr, "Invalid instruction\n"); - exit(1); + do_sigill: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = TARGET_ILL_ILLOPC; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); break; case EXCP_FEN: - fprintf(stderr, "Floating-point not allowed\n"); - exit(1); + /* No-op. Linux simply re-enables the FPU. */ break; case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1): - call_pal(env, (trapnr >> 6) | 0x80); + switch ((trapnr >> 6) | 0x80) { + case 0x80: + /* BPT */ + info.si_signo = TARGET_SIGTRAP; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); + break; + case 0x81: + /* BUGCHK */ + info.si_signo = TARGET_SIGTRAP; + info.si_errno = 0; + info.si_code = 0; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); + break; + case 0x83: + /* CALLSYS */ + trapnr = env->ir[IR_V0]; + sysret = do_syscall(env, trapnr, + env->ir[IR_A0], env->ir[IR_A1], + env->ir[IR_A2], env->ir[IR_A3], + env->ir[IR_A4], env->ir[IR_A5]); + if (trapnr != TARGET_NR_sigreturn + && trapnr != TARGET_NR_rt_sigreturn) { + env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret); + env->ir[IR_A3] = (sysret < 0); + } + break; + case 0x86: + /* IMB */ + /* ??? We can probably elide the code using page_unprotect + that is checking for self-modifying code. Instead we + could simply call tb_flush here. Until we work out the + changes required to turn off the extra write protection, + this can be a no-op. */ + break; + case 0x9E: + /* RDUNIQUE */ + /* Handled in the translator for usermode. */ + abort(); + case 0x9F: + /* WRUNIQUE */ + /* Handled in the translator for usermode. */ + abort(); + case 0xAA: + /* GENTRAP */ + info.si_signo = TARGET_SIGFPE; + switch (env->ir[IR_A0]) { + case TARGET_GEN_INTOVF: + info.si_code = TARGET_FPE_INTOVF; + break; + case TARGET_GEN_INTDIV: + info.si_code = TARGET_FPE_INTDIV; + break; + case TARGET_GEN_FLTOVF: + info.si_code = TARGET_FPE_FLTOVF; + break; + case TARGET_GEN_FLTUND: + info.si_code = TARGET_FPE_FLTUND; + break; + case TARGET_GEN_FLTINV: + info.si_code = TARGET_FPE_FLTINV; + break; + case TARGET_GEN_FLTINE: + info.si_code = TARGET_FPE_FLTRES; + break; + case TARGET_GEN_ROPRAND: + info.si_code = 0; + break; + default: + info.si_signo = TARGET_SIGTRAP; + info.si_code = 0; + break; + } + info.si_errno = 0; + info._sifields._sigfault._addr = env->pc; + queue_signal(env, info.si_signo, &info); + break; + default: + goto do_sigill; + } break; case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1): - fprintf(stderr, "Privileged call to PALcode\n"); - exit(1); - break; + goto do_sigill; case EXCP_DEBUG: - { - int sig; - - sig = gdb_handlesig (env, TARGET_SIGTRAP); - if (sig) - { - info.si_signo = sig; - info.si_errno = 0; - info.si_code = TARGET_TRAP_BRKPT; - queue_signal(env, info.si_signo, &info); - } + info.si_signo = gdb_handlesig (env, TARGET_SIGTRAP); + if (info.si_signo) { + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, &info); } break; default: |