Commit 5598473a5b40c47a8c5349dd2c2630797169cf1a

Authored by David S. Miller
1 parent 4a0342ca8e

sparc: Allow handling signals when stack is corrupted.

If we can't push the pending register windows onto the user's stack,
we disallow signal delivery even if the signal would be delivered on a
valid seperate signal stack.

Add a register window save area in the signal frame, and store any
unsavable windows there.

On sigreturn, if any windows are still queued up in the signal frame,
try to push them back onto the stack and if that fails we kill the
process immediately.

This allows the debug/tst-longjmp_chk2 glibc test case to pass.

Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 8 changed files with 468 additions and 233 deletions Side-by-side Diff

arch/sparc/include/asm/sigcontext.h
... ... @@ -45,6 +45,19 @@
45 45 int si_mask;
46 46 } __siginfo32_t;
47 47  
  48 +#define __SIGC_MAXWIN 7
  49 +
  50 +typedef struct {
  51 + unsigned long locals[8];
  52 + unsigned long ins[8];
  53 +} __siginfo_reg_window;
  54 +
  55 +typedef struct {
  56 + int wsaved;
  57 + __siginfo_reg_window reg_window[__SIGC_MAXWIN];
  58 + unsigned long rwbuf_stkptrs[__SIGC_MAXWIN];
  59 +} __siginfo_rwin_t;
  60 +
48 61 #ifdef CONFIG_SPARC64
49 62 typedef struct {
50 63 unsigned int si_float_regs [64];
... ... @@ -73,6 +86,7 @@
73 86 unsigned long ss_size;
74 87 } sigc_stack;
75 88 unsigned long sigc_mask;
  89 + __siginfo_rwin_t * sigc_rwin_save;
76 90 };
77 91  
78 92 #else
arch/sparc/kernel/Makefile
... ... @@ -32,6 +32,7 @@
32 32  
33 33 obj-y += process_$(BITS).o
34 34 obj-y += signal_$(BITS).o
  35 +obj-y += sigutil_$(BITS).o
35 36 obj-$(CONFIG_SPARC32) += ioport.o
36 37 obj-y += setup_$(BITS).o
37 38 obj-y += idprom.o
arch/sparc/kernel/signal32.c
... ... @@ -29,6 +29,8 @@
29 29 #include <asm/visasm.h>
30 30 #include <asm/compat_signal.h>
31 31  
  32 +#include "sigutil.h"
  33 +
32 34 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
33 35  
34 36 /* This magic should be in g_upper[0] for all upper parts
35 37  
... ... @@ -44,14 +46,14 @@
44 46 struct signal_frame32 {
45 47 struct sparc_stackf32 ss;
46 48 __siginfo32_t info;
47   - /* __siginfo_fpu32_t * */ u32 fpu_save;
  49 + /* __siginfo_fpu_t * */ u32 fpu_save;
48 50 unsigned int insns[2];
49 51 unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
50 52 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
51 53 /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
52 54 siginfo_extra_v8plus_t v8plus;
53   - __siginfo_fpu_t fpu_state;
54   -};
  55 + /* __siginfo_rwin_t * */u32 rwin_save;
  56 +} __attribute__((aligned(8)));
55 57  
56 58 typedef struct compat_siginfo{
57 59 int si_signo;
58 60  
59 61  
... ... @@ -110,19 +112,15 @@
110 112 compat_siginfo_t info;
111 113 struct pt_regs32 regs;
112 114 compat_sigset_t mask;
113   - /* __siginfo_fpu32_t * */ u32 fpu_save;
  115 + /* __siginfo_fpu_t * */ u32 fpu_save;
114 116 unsigned int insns[2];
115 117 stack_t32 stack;
116 118 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
117 119 /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
118 120 siginfo_extra_v8plus_t v8plus;
119   - __siginfo_fpu_t fpu_state;
120   -};
  121 + /* __siginfo_rwin_t * */u32 rwin_save;
  122 +} __attribute__((aligned(8)));
121 123  
122   -/* Align macros */
123   -#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15)))
124   -#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
125   -
126 124 int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
127 125 {
128 126 int err;
129 127  
130 128  
... ... @@ -192,30 +190,13 @@
192 190 return 0;
193 191 }
194 192  
195   -static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
196   -{
197   - unsigned long *fpregs = current_thread_info()->fpregs;
198   - unsigned long fprs;
199   - int err;
200   -
201   - err = __get_user(fprs, &fpu->si_fprs);
202   - fprs_write(0);
203   - regs->tstate &= ~TSTATE_PEF;
204   - if (fprs & FPRS_DL)
205   - err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
206   - if (fprs & FPRS_DU)
207   - err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
208   - err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
209   - err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
210   - current_thread_info()->fpsaved[0] |= fprs;
211   - return err;
212   -}
213   -
214 193 void do_sigreturn32(struct pt_regs *regs)
215 194 {
216 195 struct signal_frame32 __user *sf;
  196 + compat_uptr_t fpu_save;
  197 + compat_uptr_t rwin_save;
217 198 unsigned int psr;
218   - unsigned pc, npc, fpu_save;
  199 + unsigned pc, npc;
219 200 sigset_t set;
220 201 unsigned seta[_COMPAT_NSIG_WORDS];
221 202 int err, i;
... ... @@ -273,8 +254,13 @@
273 254 pt_regs_clear_syscall(regs);
274 255  
275 256 err |= __get_user(fpu_save, &sf->fpu_save);
276   - if (fpu_save)
277   - err |= restore_fpu_state32(regs, &sf->fpu_state);
  257 + if (!err && fpu_save)
  258 + err |= restore_fpu_state(regs, compat_ptr(fpu_save));
  259 + err |= __get_user(rwin_save, &sf->rwin_save);
  260 + if (!err && rwin_save) {
  261 + if (restore_rwin_state(compat_ptr(rwin_save)))
  262 + goto segv;
  263 + }
278 264 err |= __get_user(seta[0], &sf->info.si_mask);
279 265 err |= copy_from_user(seta+1, &sf->extramask,
280 266 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
... ... @@ -300,7 +286,9 @@
300 286 asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
301 287 {
302 288 struct rt_signal_frame32 __user *sf;
303   - unsigned int psr, pc, npc, fpu_save, u_ss_sp;
  289 + unsigned int psr, pc, npc, u_ss_sp;
  290 + compat_uptr_t fpu_save;
  291 + compat_uptr_t rwin_save;
304 292 mm_segment_t old_fs;
305 293 sigset_t set;
306 294 compat_sigset_t seta;
... ... @@ -359,8 +347,8 @@
359 347 pt_regs_clear_syscall(regs);
360 348  
361 349 err |= __get_user(fpu_save, &sf->fpu_save);
362   - if (fpu_save)
363   - err |= restore_fpu_state32(regs, &sf->fpu_state);
  350 + if (!err && fpu_save)
  351 + err |= restore_fpu_state(regs, compat_ptr(fpu_save));
364 352 err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
365 353 err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
366 354 st.ss_sp = compat_ptr(u_ss_sp);
... ... @@ -376,6 +364,12 @@
376 364 do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
377 365 set_fs(old_fs);
378 366  
  367 + err |= __get_user(rwin_save, &sf->rwin_save);
  368 + if (!err && rwin_save) {
  369 + if (restore_rwin_state(compat_ptr(rwin_save)))
  370 + goto segv;
  371 + }
  372 +
379 373 switch (_NSIG_WORDS) {
380 374 case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
381 375 case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
... ... @@ -433,26 +427,6 @@
433 427 return (void __user *) sp;
434 428 }
435 429  
436   -static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
437   -{
438   - unsigned long *fpregs = current_thread_info()->fpregs;
439   - unsigned long fprs;
440   - int err = 0;
441   -
442   - fprs = current_thread_info()->fpsaved[0];
443   - if (fprs & FPRS_DL)
444   - err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
445   - (sizeof(unsigned int) * 32));
446   - if (fprs & FPRS_DU)
447   - err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
448   - (sizeof(unsigned int) * 32));
449   - err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
450   - err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
451   - err |= __put_user(fprs, &fpu->si_fprs);
452   -
453   - return err;
454   -}
455   -
456 430 /* The I-cache flush instruction only works in the primary ASI, which
457 431 * right now is the nucleus, aka. kernel space.
458 432 *
459 433  
460 434  
461 435  
462 436  
... ... @@ -515,27 +489,31 @@
515 489 int signo, sigset_t *oldset)
516 490 {
517 491 struct signal_frame32 __user *sf;
  492 + int i, err, wsaved;
  493 + void __user *tail;
518 494 int sigframe_size;
519 495 u32 psr;
520   - int i, err;
521 496 unsigned int seta[_COMPAT_NSIG_WORDS];
522 497  
523 498 /* 1. Make sure everything is clean */
524 499 synchronize_user_stack();
525 500 save_and_clear_fpu();
526 501  
527   - sigframe_size = SF_ALIGNEDSZ;
528   - if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
529   - sigframe_size -= sizeof(__siginfo_fpu_t);
  502 + wsaved = get_thread_wsaved();
530 503  
  504 + sigframe_size = sizeof(*sf);
  505 + if (current_thread_info()->fpsaved[0] & FPRS_FEF)
  506 + sigframe_size += sizeof(__siginfo_fpu_t);
  507 + if (wsaved)
  508 + sigframe_size += sizeof(__siginfo_rwin_t);
  509 +
531 510 sf = (struct signal_frame32 __user *)
532 511 get_sigframe(&ka->sa, regs, sigframe_size);
533 512  
534 513 if (invalid_frame_pointer(sf, sigframe_size))
535 514 goto sigill;
536 515  
537   - if (get_thread_wsaved() != 0)
538   - goto sigill;
  516 + tail = (sf + 1);
539 517  
540 518 /* 2. Save the current process state */
541 519 if (test_thread_flag(TIF_32BIT)) {
542 520  
... ... @@ -560,11 +538,22 @@
560 538 &sf->v8plus.asi);
561 539  
562 540 if (psr & PSR_EF) {
563   - err |= save_fpu_state32(regs, &sf->fpu_state);
564   - err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
  541 + __siginfo_fpu_t __user *fp = tail;
  542 + tail += sizeof(*fp);
  543 + err |= save_fpu_state(regs, fp);
  544 + err |= __put_user((u64)fp, &sf->fpu_save);
565 545 } else {
566 546 err |= __put_user(0, &sf->fpu_save);
567 547 }
  548 + if (wsaved) {
  549 + __siginfo_rwin_t __user *rwp = tail;
  550 + tail += sizeof(*rwp);
  551 + err |= save_rwin_state(wsaved, rwp);
  552 + err |= __put_user((u64)rwp, &sf->rwin_save);
  553 + set_thread_wsaved(0);
  554 + } else {
  555 + err |= __put_user(0, &sf->rwin_save);
  556 + }
568 557  
569 558 switch (_NSIG_WORDS) {
570 559 case 4: seta[7] = (oldset->sig[3] >> 32);
... ... @@ -580,10 +569,21 @@
580 569 err |= __copy_to_user(sf->extramask, seta + 1,
581 570 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
582 571  
583   - err |= copy_in_user((u32 __user *)sf,
584   - (u32 __user *)(regs->u_regs[UREG_FP]),
585   - sizeof(struct reg_window32));
586   -
  572 + if (!wsaved) {
  573 + err |= copy_in_user((u32 __user *)sf,
  574 + (u32 __user *)(regs->u_regs[UREG_FP]),
  575 + sizeof(struct reg_window32));
  576 + } else {
  577 + struct reg_window *rp;
  578 +
  579 + rp = &current_thread_info()->reg_window[wsaved - 1];
  580 + for (i = 0; i < 8; i++)
  581 + err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
  582 + for (i = 0; i < 6; i++)
  583 + err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
  584 + err |= __put_user(rp->ins[6], &sf->ss.fp);
  585 + err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
  586 + }
587 587 if (err)
588 588 goto sigsegv;
589 589  
... ... @@ -613,7 +613,6 @@
613 613 err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
614 614 if (err)
615 615 goto sigsegv;
616   -
617 616 flush_signal_insns(address);
618 617 }
619 618 return 0;
620 619  
621 620  
622 621  
623 622  
... ... @@ -632,27 +631,31 @@
632 631 siginfo_t *info)
633 632 {
634 633 struct rt_signal_frame32 __user *sf;
  634 + int i, err, wsaved;
  635 + void __user *tail;
635 636 int sigframe_size;
636 637 u32 psr;
637   - int i, err;
638 638 compat_sigset_t seta;
639 639  
640 640 /* 1. Make sure everything is clean */
641 641 synchronize_user_stack();
642 642 save_and_clear_fpu();
643 643  
644   - sigframe_size = RT_ALIGNEDSZ;
645   - if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
646   - sigframe_size -= sizeof(__siginfo_fpu_t);
  644 + wsaved = get_thread_wsaved();
647 645  
  646 + sigframe_size = sizeof(*sf);
  647 + if (current_thread_info()->fpsaved[0] & FPRS_FEF)
  648 + sigframe_size += sizeof(__siginfo_fpu_t);
  649 + if (wsaved)
  650 + sigframe_size += sizeof(__siginfo_rwin_t);
  651 +
648 652 sf = (struct rt_signal_frame32 __user *)
649 653 get_sigframe(&ka->sa, regs, sigframe_size);
650 654  
651 655 if (invalid_frame_pointer(sf, sigframe_size))
652 656 goto sigill;
653 657  
654   - if (get_thread_wsaved() != 0)
655   - goto sigill;
  658 + tail = (sf + 1);
656 659  
657 660 /* 2. Save the current process state */
658 661 if (test_thread_flag(TIF_32BIT)) {
659 662  
... ... @@ -677,11 +680,22 @@
677 680 &sf->v8plus.asi);
678 681  
679 682 if (psr & PSR_EF) {
680   - err |= save_fpu_state32(regs, &sf->fpu_state);
681   - err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
  683 + __siginfo_fpu_t __user *fp = tail;
  684 + tail += sizeof(*fp);
  685 + err |= save_fpu_state(regs, fp);
  686 + err |= __put_user((u64)fp, &sf->fpu_save);
682 687 } else {
683 688 err |= __put_user(0, &sf->fpu_save);
684 689 }
  690 + if (wsaved) {
  691 + __siginfo_rwin_t __user *rwp = tail;
  692 + tail += sizeof(*rwp);
  693 + err |= save_rwin_state(wsaved, rwp);
  694 + err |= __put_user((u64)rwp, &sf->rwin_save);
  695 + set_thread_wsaved(0);
  696 + } else {
  697 + err |= __put_user(0, &sf->rwin_save);
  698 + }
685 699  
686 700 /* Update the siginfo structure. */
687 701 err |= copy_siginfo_to_user32(&sf->info, info);
... ... @@ -703,9 +717,21 @@
703 717 }
704 718 err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
705 719  
706   - err |= copy_in_user((u32 __user *)sf,
707   - (u32 __user *)(regs->u_regs[UREG_FP]),
708   - sizeof(struct reg_window32));
  720 + if (!wsaved) {
  721 + err |= copy_in_user((u32 __user *)sf,
  722 + (u32 __user *)(regs->u_regs[UREG_FP]),
  723 + sizeof(struct reg_window32));
  724 + } else {
  725 + struct reg_window *rp;
  726 +
  727 + rp = &current_thread_info()->reg_window[wsaved - 1];
  728 + for (i = 0; i < 8; i++)
  729 + err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
  730 + for (i = 0; i < 6; i++)
  731 + err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
  732 + err |= __put_user(rp->ins[6], &sf->ss.fp);
  733 + err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
  734 + }
709 735 if (err)
710 736 goto sigsegv;
711 737  
arch/sparc/kernel/signal_32.c
... ... @@ -26,6 +26,8 @@
26 26 #include <asm/pgtable.h>
27 27 #include <asm/cacheflush.h> /* flush_sig_insns */
28 28  
  29 +#include "sigutil.h"
  30 +
29 31 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
30 32  
31 33 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
... ... @@ -39,8 +41,8 @@
39 41 unsigned long insns[2] __attribute__ ((aligned (8)));
40 42 unsigned int extramask[_NSIG_WORDS - 1];
41 43 unsigned int extra_size; /* Should be 0 */
42   - __siginfo_fpu_t fpu_state;
43   -};
  44 + __siginfo_rwin_t __user *rwin_save;
  45 +} __attribute__((aligned(8)));
