diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2011-09-20 21:45:56 +0200 | 
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2011-09-20 21:45:56 +0200 | 
| commit | 1fdb4888e45f1413972a8e9da55f3ffc08b9abcb (patch) | |
| tree | 635ef73cdff38d21a529bbdcab4cd2cb39a29484 /arch/sparc/kernel/sigutil_64.c | |
| parent | 1884af9365a96314164f4110d4528d425e5dd843 (diff) | |
| parent | ceb1c532ba6220900e61ec7073a9234661efa450 (diff) | |
| download | olio-linux-3.10-1fdb4888e45f1413972a8e9da55f3ffc08b9abcb.tar.xz olio-linux-3.10-1fdb4888e45f1413972a8e9da55f3ffc08b9abcb.zip  | |
Merge branch 'omap/cleanup' into next/cleanup
Diffstat (limited to 'arch/sparc/kernel/sigutil_64.c')
| -rw-r--r-- | arch/sparc/kernel/sigutil_64.c | 93 | 
1 files changed, 93 insertions, 0 deletions
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c new file mode 100644 index 00000000000..e7dc508c38e --- /dev/null +++ b/arch/sparc/kernel/sigutil_64.c @@ -0,0 +1,93 @@ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/thread_info.h> +#include <linux/uaccess.h> + +#include <asm/sigcontext.h> +#include <asm/fpumacro.h> +#include <asm/ptrace.h> + +#include "sigutil.h" + +int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) +{ +	unsigned long *fpregs = current_thread_info()->fpregs; +	unsigned long fprs; +	int err = 0; +	 +	fprs = current_thread_info()->fpsaved[0]; +	if (fprs & FPRS_DL) +		err |= copy_to_user(&fpu->si_float_regs[0], fpregs, +				    (sizeof(unsigned int) * 32)); +	if (fprs & FPRS_DU) +		err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, +				    (sizeof(unsigned int) * 32)); +	err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr); +	err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr); +	err |= __put_user(fprs, &fpu->si_fprs); + +	return err; +} + +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) +{ +	unsigned long *fpregs = current_thread_info()->fpregs; +	unsigned long fprs; +	int err; + +	err = __get_user(fprs, &fpu->si_fprs); +	fprs_write(0); +	regs->tstate &= ~TSTATE_PEF; +	if (fprs & FPRS_DL) +		err |= copy_from_user(fpregs, &fpu->si_float_regs[0], +		       	       (sizeof(unsigned int) * 32)); +	if (fprs & FPRS_DU) +		err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], +		       	       (sizeof(unsigned int) * 32)); +	err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr); +	err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr); +	current_thread_info()->fpsaved[0] |= fprs; +	return err; +} + +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin) +{ +	int i, err = __put_user(wsaved, &rwin->wsaved); + +	for (i = 0; i < wsaved; i++) { +		struct reg_window *rp = ¤t_thread_info()->reg_window[i]; +		unsigned long fp = current_thread_info()->rwbuf_stkptrs[i]; + +		err |= copy_to_user(&rwin->reg_window[i], rp, +				    sizeof(struct reg_window)); +		err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]); +	} +	return err; +} + +int restore_rwin_state(__siginfo_rwin_t __user *rp) +{ +	struct thread_info *t = current_thread_info(); +	int i, wsaved, err; + +	__get_user(wsaved, &rp->wsaved); +	if (wsaved > NSWINS) +		return -EFAULT; + +	err = 0; +	for (i = 0; i < wsaved; i++) { +		err |= copy_from_user(&t->reg_window[i], +				      &rp->reg_window[i], +				      sizeof(struct reg_window)); +		err |= __get_user(t->rwbuf_stkptrs[i], +				  &rp->rwbuf_stkptrs[i]); +	} +	if (err) +		return err; + +	set_thread_wsaved(wsaved); +	synchronize_user_stack(); +	if (get_thread_wsaved()) +		return -EFAULT; +	return 0; +}  |