patch-2.1.23 linux/arch/sparc/kernel/signal.c
Next file: linux/arch/sparc/kernel/smp.c
Previous file: linux/arch/sparc/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 456
- Date:
Sun Jan 26 12:07:07 1997
- Orig file:
v2.1.22/linux/arch/sparc/kernel/signal.c
- Orig date:
Mon Dec 30 15:39:03 1996
diff -u --recursive --new-file v2.1.22/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
@@ -1,9 +1,10 @@
-/* $Id: signal.c,v 1.66 1996/12/20 07:54:58 davem Exp $
+/* $Id: signal.c,v 1.71 1997/01/19 22:32:21 ecd Exp $
* linux/arch/sparc/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
#include <linux/sched.h>
@@ -14,6 +15,8 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
@@ -67,10 +70,11 @@
*/
struct new_signal_frame {
- struct sparc_stackf ss;
- __siginfo_t info;
- unsigned long __pad;
- unsigned long insns [2];
+ struct sparc_stackf ss;
+ __siginfo_t info;
+ __siginfo_fpu_t *fpu_save;
+ unsigned long insns [2] __attribute__ ((aligned (8)));
+ __siginfo_fpu_t fpu_state;
};
/* Align macros */
@@ -111,59 +115,86 @@
asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
{
+ lock_kernel();
_sigpause_common(set, regs);
+ unlock_kernel();
}
asmlinkage void do_sigsuspend (struct pt_regs *regs)
{
+ lock_kernel();
_sigpause_common(regs->u_regs[UREG_I0], regs);
+ unlock_kernel();
+}
+
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+ regs->psr &= ~PSR_EF;
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = 0;
+ regs->psr &= ~PSR_EF;
+ }
+#endif
+ current->used_math = 1;
+ current->flags &= ~PF_USEDFPU;
+
+ copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 64));
+ __get_user(current->tss.fsr, &fpu->si_fsr);
+ __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+ if (current->tss.fpqdepth != 0)
+ copy_from_user(¤t->tss.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
}
void do_new_sigreturn (struct pt_regs *regs)
{
struct new_signal_frame *sf;
- unsigned long up_psr;
+ unsigned long up_psr, pc, npc, mask;
+ lock_kernel();
sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
+
/* 1. Make sure we are not getting garbage from the user */
if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
do_exit (SIGSEGV);
- return;
+ goto out;
}
if (((uint) sf) & 3){
do_exit (SIGSEGV);
- return;
+ goto out;
}
- if ((sf->info.si_regs.pc | sf->info.si_regs.npc) & 3){
+
+ __get_user(pc, &sf->info.si_regs.pc);
+ __get_user(npc, &sf->info.si_regs.npc);
+
+ if ((pc | npc) & 3) {
do_exit (SIGSEGV);
- return;
+ goto out;
}
/* 2. Restore the state */
up_psr = regs->psr;
- memcpy (regs, &sf->info.si_regs, sizeof (struct pt_regs));
+ copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs));
- /* User can only change condition codes and FPU enabling in the %psr. */
- regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | (regs->psr & (PSR_ICC | PSR_EF));
-
- if (regs->psr & PSR_EF) {
- regs->psr &= ~(PSR_EF);
-#ifndef __SMP__
- if(current == last_task_used_math)
- last_task_used_math = 0;
-#endif
- current->used_math = 1;
- current->flags &= ~(PF_USEDFPU);
-
- /* Copy signal FPU state into thread struct FPU state. */
- memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0],
- (sizeof(unsigned long) * 64));
- current->tss.fsr = sf->info.si_fsr;
- if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
- memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0],
- ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
- }
- current->blocked = sf->info.si_mask & _BLOCKABLE;
+ /* User can only change condition codes and FPU enabling in %psr. */
+ regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
+ | (regs->psr & (PSR_ICC | PSR_EF));
+
+ if (sf->fpu_save)
+ restore_fpu_state(regs, sf->fpu_save);
+
+ __get_user(mask, &sf->info.si_mask);
+ current->blocked = (mask & _BLOCKABLE);
+out:
+ unlock_kernel();
}
asmlinkage void do_sigreturn(struct pt_regs *regs)
@@ -171,10 +202,11 @@
struct sigcontext *scptr;
unsigned long pc, npc, psr;
+ lock_kernel();
synchronize_user_stack();
if (current->tss.new_signal){
do_new_sigreturn (regs);
- return;
+ goto out;
}
scptr = (struct sigcontext *) regs->u_regs[UREG_I0];
/* Check sanity of the user arg. */
@@ -204,6 +236,8 @@
__get_user(psr, &scptr->sigc_psr);
regs->psr &= ~(PSR_ICC);
regs->psr |= (psr & PSR_ICC);
+out:
+ unlock_kernel();
}
/* Checks if the fp is valid */
@@ -287,77 +321,83 @@
regs->npc = (regs->pc + 4);
}
-/* To align the structure properly. */
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr,
+ ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr,
+ ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth);
+ last_task_used_math = 0;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0],
+ (sizeof(unsigned long) * 64));
+ __put_user(current->tss.fsr, &fpu->si_fsr);
+ __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+ if (current->tss.fpqdepth != 0)
+ copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ current->used_math = 0;
+}
+
static inline void
new_setup_frame(struct sigaction *sa, struct pt_regs *regs, int signo, unsigned long oldmask)
{
struct new_signal_frame *sf;
+ int sigframe_size;
/* 1. Make sure everything is clean */
synchronize_user_stack();
- sf = (struct new_signal_frame *) regs->u_regs[UREG_FP];
- sf = (struct new_signal_frame *) (((unsigned long) sf)-NF_ALIGNEDSZ);
-
- if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){
+
+ sigframe_size = NF_ALIGNEDSZ;
+ if (!current->used_math)
+ sigframe_size -= sizeof(__siginfo_fpu_t);
+
+ sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
+
+ if (invalid_frame_pointer (sf, sigframe_size)){
do_exit(SIGILL);
return;
}
if (current->tss.w_saved != 0){
- printk ("%s[%d]: Invalid user stack frame for signal delivery.\n",
- current->comm, current->pid);
+ printk ("%s [%d]: Invalid user stack frame for "
+ "signal delivery.\n", current->comm, current->pid);
do_exit (SIGILL);
return;
}
/* 2. Save the current process state */
- memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs));
-#ifdef __SMP__
- if(current->flags & PF_USEDFPU) {
- put_psr(get_psr() | PSR_EF);
- fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
- &sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
-
- /* Save a copy into thread struct as well. */
- memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0],
- (sizeof(unsigned long) * 64));
- current->tss.fsr = sf->info.si_fsr;
- if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
- memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0],
- ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
-
- regs->psr &= ~(PSR_EF);
- current->flags &= ~(PF_USEDFPU);
- }
-#else
- if(current == last_task_used_math) {
- put_psr(get_psr() | PSR_EF);
- fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
- &sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
-
- /* Save a copy into thread struct as well. */
- memcpy(¤t->tss.float_regs[0], &sf->info.si_float_regs[0],
- (sizeof(unsigned long) * 64));
- current->tss.fsr = sf->info.si_fsr;
- if((current->tss.fpqdepth = sf->info.si_fpqdepth) != 0)
- memcpy(¤t->tss.fpqueue[0], &sf->info.si_fpqueue[0],
- ((sizeof(unsigned long) + (sizeof(unsigned long *))) * 16));
+ copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
- last_task_used_math = NULL;
- regs->psr &= ~(PSR_EF);
+ if (current->used_math) {
+ save_fpu_state(regs, &sf->fpu_state);
+ sf->fpu_save = &sf->fpu_state;
+ } else {
+ sf->fpu_save = NULL;
}
-#endif
- /* This new thread of control has not used the FPU. */
- current->used_math = 0;
-
- sf->info.si_mask = oldmask;
- memcpy (sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window));
+ __put_user(oldmask, &sf->info.si_mask);
+ copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+ sizeof (struct reg_window));
/* 3. return to kernel instructions */
- sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn,%g1 */
- sf->insns [1] = 0x91d02010; /* t 0x10 */
+ __put_user(0x821020d8, &sf->insns [0]); /* mov __NR_sigreturn, %g1 */
+ __put_user(0x91d02010, &sf->insns [1]); /* t 0x10 */
/* 4. signal handler back-trampoline and parameters */
regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -373,6 +413,7 @@
flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
}
+
/* Setup a Solaris stack frame */
static inline void
setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
@@ -491,21 +532,23 @@
{
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
+ int ret = -EFAULT;
+ lock_kernel();
synchronize_user_stack();
if (current->tss.w_saved){
printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
do_exit (SIGSEGV);
}
if(clear_user(uc, sizeof (*uc)))
- return -EFAULT;
+ goto out;
/* Setup convenience variables */
mc = &uc->mcontext;
gr = &mc->greg;
/* We only have < 32 signals, fill the first slot only */
- __put_user(current->sig->action->sa_mask, &uc->sigmask.sigbits [0]);
+ __put_user(current->blocked, &uc->sigmask.sigbits [0]);
/* Store registers */
__put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
@@ -525,7 +568,10 @@
/* The register file is not saved
* we have already stuffed all of it with sync_user_stack
*/
- return 0;
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
}
@@ -535,7 +581,9 @@
struct thread_struct *tp = ¤t->tss;
svr4_gregset_t *gr;
unsigned long pc, npc, psr;
+ int ret = -EINTR;
+ lock_kernel();
/* Fixme: restore windows, or is this already taken care of in
* svr4_setup_frame when sync_user_windows is done?
*/
@@ -544,15 +592,18 @@
if (tp->w_saved){
printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved);
do_exit(SIGSEGV);
+ goto out;
}
if (((uint) c) & 3){
printk ("Unaligned structure passed\n");
do_exit (SIGSEGV);
+ goto out;
}
if(!__access_ok((unsigned long)c, sizeof(*c))) {
/* Miguel, add nice debugging msg _here_. ;-) */
do_exit(SIGSEGV);
+ goto out;
}
/* Check for valid PC and nPC */
@@ -562,6 +613,7 @@
if((pc | npc) & 3) {
printk ("setcontext, PC or nPC were bogus\n");
do_exit (SIGSEGV);
+ goto out;
}
/* Retrieve information from passed ucontext */
/* note that nPC is ored a 1, this is used to inform entry.S */
@@ -578,8 +630,9 @@
/* Restore g[1..7] and o[0..7] registers */
copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
-
- return -EINTR;
+out:
+ unlock_kernel();
+ return ret;
}
static inline void handle_signal(unsigned long signr, struct sigaction *sa,
@@ -630,7 +683,9 @@
unsigned long signr, mask = ~current->blocked;
struct sigaction *sa;
int svr4_signal = current->personality == PER_SVR4;
+ int ret;
+ lock_kernel();
while ((signr = current->signal & mask) != 0) {
signr = ffz(~signr);
clear_bit(signr, ¤t->signal);
@@ -701,7 +756,8 @@
if(restart_syscall)
syscall_restart(orig_i0, regs, sa);
handle_signal(signr, sa, oldmask, regs, svr4_signal);
- return 1;
+ ret = 1;
+ goto out;
}
if(restart_syscall &&
(regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
@@ -712,22 +768,31 @@
regs->pc -= 4;
regs->npc -= 4;
}
- return 0;
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
}
asmlinkage int
sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr)
{
+ int ret = -EFAULT;
+
+ lock_kernel();
/* First see if old state is wanted. */
if(ossptr) {
if(copy_to_user(ossptr, ¤t->tss.sstk_info, sizeof(struct sigstack)))
- return -EFAULT;
+ goto out;
}
/* Now see if we want to update the new state. */
if(ssptr) {
if(copy_from_user(¤t->tss.sstk_info, ssptr, sizeof(struct sigstack)))
- return -EFAULT;
+ goto out;
}
- return 0;
+ ret = 0;
+out:
+ unlock_kernel();
+ return ret;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov