aboutsummaryrefslogtreecommitdiff
path: root/linux-user/main.c
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2009-12-27 18:30:03 -0800
committerAurelien Jarno <aurelien@aurel32.net>2010-02-28 17:54:52 +0100
commit6049f4f831c6f409031dfa09282b38d0cbaecad8 (patch)
treebe945d7b3470317887ebebcaf3dfbcae008a5520 /linux-user/main.c
parentf24518b502802a128ca627a746a8bcb8d9e306af (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.c137
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: