blob: 88e0d8122d2c8f7f739944ee744e9624621b9847 [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>
Roland McGrath95698462008-07-27 01:08:02 -070022#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#include <asm/uaccess.h>
25#include <asm/ptrace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <asm/pgtable.h>
27#include <asm/psrcompat.h>
28#include <asm/fpumacro.h>
29#include <asm/visasm.h>
David S. Miller14cc6ab2006-10-02 14:17:57 -070030#include <asm/compat_signal.h>
David Howellsd550bbd2012-03-28 18:30:03 +010031#include <asm/switch_to.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
David S. Miller55984732011-08-20 17:14:54 -070033#include "sigutil.h"
34
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/* This magic should be in g_upper[0] for all upper parts
38 * to be valid.
39 */
40#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269
41typedef struct {
42 unsigned int g_upper[8];
43 unsigned int o_upper[8];
44 unsigned int asi;
45} siginfo_extra_v8plus_t;
46
David S. Miller5526b7e2008-04-27 02:26:36 -070047struct signal_frame32 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 struct sparc_stackf32 ss;
49 __siginfo32_t info;
David S. Miller55984732011-08-20 17:14:54 -070050 /* __siginfo_fpu_t * */ u32 fpu_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 unsigned int insns[2];
52 unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
53 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
54 /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
55 siginfo_extra_v8plus_t v8plus;
David S. Miller55984732011-08-20 17:14:54 -070056 /* __siginfo_rwin_t * */u32 rwin_save;
57} __attribute__((aligned(8)));
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
59typedef struct compat_siginfo{
60 int si_signo;
61 int si_errno;
62 int si_code;
63
64 union {
65 int _pad[SI_PAD_SIZE32];
66
67 /* kill() */
68 struct {
69 compat_pid_t _pid; /* sender's pid */
70 unsigned int _uid; /* sender's uid */
71 } _kill;
72
73 /* POSIX.1b timers */
74 struct {
Stephen Rothwell0d77e5a2005-06-23 00:10:14 -070075 compat_timer_t _tid; /* timer id */
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 int _overrun; /* overrun count */
77 compat_sigval_t _sigval; /* same as below */
78 int _sys_private; /* not to be passed to user */
79 } _timer;
80
81 /* POSIX.1b signals */
82 struct {
83 compat_pid_t _pid; /* sender's pid */
84 unsigned int _uid; /* sender's uid */
85 compat_sigval_t _sigval;
86 } _rt;
87
88 /* SIGCHLD */
89 struct {
90 compat_pid_t _pid; /* which child */
91 unsigned int _uid; /* sender's uid */
92 int _status; /* exit code */
93 compat_clock_t _utime;
94 compat_clock_t _stime;
95 } _sigchld;
96
97 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGEMT */
98 struct {
99 u32 _addr; /* faulting insn/memory ref. */
100 int _trapno;
101 } _sigfault;
102
103 /* SIGPOLL */
104 struct {
105 int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
106 int _fd;
107 } _sigpoll;
108 } _sifields;
109}compat_siginfo_t;
110
111struct rt_signal_frame32 {
112 struct sparc_stackf32 ss;
113 compat_siginfo_t info;
114 struct pt_regs32 regs;
115 compat_sigset_t mask;
David S. Miller55984732011-08-20 17:14:54 -0700116 /* __siginfo_fpu_t * */ u32 fpu_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 unsigned int insns[2];
118 stack_t32 stack;
119 unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
120 /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
121 siginfo_extra_v8plus_t v8plus;
David S. Miller55984732011-08-20 17:14:54 -0700122 /* __siginfo_rwin_t * */u32 rwin_save;
123} __attribute__((aligned(8)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
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
David S. Miller5526b7e2008-04-27 02:26:36 -0700194void do_sigreturn32(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195{
David S. Miller5526b7e2008-04-27 02:26:36 -0700196 struct signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700197 compat_uptr_t fpu_save;
198 compat_uptr_t rwin_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 unsigned int psr;
David S. Miller55984732011-08-20 17:14:54 -0700200 unsigned pc, npc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 sigset_t set;
202 unsigned seta[_COMPAT_NSIG_WORDS];
203 int err, i;
204
David S. Miller5526b7e2008-04-27 02:26:36 -0700205 /* Always make any pending restarted system calls return -EINTR */
206 current_thread_info()->restart_block.fn = do_no_restart_syscall;
207
208 synchronize_user_stack();
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
David S. Miller5526b7e2008-04-27 02:26:36 -0700211 sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 /* 1. Make sure we are not getting garbage from the user */
214 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
215 (((unsigned long) sf) & 3))
216 goto segv;
217
Al Viro187cd442012-04-22 16:51:36 -0400218 if (get_user(pc, &sf->info.si_regs.pc) ||
219 __get_user(npc, &sf->info.si_regs.npc))
220 goto segv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221
222 if ((pc | npc) & 3)
223 goto segv;
224
225 if (test_thread_flag(TIF_32BIT)) {
226 pc &= 0xffffffff;
227 npc &= 0xffffffff;
228 }
229 regs->tpc = pc;
230 regs->tnpc = npc;
231
232 /* 2. Restore the state */
233 err = __get_user(regs->y, &sf->info.si_regs.y);
234 err |= __get_user(psr, &sf->info.si_regs.psr);
235
236 for (i = UREG_G1; i <= UREG_I7; i++)
237 err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
238 if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
239 err |= __get_user(i, &sf->v8plus.g_upper[0]);
240 if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
241 unsigned long asi;
242
243 for (i = UREG_G1; i <= UREG_I7; i++)
244 err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
245 err |= __get_user(asi, &sf->v8plus.asi);
246 regs->tstate &= ~TSTATE_ASI;
247 regs->tstate |= ((asi & 0xffUL) << 24UL);
248 }
249 }
250
251 /* User can only change condition codes in %tstate. */
252 regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
253 regs->tstate |= psr_to_tstate_icc(psr);
254
David S. Miller2678fef2008-05-01 03:30:22 -0700255 /* Prevent syscall restart. */
David S. Miller28e61032008-05-11 02:07:19 -0700256 pt_regs_clear_syscall(regs);
David S. Miller2678fef2008-05-01 03:30:22 -0700257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 err |= __get_user(fpu_save, &sf->fpu_save);
David S. Miller55984732011-08-20 17:14:54 -0700259 if (!err && fpu_save)
260 err |= restore_fpu_state(regs, compat_ptr(fpu_save));
261 err |= __get_user(rwin_save, &sf->rwin_save);
262 if (!err && rwin_save) {
263 if (restore_rwin_state(compat_ptr(rwin_save)))
264 goto segv;
265 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 err |= __get_user(seta[0], &sf->info.si_mask);
267 err |= copy_from_user(seta+1, &sf->extramask,
268 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
269 if (err)
270 goto segv;
271 switch (_NSIG_WORDS) {
272 case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32);
273 case 3: set.sig[2] = seta[4] + (((long)seta[5]) << 32);
274 case 2: set.sig[1] = seta[2] + (((long)seta[3]) << 32);
275 case 1: set.sig[0] = seta[0] + (((long)seta[1]) << 32);
276 }
277 sigdelsetmask(&set, ~_BLOCKABLE);
Matt Flemingfaddf592011-08-11 14:57:02 +0100278 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return;
280
281segv:
282 force_sig(SIGSEGV, current);
283}
284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
286{
287 struct rt_signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700288 unsigned int psr, pc, npc, u_ss_sp;
289 compat_uptr_t fpu_save;
290 compat_uptr_t rwin_save;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 mm_segment_t old_fs;
292 sigset_t set;
293 compat_sigset_t seta;
294 stack_t st;
295 int err, i;
296
297 /* Always make any pending restarted system calls return -EINTR */
298 current_thread_info()->restart_block.fn = do_no_restart_syscall;
299
300 synchronize_user_stack();
301 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
302 sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
303
304 /* 1. Make sure we are not getting garbage from the user */
305 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
306 (((unsigned long) sf) & 3))
307 goto segv;
308
Al Viro187cd442012-04-22 16:51:36 -0400309 if (get_user(pc, &sf->regs.pc) ||
310 __get_user(npc, &sf->regs.npc))
311 goto segv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312
313 if ((pc | npc) & 3)
314 goto segv;
315
316 if (test_thread_flag(TIF_32BIT)) {
317 pc &= 0xffffffff;
318 npc &= 0xffffffff;
319 }
320 regs->tpc = pc;
321 regs->tnpc = npc;
322
323 /* 2. Restore the state */
324 err = __get_user(regs->y, &sf->regs.y);
325 err |= __get_user(psr, &sf->regs.psr);
326
327 for (i = UREG_G1; i <= UREG_I7; i++)
328 err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]);
329 if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) {
330 err |= __get_user(i, &sf->v8plus.g_upper[0]);
331 if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) {
332 unsigned long asi;
333
334 for (i = UREG_G1; i <= UREG_I7; i++)
335 err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]);
336 err |= __get_user(asi, &sf->v8plus.asi);
337 regs->tstate &= ~TSTATE_ASI;
338 regs->tstate |= ((asi & 0xffUL) << 24UL);
339 }
340 }
341
342 /* User can only change condition codes in %tstate. */
343 regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC);
344 regs->tstate |= psr_to_tstate_icc(psr);
345
David S. Miller2678fef2008-05-01 03:30:22 -0700346 /* Prevent syscall restart. */
David S. Miller28e61032008-05-11 02:07:19 -0700347 pt_regs_clear_syscall(regs);
David S. Miller2678fef2008-05-01 03:30:22 -0700348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 err |= __get_user(fpu_save, &sf->fpu_save);
David S. Miller55984732011-08-20 17:14:54 -0700350 if (!err && fpu_save)
351 err |= restore_fpu_state(regs, compat_ptr(fpu_save));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
353 err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
354 st.ss_sp = compat_ptr(u_ss_sp);
355 err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
356 err |= __get_user(st.ss_size, &sf->stack.ss_size);
357 if (err)
358 goto segv;
359
360 /* It is more difficult to avoid calling this function than to
361 call it and ignore errors. */
362 old_fs = get_fs();
363 set_fs(KERNEL_DS);
364 do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
365 set_fs(old_fs);
366
David S. Miller55984732011-08-20 17:14:54 -0700367 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 switch (_NSIG_WORDS) {
374 case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
375 case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
376 case 2: set.sig[1] = seta.sig[2] + (((long)seta.sig[3]) << 32);
377 case 1: set.sig[0] = seta.sig[0] + (((long)seta.sig[1]) << 32);
378 }
379 sigdelsetmask(&set, ~_BLOCKABLE);
Matt Flemingfaddf592011-08-11 14:57:02 +0100380 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 return;
382segv:
383 force_sig(SIGSEGV, current);
384}
385
386/* Checks if the fp is valid */
387static int invalid_frame_pointer(void __user *fp, int fplen)
388{
389 if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
390 return 1;
391 return 0;
392}
393
394static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize)
395{
396 unsigned long sp;
397
398 regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL;
399 sp = regs->u_regs[UREG_FP];
400
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700401 /*
402 * If we are on the alternate signal stack and would overflow it, don't.
403 * Return an always-bogus address instead so we will die with SIGSEGV.
404 */
405 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
406 return (void __user *) -1L;
407
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 /* This is the X/Open sanctioned signal stack switching. */
409 if (sa->sa_flags & SA_ONSTACK) {
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700410 if (sas_ss_flags(sp) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 sp = current->sas_ss_sp + current->sas_ss_size;
412 }
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700413
David S. Millerf036d9f2010-02-09 16:18:40 -0800414 sp -= framesize;
415
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700416 /* Always align the stack frame. This handles two cases. First,
417 * sigaltstack need not be mindful of platform specific stack
418 * alignment. Second, if we took this signal because the stack
419 * is not aligned properly, we'd like to take the signal cleanly
420 * and report that.
421 */
David S. Millerf036d9f2010-02-09 16:18:40 -0800422 sp &= ~15UL;
David S. Millerdc5dc7e2008-05-07 18:54:05 -0700423
David S. Millerf036d9f2010-02-09 16:18:40 -0800424 return (void __user *) sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425}
426
David S. Miller05c5e762010-09-20 23:24:52 -0700427/* The I-cache flush instruction only works in the primary ASI, which
428 * right now is the nucleus, aka. kernel space.
429 *
430 * Therefore we have to kick the instructions out using the kernel
431 * side linear mapping of the physical address backing the user
432 * instructions.
433 */
434static void flush_signal_insns(unsigned long address)
435{
436 unsigned long pstate, paddr;
437 pte_t *ptep, pte;
438 pgd_t *pgdp;
439 pud_t *pudp;
440 pmd_t *pmdp;
441
442 /* Commit all stores of the instructions we are about to flush. */
443 wmb();
444
445 /* Disable cross-call reception. In this way even a very wide
446 * munmap() on another cpu can't tear down the page table
447 * hierarchy from underneath us, since that can't complete
448 * until the IPI tlb flush returns.
449 */
450
451 __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
452 __asm__ __volatile__("wrpr %0, %1, %%pstate"
453 : : "r" (pstate), "i" (PSTATE_IE));
454
455 pgdp = pgd_offset(current->mm, address);
456 if (pgd_none(*pgdp))
457 goto out_irqs_on;
458 pudp = pud_offset(pgdp, address);
459 if (pud_none(*pudp))
460 goto out_irqs_on;
461 pmdp = pmd_offset(pudp, address);
462 if (pmd_none(*pmdp))
463 goto out_irqs_on;
464
465 ptep = pte_offset_map(pmdp, address);
466 pte = *ptep;
467 if (!pte_present(pte))
468 goto out_unmap;
469
470 paddr = (unsigned long) page_address(pte_page(pte));
471
472 __asm__ __volatile__("flush %0 + %1"
473 : /* no outputs */
474 : "r" (paddr),
475 "r" (address & (PAGE_SIZE - 1))
476 : "memory");
477
478out_unmap:
479 pte_unmap(ptep);
480out_irqs_on:
481 __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
482
483}
484
David S. Miller392c2182010-09-21 21:41:12 -0700485static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
486 int signo, sigset_t *oldset)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
David S. Miller5526b7e2008-04-27 02:26:36 -0700488 struct signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700489 int i, err, wsaved;
490 void __user *tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 int sigframe_size;
492 u32 psr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 unsigned int seta[_COMPAT_NSIG_WORDS];
494
495 /* 1. Make sure everything is clean */
496 synchronize_user_stack();
497 save_and_clear_fpu();
498
David S. Miller55984732011-08-20 17:14:54 -0700499 wsaved = get_thread_wsaved();
500
501 sigframe_size = sizeof(*sf);
502 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
503 sigframe_size += sizeof(__siginfo_fpu_t);
504 if (wsaved)
505 sigframe_size += sizeof(__siginfo_rwin_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
David S. Miller5526b7e2008-04-27 02:26:36 -0700507 sf = (struct signal_frame32 __user *)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 get_sigframe(&ka->sa, regs, sigframe_size);
509
510 if (invalid_frame_pointer(sf, sigframe_size))
511 goto sigill;
512
David S. Miller55984732011-08-20 17:14:54 -0700513 tail = (sf + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514
515 /* 2. Save the current process state */
516 if (test_thread_flag(TIF_32BIT)) {
517 regs->tpc &= 0xffffffff;
518 regs->tnpc &= 0xffffffff;
519 }
520 err = put_user(regs->tpc, &sf->info.si_regs.pc);
521 err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
522 err |= __put_user(regs->y, &sf->info.si_regs.y);
523 psr = tstate_to_psr(regs->tstate);
524 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
525 psr |= PSR_EF;
526 err |= __put_user(psr, &sf->info.si_regs.psr);
527 for (i = 0; i < 16; i++)
528 err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
529 err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
530 err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
531 for (i = 1; i < 16; i++)
532 err |= __put_user(((u32 *)regs->u_regs)[2*i],
533 &sf->v8plus.g_upper[i]);
534 err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
535 &sf->v8plus.asi);
536
537 if (psr & PSR_EF) {
David S. Miller55984732011-08-20 17:14:54 -0700538 __siginfo_fpu_t __user *fp = tail;
539 tail += sizeof(*fp);
540 err |= save_fpu_state(regs, fp);
541 err |= __put_user((u64)fp, &sf->fpu_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 } else {
543 err |= __put_user(0, &sf->fpu_save);
544 }
David S. Miller55984732011-08-20 17:14:54 -0700545 if (wsaved) {
546 __siginfo_rwin_t __user *rwp = tail;
547 tail += sizeof(*rwp);
548 err |= save_rwin_state(wsaved, rwp);
549 err |= __put_user((u64)rwp, &sf->rwin_save);
550 set_thread_wsaved(0);
551 } else {
552 err |= __put_user(0, &sf->rwin_save);
553 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
555 switch (_NSIG_WORDS) {
556 case 4: seta[7] = (oldset->sig[3] >> 32);
557 seta[6] = oldset->sig[3];
558 case 3: seta[5] = (oldset->sig[2] >> 32);
559 seta[4] = oldset->sig[2];
560 case 2: seta[3] = (oldset->sig[1] >> 32);
561 seta[2] = oldset->sig[1];
562 case 1: seta[1] = (oldset->sig[0] >> 32);
563 seta[0] = oldset->sig[0];
564 }
565 err |= __put_user(seta[0], &sf->info.si_mask);
566 err |= __copy_to_user(sf->extramask, seta + 1,
567 (_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
568
David S. Miller55984732011-08-20 17:14:54 -0700569 if (!wsaved) {
570 err |= copy_in_user((u32 __user *)sf,
571 (u32 __user *)(regs->u_regs[UREG_FP]),
572 sizeof(struct reg_window32));
573 } else {
574 struct reg_window *rp;
575
576 rp = &current_thread_info()->reg_window[wsaved - 1];
577 for (i = 0; i < 8; i++)
578 err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
579 for (i = 0; i < 6; i++)
580 err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
581 err |= __put_user(rp->ins[6], &sf->ss.fp);
582 err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (err)
585 goto sigsegv;
586
587 /* 3. signal handler back-trampoline and parameters */
588 regs->u_regs[UREG_FP] = (unsigned long) sf;
589 regs->u_regs[UREG_I0] = signo;
590 regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
591 regs->u_regs[UREG_I2] = (unsigned long) &sf->info;
592
593 /* 4. signal handler */
594 regs->tpc = (unsigned long) ka->sa.sa_handler;
595 regs->tnpc = (regs->tpc + 4);
596 if (test_thread_flag(TIF_32BIT)) {
597 regs->tpc &= 0xffffffff;
598 regs->tnpc &= 0xffffffff;
599 }
600
601 /* 5. return to kernel instructions */
602 if (ka->ka_restorer) {
603 regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
604 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 unsigned long address = ((unsigned long)&(sf->insns[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
608
609 err = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
610 err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
611 if (err)
612 goto sigsegv;
David S. Miller05c5e762010-09-20 23:24:52 -0700613 flush_signal_insns(address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
David S. Millerc2785252010-09-21 22:30:13 -0700615 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617sigill:
618 do_exit(SIGILL);
David S. Miller392c2182010-09-21 21:41:12 -0700619 return -EINVAL;
620
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621sigsegv:
622 force_sigsegv(signo, current);
David S. Miller392c2182010-09-21 21:41:12 -0700623 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624}
625
David S. Miller392c2182010-09-21 21:41:12 -0700626static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
627 unsigned long signr, sigset_t *oldset,
628 siginfo_t *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 struct rt_signal_frame32 __user *sf;
David S. Miller55984732011-08-20 17:14:54 -0700631 int i, err, wsaved;
632 void __user *tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 int sigframe_size;
634 u32 psr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 compat_sigset_t seta;
636
637 /* 1. Make sure everything is clean */
638 synchronize_user_stack();
639 save_and_clear_fpu();
640
David S. Miller55984732011-08-20 17:14:54 -0700641 wsaved = get_thread_wsaved();
642
643 sigframe_size = sizeof(*sf);
644 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
645 sigframe_size += sizeof(__siginfo_fpu_t);
646 if (wsaved)
647 sigframe_size += sizeof(__siginfo_rwin_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 sf = (struct rt_signal_frame32 __user *)
650 get_sigframe(&ka->sa, regs, sigframe_size);
651
652 if (invalid_frame_pointer(sf, sigframe_size))
653 goto sigill;
654
David S. Miller55984732011-08-20 17:14:54 -0700655 tail = (sf + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 /* 2. Save the current process state */
658 if (test_thread_flag(TIF_32BIT)) {
659 regs->tpc &= 0xffffffff;
660 regs->tnpc &= 0xffffffff;
661 }
662 err = put_user(regs->tpc, &sf->regs.pc);
663 err |= __put_user(regs->tnpc, &sf->regs.npc);
664 err |= __put_user(regs->y, &sf->regs.y);
665 psr = tstate_to_psr(regs->tstate);
666 if (current_thread_info()->fpsaved[0] & FPRS_FEF)
667 psr |= PSR_EF;
668 err |= __put_user(psr, &sf->regs.psr);
669 for (i = 0; i < 16; i++)
670 err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
671 err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size);
672 err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]);
673 for (i = 1; i < 16; i++)
674 err |= __put_user(((u32 *)regs->u_regs)[2*i],
675 &sf->v8plus.g_upper[i]);
676 err |= __put_user((regs->tstate & TSTATE_ASI) >> 24UL,
677 &sf->v8plus.asi);
678
679 if (psr & PSR_EF) {
David S. Miller55984732011-08-20 17:14:54 -0700680 __siginfo_fpu_t __user *fp = tail;
681 tail += sizeof(*fp);
682 err |= save_fpu_state(regs, fp);
683 err |= __put_user((u64)fp, &sf->fpu_save);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 } else {
685 err |= __put_user(0, &sf->fpu_save);
686 }
David S. Miller55984732011-08-20 17:14:54 -0700687 if (wsaved) {
688 __siginfo_rwin_t __user *rwp = tail;
689 tail += sizeof(*rwp);
690 err |= save_rwin_state(wsaved, rwp);
691 err |= __put_user((u64)rwp, &sf->rwin_save);
692 set_thread_wsaved(0);
693 } else {
694 err |= __put_user(0, &sf->rwin_save);
695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696
697 /* Update the siginfo structure. */
698 err |= copy_siginfo_to_user32(&sf->info, info);
699
700 /* Setup sigaltstack */
701 err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
702 err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
703 err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
704
705 switch (_NSIG_WORDS) {
706 case 4: seta.sig[7] = (oldset->sig[3] >> 32);
707 seta.sig[6] = oldset->sig[3];
708 case 3: seta.sig[5] = (oldset->sig[2] >> 32);
709 seta.sig[4] = oldset->sig[2];
710 case 2: seta.sig[3] = (oldset->sig[1] >> 32);
711 seta.sig[2] = oldset->sig[1];
712 case 1: seta.sig[1] = (oldset->sig[0] >> 32);
713 seta.sig[0] = oldset->sig[0];
714 }
715 err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
716
David S. Miller55984732011-08-20 17:14:54 -0700717 if (!wsaved) {
718 err |= copy_in_user((u32 __user *)sf,
719 (u32 __user *)(regs->u_regs[UREG_FP]),
720 sizeof(struct reg_window32));
721 } else {
722 struct reg_window *rp;
723
724 rp = &current_thread_info()->reg_window[wsaved - 1];
725 for (i = 0; i < 8; i++)
726 err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
727 for (i = 0; i < 6; i++)
728 err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
729 err |= __put_user(rp->ins[6], &sf->ss.fp);
730 err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (err)
733 goto sigsegv;
734
735 /* 3. signal handler back-trampoline and parameters */
736 regs->u_regs[UREG_FP] = (unsigned long) sf;
737 regs->u_regs[UREG_I0] = signr;
738 regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
739 regs->u_regs[UREG_I2] = (unsigned long) &sf->regs;
740
741 /* 4. signal handler */
742 regs->tpc = (unsigned long) ka->sa.sa_handler;
743 regs->tnpc = (regs->tpc + 4);
744 if (test_thread_flag(TIF_32BIT)) {
745 regs->tpc &= 0xffffffff;
746 regs->tnpc &= 0xffffffff;
747 }
748
749 /* 5. return to kernel instructions */
750 if (ka->ka_restorer)
751 regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer;
752 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 unsigned long address = ((unsigned long)&(sf->insns[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
755 regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
756
757 /* mov __NR_rt_sigreturn, %g1 */
758 err |= __put_user(0x82102065, &sf->insns[0]);
759
760 /* t 0x10 */
761 err |= __put_user(0x91d02010, &sf->insns[1]);
762 if (err)
763 goto sigsegv;
764
David S. Miller05c5e762010-09-20 23:24:52 -0700765 flush_signal_insns(address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
David S. Miller392c2182010-09-21 21:41:12 -0700767 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
769sigill:
770 do_exit(SIGILL);
David S. Miller392c2182010-09-21 21:41:12 -0700771 return -EINVAL;
772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773sigsegv:
774 force_sigsegv(signr, current);
David S. Miller392c2182010-09-21 21:41:12 -0700775 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776}
777
David S. Miller392c2182010-09-21 21:41:12 -0700778static inline int handle_signal32(unsigned long signr, struct k_sigaction *ka,
779 siginfo_t *info,
780 sigset_t *oldset, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
David S. Miller392c2182010-09-21 21:41:12 -0700782 int err;
783
David S. Millerec98c6b2008-04-20 02:14:23 -0700784 if (ka->sa.sa_flags & SA_SIGINFO)
David S. Miller392c2182010-09-21 21:41:12 -0700785 err = setup_rt_frame32(ka, regs, signr, oldset, info);
David S. Millerec98c6b2008-04-20 02:14:23 -0700786 else
David S. Miller392c2182010-09-21 21:41:12 -0700787 err = setup_frame32(ka, regs, signr, oldset);
788
789 if (err)
790 return err;
David S. Miller5526b7e2008-04-27 02:26:36 -0700791
Matt Flemingce24d8a2012-03-21 16:33:46 -0700792 block_sigmask(ka, signr);
David S. Miller392c2182010-09-21 21:41:12 -0700793 tracehook_signal_handler(signr, info, ka, regs, 0);
794
795 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796}
797
798static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs,
799 struct sigaction *sa)
800{
801 switch (regs->u_regs[UREG_I0]) {
802 case ERESTART_RESTARTBLOCK:
803 case ERESTARTNOHAND:
804 no_system_call_restart:
805 regs->u_regs[UREG_I0] = EINTR;
806 regs->tstate |= TSTATE_ICARRY;
807 break;
808 case ERESTARTSYS:
809 if (!(sa->sa_flags & SA_RESTART))
810 goto no_system_call_restart;
811 /* fallthrough */
812 case ERESTARTNOINTR:
813 regs->u_regs[UREG_I0] = orig_i0;
814 regs->tpc -= 4;
815 regs->tnpc -= 4;
816 }
817}
818
819/* Note that 'init' is a special process: it doesn't get signals it doesn't
820 * want to handle. Thus you cannot kill init even with a SIGKILL even by
821 * mistake.
822 */
David S. Miller1d299bc2011-11-14 20:32:16 -0800823void do_signal32(sigset_t *oldset, struct pt_regs * regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 struct k_sigaction ka;
David S. Miller1d299bc2011-11-14 20:32:16 -0800826 unsigned long orig_i0;
827 int restart_syscall;
David S. Miller238468b2008-04-24 03:01:48 -0700828 siginfo_t info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 int signr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
David S. Miller28e61032008-05-11 02:07:19 -0700831 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
832
David S. Miller1d299bc2011-11-14 20:32:16 -0800833 restart_syscall = 0;
834 orig_i0 = 0;
835 if (pt_regs_is_syscall(regs) &&
836 (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
837 restart_syscall = 1;
David S. Millere88d2462011-11-15 12:57:00 -0800838 orig_i0 = regs->u_regs[UREG_G6];
David S. Miller1d299bc2011-11-14 20:32:16 -0800839 }
David S. Miller28e61032008-05-11 02:07:19 -0700840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 if (signr > 0) {
David S. Miller28e61032008-05-11 02:07:19 -0700842 if (restart_syscall)
843 syscall_restart32(orig_i0, regs, &ka.sa);
David S. Miller392c2182010-09-21 21:41:12 -0700844 if (handle_signal32(signr, &ka, &info, oldset, regs) == 0) {
845 /* A signal was successfully delivered; the saved
846 * sigmask will have been stored in the signal frame,
847 * and will be restored by sigreturn, so we can simply
848 * clear the TS_RESTORE_SIGMASK flag.
849 */
850 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
851 }
David S. Miller2d7d5f02006-01-19 02:42:49 -0800852 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 }
David S. Miller28e61032008-05-11 02:07:19 -0700854 if (restart_syscall &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 (regs->u_regs[UREG_I0] == ERESTARTNOHAND ||
856 regs->u_regs[UREG_I0] == ERESTARTSYS ||
857 regs->u_regs[UREG_I0] == ERESTARTNOINTR)) {
858 /* replay the system call when we are done */
David S. Miller28e61032008-05-11 02:07:19 -0700859 regs->u_regs[UREG_I0] = orig_i0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 regs->tpc -= 4;
861 regs->tnpc -= 4;
David S. Millerc2785252010-09-21 22:30:13 -0700862 pt_regs_clear_syscall(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 }
David S. Miller28e61032008-05-11 02:07:19 -0700864 if (restart_syscall &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) {
866 regs->u_regs[UREG_G1] = __NR_restart_syscall;
867 regs->tpc -= 4;
868 regs->tnpc -= 4;
David S. Millerc2785252010-09-21 22:30:13 -0700869 pt_regs_clear_syscall(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 }
David S. Miller2d7d5f02006-01-19 02:42:49 -0800871
David S. Miller9a28dbf2008-05-12 22:45:15 -0700872 /* If there's no signal to deliver, we just put the saved sigmask
David S. Miller2d7d5f02006-01-19 02:42:49 -0800873 * back
874 */
Al Viro51a7b442012-05-21 23:33:55 -0400875 restore_saved_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878struct sigstack32 {
879 u32 the_stack;
880 int cur_status;
881};
882
883asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp)
884{
885 struct sigstack32 __user *ssptr =
886 (struct sigstack32 __user *)((unsigned long)(u_ssptr));
887 struct sigstack32 __user *ossptr =
888 (struct sigstack32 __user *)((unsigned long)(u_ossptr));
889 int ret = -EFAULT;
890
891 /* First see if old state is wanted. */
892 if (ossptr) {
893 if (put_user(current->sas_ss_sp + current->sas_ss_size,
894 &ossptr->the_stack) ||
895 __put_user(on_sig_stack(sp), &ossptr->cur_status))
896 goto out;
897 }
898
899 /* Now see if we want to update the new state. */
900 if (ssptr) {
901 u32 ss_sp;
902
903 if (get_user(ss_sp, &ssptr->the_stack))
904 goto out;
905
906 /* If the current stack was set with sigaltstack, don't
907 * swap stacks while we are on it.
908 */
909 ret = -EPERM;
910 if (current->sas_ss_sp && on_sig_stack(sp))
911 goto out;
912
913 /* Since we don't know the extent of the stack, and we don't
914 * track onstack-ness, but rather calculate it, we must
915 * presume a size. Ho hum this interface is lossy.
916 */
917 current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
918 current->sas_ss_size = SIGSTKSZ;
919 }
920
921 ret = 0;
922out:
923 return ret;
924}
925
926asmlinkage long do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
927{
928 stack_t uss, uoss;
929 u32 u_ss_sp = 0;
930 int ret;
931 mm_segment_t old_fs;
932 stack_t32 __user *uss32 = compat_ptr(ussa);
933 stack_t32 __user *uoss32 = compat_ptr(uossa);
934
935 if (ussa && (get_user(u_ss_sp, &uss32->ss_sp) ||
936 __get_user(uss.ss_flags, &uss32->ss_flags) ||
937 __get_user(uss.ss_size, &uss32->ss_size)))
938 return -EFAULT;
939 uss.ss_sp = compat_ptr(u_ss_sp);
940 old_fs = get_fs();
941 set_fs(KERNEL_DS);
942 ret = do_sigaltstack(ussa ? (stack_t __user *) &uss : NULL,
943 uossa ? (stack_t __user *) &uoss : NULL, sp);
944 set_fs(old_fs);
945 if (!ret && uossa && (put_user(ptr_to_compat(uoss.ss_sp), &uoss32->ss_sp) ||
946 __put_user(uoss.ss_flags, &uoss32->ss_flags) ||
947 __put_user(uoss.ss_size, &uoss32->ss_size)))
948 return -EFAULT;
949 return ret;
950}