summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/signal.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
committerRalf Baechle <ralf@linux-mips.org>1997-09-12 01:29:55 +0000
commit545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch)
treee9ce4bc598d06374bda906f18365984bf22a526a /arch/sparc64/kernel/signal.c
parent4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff)
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'arch/sparc64/kernel/signal.c')
-rw-r--r--arch/sparc64/kernel/signal.c96
1 files changed, 74 insertions, 22 deletions
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index cfc55fc2e..87241f8e3 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
+/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $
* arch/sparc64/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
@@ -54,12 +54,12 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
if(tp->w_saved ||
(((unsigned long)ucp) & (sizeof(unsigned long)-1)) ||
(!__access_ok((unsigned long)ucp, sizeof(*ucp))))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
grp = &ucp->uc_mcontext.mc_gregs;
__get_user(pc, &((*grp)[MC_PC]));
__get_user(npc, &((*grp)[MC_NPC]));
if((pc | npc) & 3)
- do_exit(SIGSEGV);
+ goto do_sigsegv;
if(regs->u_regs[UREG_I1]) {
__get_user(current->blocked, &ucp->uc_sigmask);
current->blocked &= _BLOCKABLE;
@@ -67,7 +67,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
regs->tpc = pc;
regs->tnpc = npc;
__get_user(regs->y, &((*grp)[MC_Y]));
- __get_user(tstate, &((*grp)[MC_Y]));
+ __get_user(tstate, &((*grp)[MC_TSTATE]));
regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
__get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
@@ -94,12 +94,23 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
__get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
if(fenab) {
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
- (sizeof(unsigned long) * 32));
+ unsigned long fprs;
+ __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
+ (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
__get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
- regs->fprs = FPRS_FEF;
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
asmlinkage void sparc64_get_context(struct pt_regs *regs)
@@ -109,11 +120,11 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
mc_gregset_t *grp;
mcontext_t *mcp;
unsigned long fp, i7;
- unsigned char fenab = (current->flags & PF_USEDFPU);
+ unsigned char fenab = (current->tss.flags & SPARC_FLAG_USEDFPU);
synchronize_user_stack();
if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
- do_exit(SIGSEGV);
+ goto do_sigsegv;
mcp = &ucp->uc_mcontext;
grp = &mcp->mc_gregs;
@@ -150,12 +161,30 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
__put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
if(fenab) {
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
- (sizeof(unsigned long) * 32));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&(mcp->mc_fpregs.mcfpu_fregs),
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16,
+ (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr));
__put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
- __put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs));
+ __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
}
+ return;
+do_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/*
@@ -233,11 +262,19 @@ static inline void
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_from_user(fpregs, &fpu->si_float_regs[0],
- (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ __get_user(fprs, &fpu->si_fprs);
+ if (fprs & FPRS_DL)
+ copy_from_user(fpregs, &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
__get_user(fpregs[32], &fpu->si_fsr);
__get_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = FPRS_FEF;
+ regs->fprs = fprs;
+ regs->tstate |= TSTATE_PEF;
}
void do_sigreturn(struct pt_regs *regs)
@@ -304,11 +341,26 @@ static inline void
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
{
unsigned long *fpregs = (unsigned long *)(regs+1);
- copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 64));
+ unsigned long fprs;
+
+ fprs = (regs->fprs & FPRS_FEF) |
+ (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU));
+ if (fprs & FPRS_DL)
+ copy_to_user(&fpu->si_float_regs[0], fpregs,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+ (sizeof(unsigned int) * 32));
+ else
+ clear_user(&fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
__put_user(fpregs[32], &fpu->si_fsr);
__put_user(fpregs[33], &fpu->si_gsr);
- regs->fprs = 0;
+ __put_user(fprs, &fpu->si_fprs);
+ regs->tstate &= ~TSTATE_PEF;
}
static inline void
@@ -321,7 +373,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
/* 1. Make sure everything is clean */
synchronize_user_stack();
sigframe_size = NF_ALIGNEDSZ;
- if (!(current->flags & PF_USEDFPU))
+ if (!(current->tss.flags & SPARC_FLAG_USEDFPU))
sigframe_size -= sizeof(__siginfo_fpu_t);
sf = (struct new_signal_frame *)
@@ -339,7 +391,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs,
/* 2. Save the current process state */
copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
- if (current->flags & PF_USEDFPU) {
+ if (current->tss.flags & SPARC_FLAG_USEDFPU) {
save_fpu_state(regs, &sf->fpu_state);
__put_user((u64)&sf->fpu_state, &sf->fpu_save);
} else {
@@ -452,7 +504,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -498,7 +550,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
current->exit_code = signr;
if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;