* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/cache.h>
+#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/compat.h>
+#include <linux/bitops.h>
#include <asm/asm.h>
-#include <asm/bitops.h>
+#include <asm/cacheflush.h>
#include <asm/sim.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
#include <asm/system.h>
#include <asm/fpu.h>
+#include <asm/cpu-features.h>
+#include <asm/war.h>
+
+#include "signal-common.h"
/*
- * Including <asm/unistd.h would give use the 64-bit syscall numbers ...
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
*/
#define __NR_N32_rt_sigreturn 6211
#define __NR_N32_restart_syscall 6214
+#define DEBUG_SIG 0
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/* IRIX compatible stack_t */
struct rt_sigframe_n32 {
u32 rs_ass[4]; /* argument save space for o32 */
+#if ICACHE_REFILLS_WORKAROUND_WAR
+ u32 rs_pad[2];
+#else
u32 rs_code[2]; /* signal trampoline */
+#endif
struct siginfo rs_info;
struct ucontextn32 rs_uc;
+#if ICACHE_REFILLS_WORKAROUND_WAR
+ u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
+#endif
};
-extern asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
-extern int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
+extern void sigset_from_compat (sigset_t *set, compat_sigset_t *compat);
+
+save_static_function(sysn32_rt_sigsuspend);
+__attribute_used__ noinline static int
+_sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
+{
+ compat_sigset_t __user *unewset, uset;
+ size_t sigsetsize;
+ sigset_t newset;
+
+ /* XXX Don't preclude handling different sized sigset_t's. */
+ sigsetsize = regs.regs[5];
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ unewset = (compat_sigset_t __user *) regs.regs[4];
+ if (copy_from_user(&uset, unewset, sizeof(uset)))
+ return -EFAULT;
+ sigset_from_compat (&newset, &uset);
+ sigdelsetmask(&newset, ~_BLOCKABLE);
+
+ spin_lock_irq(¤t->sighand->siglock);
+ current->saved_sigmask = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
+}
-asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
+save_static_function(sysn32_rt_sigreturn);
+__attribute_used__ noinline static void
+_sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
{
- struct rt_sigframe_n32 *frame;
+ struct rt_sigframe_n32 __user *frame;
sigset_t set;
stack_t st;
s32 sp;
- frame = (struct rt_sigframe_n32 *) regs.regs[29];
+ frame = (struct rt_sigframe_n32 __user *) regs.regs[29];
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
/* The ucontext contains a stack32_t, so we must convert! */
if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
goto badframe;
- st.ss_size = (long) sp;
+ st.ss_sp = (void *)(long) sp;
if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
goto badframe;
if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs.regs[29]);
+ do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]);
/*
* Don't let your children do this ...
force_sig(SIGSEGV, current);
}
-/*
- * Determine which stack to use..
- */
-static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
- size_t frame_size)
-{
- unsigned long sp;
-
- /* Default to using normal stack */
- sp = regs->regs[29];
-
- /*
- * FPU emulator may have it's 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.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
- sp = current->sas_ss_sp + current->sas_ss_size;
-
- return (void *)((sp - frame_size) & ALMASK);
-}
-
-void setup_rt_frame_n32(struct k_sigaction * ka,
+int setup_rt_frame_n32(struct k_sigaction * ka,
struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
{
- struct rt_sigframe_n32 *frame;
+ struct rt_sigframe_n32 __user *frame;
int err = 0;
s32 sp;
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto give_sigsegv;
- /*
- * Set up the return code ...
- *
- * li v0, __NR_rt_sigreturn
- * syscall
- */
- err |= __put_user(0x24020000 + __NR_N32_rt_sigreturn, frame->rs_code + 0);
- err |= __put_user(0x0000000c , frame->rs_code + 1);
- flush_cache_sigtramp((unsigned long) frame->rs_code);
+ install_sigtramp(frame->rs_code, __NR_N32_rt_sigreturn);
/* Create siginfo. */
err |= copy_siginfo_to_user(&frame->rs_info, info);
current->comm, current->pid,
frame, regs->cp0_epc, regs->regs[31]);
#endif
- return;
+ return 0;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
+ return -EFAULT;
}