patch-2.1.23 linux/arch/sparc64/kernel/signal32.c
Next file: linux/arch/sparc64/kernel/ttable.S
Previous file: linux/arch/sparc64/kernel/initobj.S
Back to the patch index
Back to the overall index
- Lines: 237
- Date:
Sun Jan 26 12:07:09 1997
- Orig file:
v2.1.22/linux/arch/sparc64/kernel/signal32.c
- Orig date:
Tue Dec 31 21:41:00 1996
diff -u --recursive --new-file v2.1.22/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
@@ -1,9 +1,10 @@
-/* $Id: signal32.c,v 1.1 1996/12/26 10:16:41 davem Exp $
+/* $Id: signal32.c,v 1.3 1997/01/19 22:32:30 ecd Exp $
* arch/sparc64/kernel/signal32.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>
@@ -67,10 +68,11 @@
*/
struct new_signal_frame32 {
- struct sparc_stackf_32 ss;
- __siginfo32_t info;
- unsigned int __pad;
- unsigned int insns [2];
+ struct sparc_stackf_32 ss;
+ __siginfo32_t info;
+ __siginfo_fpu32_t *fpu_save;
+ unsigned int insns [2];
+ __siginfo_fpu32_t fpu_state;
};
/* Align macros */
@@ -119,6 +121,34 @@
_sigpause32_common(regs->u_regs[UREG_I0], regs);
}
+
+static inline void
+restore_fpu_state(struct pt_regs *regs, __siginfo_fpu32_t *fpu)
+{
+#ifdef __SMP__
+ if (current->flags & PF_USEDFPU)
+ regs->psr &= ~(TSTATE_PEF);
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = 0;
+ regs->psr &= ~(TSTATE_PEF);
+ }
+#endif
+ current->used_math = 1;
+ current->flags &= ~PF_USEDFPU;
+
+ copy_32bit_to_kernel_fpuregs(¤t->tss.float_regs[0],
+ &sf->info.si_float_regs[0],
+ (sizeof(unsigned int) * 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_sigreturn32(struct pt_regs *regs)
{
struct new_signal_frame32 *sf;
@@ -138,33 +168,19 @@
do_exit (SIGSEGV);
return;
}
-
+
/* 2. Restore the state */
- copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs, sizeof (struct pt_regs));
+ copy_32bit_to_kernel_ptregs (regs, &sf->info.si_regs,
+ sizeof (struct pt_regs));
- /* User can only change condition codes and FPU enabling in the %tstate. */
+ /* User can only change condition codes and FPU enabling in %tstate. */
regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
regs->tstate |= psr_to_tstate_icc(sf->info.si_regs.psr);
regs->tstate |= (sf->info.si_regs.psr & PSR_EF);
- if (regs->tstate & TSTATE_PEF) {
- regs->psr &= ~(TSTATE_PEF);
-#ifndef __SMP__
- if(current == last_task_used_math)
- last_task_used_math = 0;
-#endif
- current->used_math = 1;
- current->flags &= ~(PF_USEDFPU);
+ if (sf->fpu_save)
+ restore_fpu_state(regs, sf->fpu_state);
- /* Copy signal FPU state into thread struct FPU state. */
- copy_32bit_to_kernel_fpuregs(¤t->tss.float_regs[0],
- &sf->info.si_float_regs[0],
- (sizeof(unsigned int) * 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 int) + (sizeof(unsigned int *))) * 16));
- }
current->blocked = sf->info.si_mask & _BLOCKABLE;
}
@@ -284,77 +300,80 @@
regs->npc = (regs->pc + 4);
}
-/* To align the structure properly. */
+
+static inline void
+save_fpu_state(struct pt_regs *regs, __siginfo_fpu32_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_frame32(struct sigaction *sa, struct pt_regs *regs,
int signo, unsigned long oldmask)
{
struct new_signal_frame32 *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);
+ sigframe_size = NF_ALIGNEDSZ;
+ if (!current->used_math)
+ sigframe_size -= sizeof(__siginfo_fpu32_t);
+
+ sf = (struct new_signal_frame *)(regs->u_regs[UREG_FP] - sigframe_size);
- if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){
+ 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));
-
- 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));
+ memcpy (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 [0] = 0x821020d8; /* mov __NR_sigreturn, %g1 */
sf->insns [1] = 0x91d02010; /* t 0x10 */
/* 4. signal handler back-trampoline and parameters */
@@ -503,7 +522,7 @@
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]);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov