From patchwork Mon Dec 28 02:30:03 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 45051 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id F2B9AB7C7E for ; Thu, 11 Feb 2010 05:26:12 +1100 (EST) Received: from localhost ([127.0.0.1]:38409 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NfHG6-00035i-Oo for incoming@patchwork.ozlabs.org; Wed, 10 Feb 2010 13:25:54 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NfHEm-0002Cv-8h for qemu-devel@nongnu.org; Wed, 10 Feb 2010 13:24:32 -0500 Received: from [199.232.76.173] (port=43759 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NfHEl-0002CS-Qm for qemu-devel@nongnu.org; Wed, 10 Feb 2010 13:24:31 -0500 Received: from Debian-exim by monty-python.gnu.org with spam-scanned (Exim 4.60) (envelope-from ) id 1NfHEi-00009K-OY for qemu-devel@nongnu.org; Wed, 10 Feb 2010 13:24:31 -0500 Received: from are.twiddle.net ([75.149.56.221]:56628) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1NfHEi-00009A-0L for qemu-devel@nongnu.org; Wed, 10 Feb 2010 13:24:28 -0500 Received: by are.twiddle.net (Postfix, from userid 5000) id B2572C28; Wed, 10 Feb 2010 10:24:26 -0800 (PST) In-Reply-To: <4B72EE50.7000104@twiddle.net> References: <4B72EE50.7000104@twiddle.net> From: Richard Henderson Date: Sun, 27 Dec 2009 18:30:03 -0800 To: qemu-devel@nongnu.org Message-Id: <20100210182426.B2572C28@are.twiddle.net> X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Cc: riku.voipio@iki.fi Subject: [Qemu-devel] [PATCH] alpha-linux-user: Implement signals. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- Makefile.target | 3 +- hw/alpha_palcode.c | 81 +----------- linux-user/alpha/target_signal.h | 27 ++++ linux-user/main.c | 137 ++++++++++++++++---- linux-user/signal.c | 267 ++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 61 ++++++++- linux-user/syscall_defs.h | 23 +++- target-alpha/cpu.h | 4 +- target-alpha/translate.c | 3 +- 9 files changed, 489 insertions(+), 117 deletions(-) diff --git a/Makefile.target b/Makefile.target index f498574..f752210 100644 --- a/Makefile.target +++ b/Makefile.target @@ -51,7 +51,6 @@ libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o libobj-y += op_helper.o helper.o libobj-$(CONFIG_NEED_MMU) += mmu.o libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o -libobj-$(TARGET_ALPHA) += alpha_palcode.o # NOTE: the disassembler code is only needed for debugging libobj-y += disas.o @@ -311,6 +310,8 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o obj-s390x-y = s390-virtio-bus.o s390-virtio.o +obj-alpha-y = alpha_palcode.o + main.o vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS) diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c index 843bd14..c1220ad 100644 --- a/hw/alpha_palcode.c +++ b/hw/alpha_palcode.c @@ -21,11 +21,9 @@ #include #include -#include "qemu.h" #include "cpu.h" #include "exec-all.h" -#if !defined (CONFIG_USER_ONLY) /* Shared handlers */ static void pal_reset (CPUState *env); /* Console handlers */ @@ -997,12 +995,9 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, uint64_t physical, page_size, end; int prot, zbits, ret; -#if defined(CONFIG_USER_ONLY) - ret = 2; -#else - ret = virtual_to_physical(env, &physical, &zbits, &prot, - address, mmu_idx, rw); -#endif + ret = virtual_to_physical(env, &physical, &zbits, &prot, + address, mmu_idx, rw); + switch (ret) { case 0: /* No fault */ @@ -1050,73 +1045,3 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, return ret; } #endif - -#else /* !defined (CONFIG_USER_ONLY) */ -void pal_init (CPUState *env) -{ -} - -void call_pal (CPUState *env, int palcode) -{ - target_long ret; - - switch (palcode) { - case 0x80: - /* BPT */ - qemu_log("BPT\n"); - /* FIXME: Sends SIGTRAP, si_code=TRAP_BRKPT. */ - exit(1); - case 0x81: - /* BUGCHK */ - qemu_log("BUGCHK\n"); - /* FIXME: Sends SIGTRAP, si_code=SI_FAULT. */ - exit(1); - case 0x83: - /* CALLSYS */ - qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); - ret = do_syscall(env, env->ir[IR_V0], 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 (ret >= 0) { - env->ir[IR_A3] = 0; - env->ir[IR_V0] = ret; - } else { - env->ir[IR_A3] = 1; - env->ir[IR_V0] = -ret; - } - break; - case 0x86: - /* IMB */ - qemu_log("IMB\n"); - /* ??? 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 */ - qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); - /* Handled in the translator for usermode. */ - abort(); - case 0x9F: - /* WRUNIQUE */ - qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->ir[IR_A0]); - /* Handled in the translator for usermode. */ - abort(); - case 0xAA: - /* GENTRAP */ - qemu_log("GENTRAP: " TARGET_FMT_lx "\n", env->ir[IR_A0]); - /* FIXME: This is supposed to send a signal: - SIGFPE: - GEN_INTOVF, GEN_INTDIV, GEN_FLTOVF, GEN_FLTDIV, - GEN_FLTUND, GEN_FLTINV, GEN_FLTINE, GEN_ROPRAND - SIGTRAP: - others - with various settings of si_code. */ - exit(1); - default: - qemu_log("%s: unhandled palcode %02x\n", __func__, palcode); - exit(1); - } -} -#endif diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h index 2382ffd..cb86402 100644 --- a/linux-user/alpha/target_signal.h +++ b/linux-user/alpha/target_signal.h @@ -26,4 +26,31 @@ static inline abi_ulong get_sp_from_cpustate(CPUAlphaState *state) return state->ir[IR_SP]; } +/* From . */ +#define TARGET_GEN_INTOVF -1 /* integer overflow */ +#define TARGET_GEN_INTDIV -2 /* integer division by zero */ +#define TARGET_GEN_FLTOVF -3 /* fp overflow */ +#define TARGET_GEN_FLTDIV -4 /* fp division by zero */ +#define TARGET_GEN_FLTUND -5 /* fp underflow */ +#define TARGET_GEN_FLTINV -6 /* invalid fp operand */ +#define TARGET_GEN_FLTINE -7 /* inexact fp operand */ +#define TARGET_GEN_DECOVF -8 /* decimal overflow (for COBOL??) */ +#define TARGET_GEN_DECDIV -9 /* decimal division by zero */ +#define TARGET_GEN_DECINV -10 /* invalid decimal operand */ +#define TARGET_GEN_ROPRAND -11 /* reserved operand */ +#define TARGET_GEN_ASSERTERR -12 /* assertion error */ +#define TARGET_GEN_NULPTRERR -13 /* null pointer error */ +#define TARGET_GEN_STKOVF -14 /* stack overflow */ +#define TARGET_GEN_STRLENERR -15 /* string length error */ +#define TARGET_GEN_SUBSTRERR -16 /* substring error */ +#define TARGET_GEN_RANGERR -17 /* range error */ +#define TARGET_GEN_SUBRNG -18 +#define TARGET_GEN_SUBRNG1 -19 +#define TARGET_GEN_SUBRNG2 -20 +#define TARGET_GEN_SUBRNG3 -21 +#define TARGET_GEN_SUBRNG4 -22 +#define TARGET_GEN_SUBRNG5 -23 +#define TARGET_GEN_SUBRNG6 -24 +#define TARGET_GEN_SUBRNG7 -25 + #endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/main.c b/linux-user/main.c index a0d8ce7..632b154 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: diff --git a/linux-user/signal.c b/linux-user/signal.c index b0faf2e..e9abb1a 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -4410,6 +4410,273 @@ badframe: return 0; } +#elif defined(TARGET_ALPHA) + +struct target_sigcontext { + abi_long sc_onstack; + abi_long sc_mask; + abi_long sc_pc; + abi_long sc_ps; + abi_long sc_regs[32]; + abi_long sc_ownedfp; + abi_long sc_fpregs[32]; + abi_ulong sc_fpcr; + abi_ulong sc_fp_control; + abi_ulong sc_reserved1; + abi_ulong sc_reserved2; + abi_ulong sc_ssize; + abi_ulong sc_sbase; + abi_ulong sc_traparg_a0; + abi_ulong sc_traparg_a1; + abi_ulong sc_traparg_a2; + abi_ulong sc_fp_trap_pc; + abi_ulong sc_fp_trigger_sum; + abi_ulong sc_fp_trigger_inst; +}; + +struct target_ucontext { + abi_ulong uc_flags; + abi_ulong uc_link; + abi_ulong uc_osf_sigmask; + target_stack_t uc_stack; + struct target_sigcontext uc_mcontext; + target_sigset_t uc_sigmask; +}; + +struct target_sigframe { + struct target_sigcontext sc; + unsigned int retcode[3]; +}; + +struct target_rt_sigframe { + target_siginfo_t info; + struct target_ucontext uc; + unsigned int retcode[3]; +}; + +#define INSN_MOV_R30_R16 0x47fe0410 +#define INSN_LDI_R0 0x201f0000 +#define INSN_CALLSYS 0x00000083 + +static int setup_sigcontext(struct target_sigcontext *sc, CPUState *env, + abi_ulong frame_addr, target_sigset_t *set) +{ + int i, err = 0; + + err |= __put_user(on_sig_stack(frame_addr), &sc->sc_onstack); + err |= __put_user(set->sig[0], &sc->sc_mask); + err |= __put_user(env->pc, &sc->sc_pc); + err |= __put_user(8, &sc->sc_ps); + + for (i = 0; i < 31; ++i) { + err |= __put_user(env->ir[i], &sc->sc_regs[i]); + } + err |= __put_user(0, &sc->sc_regs[31]); + + for (i = 0; i < 31; ++i) { + err |= __put_user(env->fir[i], &sc->sc_fpregs[i]); + } + err |= __put_user(0, &sc->sc_fpregs[31]); + err |= __put_user(cpu_alpha_load_fpcr(env), &sc->sc_fpcr); + + err |= __put_user(0, &sc->sc_traparg_a0); /* FIXME */ + err |= __put_user(0, &sc->sc_traparg_a1); /* FIXME */ + err |= __put_user(0, &sc->sc_traparg_a2); /* FIXME */ + + return err; +} + +static int restore_sigcontext(CPUState *env, struct target_sigcontext *sc) +{ + uint64_t fpcr; + int i, err = 0; + + err |= __get_user(env->pc, &sc->sc_pc); + + for (i = 0; i < 31; ++i) { + err |= __get_user(env->ir[i], &sc->sc_regs[i]); + } + for (i = 0; i < 31; ++i) { + err |= __get_user(env->fir[i], &sc->sc_fpregs[i]); + } + + err |= __get_user(fpcr, &sc->sc_fpcr); + cpu_alpha_store_fpcr(env, fpcr); + + return err; +} + +static inline abi_ulong get_sigframe(struct target_sigaction *sa, + CPUState *env, unsigned long framesize) +{ + abi_ulong sp = env->ir[IR_SP]; + + /* This is the X/Open sanctioned signal stack switching. */ + if ((sa->sa_flags & TARGET_SA_ONSTACK) != 0 && !sas_ss_flags(sp)) { + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + } + return (sp - framesize) & -32; +} + +static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + abi_ulong frame_addr, r26; + struct target_sigframe *frame; + int err = 0; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + err |= setup_sigcontext(&frame->sc, env, frame_addr, set); + + if (ka->sa_restorer) { + r26 = ka->sa_restorer; + } else { + err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + err |= __put_user(INSN_LDI_R0 + TARGET_NR_sigreturn, + &frame->retcode[1]); + err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); + /* imb() */ + r26 = frame_addr; + } + + unlock_user_struct(frame, frame_addr, 1); + + if (err) { + give_sigsegv: + if (sig == TARGET_SIGSEGV) { + ka->_sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV); + } + + env->ir[IR_RA] = r26; + env->ir[IR_PV] = env->pc = ka->_sa_handler; + env->ir[IR_A0] = sig; + env->ir[IR_A1] = 0; + env->ir[IR_A2] = frame_addr + offsetof(struct target_sigframe, sc); + env->ir[IR_SP] = frame_addr; +} + +static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + abi_ulong frame_addr, r26; + struct target_rt_sigframe *frame; + int i, err = 0; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + err |= copy_siginfo_to_user(&frame->info, info); + + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); + err |= __put_user(target_sigaltstack_used.ss_sp, + &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(env->ir[IR_SP]), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(target_sigaltstack_used.ss_size, + &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, env, frame_addr, set); + for (i = 0; i < TARGET_NSIG_WORDS; ++i) { + err |= __put_user(set->sig[i], &frame->uc.uc_sigmask.sig[i]); + } + + if (ka->sa_restorer) { + r26 = ka->sa_restorer; + } else { + err |= __put_user(INSN_MOV_R30_R16, &frame->retcode[0]); + err |= __put_user(INSN_LDI_R0 + TARGET_NR_rt_sigreturn, + &frame->retcode[1]); + err |= __put_user(INSN_CALLSYS, &frame->retcode[2]); + /* imb(); */ + r26 = frame_addr; + } + + if (err) { + give_sigsegv: + if (sig == TARGET_SIGSEGV) { + ka->_sa_handler = TARGET_SIG_DFL; + } + force_sig(TARGET_SIGSEGV); + } + + env->ir[IR_RA] = r26; + env->ir[IR_PV] = env->pc = ka->_sa_handler; + env->ir[IR_A0] = sig; + env->ir[IR_A1] = frame_addr + offsetof(struct target_rt_sigframe, info); + env->ir[IR_A2] = frame_addr + offsetof(struct target_rt_sigframe, uc); + env->ir[IR_SP] = frame_addr; +} + +long do_sigreturn(CPUState *env) +{ + struct target_sigcontext *sc; + abi_ulong sc_addr = env->ir[IR_A0]; + target_sigset_t target_set; + sigset_t set; + + if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1)) { + goto badframe; + } + + target_sigemptyset(&target_set); + if (__get_user(target_set.sig[0], &sc->sc_mask)) { + goto badframe; + } + + target_to_host_sigset_internal(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + if (restore_sigcontext(env, sc)) { + goto badframe; + } + unlock_user_struct(sc, sc_addr, 0); + return env->ir[IR_V0]; + + badframe: + unlock_user_struct(sc, sc_addr, 0); + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + abi_ulong frame_addr = env->ir[IR_A0]; + struct target_rt_sigframe *frame; + sigset_t set; + + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + target_to_host_sigset(&set, &frame->uc.uc_sigmask); + sigprocmask(SIG_SETMASK, &set, NULL); + + if (restore_sigcontext(env, &frame->uc.uc_mcontext)) { + goto badframe; + } + if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe, + uc.uc_stack), + 0, env->ir[IR_SP]) == -EFAULT) { + goto badframe; + } + + unlock_user_struct(frame, frame_addr, 0); + return env->ir[IR_V0]; + + + badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); +} + #else static void setup_frame(int sig, struct target_sigaction *ka, diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 9fb493f..38eb35f 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4775,20 +4775,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #ifdef TARGET_NR_sigaction case TARGET_NR_sigaction: { -#if !defined(TARGET_MIPS) +#if defined(TARGET_ALPHA) + struct target_sigaction act, oact, *pact = 0; struct target_old_sigaction *old_act; - struct target_sigaction act, oact, *pact; if (arg2) { if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) goto efault; act._sa_handler = old_act->_sa_handler; target_siginitset(&act.sa_mask, old_act->sa_mask); act.sa_flags = old_act->sa_flags; - act.sa_restorer = old_act->sa_restorer; + act.sa_restorer = 0; unlock_user_struct(old_act, arg2, 0); pact = &act; - } else { - pact = NULL; } ret = get_errno(do_sigaction(arg1, pact, &oact)); if (!is_error(ret) && arg3) { @@ -4797,10 +4795,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, old_act->_sa_handler = oact._sa_handler; old_act->sa_mask = oact.sa_mask.sig[0]; old_act->sa_flags = oact.sa_flags; - old_act->sa_restorer = oact.sa_restorer; unlock_user_struct(old_act, arg3, 1); } -#else +#elif defined(TARGET_MIPS) struct target_sigaction act, oact, *pact, *old_act; if (arg2) { @@ -4828,12 +4825,61 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, old_act->sa_mask.sig[3] = 0; unlock_user_struct(old_act, arg3, 1); } +#else + struct target_old_sigaction *old_act; + struct target_sigaction act, oact, *pact; + if (arg2) { + if (!lock_user_struct(VERIFY_READ, old_act, arg2, 1)) + goto efault; + act._sa_handler = old_act->_sa_handler; + target_siginitset(&act.sa_mask, old_act->sa_mask); + act.sa_flags = old_act->sa_flags; + act.sa_restorer = old_act->sa_restorer; + unlock_user_struct(old_act, arg2, 0); + pact = &act; + } else { + pact = NULL; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && arg3) { + if (!lock_user_struct(VERIFY_WRITE, old_act, arg3, 0)) + goto efault; + old_act->_sa_handler = oact._sa_handler; + old_act->sa_mask = oact.sa_mask.sig[0]; + old_act->sa_flags = oact.sa_flags; + old_act->sa_restorer = oact.sa_restorer; + unlock_user_struct(old_act, arg3, 1); + } #endif } break; #endif case TARGET_NR_rt_sigaction: { +#if defined(TARGET_ALPHA) + struct target_sigaction act, oact, *pact = 0; + struct target_rt_sigaction *rt_act; + /* ??? arg4 == sizeof(sigset_t). */ + if (arg2) { + if (!lock_user_struct(VERIFY_READ, rt_act, arg2, 1)) + goto efault; + act._sa_handler = rt_act->_sa_handler; + act.sa_mask = rt_act->sa_mask; + act.sa_flags = rt_act->sa_flags; + act.sa_restorer = arg5; + unlock_user_struct(rt_act, arg2, 0); + pact = &act; + } + ret = get_errno(do_sigaction(arg1, pact, &oact)); + if (!is_error(ret) && arg3) { + if (!lock_user_struct(VERIFY_WRITE, rt_act, arg3, 0)) + goto efault; + rt_act->_sa_handler = oact._sa_handler; + rt_act->sa_mask = oact.sa_mask; + rt_act->sa_flags = oact.sa_flags; + unlock_user_struct(rt_act, arg3, 1); + } +#else struct target_sigaction *act; struct target_sigaction *oact; @@ -4855,6 +4901,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, unlock_user_struct(act, arg2, 0); if (oact) unlock_user_struct(oact, arg3, 1); +#endif } break; #ifdef TARGET_NR_sgetmask /* not on alpha */ diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 2d45753..63c2bc3 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -472,8 +472,28 @@ int do_sigaction(int sig, const struct target_sigaction *act, #endif -#if defined(TARGET_MIPS) +#if defined(TARGET_ALPHA) +struct target_old_sigaction { + abi_ulong _sa_handler; + abi_ulong sa_mask; + abi_ulong sa_flags; +}; + +struct target_rt_sigaction { + abi_ulong _sa_handler; + abi_ulong sa_flags; + target_sigset_t sa_mask; +}; +/* This is the struct used inside the kernel. The ka_restorer + field comes from the 5th argument to sys_rt_sigaction. */ +struct target_sigaction { + abi_ulong _sa_handler; + abi_ulong sa_flags; + target_sigset_t sa_mask; + abi_ulong sa_restorer; +}; +#elif defined(TARGET_MIPS) struct target_sigaction { uint32_t sa_flags; #if defined(TARGET_ABI_MIPSN32) @@ -483,7 +503,6 @@ struct target_sigaction { #endif target_sigset_t sa_mask; }; - #else struct target_old_sigaction { abi_ulong _sa_handler; diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index c0dff4b..f9b1a6d 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -487,11 +487,9 @@ uint64_t cpu_alpha_load_fpcr (CPUState *env); void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); -void pal_init (CPUState *env); #if !defined (CONFIG_USER_ONLY) +void pal_init (CPUState *env); void call_pal (CPUState *env); -#else -void call_pal (CPUState *env, int palcode); #endif static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 87813e7..36afcfc 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2750,8 +2750,9 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) env->ps |= 1 << 3; cpu_alpha_store_fpcr(env, (FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_UNFD | FPCR_INED | FPCR_DNOD)); -#endif +#else pal_init(env); +#endif /* Initialize IPR */ hwpcb = env->ipr[IPR_PCBB]; env->ipr[IPR_ASN] = 0;