blob: 9415d2c918c5fc8301aa9e45c499fbe86539552c [file] [log] [blame]
David S. Miller5526b7e2008-04-27 02:26:36 -07001/* arch/sparc64/kernel/signal32.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
3 * Copyright (C) 1991, 1992 Linus Torvalds
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
7 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
8 */
9
10#include <linux/sched.h>
11#include <linux/kernel.h>
12#include <linux/signal.h>
13#include <linux/errno.h>
14#include <linux/wait.h>
15#include <linux/ptrace.h>
16#include <linux/unistd.h>
17#include <linux/mm.h>
18#include <linux/tty.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/binfmts.h>
20#include <linux/compat.h>
21#include <linux/bitops.h>
22
23#include <asm/uaccess.h>
24#include <asm/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <asm/pgtable.h>
26#include <asm/psrcompat.h>
27#include <asm/fpumacro.h>
28#include <asm/visasm.h>
David S. Miller14cc6ab2006-10-02 14:17:57 -070029#include <asm/compat_signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
32
Linus Torvalds1da177e2005-04-16 15:20:36 -070033/* This magic should be in g_upper[0] for all upper parts
34 * to be valid.
35 */
36#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
37typedef struct {
38 unsigned int g_upper[8];
39 unsigned int o_upper[8];
40 unsigned int asi;
41} siginfo_extra_v8plus_t;
42
David S. Miller5526b7e2008-04-27 02:26:36 -070043struct signal_frame32 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 struct sparc_stackf32 ss;
45 __siginfo32_t info;
46 /* __siginfo_fpu32_t * */ u32 fpu_save;
47 unsigned int insns[2];
48 unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
49 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
50 /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
51 siginfo_extra_v8plus_t v8plus;
52 __siginfo_fpu_t fpu_state;
53};
54
55typedef struct compat_siginfo{
56 int si_signo;
57 int si_errno;
58 int si_code;
59
60 union {
61 int _pad[SI_PAD_SIZE32];
62
63 /* kill() */
64 struct {
65 compat_pid_t _pid; /* sender's pid */
66 unsigned int _uid; /* sender's uid */
67 } _kill;
68
69 /* POSIX.1b timers */
70 struct {
Stephen Rothwell0d77e5a2005-06-23 00:10:14 -070071 compat_timer_t _tid; /* timer id */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 int _overrun; /* overrun count */
73 compat_sigval_t _sigval; /* same as below */
74 int _sys_private; /* not to be passed to user */
75 } _timer;
76
77 /* POSIX.1b signals */
78 struct {
79 compat_pid_t _pid; /* sender's pid */
80 unsigned int _uid; /* sender's uid */
81 compat_sigval_t _sigval;
82 } _rt;
83
84 /* SIGCHLD */
85 struct {
86 compat_pid_t _pid; /* which child */
87 unsigned int _uid; /* sender's uid */
88 int _status; /* exit code */
89 compat_clock_t _utime;
90 compat_clock_t _stime;
91 } _sigchld;
92
93 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
94 struct {
95 u32 _addr; /* faulting insn/memory ref. */
96 int _trapno;
97 } _sigfault;
98
99 /* SIGPOLL */
100 struct {
101 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
102 int _fd;
103 } _sigpoll;
104 } _sifields;
105}compat_siginfo_t;
106
107struct rt_signal_frame32 {
108 struct sparc_stackf32 ss;
109 compat_siginfo_t info;
110 struct pt_regs32 regs;
111 compat_sigset_t mask;
112 /* __siginfo_fpu32_t * */ u32 fpu_save;
113 unsigned int insns[2];
114 stack_t32 stack;
115 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
116 /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
117 siginfo_extra_v8plus_t v8plus;
118 __siginfo_fpu_t fpu_state;
119};
120
121/* Align macros */
David S. Miller5526b7e2008-04-27 02:26:36 -0700122#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 7) & (~7)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 7) & (~7)))
124
125int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
126{
127 int err;
128
129 if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
130 return -EFAULT;
131
132 /* If you change siginfo_t structure, please be sure
133 this code is fixed accordingly.
134 It should never copy any pad contained in the structure
135 to avoid security leaks, but must copy the generic
136 3 ints plus the relevant union member.
137 This routine must convert siginfo from 64bit to 32bit as well
138 at the same time. */
139 err = __put_user(from->si_signo, &to->si_signo);
140 err |= __put_user(from->si_errno, &to->si_errno);
141 err |= __put_user((short)from->si_code, &to->si_code);
142 if (from->si_code < 0)
143 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
144 else {
145 switch (from->si_code >> 16) {
146 case __SI_TIMER >> 16:
147 err |= __put_user(from->si_tid, &to->si_tid);
148 err |= __put_user(from->si_overrun, &to->si_overrun);
149 err |= __put_user(from->si_int, &to->si_int);
150 break;
151 case __SI_CHLD >> 16:
152 err |= __put_user(from->si_utime, &to->si_utime);
153 err |= __put_user(from->si_stime, &to->si_stime);
154 err |= __put_user(from->si_status, &to->si_status);
155 default:
156 err |= __put_user(from->si_pid, &to->si_pid);
157 err |= __put_user(from->si_uid, &to->si_uid);
158 break;
159 case __SI_FAULT >> 16:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 err |= __put_user(from->si_trapno, &to->si_trapno);
161 err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
162 break;
Jurij Smakov9c7d3b32005-04-17 18:03:12 -0700163 case __SI_POLL >> 16:
164 err |= __put_user(from->si_band, &to->si_band);
165 err |= __put_user(from->si_fd, &to->si_fd);
166 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
168 case __SI_MESGQ >> 16:
169 err |= __put_user(from->si_pid, &to->si_pid);
170 err |= __put_user(from->si_uid, &to->si_uid);
171 err |= __put_user(from->si_int, &to->si_int);
172 break;
173 }
174 }
175 return err;
176}
177
178/* CAUTION: This is just a very minimalist implementation for the
179 * sake of compat_sys_rt_sigqueueinfo()
180 */
181int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
182{
183 if (!access_ok(VERIFY_WRITE, from, sizeof(compat_siginfo_t)))
184 return -EFAULT;
185
186 if (copy_from_user(to, from, 3*sizeof(int)) ||
187 copy_from_user(to->_sifields._pad, from->_sifields._pad,
188 SI_PAD_SIZE))
189 return -EFAULT;
190
191 return 0;
192}
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
195{
196 unsigned long *fpregs = current_thread_info()->fpregs;
197 unsigned long fprs;
198 int err;
199
200 err = __get_user(fprs, &fpu->si_fprs);
201 fprs_write(0);
202 regs->tstate &= ~TSTATE_PEF;
203 if (fprs & FPRS_DL)
204 err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
205 if (fprs & FPRS_DU)
206 err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
207 err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
208 err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
209 current_thread_info()->fpsaved[0] |= fprs;
210 return err;
211}
212
David S. Miller5526b7e2008-04-27 02:26:36 -0700213void do_sigreturn32(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
David S. Miller5526b7e2008-04-27 02:26:36 -0700215 struct signal_frame32 __user *sf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 unsigned int psr;
217 unsigned pc, npc, fpu_save;
218 sigset_t set;
219 unsigned seta[_COMPAT_NSIG_WORDS];
220 int err, i;
221
David S. Miller5526b7e2008-04-27 02:26:36 -0700222 /* Always make any pending restarted system calls return -EINTR */
223 current_thread_info()->restart_block.fn = do_no_restart_syscall;
224
225 synchronize_user_stack();
226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
David S. Miller5526b7e2008-04-27 02:26:36 -0700228 sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 /* 1. Make sure we are not getting garbage from the user */
231 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
232 (((unsigned long) sf) & 3))
233 goto segv;
234
235 get_user(pc, &sf->info.si_regs.pc);
236 __get_user(npc, &sf->info.si_regs.npc);
237
238 if ((pc | npc) & 3)
239 goto segv;
240
241 if (test_thread_flag(TIF_32BIT)) {
242 pc &= 0xffffffff;
243 npc &= 0xffffffff;
244 }
245 regs->tpc = pc;
246 regs->tnpc = npc;
247
248 /* 2. Restore the state */
249 err = __get_user(regs->y, &sf->info.si_regs.y);
250 err |= __get_user(psr, &sf->info.si_regs.psr);
251
252 for (i = UREG_G1; i <= UREG_I7; i++)
253 err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
254 if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
255 err |= __get_user(i, &sf->v8plus.g_upper[0]);
256 if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
257 unsigned long asi;
258
259 for (i = UREG_G1; i <= UREG_I7; i++)
260 err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
261 err |= __get_user(asi, &sf->v8plus.asi);
262 regs->tstate &= ~TSTATE_ASI;
263 regs->tstate |= ((asi & 0xffUL) << 24UL);
264 }
265 }
266
267 /* User can only change condition codes in %tstate. */
268 regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
269 regs->tstate |= psr_to_tstate_icc(psr);
270
David S. Miller2678fef2008-05-01 03:30:22 -0700271 /* Prevent syscall restart. */
272 pt_regs_clear_trap_type(regs);
273
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 err |= __get_user(fpu_save, &sf->fpu_save);
275 if (fpu_save)
276 err |= restore_fpu_state32(regs, &sf->fpu_state);
277 err |= __get_user(seta[0], &sf->info.si_mask);
278 err |= copy_from_user(seta+1, &sf->extramask,
279 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
280 if (err)
281 goto segv;
282 switch (_NSIG_WORDS) {
283 case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
284 case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);
285 case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
286 case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
287 }
288 sigdelsetmask(&set, ~_BLOCKABLE);
289 spin_lock_irq(&current->sighand->siglock);
290 current->blocked = set;
291 recalc_sigpending();
292 spin_unlock_irq(&current->sighand->siglock);
293 return;
294
295segv:
296 force_sig(SIGSEGV, current);
297}
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
300{
301 struct rt_signal_frame32 __user *sf;
302 unsigned int psr, pc, npc, fpu_save, u_ss_sp;
303 mm_segment_t old_fs;
304 sigset_t set;
305 compat_sigset_t seta;
306 stack_t st;
307 int err, i;
308
309 /* Always make any pending restarted system calls return -EINTR */
310 current_thread_info()->restart_block.fn = do_no_restart_syscall;
311
312 synchronize_user_stack();
313 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
314 sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
315
316 /* 1. Make sure we are not getting garbage from the user */
317 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
318 (((unsigned long) sf) & 3))
319 goto segv;
320
321 get_user(pc, &sf->regs.pc);
322 __get_user(npc, &sf->regs.npc);
323
324 if ((pc | npc) & 3)
325 goto segv;
326
327 if (test_thread_flag(TIF_32BIT)) {
328 pc &= 0xffffffff;
329 npc &= 0xffffffff;
330 }
331 regs->tpc = pc;
332 regs->tnpc = npc;
333
334 /* 2. Restore the state */
335 err = __get_user(regs->y, &sf->regs.y);
336 err |= __get_user(psr, &sf->regs.psr);
337
338 for (i = UREG_G1; i <= UREG_I7; i++)
339 err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
340 if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
341 err |= __get_user(i, &sf->v8plus.g_upper[0]);
342 if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
343 unsigned long asi;
344
345 for (i = UREG_G1; i <= UREG_I7; i++)
346 err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
347 err |= __get_user(asi, &sf->v8plus.asi);
348 regs->tstate &= ~TSTATE_ASI;
349 regs->tstate |= ((asi & 0xffUL) << 24UL);
350 }
351 }
352
353 /* User can only change condition codes in %tstate. */
354 regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
355 regs->tstate |= psr_to_tstate_icc(psr);
356
David S. Miller2678fef2008-05-01 03:30:22 -0700357 /* Prevent syscall restart. */
358 pt_regs_clear_trap_type(regs);
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 err |= __get_user(fpu_save, &sf->fpu_save);
361 if (fpu_save)
362 err |= restore_fpu_state32(regs, &sf->fpu_state);
363 err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
364 err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
365 st.ss_sp = compat_ptr(u_ss_sp);
366 err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
367 err |= __get_user(st.ss_size, &sf->stack.ss_size);
368 if (err)
369 goto segv;
370
371 /* It is more difficult to avoid calling this function than to
372 call it and ignore errors. */
373 old_fs = get_fs();
374 set_fs(KERNEL_DS);
375 do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
376 set_fs(old_fs);
377
378 switch (_NSIG_WORDS) {
379 case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
380 case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
381 case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32);
382 case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
383 }
384 sigdelsetmask(&set, ~_BLOCKABLE);
385 spin_lock_irq(&current->sighand->siglock);
386 current->blocked = set;
387 recalc_sigpending();
388 spin_unlock_irq(&current->sighand->siglock);
389 return;
390segv:
391 force_sig(SIGSEGV, current);
392}
393
394/* Checks if the fp is valid */
395static int invalid_frame_pointer(void __user *fp, int fplen)
396{
397 if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
398 return 1;
399 return 0;
400}
401
402static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
403{
404 unsigned long sp;
405
406 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
407 sp = regs->u_regs[UREG_FP];
408
409 /* This is the X/Open sanctioned signal stack switching. */
410 if (sa->sa_flags & SA_ONSTACK) {
411 if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
412 sp = current->sas_ss_sp + current->sas_ss_size;
413 }
414 return (void __user *)(sp - framesize);
415}
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
418{
419 unsigned long *fpregs = current_thread_info()->fpregs;
420 unsigned long fprs;
421 int err = 0;
422
423 fprs = current_thread_info()->fpsaved[0];
424 if (fprs & FPRS_DL)
425 err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
426 (sizeof(unsigned int) * 32));
427 if (fprs & FPRS_DU)
428 err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
429 (sizeof(unsigned int) * 32));
430 err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
431 err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
432 err |= __put_user(fprs, &fpu->si_fprs);
433
434 return err;
435}
436
David S. Miller5526b7e2008-04-27 02:26:36 -0700437static void setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
438 int signo, sigset_t *oldset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
David S. Miller5526b7e2008-04-27 02:26:36 -0700440 struct signal_frame32 __user *sf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 int sigframe_size;
442 u32 psr;
443 int i, err;
444 unsigned int seta[_COMPAT_NSIG_WORDS];
445
446 /* 1. Make sure everything is clean */
447 synchronize_user_stack();
448 save_and_clear_fpu();
449
David S. Miller5526b7e2008-04-27 02:26:36 -0700450 sigframe_size = SF_ALIGNEDSZ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
452 sigframe_size -= sizeof(__siginfo_fpu_t);
453
David S. Miller5526b7e2008-04-27 02:26:36 -0700454 sf = (struct signal_frame32 __user *)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 get_sigframe(&ka->sa, regs, sigframe_size);
456
457 if (invalid_frame_pointer(sf, sigframe_size))
458 goto sigill;
459
460 if (get_thread_wsaved() != 0)
461 goto sigill;
462
463 /* 2. Save the current process state */
464 if (test_thread_flag(TIF_32BIT)) {
465 regs->tpc &= 0xffffffff;
466 regs->tnpc &= 0xffffffff;
467 }
468 err = put_user(regs->tpc, &sf->info.si_regs.pc);
469 err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
470 err |= __put_user(regs->y, &sf->info.si_regs.y);
471 psr = tstate_to_psr(regs->tstate);
472 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
473 psr |= PSR_EF;
474 err |= __put_user(psr, &sf->info.si_regs.psr);
475 for (i = 0; i < 16; i++)
476 err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
477 err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
478 err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
479 for (i = 1; i < 16; i++)
480 err |= __put_user(((u32 *)regs->u_regs)[2*i],
481 &sf->v8plus.g_upper[i]);
482 err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
483 &sf->v8plus.asi);
484
485 if (psr & PSR_EF) {
486 err |= save_fpu_state32(regs, &sf->fpu_state);
487 err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
488 } else {
489 err |= __put_user(0, &sf->fpu_save);
490 }
491
492 switch (_NSIG_WORDS) {
493 case 4: seta[7] = (oldset->sig[3] >> 32);
494 seta[6] = oldset->sig[3];
495 case 3: seta[5] = (oldset->sig[2] >> 32);
496 seta[4] = oldset->sig[2];
497 case 2: seta[3] = (oldset->sig[1] >> 32);
498 seta[2] = oldset->sig[1];
499 case 1: seta[1] = (oldset->sig[0] >> 32);
500 seta[0] = oldset->sig[0];
501 }
502 err |= __put_user(seta[0], &sf->info.si_mask);
503 err |= __copy_to_user(sf->extramask, seta + 1,
504 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
505
506 err |= copy_in_user((u32 __user *)sf,
507 (u32 __user *)(regs->u_regs[UREG_FP]),
508 sizeof(struct reg_window32));
509
510 if (err)
511 goto sigsegv;
512
513 /* 3. signal handler back-trampoline and parameters */
514 regs->u_regs[UREG_FP] = (unsigned long) sf;
515 regs->u_regs[UREG_I0] = signo;
516 regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
517 regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
518
519 /* 4. signal handler */
520 regs->tpc = (unsigned long) ka->sa.sa_handler;
521 regs->tnpc = (regs->tpc + 4);
522 if (test_thread_flag(TIF_32BIT)) {
523 regs->tpc &= 0xffffffff;
524 regs->tnpc &= 0xffffffff;
525 }
526
527 /* 5. return to kernel instructions */
528 if (ka->ka_restorer) {
529 regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
530 } else {
531 /* Flush instruction space. */
532 unsigned long address = ((unsigned long)&(sf->insns[0]));
533 pgd_t *pgdp = pgd_offset(current->mm, address);
534 pud_t *pudp = pud_offset(pgdp, address);
535 pmd_t *pmdp = pmd_offset(pudp, address);
536 pte_t *ptep;
Hugh Dickinsb8ae4862005-11-07 14:08:46 -0800537 pte_t pte;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
540
541 err = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
542 err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
543 if (err)
544 goto sigsegv;
545
546 preempt_disable();
547 ptep = pte_offset_map(pmdp, address);
Hugh Dickinsb8ae4862005-11-07 14:08:46 -0800548 pte = *ptep;
549 if (pte_present(pte)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 unsigned long page = (unsigned long)
Hugh Dickinsb8ae4862005-11-07 14:08:46 -0800551 page_address(pte_page(pte));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
David S. Miller4f071182005-08-29 12:46:22 -0700553 wmb();
554 __asm__ __volatile__("flush %0 + %1"
555 : /* no outputs */
556 : "r" (page),
557 "r" (address & (PAGE_SIZE - 1))
558 : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
560 pte_unmap(ptep);
561 preempt_enable();
562 }
563 return;
564
565sigill:
566 do_exit(SIGILL);
567sigsegv:
568 force_sigsegv(signo, current);
569}
570
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
572 unsigned long signr, sigset_t *oldset,
573 siginfo_t *info)
574{
575 struct rt_signal_frame32 __user *sf;
576 int sigframe_size;
577 u32 psr;
578 int i, err;
579 compat_sigset_t seta;
580
581 /* 1. Make sure everything is clean */
582 synchronize_user_stack();
583 save_and_clear_fpu();
584
585 sigframe_size = RT_ALIGNEDSZ;
586 if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
587 sigframe_size -= sizeof(__siginfo_fpu_t);
588
589 sf = (struct rt_signal_frame32 __user *)
590 get_sigframe(&ka->sa, regs, sigframe_size);
591
592 if (invalid_frame_pointer(sf, sigframe_size))
593 goto sigill;
594
595 if (get_thread_wsaved() != 0)
596 goto sigill;
597
598 /* 2. Save the current process state */
599 if (test_thread_flag(TIF_32BIT)) {
600 regs->tpc &= 0xffffffff;
601 regs->tnpc &= 0xffffffff;
602 }
603 err = put_user(regs->tpc, &sf->regs.pc);
604 err |= __put_user(regs->tnpc, &sf->regs.npc);
605 err |= __put_user(regs->y, &sf->regs.y);
606 psr = tstate_to_psr(regs->tstate);
607 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
608 psr |= PSR_EF;
609 err |= __put_user(psr, &sf->regs.psr);
610 for (i = 0; i < 16; i++)
611 err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
612 err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
613 err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
614 for (i = 1; i < 16; i++)
615 err |= __put_user(((u32 *)regs->u_regs)[2*i],
616 &sf->v8plus.g_upper[i]);
617 err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
618 &sf->v8plus.asi);
619
620 if (psr & PSR_EF) {
621 err |= save_fpu_state32(regs, &sf->fpu_state);
622 err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
623 } else {
624 err |= __put_user(0, &sf->fpu_save);
625 }
626
627 /* Update the siginfo structure. */
628 err |= copy_siginfo_to_user32(&sf->info, info);
629
630 /* Setup sigaltstack */
631 err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
632 err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
633 err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
634
635 switch (_NSIG_WORDS) {
636 case 4: seta.sig[7] = (oldset->sig[3] >> 32);
637 seta.sig[6] = oldset->sig[3];
638 case 3: seta.sig[5] = (oldset->sig[2] >> 32);
639 seta.sig[4] = oldset->sig[2];
640 case 2: seta.sig[3] = (oldset->sig[1] >> 32);
641 seta.sig[2] = oldset->sig[1];
642 case 1: seta.sig[1] = (oldset->sig[0] >> 32);
643 seta.sig[0] = oldset->sig[0];
644 }
645 err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
646
647 err |= copy_in_user((u32 __user *)sf,
648 (u32 __user *)(regs->u_regs[UREG_FP]),
649 sizeof(struct reg_window32));
650 if (err)
651 goto sigsegv;
652
653 /* 3. signal handler back-trampoline and parameters */
654 regs->u_regs[UREG_FP] = (unsigned long) sf;
655 regs->u_regs[UREG_I0] = signr;
656 regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
657 regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
658
659 /* 4. signal handler */
660 regs->tpc = (unsigned long) ka->sa.sa_handler;
661 regs->tnpc = (regs->tpc + 4);
662 if (test_thread_flag(TIF_32BIT)) {
663 regs->tpc &= 0xffffffff;
664 regs->tnpc &= 0xffffffff;
665 }
666
667 /* 5. return to kernel instructions */
668 if (ka->ka_restorer)
669 regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
670 else {
671 /* Flush instruction space. */
672 unsigned long address = ((unsigned long)&(sf->insns[0]));
673 pgd_t *pgdp = pgd_offset(current->mm, address);
674 pud_t *pudp = pud_offset(pgdp, address);
675 pmd_t *pmdp = pmd_offset(pudp, address);
676 pte_t *ptep;
677
678 regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
679
680 /* mov __NR_rt_sigreturn, %g1 */
681 err |= __put_user(0x82102065, &sf->insns[0]);
682
683 /* t 0x10 */
684 err |= __put_user(0x91d02010, &sf->insns[1]);
685 if (err)
686 goto sigsegv;
687
688 preempt_disable();
689 ptep = pte_offset_map(pmdp, address);
690 if (pte_present(*ptep)) {
691 unsigned long page = (unsigned long)
692 page_address(pte_page(*ptep));
693
David S. Miller4f071182005-08-29 12:46:22 -0700694 wmb();
695 __asm__ __volatile__("flush %0 + %1"
696 : /* no outputs */
697 : "r" (page),
698 "r" (address & (PAGE_SIZE - 1))
699 : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 }
701 pte_unmap(ptep);
702 preempt_enable();
703 }
704 return;
705
706sigill:
707 do_exit(SIGILL);
708sigsegv:
709 force_sigsegv(signr, current);
710}
711
712static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
713 siginfo_t *info,
David S. Millerec98c6b2008-04-20 02:14:23 -0700714 sigset_t *oldset, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
David S. Millerec98c6b2008-04-20 02:14:23 -0700716 if (ka->sa.sa_flags & SA_SIGINFO)
717 setup_rt_frame32(ka, regs, signr, oldset, info);
David S. Millerec98c6b2008-04-20 02:14:23 -0700718 else
David S. Miller5526b7e2008-04-27 02:26:36 -0700719 setup_frame32(ka, regs, signr, oldset);
720
Steven Rostedt69be8f12005-08-29 11:44:09 -0400721 spin_lock_irq(&current->sighand->siglock);
722 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
723 if (!(ka->sa.sa_flags & SA_NOMASK))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 sigaddset(&current->blocked,signr);
Steven Rostedt69be8f12005-08-29 11:44:09 -0400725 recalc_sigpending();
726 spin_unlock_irq(&current->sighand->siglock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727}
728
729static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
730 struct sigaction *sa)
731{
732 switch (regs->u_regs[UREG_I0]) {
733 case ERESTART_RESTARTBLOCK:
734 case ERESTARTNOHAND:
735 no_system_call_restart:
736 regs->u_regs[UREG_I0] = EINTR;
737 regs->tstate |= TSTATE_ICARRY;
738 break;
739 case ERESTARTSYS:
740 if (!(sa->sa_flags & SA_RESTART))
741 goto no_system_call_restart;
742 /* fallthrough */
743 case ERESTARTNOINTR:
744 regs->u_regs[UREG_I0] = orig_i0;
745 regs->tpc -= 4;
746 regs->tnpc -= 4;
747 }
748}
749
750/* Note that 'init' is a special process: it doesn't get signals it doesn't
751 * want to handle. Thus you cannot kill init even with a SIGKILL even by
752 * mistake.
753 */
David S. Miller2d7d5f02006-01-19 02:42:49 -0800754void do_signal32(sigset_t *oldset, struct pt_regs * regs,
David S. Miller238468b2008-04-24 03:01:48 -0700755 struct signal_deliver_cookie *cookie)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 struct k_sigaction ka;
David S. Miller238468b2008-04-24 03:01:48 -0700758 siginfo_t info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 int signr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760
David S. Miller238468b2008-04-24 03:01:48 -0700761 signr = get_signal_to_deliver(&info, &ka, regs, cookie);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (signr > 0) {
David S. Miller238468b2008-04-24 03:01:48 -0700763 if (cookie->restart_syscall)
764 syscall_restart32(cookie->orig_i0, regs, &ka.sa);
David S. Millerec98c6b2008-04-20 02:14:23 -0700765 handle_signal32(signr, &ka, &info, oldset, regs);
David S. Miller2d7d5f02006-01-19 02:42:49 -0800766
767 /* a signal was successfully delivered; the saved
768 * sigmask will have been stored in the signal frame,
769 * and will be restored by sigreturn, so we can simply
770 * clear the TIF_RESTORE_SIGMASK flag.
771 */
772 if (test_thread_flag(TIF_RESTORE_SIGMASK))
773 clear_thread_flag(TIF_RESTORE_SIGMASK);
774 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
David S. Miller238468b2008-04-24 03:01:48 -0700776 if (cookie->restart_syscall &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
778 regs->u_regs[UREG_I0] == ERESTARTSYS ||
779 regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
780 /* replay the system call when we are done */
David S. Miller238468b2008-04-24 03:01:48 -0700781 regs->u_regs[UREG_I0] = cookie->orig_i0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 regs->tpc -= 4;
783 regs->tnpc -= 4;
784 }
David S. Miller238468b2008-04-24 03:01:48 -0700785 if (cookie->restart_syscall &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
787 regs->u_regs[UREG_G1] = __NR_restart_syscall;
788 regs->tpc -= 4;
789 regs->tnpc -= 4;
790 }
David S. Miller2d7d5f02006-01-19 02:42:49 -0800791
792 /* if there's no signal to deliver, we just put the saved sigmask
793 * back
794 */
795 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
796 clear_thread_flag(TIF_RESTORE_SIGMASK);
797 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799}
800
801struct sigstack32 {
802 u32 the_stack;
803 int cur_status;
804};
805
806asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
807{
808 struct sigstack32 __user *ssptr =
809 (struct sigstack32 __user *)((unsigned long)(u_ssptr));
810 struct sigstack32 __user *ossptr =
811 (struct sigstack32 __user *)((unsigned long)(u_ossptr));
812 int ret = -EFAULT;
813
814 /* First see if old state is wanted. */
815 if (ossptr) {
816 if (put_user(current->sas_ss_sp + current->sas_ss_size,
817 &ossptr->the_stack) ||
818 __put_user(on_sig_stack(sp), &ossptr->cur_status))
819 goto out;
820 }
821
822 /* Now see if we want to update the new state. */
823 if (ssptr) {
824 u32 ss_sp;
825
826 if (get_user(ss_sp, &ssptr->the_stack))
827 goto out;
828
829 /* If the current stack was set with sigaltstack, don't
830 * swap stacks while we are on it.
831 */
832 ret = -EPERM;
833 if (current->sas_ss_sp && on_sig_stack(sp))
834 goto out;
835
836 /* Since we don't know the extent of the stack, and we don't
837 * track onstack-ness, but rather calculate it, we must
838 * presume a size. Ho hum this interface is lossy.
839 */
840 current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
841 current->sas_ss_size = SIGSTKSZ;
842 }
843
844 ret = 0;
845out:
846 return ret;
847}
848
849asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
850{
851 stack_t uss, uoss;
852 u32 u_ss_sp = 0;
853 int ret;
854 mm_segment_t old_fs;
855 stack_t32 __user *uss32 = compat_ptr(ussa);
856 stack_t32 __user *uoss32 = compat_ptr(uossa);
857
858 if (ussa && (get_user(u_ss_sp, &uss32->ss_sp) ||
859 __get_user(uss.ss_flags, &uss32->ss_flags) ||
860 __get_user(uss.ss_size, &uss32->ss_size)))
861 return -EFAULT;
862 uss.ss_sp = compat_ptr(u_ss_sp);
863 old_fs = get_fs();
864 set_fs(KERNEL_DS);
865 ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL,
866 uossa ? (stack_t __user *) &uoss : NULL, sp);
867 set_fs(old_fs);
868 if (!ret && uossa && (put_user(ptr_to_compat(uoss.ss_sp), &uoss32->ss_sp) ||
869 __put_user(uoss.ss_flags, &uoss32->ss_flags) ||
870 __put_user(uoss.ss_size, &uoss32->ss_size)))
871 return -EFAULT;
872 return ret;
873}