44 46  
45 47 struct rt_signal_frame {
46 48 struct sparc_stackf ss;
... ... @@ -51,8 +53,8 @@
51 53 unsigned int insns[2];
52 54 stack_t stack;
53 55 unsigned int extra_size; /* Should be 0 */
54   - __siginfo_fpu_t fpu_state;
55   -};
  56 + __siginfo_rwin_t __user *rwin_save;
  57 +} __attribute__((aligned(8)));
56 58  
57 59 /* Align macros */
58 60 #define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
59 61  
... ... @@ -79,43 +81,13 @@
79 81 return _sigpause_common(set);
80 82 }
81 83  
82   -static inline int
83   -restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
84   -{
85   - int err;
86   -#ifdef CONFIG_SMP
87   - if (test_tsk_thread_flag(current, TIF_USEDFPU))
88   - regs->psr &= ~PSR_EF;
89   -#else
90   - if (current == last_task_used_math) {
91   - last_task_used_math = NULL;
92   - regs->psr &= ~PSR_EF;
93   - }
94   -#endif
95   - set_used_math();
96   - clear_tsk_thread_flag(current, TIF_USEDFPU);
97   -
98   - if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
99   - return -EFAULT;
100   -
101   - err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
102   - (sizeof(unsigned long) * 32));
103   - err |= __get_user(current->thread.fsr, &fpu->si_fsr);
104   - err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
105   - if (current->thread.fpqdepth != 0)
106   - err |= __copy_from_user(&current->thread.fpqueue[0],
107   - &fpu->si_fpqueue[0],
108   - ((sizeof(unsigned long) +
109   - (sizeof(unsigned long *)))*16));
110   - return err;
111   -}
112   -
113 84 asmlinkage void do_sigreturn(struct pt_regs *regs)
114 85 {
115 86 struct signal_frame __user *sf;
116 87 unsigned long up_psr, pc, npc;
117 88 sigset_t set;
118 89 __siginfo_fpu_t __user *fpu_save;
  90 + __siginfo_rwin_t __user *rwin_save;
119 91 int err;
120 92  
121 93 /* Always make any pending restarted system calls return -EINTR */
122 94  
... ... @@ -150,9 +122,11 @@
150 122 pt_regs_clear_syscall(regs);
151 123  
152 124 err |= __get_user(fpu_save, &sf->fpu_save);
153   -
154 125 if (fpu_save)
155 126 err |= restore_fpu_state(regs, fpu_save);
  127 + err |= __get_user(rwin_save, &sf->rwin_save);
  128 + if (rwin_save)
  129 + err |= restore_rwin_state(rwin_save);
156 130  
157 131 /* This is pretty much atomic, no amount locking would prevent
158 132 * the races which exist anyways.
... ... @@ -180,6 +154,7 @@
180 154 struct rt_signal_frame __user *sf;
181 155 unsigned int psr, pc, npc;
182 156 __siginfo_fpu_t __user *fpu_save;
  157 + __siginfo_rwin_t __user *rwin_save;
183 158 mm_segment_t old_fs;
184 159 sigset_t set;
185 160 stack_t st;
... ... @@ -207,8 +182,7 @@
207 182 pt_regs_clear_syscall(regs);
208 183  
209 184 err |= __get_user(fpu_save, &sf->fpu_save);
210   -
211   - if (fpu_save)
  185 + if (!err && fpu_save)
212 186 err |= restore_fpu_state(regs, fpu_save);
213 187 err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
214 188  
... ... @@ -228,6 +202,12 @@
228 202 do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
229 203 set_fs(old_fs);
230 204  
  205 + err |= __get_user(rwin_save, &sf->rwin_save);
  206 + if (!err && rwin_save) {
  207 + if (restore_rwin_state(rwin_save))
  208 + goto segv;
  209 + }
  210 +
231 211 sigdelsetmask(&set, ~_BLOCKABLE);
232 212 spin_lock_irq(&current->sighand->siglock);
233 213 current->blocked = set;
234 214  
235 215  
236 216  
237 217  
... ... @@ -280,62 +260,31 @@
280 260 return (void __user *) sp;
281 261 }
282 262  
283   -static inline int
284   -save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
285   -{
286   - int err = 0;
287   -#ifdef CONFIG_SMP
288   - if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
289   - put_psr(get_psr() | PSR_EF);
290   - fpsave(&current->thread.float_regs[0], &current->thread.fsr,
291   - &current->thread.fpqueue[0], &current->thread.fpqdepth);
292   - regs->psr &= ~(PSR_EF);
293   - clear_tsk_thread_flag(current, TIF_USEDFPU);
294   - }
295   -#else
296   - if (current == last_task_used_math) {
297   - put_psr(get_psr() | PSR_EF);
298   - fpsave(&current->thread.float_regs[0], &current->thread.fsr,
299   - &current->thread.fpqueue[0], &current->thread.fpqdepth);
300   - last_task_used_math = NULL;
301   - regs->psr &= ~(PSR_EF);
302   - }
303   -#endif
304   - err |= __copy_to_user(&fpu->si_float_regs[0],
305   - &current->thread.float_regs[0],
306   - (sizeof(unsigned long) * 32));
307   - err |= __put_user(current->thread.fsr, &fpu->si_fsr);
308   - err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
309   - if (current->thread.fpqdepth != 0)
310   - err |= __copy_to_user(&fpu->si_fpqueue[0],
311   - &current->thread.fpqueue[0],
312   - ((sizeof(unsigned long) +
313   - (sizeof(unsigned long *)))*16));
314   - clear_used_math();
315   - return err;
316   -}
317   -
318 263 static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
319 264 int signo, sigset_t *oldset)
320 265 {
321 266 struct signal_frame __user *sf;
322   - int sigframe_size, err;
  267 + int sigframe_size, err, wsaved;
  268 + void __user *tail;
323 269  
324 270 /* 1. Make sure everything is clean */
325 271 synchronize_user_stack();
326 272  
327   - sigframe_size = SF_ALIGNEDSZ;
328   - if (!used_math())
329   - sigframe_size -= sizeof(__siginfo_fpu_t);
  273 + wsaved = current_thread_info()->w_saved;
330 274  
  275 + sigframe_size = sizeof(*sf);
  276 + if (used_math())
  277 + sigframe_size += sizeof(__siginfo_fpu_t);
  278 + if (wsaved)
  279 + sigframe_size += sizeof(__siginfo_rwin_t);
  280 +
331 281 sf = (struct signal_frame __user *)
332 282 get_sigframe(&ka->sa, regs, sigframe_size);
333 283  
334 284 if (invalid_frame_pointer(sf, sigframe_size))
335 285 goto sigill_and_return;
336 286  
337   - if (current_thread_info()->w_saved != 0)
338   - goto sigill_and_return;
  287 + tail = sf + 1;
339 288  
340 289 /* 2. Save the current process state */
341 290 err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
342 291  
343 292  
... ... @@ -343,17 +292,34 @@
343 292 err |= __put_user(0, &sf->extra_size);
344 293  
345 294 if (used_math()) {
346   - err |= save_fpu_state(regs, &sf->fpu_state);
347   - err |= __put_user(&sf->fpu_state, &sf->fpu_save);
  295 + __siginfo_fpu_t __user *fp = tail;
  296 + tail += sizeof(*fp);
  297 + err |= save_fpu_state(regs, fp);
  298 + err |= __put_user(fp, &sf->fpu_save);
348 299 } else {
349 300 err |= __put_user(0, &sf->fpu_save);
350 301 }
  302 + if (wsaved) {
  303 + __siginfo_rwin_t __user *rwp = tail;
  304 + tail += sizeof(*rwp);
  305 + err |= save_rwin_state(wsaved, rwp);
  306 + err |= __put_user(rwp, &sf->rwin_save);
  307 + } else {
  308 + err |= __put_user(0, &sf->rwin_save);
  309 + }
351 310  
352 311 err |= __put_user(oldset->sig[0], &sf->info.si_mask);
353 312 err |= __copy_to_user(sf->extramask, &oldset->sig[1],
354 313 (_NSIG_WORDS - 1) * sizeof(unsigned int));
355   - err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
356   - sizeof(struct reg_window32));
  314 + if (!wsaved) {
  315 + err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
  316 + sizeof(struct reg_window32));
  317 + } else {
  318 + struct reg_window32 *rp;
  319 +
  320 + rp = &current_thread_info()->reg_window[wsaved - 1];
  321 + err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
  322 + }
