aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-user/mips/signal.c382
-rw-r--r--linux-user/mips/target_signal.h9
-rw-r--r--linux-user/mips64/signal.c2
-rw-r--r--linux-user/mips64/target_signal.h4
-rw-r--r--linux-user/signal.c381
5 files changed, 396 insertions, 382 deletions
diff --git a/linux-user/mips/signal.c b/linux-user/mips/signal.c
index 02ca338b6c..adeb5a4241 100644
--- a/linux-user/mips/signal.c
+++ b/linux-user/mips/signal.c
@@ -16,3 +16,385 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+# if defined(TARGET_ABI_MIPSO32)
+struct target_sigcontext {
+ uint32_t sc_regmask; /* Unused */
+ uint32_t sc_status;
+ uint64_t sc_pc;
+ uint64_t sc_regs[32];
+ uint64_t sc_fpregs[32];
+ uint32_t sc_ownedfp; /* Unused */
+ uint32_t sc_fpc_csr;
+ uint32_t sc_fpc_eir; /* Unused */
+ uint32_t sc_used_math;
+ uint32_t sc_dsp; /* dsp status, was sc_ssflags */
+ uint32_t pad0;
+ uint64_t sc_mdhi;
+ uint64_t sc_mdlo;
+ target_ulong sc_hi1; /* Was sc_cause */
+ target_ulong sc_lo1; /* Was sc_badvaddr */
+ target_ulong sc_hi2; /* Was sc_sigset[4] */
+ target_ulong sc_lo2;
+ target_ulong sc_hi3;
+ target_ulong sc_lo3;
+};
+# else /* N32 || N64 */
+struct target_sigcontext {
+ uint64_t sc_regs[32];
+ uint64_t sc_fpregs[32];
+ uint64_t sc_mdhi;
+ uint64_t sc_hi1;
+ uint64_t sc_hi2;
+ uint64_t sc_hi3;
+ uint64_t sc_mdlo;
+ uint64_t sc_lo1;
+ uint64_t sc_lo2;
+ uint64_t sc_lo3;
+ uint64_t sc_pc;
+ uint32_t sc_fpc_csr;
+ uint32_t sc_used_math;
+ uint32_t sc_dsp;
+ uint32_t sc_reserved;
+};
+# endif /* O32 */
+
+struct sigframe {
+ uint32_t sf_ass[4]; /* argument save space for o32 */
+ uint32_t sf_code[2]; /* signal trampoline */
+ struct target_sigcontext sf_sc;
+ target_sigset_t sf_mask;
+};
+
+struct target_ucontext {
+ target_ulong tuc_flags;
+ target_ulong tuc_link;
+ target_stack_t tuc_stack;
+ target_ulong pad0;
+ struct target_sigcontext tuc_mcontext;
+ target_sigset_t tuc_sigmask;
+};
+
+struct target_rt_sigframe {
+ uint32_t rs_ass[4]; /* argument save space for o32 */
+ uint32_t rs_code[2]; /* signal trampoline */
+ struct target_siginfo rs_info;
+ struct target_ucontext rs_uc;
+};
+
+/* Install trampoline to jump back from signal handler */
+static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
+{
+ int err = 0;
+
+ /*
+ * Set up the return code ...
+ *
+ * li v0, __NR__foo_sigreturn
+ * syscall
+ */
+
+ __put_user(0x24020000 + syscall, tramp + 0);
+ __put_user(0x0000000c , tramp + 1);
+ return err;
+}
+
+static inline void setup_sigcontext(CPUMIPSState *regs,
+ struct target_sigcontext *sc)
+{
+ int i;
+
+ __put_user(exception_resume_pc(regs), &sc->sc_pc);
+ regs->hflags &= ~MIPS_HFLAG_BMASK;
+
+ __put_user(0, &sc->sc_regs[0]);
+ for (i = 1; i < 32; ++i) {
+ __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
+ }
+
+ __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+ __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
+
+ /* Rather than checking for dsp existence, always copy. The storage
+ would just be garbage otherwise. */
+ __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
+ __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
+ __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
+ __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
+ __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
+ __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
+ {
+ uint32_t dsp = cpu_rddsp(0x3ff, regs);
+ __put_user(dsp, &sc->sc_dsp);
+ }
+
+ __put_user(1, &sc->sc_used_math);
+
+ for (i = 0; i < 32; ++i) {
+ __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
+ }
+}
+
+static inline void
+restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
+{
+ int i;
+
+ __get_user(regs->CP0_EPC, &sc->sc_pc);
+
+ __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
+ __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
+
+ for (i = 1; i < 32; ++i) {
+ __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
+ }
+
+ __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
+ __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
+ __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
+ __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
+ __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
+ __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
+ {
+ uint32_t dsp;
+ __get_user(dsp, &sc->sc_dsp);
+ cpu_wrdsp(dsp, 0x3ff, regs);
+ }
+
+ for (i = 0; i < 32; ++i) {
+ __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
+ }
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline abi_ulong
+get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = regs->active_tc.gpr[29];
+
+ /*
+ * FPU emulator may have its own trampoline active just
+ * above the user stack, 16-bytes before the next lowest
+ * 16 byte boundary. Try to avoid trashing it.
+ */
+ sp -= 32;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
+ sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+ }
+
+ return (sp - frame_size) & ~7;
+}
+
+static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
+{
+ if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
+ env->hflags &= ~MIPS_HFLAG_M16;
+ env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
+ env->active_tc.PC &= ~(target_ulong) 1;
+ }
+}
+
+# if defined(TARGET_ABI_MIPSO32)
+/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
+void setup_frame(int sig, struct target_sigaction * ka,
+ target_sigset_t *set, CPUMIPSState *regs)
+{
+ struct sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, regs, sizeof(*frame));
+ trace_user_setup_frame(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
+
+ setup_sigcontext(regs, &frame->sf_sc);
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->sf_mask.sig[i]);
+ }
+
+ /*
+ * Arguments to signal handler:
+ *
+ * a0 = signal number
+ * a1 = 0 (should be cause)
+ * a2 = pointer to struct sigcontext
+ *
+ * $25 and PC point to the signal handler, $29 points to the
+ * struct sigframe.
+ */
+ regs->active_tc.gpr[ 4] = sig;
+ regs->active_tc.gpr[ 5] = 0;
+ regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
+ regs->active_tc.gpr[29] = frame_addr;
+ regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
+ /* The original kernel code sets CP0_EPC to the handler
+ * since it returns to userland using eret
+ * we cannot do this here, and we must set PC directly */
+ regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
+ mips_set_hflags_isa_mode_from_pc(regs);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ force_sigsegv(sig);
+}
+
+long do_sigreturn(CPUMIPSState *regs)
+{
+ struct sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+ target_sigset_t target_set;
+ int i;
+
+ frame_addr = regs->active_tc.gpr[29];
+ trace_user_do_sigreturn(regs, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
+ goto badframe;
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
+ }
+
+ target_to_host_sigset_internal(&blocked, &target_set);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(regs, &frame->sf_sc);
+
+#if 0
+ /*
+ * Don't let your children do this ...
+ */
+ __asm__ __volatile__(
+ "move\t$29, %0\n\t"
+ "j\tsyscall_exit"
+ :/* no outputs */
+ :"r" (&regs));
+ /* Unreached */
+#endif
+
+ regs->active_tc.PC = regs->CP0_EPC;
+ mips_set_hflags_isa_mode_from_pc(regs);
+ /* I am not sure this is right, but it seems to work
+ * maybe a problem with nested signals ? */
+ regs->CP0_EPC = 0;
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
+# endif /* O32 */
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUMIPSState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ int i;
+
+ frame_addr = get_sigframe(ka, env, sizeof(*frame));
+ trace_user_setup_rt_frame(env, frame_addr);
+ if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
+ goto give_sigsegv;
+ }
+
+ install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
+
+ tswap_siginfo(&frame->rs_info, info);
+
+ __put_user(0, &frame->rs_uc.tuc_flags);
+ __put_user(0, &frame->rs_uc.tuc_link);
+ __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
+ __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
+ __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
+ &frame->rs_uc.tuc_stack.ss_flags);
+
+ setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+ for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
+ }
+
+ /*
+ * Arguments to signal handler:
+ *
+ * a0 = signal number
+ * a1 = pointer to siginfo_t
+ * a2 = pointer to ucontext_t
+ *
+ * $25 and PC point to the signal handler, $29 points to the
+ * struct sigframe.
+ */
+ env->active_tc.gpr[ 4] = sig;
+ env->active_tc.gpr[ 5] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_info);
+ env->active_tc.gpr[ 6] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_uc);
+ env->active_tc.gpr[29] = frame_addr;
+ env->active_tc.gpr[31] = frame_addr
+ + offsetof(struct target_rt_sigframe, rs_code);
+ /* The original kernel code sets CP0_EPC to the handler
+ * since it returns to userland using eret
+ * we cannot do this here, and we must set PC directly */
+ env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
+ mips_set_hflags_isa_mode_from_pc(env);
+ unlock_user_struct(frame, frame_addr, 1);
+ return;
+
+give_sigsegv:
+ unlock_user_struct(frame, frame_addr, 1);
+ force_sigsegv(sig);
+}
+
+long do_rt_sigreturn(CPUMIPSState *env)
+{
+ struct target_rt_sigframe *frame;
+ abi_ulong frame_addr;
+ sigset_t blocked;
+
+ frame_addr = env->active_tc.gpr[29];
+ trace_user_do_rt_sigreturn(env, frame_addr);
+ if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
+ goto badframe;
+ }
+
+ target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
+ set_sigmask(&blocked);
+
+ restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
+
+ if (do_sigaltstack(frame_addr +
+ offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
+ 0, get_sp_from_cpustate(env)) == -EFAULT)
+ goto badframe;
+
+ env->active_tc.PC = env->CP0_EPC;
+ mips_set_hflags_isa_mode_from_pc(env);
+ /* I am not sure this is right, but it seems to work
+ * maybe a problem with nested signals ? */
+ env->CP0_EPC = 0;
+ return -TARGET_QEMU_ESIGRETURN;
+
+badframe:
+ force_sig(TARGET_SIGSEGV);
+ return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
index 8dd27cef35..22ab3e4a94 100644
--- a/linux-user/mips/target_signal.h
+++ b/linux-user/mips/target_signal.h
@@ -26,5 +26,12 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
return state->active_tc.gpr[29];
}
-
+# if defined(TARGET_ABI_MIPSO32)
+/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
+void setup_frame(int sig, struct target_sigaction * ka,
+ target_sigset_t *set, CPUMIPSState *regs);
+#endif
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUMIPSState *env);
#endif /* MIPS_TARGET_SIGNAL_H */
diff --git a/linux-user/mips64/signal.c b/linux-user/mips64/signal.c
index 02ca338b6c..4ed0ed90b3 100644
--- a/linux-user/mips64/signal.c
+++ b/linux-user/mips64/signal.c
@@ -16,3 +16,5 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#define MIPS_TARGET_SIGNAL_H /* to only include mips64/target_signal.h */
+#include "../mips/signal.c"
diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h
index 67ef5a18f4..70dfe40978 100644
--- a/linux-user/mips64/target_signal.h
+++ b/linux-user/mips64/target_signal.h
@@ -26,5 +26,7 @@ static inline abi_ulong get_sp_from_cpustate(CPUMIPSState *state)
return state->active_tc.gpr[29];
}
-
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+ target_siginfo_t *info,
+ target_sigset_t *set, CPUMIPSState *env);
#endif /* MIPS64_TARGET_SIGNAL_H */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 27c3769c5e..18acf6a4b0 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -803,386 +803,7 @@ int do_sigaction(int sig, const struct target_sigaction *act,
return ret;
}
-#if defined(TARGET_MIPS) || defined(TARGET_MIPS64)
-
-# if defined(TARGET_ABI_MIPSO32)
-struct target_sigcontext {
- uint32_t sc_regmask; /* Unused */
- uint32_t sc_status;
- uint64_t sc_pc;
- uint64_t sc_regs[32];
- uint64_t sc_fpregs[32];
- uint32_t sc_ownedfp; /* Unused */
- uint32_t sc_fpc_csr;
- uint32_t sc_fpc_eir; /* Unused */
- uint32_t sc_used_math;
- uint32_t sc_dsp; /* dsp status, was sc_ssflags */
- uint32_t pad0;
- uint64_t sc_mdhi;
- uint64_t sc_mdlo;
- target_ulong sc_hi1; /* Was sc_cause */
- target_ulong sc_lo1; /* Was sc_badvaddr */
- target_ulong sc_hi2; /* Was sc_sigset[4] */
- target_ulong sc_lo2;
- target_ulong sc_hi3;
- target_ulong sc_lo3;
-};
-# else /* N32 || N64 */
-struct target_sigcontext {
- uint64_t sc_regs[32];
- uint64_t sc_fpregs[32];
- uint64_t sc_mdhi;
- uint64_t sc_hi1;
- uint64_t sc_hi2;
- uint64_t sc_hi3;
- uint64_t sc_mdlo;
- uint64_t sc_lo1;
- uint64_t sc_lo2;
- uint64_t sc_lo3;
- uint64_t sc_pc;
- uint32_t sc_fpc_csr;
- uint32_t sc_used_math;
- uint32_t sc_dsp;
- uint32_t sc_reserved;
-};
-# endif /* O32 */
-
-struct sigframe {
- uint32_t sf_ass[4]; /* argument save space for o32 */
- uint32_t sf_code[2]; /* signal trampoline */
- struct target_sigcontext sf_sc;
- target_sigset_t sf_mask;
-};
-
-struct target_ucontext {
- target_ulong tuc_flags;
- target_ulong tuc_link;
- target_stack_t tuc_stack;
- target_ulong pad0;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask;
-};
-
-struct target_rt_sigframe {
- uint32_t rs_ass[4]; /* argument save space for o32 */
- uint32_t rs_code[2]; /* signal trampoline */
- struct target_siginfo rs_info;
- struct target_ucontext rs_uc;
-};
-
-/* Install trampoline to jump back from signal handler */
-static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
-{
- int err = 0;
-
- /*
- * Set up the return code ...
- *
- * li v0, __NR__foo_sigreturn
- * syscall
- */
-
- __put_user(0x24020000 + syscall, tramp + 0);
- __put_user(0x0000000c , tramp + 1);
- return err;
-}
-
-static inline void setup_sigcontext(CPUMIPSState *regs,
- struct target_sigcontext *sc)
-{
- int i;
-
- __put_user(exception_resume_pc(regs), &sc->sc_pc);
- regs->hflags &= ~MIPS_HFLAG_BMASK;
-
- __put_user(0, &sc->sc_regs[0]);
- for (i = 1; i < 32; ++i) {
- __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
- }
-
- __put_user(regs->active_tc.HI[0], &sc->sc_mdhi);
- __put_user(regs->active_tc.LO[0], &sc->sc_mdlo);
-
- /* Rather than checking for dsp existence, always copy. The storage
- would just be garbage otherwise. */
- __put_user(regs->active_tc.HI[1], &sc->sc_hi1);
- __put_user(regs->active_tc.HI[2], &sc->sc_hi2);
- __put_user(regs->active_tc.HI[3], &sc->sc_hi3);
- __put_user(regs->active_tc.LO[1], &sc->sc_lo1);
- __put_user(regs->active_tc.LO[2], &sc->sc_lo2);
- __put_user(regs->active_tc.LO[3], &sc->sc_lo3);
- {
- uint32_t dsp = cpu_rddsp(0x3ff, regs);
- __put_user(dsp, &sc->sc_dsp);
- }
-
- __put_user(1, &sc->sc_used_math);
-
- for (i = 0; i < 32; ++i) {
- __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
- }
-}
-
-static inline void
-restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
-{
- int i;
-
- __get_user(regs->CP0_EPC, &sc->sc_pc);
-
- __get_user(regs->active_tc.HI[0], &sc->sc_mdhi);
- __get_user(regs->active_tc.LO[0], &sc->sc_mdlo);
-
- for (i = 1; i < 32; ++i) {
- __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]);
- }
-
- __get_user(regs->active_tc.HI[1], &sc->sc_hi1);
- __get_user(regs->active_tc.HI[2], &sc->sc_hi2);
- __get_user(regs->active_tc.HI[3], &sc->sc_hi3);
- __get_user(regs->active_tc.LO[1], &sc->sc_lo1);
- __get_user(regs->active_tc.LO[2], &sc->sc_lo2);
- __get_user(regs->active_tc.LO[3], &sc->sc_lo3);
- {
- uint32_t dsp;
- __get_user(dsp, &sc->sc_dsp);
- cpu_wrdsp(dsp, 0x3ff, regs);
- }
-
- for (i = 0; i < 32; ++i) {
- __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
- }
-}
-
-/*
- * Determine which stack to use..
- */
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUMIPSState *regs, size_t frame_size)
-{
- unsigned long sp;
-
- /* Default to using normal stack */
- sp = regs->active_tc.gpr[29];
-
- /*
- * FPU emulator may have its own trampoline active just
- * above the user stack, 16-bytes before the next lowest
- * 16 byte boundary. Try to avoid trashing it.
- */
- sp -= 32;
-
- /* This is the X/Open sanctioned signal stack switching. */
- if ((ka->sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
- sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
- }
-
- return (sp - frame_size) & ~7;
-}
-
-static void mips_set_hflags_isa_mode_from_pc(CPUMIPSState *env)
-{
- if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
- env->hflags &= ~MIPS_HFLAG_M16;
- env->hflags |= (env->active_tc.PC & 1) << MIPS_HFLAG_M16_SHIFT;
- env->active_tc.PC &= ~(target_ulong) 1;
- }
-}
-
-# if defined(TARGET_ABI_MIPSO32)
-/* compare linux/arch/mips/kernel/signal.c:setup_frame() */
-static void setup_frame(int sig, struct target_sigaction * ka,
- target_sigset_t *set, CPUMIPSState *regs)
-{
- struct sigframe *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(ka, regs, sizeof(*frame));
- trace_user_setup_frame(regs, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
-
- setup_sigcontext(regs, &frame->sf_sc);
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->sf_mask.sig[i]);
- }
-
- /*
- * Arguments to signal handler:
- *
- * a0 = signal number
- * a1 = 0 (should be cause)
- * a2 = pointer to struct sigcontext
- *
- * $25 and PC point to the signal handler, $29 points to the
- * struct sigframe.
- */
- regs->active_tc.gpr[ 4] = sig;
- regs->active_tc.gpr[ 5] = 0;
- regs->active_tc.gpr[ 6] = frame_addr + offsetof(struct sigframe, sf_sc);
- regs->active_tc.gpr[29] = frame_addr;
- regs->active_tc.gpr[31] = frame_addr + offsetof(struct sigframe, sf_code);
- /* The original kernel code sets CP0_EPC to the handler
- * since it returns to userland using eret
- * we cannot do this here, and we must set PC directly */
- regs->active_tc.PC = regs->active_tc.gpr[25] = ka->_sa_handler;
- mips_set_hflags_isa_mode_from_pc(regs);
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- force_sigsegv(sig);
-}
-
-long do_sigreturn(CPUMIPSState *regs)
-{
- struct sigframe *frame;
- abi_ulong frame_addr;
- sigset_t blocked;
- target_sigset_t target_set;
- int i;
-
- frame_addr = regs->active_tc.gpr[29];
- trace_user_do_sigreturn(regs, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1))
- goto badframe;
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __get_user(target_set.sig[i], &frame->sf_mask.sig[i]);
- }
-
- target_to_host_sigset_internal(&blocked, &target_set);
- set_sigmask(&blocked);
-
- restore_sigcontext(regs, &frame->sf_sc);
-
-#if 0
- /*
- * Don't let your children do this ...
- */
- __asm__ __volatile__(
- "move\t$29, %0\n\t"
- "j\tsyscall_exit"
- :/* no outputs */
- :"r" (&regs));
- /* Unreached */
-#endif
-
- regs->active_tc.PC = regs->CP0_EPC;
- mips_set_hflags_isa_mode_from_pc(regs);
- /* I am not sure this is right, but it seems to work
- * maybe a problem with nested signals ? */
- regs->CP0_EPC = 0;
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-# endif /* O32 */
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUMIPSState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- int i;
-
- frame_addr = get_sigframe(ka, env, sizeof(*frame));
- trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
- goto give_sigsegv;
- }
-
- install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn);
-
- tswap_siginfo(&frame->rs_info, info);
-
- __put_user(0, &frame->rs_uc.tuc_flags);
- __put_user(0, &frame->rs_uc.tuc_link);
- __put_user(target_sigaltstack_used.ss_sp, &frame->rs_uc.tuc_stack.ss_sp);
- __put_user(target_sigaltstack_used.ss_size, &frame->rs_uc.tuc_stack.ss_size);
- __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
- &frame->rs_uc.tuc_stack.ss_flags);
-
- setup_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]);
- }
-
- /*
- * Arguments to signal handler:
- *
- * a0 = signal number
- * a1 = pointer to siginfo_t
- * a2 = pointer to ucontext_t
- *
- * $25 and PC point to the signal handler, $29 points to the
- * struct sigframe.
- */
- env->active_tc.gpr[ 4] = sig;
- env->active_tc.gpr[ 5] = frame_addr
- + offsetof(struct target_rt_sigframe, rs_info);
- env->active_tc.gpr[ 6] = frame_addr
- + offsetof(struct target_rt_sigframe, rs_uc);
- env->active_tc.gpr[29] = frame_addr;
- env->active_tc.gpr[31] = frame_addr
- + offsetof(struct target_rt_sigframe, rs_code);
- /* The original kernel code sets CP0_EPC to the handler
- * since it returns to userland using eret
- * we cannot do this here, and we must set PC directly */
- env->active_tc.PC = env->active_tc.gpr[25] = ka->_sa_handler;
- mips_set_hflags_isa_mode_from_pc(env);
- unlock_user_struct(frame, frame_addr, 1);
- return;
-
-give_sigsegv:
- unlock_user_struct(frame, frame_addr, 1);
- force_sigsegv(sig);
-}
-
-long do_rt_sigreturn(CPUMIPSState *env)
-{
- struct target_rt_sigframe *frame;
- abi_ulong frame_addr;
- sigset_t blocked;
-
- frame_addr = env->active_tc.gpr[29];
- trace_user_do_rt_sigreturn(env, frame_addr);
- if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
- goto badframe;
- }
-
- target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask);
- set_sigmask(&blocked);
-
- restore_sigcontext(env, &frame->rs_uc.tuc_mcontext);
-
- if (do_sigaltstack(frame_addr +
- offsetof(struct target_rt_sigframe, rs_uc.tuc_stack),
- 0, get_sp_from_cpustate(env)) == -EFAULT)
- goto badframe;
-
- env->active_tc.PC = env->CP0_EPC;
- mips_set_hflags_isa_mode_from_pc(env);
- /* I am not sure this is right, but it seems to work
- * maybe a problem with nested signals ? */
- env->CP0_EPC = 0;
- return -TARGET_QEMU_ESIGRETURN;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return -TARGET_QEMU_ESIGRETURN;
-}
-
-#elif defined(TARGET_PPC)
+#if defined(TARGET_PPC)
/* Size of dummy stack frame allocated when calling signal handler.
See arch/powerpc/include/asm/ptrace.h. */