diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
commit | 545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch) | |
tree | e9ce4bc598d06374bda906f18365984bf22a526a /arch/sparc64/kernel/signal.c | |
parent | 4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (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.c | 96 |
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; |