357 323 if (err)
358 324 goto sigsegv;
359 325  
360 326  
361 327  
362 328  
... ... @@ -399,21 +365,24 @@
399 365 int signo, sigset_t *oldset, siginfo_t *info)
400 366 {
401 367 struct rt_signal_frame __user *sf;
402   - int sigframe_size;
  368 + int sigframe_size, wsaved;
  369 + void __user *tail;
403 370 unsigned int psr;
404 371 int err;
405 372  
406 373 synchronize_user_stack();
407   - sigframe_size = RT_ALIGNEDSZ;
408   - if (!used_math())
409   - sigframe_size -= sizeof(__siginfo_fpu_t);
  374 + wsaved = current_thread_info()->w_saved;
  375 + sigframe_size = sizeof(*sf);
  376 + if (used_math())
  377 + sigframe_size += sizeof(__siginfo_fpu_t);
  378 + if (wsaved)
  379 + sigframe_size += sizeof(__siginfo_rwin_t);
410 380 sf = (struct rt_signal_frame __user *)
411 381 get_sigframe(&ka->sa, regs, sigframe_size);
412 382 if (invalid_frame_pointer(sf, sigframe_size))
413 383 goto sigill;
414   - if (current_thread_info()->w_saved != 0)
415   - goto sigill;
416 384  
  385 + tail = sf + 1;
417 386 err = __put_user(regs->pc, &sf->regs.pc);
418 387 err |= __put_user(regs->npc, &sf->regs.npc);
419 388 err |= __put_user(regs->y, &sf->regs.y);
420 389  
... ... @@ -425,11 +394,21 @@
425 394 err |= __put_user(0, &sf->extra_size);
426 395  
427 396 if (psr & PSR_EF) {
428   - err |= save_fpu_state(regs, &sf->fpu_state);
429   - err |= __put_user(&sf->fpu_state, &sf->fpu_save);
  397 + __siginfo_fpu_t *fp = tail;
  398 + tail += sizeof(*fp);
  399 + err |= save_fpu_state(regs, fp);
  400 + err |= __put_user(fp, &sf->fpu_save);
430 401 } else {
431 402 err |= __put_user(0, &sf->fpu_save);
432 403 }
  404 + if (wsaved) {
  405 + __siginfo_rwin_t *rwp = tail;
  406 + tail += sizeof(*rwp);
  407 + err |= save_rwin_state(wsaved, rwp);
  408 + err |= __put_user(rwp, &sf->rwin_save);
  409 + } else {
  410 + err |= __put_user(0, &sf->rwin_save);
  411 + }
433 412 err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
434 413  
435 414 /* Setup sigaltstack */
... ... @@ -437,8 +416,15 @@
437 416 err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
438 417 err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
439 418  
440   - err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
441   - sizeof(struct reg_window32));
  419 + if (!wsaved) {
  420 + err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
  421 + sizeof(struct reg_window32));
  422 + } else {
  423 + struct reg_window32 *rp;
  424 +
  425 + rp = &current_thread_info()->reg_window[wsaved - 1];
  426 + err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
  427 + }
442 428  
443 429 err |= copy_siginfo_to_user(&sf->info, info);
444 430  
arch/sparc/kernel/signal_64.c
... ... @@ -34,6 +34,7 @@
34 34  
35 35 #include "entry.h"
36 36 #include "systbls.h"
  37 +#include "sigutil.h"
37 38  
38 39 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
39 40  
... ... @@ -236,7 +237,7 @@
236 237 __siginfo_fpu_t __user *fpu_save;
237 238 stack_t stack;
238 239 sigset_t mask;
239   - __siginfo_fpu_t fpu_state;
  240 + __siginfo_rwin_t *rwin_save;
240 241 };
241 242  
242 243 static long _sigpause_common(old_sigset_t set)
243 244  
... ... @@ -266,33 +267,12 @@
266 267 return _sigpause_common(set);
267 268 }
268 269  
269   -static inline int
270   -restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
271   -{
272   - unsigned long *fpregs = current_thread_info()->fpregs;
273   - unsigned long fprs;
274   - int err;
275   -
276   - err = __get_user(fprs, &fpu->si_fprs);
277   - fprs_write(0);
278   - regs->tstate &= ~TSTATE_PEF;
279   - if (fprs & FPRS_DL)
280   - err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
281   - (sizeof(unsigned int) * 32));
282   - if (fprs & FPRS_DU)
283   - err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
284   - (sizeof(unsigned int) * 32));
285   - err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
286   - err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
287   - current_thread_info()->fpsaved[0] |= fprs;
288   - return err;
289   -}
290   -
291 270 void do_rt_sigreturn(struct pt_regs *regs)
292 271 {
293 272 struct rt_signal_frame __user *sf;
294 273 unsigned long tpc, tnpc, tstate;
295 274 __siginfo_fpu_t __user *fpu_save;
  275 + __siginfo_rwin_t __user *rwin_save;
296 276 sigset_t set;
297 277 int err;
298 278  
... ... @@ -325,8 +305,8 @@
325 305 regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
326 306  
327 307 err |= __get_user(fpu_save, &sf->fpu_save);
328   - if (fpu_save)
329   - err |= restore_fpu_state(regs, &sf->fpu_state);
  308 + if (!err && fpu_save)
  309 + err |= restore_fpu_state(regs, fpu_save);
330 310  
331 311 err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
332 312 err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
... ... @@ -334,6 +314,12 @@
334 314 if (err)
335 315 goto segv;
336 316  
  317 + err |= __get_user(rwin_save, &sf->rwin_save);
  318 + if (!err && rwin_save) {
  319 + if (restore_rwin_state(rwin_save))
  320 + goto segv;
  321 + }
  322 +
337 323 regs->tpc = tpc;
338 324 regs->tnpc = tnpc;
339 325  
340 326  
... ... @@ -351,34 +337,13 @@
351 337 }
352 338  
353 339 /* Checks if the fp is valid */
354   -static int invalid_frame_pointer(void __user *fp, int fplen)
  340 +static int invalid_frame_pointer(void __user *fp)
355 341 {
356 342 if (((unsigned long) fp) & 15)
357 343 return 1;
358 344 return 0;
359 345 }
360 346  
361   -static inline int
362   -save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
363   -{
364   - unsigned long *fpregs = current_thread_info()->fpregs;
365   - unsigned long fprs;
366   - int err = 0;
367   -
368   - fprs = current_thread_info()->fpsaved[0];
369   - if (fprs & FPRS_DL)
370   - err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
371   - (sizeof(unsigned int) * 32));
372   - if (fprs & FPRS_DU)
373   - err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
374   - (sizeof(unsigned int) * 32));
375   - err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
376   - err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
377   - err |= __put_user(fprs, &fpu->si_fprs);
378   -
379   - return err;
380   -}
381   -
382 347 static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
383 348 {
384 349 unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
385 350  
386 351  
387 352  
388 353  
389 354  
390 355  
391 356  
... ... @@ -414,34 +379,48 @@
414 379 int signo, sigset_t *oldset, siginfo_t *info)
415 380 {
416 381 struct rt_signal_frame __user *sf;
417   - int sigframe_size, err;
  382 + int wsaved, err, sf_size;
  383 + void __user *tail;
418 384  
419 385 /* 1. Make sure everything is clean */
420 386 synchronize_user_stack();
421 387 save_and_clear_fpu();
422 388  
423   - sigframe_size = sizeof(struct rt_signal_frame);
424   - if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
425   - sigframe_size -= sizeof(__siginfo_fpu_t);
  389 + wsaved = get_thread_wsaved();
426 390  
  391 + sf_size = sizeof(struct rt_signal_frame);
  392 + if (current_thread_info()->fpsaved[0] & FPRS_FEF)
  393 + sf_size += sizeof(__siginfo_fpu_t);
  394 + if (wsaved)
  395 + sf_size += sizeof(__siginfo_rwin_t);
427 396 sf = (struct rt_signal_frame __user *)
428   - get_sigframe(ka, regs, sigframe_size);
429   -
430   - if (invalid_frame_pointer (sf, sigframe_size))
431   - goto sigill;
  397 + get_sigframe(ka, regs, sf_size);
432 398  
433   - if (get_thread_wsaved() != 0)
  399 + if (invalid_frame_pointer (sf))
434 400 goto sigill;
435 401  
  402 + tail = (sf + 1);
  403 +
436 404 /* 2. Save the current process state */
437 405 err = copy_to_user(&sf->regs, regs, sizeof (*regs));
438 406  
439 407 if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
440   - err |= save_fpu_state(regs, &sf->fpu_state);
441   - err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
  408 + __siginfo_fpu_t __user *fpu_save = tail;
  409 + tail += sizeof(__siginfo_fpu_t);
  410 + err |= save_fpu_state(regs, fpu_save);
  411 + err |= __put_user((u64)fpu_save, &sf->fpu_save);
442 412 } else {
443 413 err |= __put_user(0, &sf->fpu_save);
444 414 }
  415 + if (wsaved) {
  416 + __siginfo_rwin_t __user *rwin_save = tail;
  417 + tail += sizeof(__siginfo_rwin_t);
  418 + err |= save_rwin_state(wsaved, rwin_save);
  419 + err |= __put_user((u64)rwin_save, &sf->rwin_save);
  420 + set_thread_wsaved(0);
  421 + } else {
  422 + err |= __put_user(0, &sf->rwin_save);
  423 + }
