aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/signal_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/signal_32.c')
-rw-r--r--arch/sparc/kernel/signal_32.c172
1 files changed, 79 insertions, 93 deletions
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 5e5c5fd0378..04ede8f04ad 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -26,6 +26,8 @@
26#include <asm/pgtable.h> 26#include <asm/pgtable.h>
27#include <asm/cacheflush.h> /* flush_sig_insns */ 27#include <asm/cacheflush.h> /* flush_sig_insns */
28 28
29#include "sigutil.h"
30
29#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 31#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
30 32
31extern void fpsave(unsigned long *fpregs, unsigned long *fsr, 33extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -39,8 +41,8 @@ struct signal_frame {
39 unsigned long insns[2] __attribute__ ((aligned (8))); 41 unsigned long insns[2] __attribute__ ((aligned (8)));
40 unsigned int extramask[_NSIG_WORDS - 1]; 42 unsigned int extramask[_NSIG_WORDS - 1];
41 unsigned int extra_size; /* Should be 0 */ 43 unsigned int extra_size; /* Should be 0 */
42 __siginfo_fpu_t fpu_state; 44 __siginfo_rwin_t __user *rwin_save;
43}; 45} __attribute__((aligned(8)));
44 46
45struct rt_signal_frame { 47struct rt_signal_frame {
46 struct sparc_stackf ss; 48 struct sparc_stackf ss;
@@ -51,8 +53,8 @@ struct rt_signal_frame {
51 unsigned int insns[2]; 53 unsigned int insns[2];
52 stack_t stack; 54 stack_t stack;
53 unsigned int extra_size; /* Should be 0 */ 55 unsigned int extra_size; /* Should be 0 */
54 __siginfo_fpu_t fpu_state; 56 __siginfo_rwin_t __user *rwin_save;
55}; 57} __attribute__((aligned(8)));
56 58
57/* Align macros */ 59/* Align macros */
58#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) 60#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
@@ -79,43 +81,13 @@ asmlinkage int sys_sigsuspend(old_sigset_t set)
79 return _sigpause_common(set); 81 return _sigpause_common(set);
80} 82}
81 83
82static inline int
83restore_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
113asmlinkage void do_sigreturn(struct pt_regs *regs) 84asmlinkage void do_sigreturn(struct pt_regs *regs)
114{ 85{
115 struct signal_frame __user *sf; 86 struct signal_frame __user *sf;
116 unsigned long up_psr, pc, npc; 87 unsigned long up_psr, pc, npc;
117 sigset_t set; 88 sigset_t set;
118 __siginfo_fpu_t __user *fpu_save; 89 __siginfo_fpu_t __user *fpu_save;
90 __siginfo_rwin_t __user *rwin_save;
119 int err; 91 int err;
120 92
121 /* Always make any pending restarted system calls return -EINTR */ 93 /* Always make any pending restarted system calls return -EINTR */
@@ -150,9 +122,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
150 pt_regs_clear_syscall(regs); 122 pt_regs_clear_syscall(regs);
151 123
152 err |= __get_user(fpu_save, &sf->fpu_save); 124 err |= __get_user(fpu_save, &sf->fpu_save);
153
154 if (fpu_save) 125 if (fpu_save)
155 err |= restore_fpu_state(regs, fpu_save); 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 /* This is pretty much atomic, no amount locking would prevent 131 /* This is pretty much atomic, no amount locking would prevent
158 * the races which exist anyways. 132 * the races which exist anyways.
@@ -180,6 +154,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
180 struct rt_signal_frame __user *sf; 154 struct rt_signal_frame __user *sf;
181 unsigned int psr, pc, npc; 155 unsigned int psr, pc, npc;
182 __siginfo_fpu_t __user *fpu_save; 156 __siginfo_fpu_t __user *fpu_save;
157 __siginfo_rwin_t __user *rwin_save;
183 mm_segment_t old_fs; 158 mm_segment_t old_fs;
184 sigset_t set; 159 sigset_t set;
185 stack_t st; 160 stack_t st;
@@ -207,8 +182,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
207 pt_regs_clear_syscall(regs); 182 pt_regs_clear_syscall(regs);
208 183
209 err |= __get_user(fpu_save, &sf->fpu_save); 184 err |= __get_user(fpu_save, &sf->fpu_save);
210 185 if (!err && fpu_save)
211 if (fpu_save)
212 err |= restore_fpu_state(regs, fpu_save); 186 err |= restore_fpu_state(regs, fpu_save);
213 err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); 187 err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
214 188
@@ -228,6 +202,12 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
228 do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf); 202 do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
229 set_fs(old_fs); 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 sigdelsetmask(&set, ~_BLOCKABLE); 211 sigdelsetmask(&set, ~_BLOCKABLE);
232 spin_lock_irq(&current->sighand->siglock); 212 spin_lock_irq(&current->sighand->siglock);
233 current->blocked = set; 213 current->blocked = set;
@@ -280,53 +260,23 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
280 return (void __user *) sp; 260 return (void __user *) sp;
281} 261}
282 262
283static inline int
284save_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
318static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, 263static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
319 int signo, sigset_t *oldset) 264 int signo, sigset_t *oldset)
320{ 265{
321 struct signal_frame __user *sf; 266 struct signal_frame __user *sf;
322 int sigframe_size, err; 267 int sigframe_size, err, wsaved;
268 void __user *tail;
323 269
324 /* 1. Make sure everything is clean */ 270 /* 1. Make sure everything is clean */
325 synchronize_user_stack(); 271 synchronize_user_stack();
326 272
327 sigframe_size = SF_ALIGNEDSZ; 273 wsaved = current_thread_info()->w_saved;
328 if (!used_math()) 274
329 sigframe_size -= sizeof(__siginfo_fpu_t); 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);
330 280
331 sf = (struct signal_frame __user *) 281 sf = (struct signal_frame __user *)
332 get_sigframe(&ka->sa, regs, sigframe_size); 282 get_sigframe(&ka->sa, regs, sigframe_size);
@@ -334,8 +284,7 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
334 if (invalid_frame_pointer(sf, sigframe_size)) 284 if (invalid_frame_pointer(sf, sigframe_size))
335 goto sigill_and_return; 285 goto sigill_and_return;
336 286
337 if (current_thread_info()->w_saved != 0) 287 tail = sf + 1;
338 goto sigill_and_return;
339 288
340 /* 2. Save the current process state */ 289 /* 2. Save the current process state */
341 err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs)); 290 err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
@@ -343,17 +292,34 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
343 err |= __put_user(0, &sf->extra_size); 292 err |= __put_user(0, &sf->extra_size);
344 293
345 if (used_math()) { 294 if (used_math()) {
346 err |= save_fpu_state(regs, &sf->fpu_state); 295 __siginfo_fpu_t __user *fp = tail;
347 err |= __put_user(&sf->fpu_state, &sf->fpu_save); 296 tail += sizeof(*fp);
297 err |= save_fpu_state(regs, fp);
298 err |= __put_user(fp, &sf->fpu_save);
348 } else { 299 } else {
349 err |= __put_user(0, &sf->fpu_save); 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 err |= __put_user(oldset->sig[0], &sf->info.si_mask); 311 err |= __put_user(oldset->sig[0], &sf->info.si_mask);
353 err |= __copy_to_user(sf->extramask, &oldset->sig[1], 312 err |= __copy_to_user(sf->extramask, &oldset->sig[1],
354 (_NSIG_WORDS - 1) * sizeof(unsigned int)); 313 (_NSIG_WORDS - 1) * sizeof(unsigned int));
355 err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], 314 if (!wsaved) {
356 sizeof(struct reg_window32)); 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 if (err) 323 if (err)
358 goto sigsegv; 324 goto sigsegv;
359 325
@@ -399,21 +365,24 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
399 int signo, sigset_t *oldset, siginfo_t *info) 365 int signo, sigset_t *oldset, siginfo_t *info)
400{ 366{
401 struct rt_signal_frame __user *sf; 367 struct rt_signal_frame __user *sf;
402 int sigframe_size; 368 int sigframe_size, wsaved;
369 void __user *tail;
403 unsigned int psr; 370 unsigned int psr;
404 int err; 371 int err;
405 372
406 synchronize_user_stack(); 373 synchronize_user_stack();
407 sigframe_size = RT_ALIGNEDSZ; 374 wsaved = current_thread_info()->w_saved;
408 if (!used_math()) 375 sigframe_size = sizeof(*sf);
409 sigframe_size -= sizeof(__siginfo_fpu_t); 376 if (used_math())
377 sigframe_size += sizeof(__siginfo_fpu_t);
378 if (wsaved)
379 sigframe_size += sizeof(__siginfo_rwin_t);
410 sf = (struct rt_signal_frame __user *) 380 sf = (struct rt_signal_frame __user *)
411 get_sigframe(&ka->sa, regs, sigframe_size); 381 get_sigframe(&ka->sa, regs, sigframe_size);
412 if (invalid_frame_pointer(sf, sigframe_size)) 382 if (invalid_frame_pointer(sf, sigframe_size))
413 goto sigill; 383 goto sigill;
414 if (current_thread_info()->w_saved != 0)
415 goto sigill;
416 384
385 tail = sf + 1;
417 err = __put_user(regs->pc, &sf->regs.pc); 386 err = __put_user(regs->pc, &sf->regs.pc);
418 err |= __put_user(regs->npc, &sf->regs.npc); 387 err |= __put_user(regs->npc, &sf->regs.npc);
419 err |= __put_user(regs->y, &sf->regs.y); 388 err |= __put_user(regs->y, &sf->regs.y);
@@ -425,11 +394,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
425 err |= __put_user(0, &sf->extra_size); 394 err |= __put_user(0, &sf->extra_size);
426 395
427 if (psr & PSR_EF) { 396 if (psr & PSR_EF) {
428 err |= save_fpu_state(regs, &sf->fpu_state); 397 __siginfo_fpu_t *fp = tail;
429 err |= __put_user(&sf->fpu_state, &sf->fpu_save); 398 tail += sizeof(*fp);
399 err |= save_fpu_state(regs, fp);
400 err |= __put_user(fp, &sf->fpu_save);
430 } else { 401 } else {
431 err |= __put_user(0, &sf->fpu_save); 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 err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); 412 err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
434 413
435 /* Setup sigaltstack */ 414 /* Setup sigaltstack */
@@ -437,8 +416,15 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
437 err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); 416 err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
438 err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); 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], 419 if (!wsaved) {
441 sizeof(struct reg_window32)); 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 err |= copy_siginfo_to_user(&sf->info, info); 429 err |= copy_siginfo_to_user(&sf->info, info);
444 430