Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[pandora-kernel.git] / arch / sparc / kernel / sigutil_64.c
1 #include <linux/kernel.h>
2 #include <linux/types.h>
3 #include <linux/thread_info.h>
4 #include <linux/uaccess.h>
5 #include <linux/errno.h>
6
7 #include <asm/sigcontext.h>
8 #include <asm/fpumacro.h>
9 #include <asm/ptrace.h>
10
11 #include "sigutil.h"
12
13 int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
14 {
15         unsigned long *fpregs = current_thread_info()->fpregs;
16         unsigned long fprs;
17         int err = 0;
18         
19         fprs = current_thread_info()->fpsaved[0];
20         if (fprs & FPRS_DL)
21                 err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
22                                     (sizeof(unsigned int) * 32));
23         if (fprs & FPRS_DU)
24                 err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
25                                     (sizeof(unsigned int) * 32));
26         err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
27         err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
28         err |= __put_user(fprs, &fpu->si_fprs);
29
30         return err;
31 }
32
33 int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
34 {
35         unsigned long *fpregs = current_thread_info()->fpregs;
36         unsigned long fprs;
37         int err;
38
39         err = __get_user(fprs, &fpu->si_fprs);
40         fprs_write(0);
41         regs->tstate &= ~TSTATE_PEF;
42         if (fprs & FPRS_DL)
43                 err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
44                                (sizeof(unsigned int) * 32));
45         if (fprs & FPRS_DU)
46                 err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
47                                (sizeof(unsigned int) * 32));
48         err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
49         err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
50         current_thread_info()->fpsaved[0] |= fprs;
51         return err;
52 }
53
54 int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
55 {
56         int i, err = __put_user(wsaved, &rwin->wsaved);
57
58         for (i = 0; i < wsaved; i++) {
59                 struct reg_window *rp = &current_thread_info()->reg_window[i];
60                 unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
61
62                 err |= copy_to_user(&rwin->reg_window[i], rp,
63                                     sizeof(struct reg_window));
64                 err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
65         }
66         return err;
67 }
68
69 int restore_rwin_state(__siginfo_rwin_t __user *rp)
70 {
71         struct thread_info *t = current_thread_info();
72         int i, wsaved, err;
73
74         __get_user(wsaved, &rp->wsaved);
75         if (wsaved > NSWINS)
76                 return -EFAULT;
77
78         err = 0;
79         for (i = 0; i < wsaved; i++) {
80                 err |= copy_from_user(&t->reg_window[i],
81                                       &rp->reg_window[i],
82                                       sizeof(struct reg_window));
83                 err |= __get_user(t->rwbuf_stkptrs[i],
84                                   &rp->rwbuf_stkptrs[i]);
85         }
86         if (err)
87                 return err;
88
89         set_thread_wsaved(wsaved);
90         synchronize_user_stack();
91         if (get_thread_wsaved())
92                 return -EFAULT;
93         return 0;
94 }