445 424  
446 425 /* Setup sigaltstack */
447 426 err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
448 427  
... ... @@ -450,10 +429,17 @@
450 429  
451 430 err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
452 431  
453   - err |= copy_in_user((u64 __user *)sf,
454   - (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
455   - sizeof(struct reg_window));
  432 + if (!wsaved) {
  433 + err |= copy_in_user((u64 __user *)sf,
  434 + (u64 __user *)(regs->u_regs[UREG_FP] +
  435 + STACK_BIAS),
  436 + sizeof(struct reg_window));
  437 + } else {
  438 + struct reg_window *rp;
456 439  
  440 + rp = &current_thread_info()->reg_window[wsaved - 1];
  441 + err |= copy_to_user(sf, rp, sizeof(struct reg_window));
  442 + }
457 443 if (info)
458 444 err |= copy_siginfo_to_user(&sf->info, info);
459 445 else {
arch/sparc/kernel/sigutil.h
  1 +#ifndef _SIGUTIL_H
  2 +#define _SIGUTIL_H
  3 +
  4 +int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
  5 +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
  6 +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
  7 +int restore_rwin_state(__siginfo_rwin_t __user *rp);
  8 +
  9 +#endif /* _SIGUTIL_H */
arch/sparc/kernel/sigutil_32.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/sched.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 + int err = 0;
  16 +#ifdef CONFIG_SMP
  17 + if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
  18 + put_psr(get_psr() | PSR_EF);
  19 + fpsave(&current->thread.float_regs[0], &current->thread.fsr,
  20 + &current->thread.fpqueue[0], &current->thread.fpqdepth);
  21 + regs->psr &= ~(PSR_EF);
  22 + clear_tsk_thread_flag(current, TIF_USEDFPU);
  23 + }
  24 +#else
  25 + if (current == last_task_used_math) {
  26 + put_psr(get_psr() | PSR_EF);
  27 + fpsave(&current->thread.float_regs[0], &current->thread.fsr,
  28 + &current->thread.fpqueue[0], &current->thread.fpqdepth);
  29 + last_task_used_math = NULL;
  30 + regs->psr &= ~(PSR_EF);
  31 + }
  32 +#endif
  33 + err |= __copy_to_user(&fpu->si_float_regs[0],
  34 + &current->thread.float_regs[0],
  35 + (sizeof(unsigned long) * 32));
  36 + err |= __put_user(current->thread.fsr, &fpu->si_fsr);
  37 + err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
  38 + if (current->thread.fpqdepth != 0)
  39 + err |= __copy_to_user(&fpu->si_fpqueue[0],
  40 + &current->thread.fpqueue[0],
  41 + ((sizeof(unsigned long) +
  42 + (sizeof(unsigned long *)))*16));
  43 + clear_used_math();
  44 + return err;
  45 +}
  46 +
  47 +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
  48 +{
  49 + int err;
  50 +#ifdef CONFIG_SMP
  51 + if (test_tsk_thread_flag(current, TIF_USEDFPU))
  52 + regs->psr &= ~PSR_EF;
  53 +#else
  54 + if (current == last_task_used_math) {
  55 + last_task_used_math = NULL;
  56 + regs->psr &= ~PSR_EF;
  57 + }
  58 +#endif
  59 + set_used_math();
  60 + clear_tsk_thread_flag(current, TIF_USEDFPU);
  61 +
  62 + if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
  63 + return -EFAULT;
  64 +
  65 + err = __copy_from_user(&current->thread.float_regs[0], &fpu->si_float_regs[0],
  66 + (sizeof(unsigned long) * 32));
  67 + err |= __get_user(current->thread.fsr, &fpu->si_fsr);
  68 + err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
  69 + if (current->thread.fpqdepth != 0)
  70 + err |= __copy_from_user(&current->thread.fpqueue[0],
  71 + &fpu->si_fpqueue[0],
  72 + ((sizeof(unsigned long) +
  73 + (sizeof(unsigned long *)))*16));
  74 + return err;
  75 +}
  76 +
  77 +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
  78 +{
  79 + int i, err = __put_user(wsaved, &rwin->wsaved);
  80 +
  81 + for (i = 0; i < wsaved; i++) {
  82 + struct reg_window32 *rp;
  83 + unsigned long fp;
  84 +
  85 + rp = &current_thread_info()->reg_window[i];
  86 + fp = current_thread_info()->rwbuf_stkptrs[i];
  87 + err |= copy_to_user(&rwin->reg_window[i], rp,
  88 + sizeof(struct reg_window32));
  89 + err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
  90 + }
  91 + return err;
  92 +}
  93 +
  94 +int restore_rwin_state(__siginfo_rwin_t __user *rp)
  95 +{
  96 + struct thread_info *t = current_thread_info();
  97 + int i, wsaved, err;
  98 +
  99 + __get_user(wsaved, &rp->wsaved);
  100 + if (wsaved > NSWINS)
  101 + return -EFAULT;
  102 +
  103 + err = 0;
  104 + for (i = 0; i < wsaved; i++) {
  105 + err |= copy_from_user(&t->reg_window[i],
  106 + &rp->reg_window[i],
  107 + sizeof(struct reg_window32));
  108 + err |= __get_user(t->rwbuf_stkptrs[i],
  109 + &rp->rwbuf_stkptrs[i]);
  110 + }
  111 + if (err)
  112 + return err;
  113 +
  114 + t->w_saved = wsaved;
  115 + synchronize_user_stack();
  116 + if (t->w_saved)
  117 + return -EFAULT;
  118 + return 0;
  119 +
  120 +}
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 +
  6 +#include <asm/sigcontext.h>
  7 +#include <asm/fpumacro.h>
  8 +#include <asm/ptrace.h>
  9 +
  10 +#include "sigutil.h"
  11 +
  12 +int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
  13 +{
  14 + unsigned long *fpregs = current_thread_info()->fpregs;
  15 + unsigned long fprs;
  16 + int err = 0;
  17 +
  18 + fprs = current_thread_info()->fpsaved[0];
  19 + if (fprs & FPRS_DL)
  20 + err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
  21 + (sizeof(unsigned int) * 32));
  22 + if (fprs & FPRS_DU)
  23 + err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
  24 + (sizeof(unsigned int) * 32));
  25 + err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
  26 + err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
  27 + err |= __put_user(fprs, &fpu->si_fprs);
  28 +
  29 + return err;
  30 +}
  31 +
  32 +int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
  33 +{
  34 + unsigned long *fpregs = current_thread_info()->fpregs;
  35 + unsigned long fprs;
  36 + int err;
  37 +
  38 + err = __get_user(fprs, &fpu->si_fprs);
  39 + fprs_write(0);
  40 + regs->tstate &= ~TSTATE_PEF;
  41 + if (fprs & FPRS_DL)
  42 + err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
  43 + (sizeof(unsigned int) * 32));
  44 + if (fprs & FPRS_DU)
  45 + err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
  46 + (sizeof(unsigned int) * 32));
  47 + err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
  48 + err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
  49 + current_thread_info()->fpsaved[0] |= fprs;
  50 + return err;
  51 +}
  52 +
  53 +int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
  54 +{
  55 + int i, err = __put_user(wsaved, &rwin->wsaved);
  56 +
  57 + for (i = 0; i < wsaved; i++) {
  58 + struct reg_window *rp = &current_thread_info()->reg_window[i];
  59 + unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
  60 +
  61 + err |= copy_to_user(&rwin->reg_window[i], rp,
  62 + sizeof(struct reg_window));
  63 + err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
  64 + }
  65 + return err;
  66 +}
  67 +
  68 +int restore_rwin_state(__siginfo_rwin_t __user *rp)
  69 +{
  70 + struct thread_info *t = current_thread_info();
  71 + int i, wsaved, err;
  72 +
  73 + __get_user(wsaved, &rp->wsaved);
  74 + if (wsaved > NSWINS)
  75 + return -EFAULT;
  76 +
  77 + err = 0;
  78 + for (i = 0; i < wsaved; i++) {
  79 + err |= copy_from_user(&t->reg_window[i],
  80 + &rp->reg_window[i],
  81 + sizeof(struct reg_window));
  82 + err |= __get_user(t->rwbuf_stkptrs[i],
  83 + &rp->rwbuf_stkptrs[i]);
  84 + }
  85 + if (err)
  86 + return err;
  87 +
  88 + set_thread_wsaved(wsaved);
  89 + synchronize_user_stack();
  90 + if (get_thread_wsaved())
  91 + return -EFAULT;
  92 + return 0;
  93 +}