blob: 0bdca3ac9a61713e2d858b2d848a30e64ab92534 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Heiko Carstens54dfe5d2006-02-01 03:06:38 -08002 * arch/s390/kernel/compat_signal.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Heiko Carstens54dfe5d2006-02-01 03:06:38 -08004 * Copyright (C) IBM Corp. 2000,2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
6 * Gerhard Tonn (ton@de.ibm.com)
7 *
8 * Copyright (C) 1991, 1992 Linus Torvalds
9 *
10 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
11 */
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/compat.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/kernel.h>
18#include <linux/signal.h>
19#include <linux/errno.h>
20#include <linux/wait.h>
21#include <linux/ptrace.h>
22#include <linux/unistd.h>
23#include <linux/stddef.h>
24#include <linux/tty.h>
25#include <linux/personality.h>
26#include <linux/binfmts.h>
27#include <asm/ucontext.h>
28#include <asm/uaccess.h>
29#include <asm/lowcore.h>
David Howellsa0616cd2012-03-28 18:30:02 +010030#include <asm/switch_to.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "compat_linux.h"
32#include "compat_ptrace.h"
Heiko Carstensa8061702008-04-17 07:46:26 +020033#include "entry.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
36
37typedef struct
38{
39 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
40 struct sigcontext32 sc;
41 _sigregs32 sregs;
42 int signo;
Heiko Carstensea2a4d32009-10-06 10:34:13 +020043 __u32 gprs_high[NUM_GPRS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 __u8 retcode[S390_SYSCALL_SIZE];
45} sigframe32;
46
47typedef struct
48{
49 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
50 __u8 retcode[S390_SYSCALL_SIZE];
51 compat_siginfo_t info;
52 struct ucontext32 uc;
Heiko Carstensea2a4d32009-10-06 10:34:13 +020053 __u32 gprs_high[NUM_GPRS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070054} rt_sigframe32;
55
Linus Torvalds1da177e2005-04-16 15:20:36 -070056int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
57{
58 int err;
59
60 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
61 return -EFAULT;
62
63 /* If you change siginfo_t structure, please be sure
64 this code is fixed accordingly.
65 It should never copy any pad contained in the structure
66 to avoid security leaks, but must copy the generic
67 3 ints plus the relevant union member.
68 This routine must convert siginfo from 64bit to 32bit as well
69 at the same time. */
70 err = __put_user(from->si_signo, &to->si_signo);
71 err |= __put_user(from->si_errno, &to->si_errno);
72 err |= __put_user((short)from->si_code, &to->si_code);
73 if (from->si_code < 0)
74 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
75 else {
76 switch (from->si_code >> 16) {
77 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
78 case __SI_MESGQ >> 16:
79 err |= __put_user(from->si_int, &to->si_int);
80 /* fallthrough */
81 case __SI_KILL >> 16:
82 err |= __put_user(from->si_pid, &to->si_pid);
83 err |= __put_user(from->si_uid, &to->si_uid);
84 break;
85 case __SI_CHLD >> 16:
86 err |= __put_user(from->si_pid, &to->si_pid);
87 err |= __put_user(from->si_uid, &to->si_uid);
88 err |= __put_user(from->si_utime, &to->si_utime);
89 err |= __put_user(from->si_stime, &to->si_stime);
90 err |= __put_user(from->si_status, &to->si_status);
91 break;
92 case __SI_FAULT >> 16:
93 err |= __put_user((unsigned long) from->si_addr,
94 &to->si_addr);
95 break;
96 case __SI_POLL >> 16:
97 err |= __put_user(from->si_band, &to->si_band);
98 err |= __put_user(from->si_fd, &to->si_fd);
99 break;
100 case __SI_TIMER >> 16:
101 err |= __put_user(from->si_tid, &to->si_tid);
102 err |= __put_user(from->si_overrun, &to->si_overrun);
103 err |= __put_user(from->si_int, &to->si_int);
104 break;
105 default:
106 break;
107 }
108 }
109 return err;
110}
111
112int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
113{
114 int err;
115 u32 tmp;
116
117 if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
118 return -EFAULT;
119
120 err = __get_user(to->si_signo, &from->si_signo);
121 err |= __get_user(to->si_errno, &from->si_errno);
122 err |= __get_user(to->si_code, &from->si_code);
123
124 if (to->si_code < 0)
125 err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
126 else {
127 switch (to->si_code >> 16) {
128 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
129 case __SI_MESGQ >> 16:
130 err |= __get_user(to->si_int, &from->si_int);
131 /* fallthrough */
132 case __SI_KILL >> 16:
133 err |= __get_user(to->si_pid, &from->si_pid);
134 err |= __get_user(to->si_uid, &from->si_uid);
135 break;
136 case __SI_CHLD >> 16:
137 err |= __get_user(to->si_pid, &from->si_pid);
138 err |= __get_user(to->si_uid, &from->si_uid);
139 err |= __get_user(to->si_utime, &from->si_utime);
140 err |= __get_user(to->si_stime, &from->si_stime);
141 err |= __get_user(to->si_status, &from->si_status);
142 break;
143 case __SI_FAULT >> 16:
144 err |= __get_user(tmp, &from->si_addr);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100145 to->si_addr = (void __force __user *)
146 (u64) (tmp & PSW32_ADDR_INSN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 break;
148 case __SI_POLL >> 16:
149 err |= __get_user(to->si_band, &from->si_band);
150 err |= __get_user(to->si_fd, &from->si_fd);
151 break;
152 case __SI_TIMER >> 16:
153 err |= __get_user(to->si_tid, &from->si_tid);
154 err |= __get_user(to->si_overrun, &from->si_overrun);
155 err |= __get_user(to->si_int, &from->si_int);
156 break;
157 default:
158 break;
159 }
160 }
161 return err;
162}
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164asmlinkage long
165sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
166 struct old_sigaction32 __user *oact)
167{
168 struct k_sigaction new_ka, old_ka;
169 unsigned long sa_handler, sa_restorer;
170 int ret;
171
172 if (act) {
173 compat_old_sigset_t mask;
174 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
175 __get_user(sa_handler, &act->sa_handler) ||
Heiko Carstens12bae232006-10-27 12:39:22 +0200176 __get_user(sa_restorer, &act->sa_restorer) ||
177 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
178 __get_user(mask, &act->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 return -EFAULT;
180 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
181 new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 siginitset(&new_ka.sa.sa_mask, mask);
183 }
184
185 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
186
187 if (!ret && oact) {
188 sa_handler = (unsigned long) old_ka.sa.sa_handler;
189 sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
190 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
191 __put_user(sa_handler, &oact->sa_handler) ||
Heiko Carstens12bae232006-10-27 12:39:22 +0200192 __put_user(sa_restorer, &oact->sa_restorer) ||
193 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
194 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 }
197
198 return ret;
199}
200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201asmlinkage long
202sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
203 struct sigaction32 __user *oact, size_t sigsetsize)
204{
205 struct k_sigaction new_ka, old_ka;
206 unsigned long sa_handler;
207 int ret;
208 compat_sigset_t set32;
209
210 /* XXX: Don't preclude handling different sized sigset_t's. */
211 if (sigsetsize != sizeof(compat_sigset_t))
212 return -EINVAL;
213
214 if (act) {
215 ret = get_user(sa_handler, &act->sa_handler);
216 ret |= __copy_from_user(&set32, &act->sa_mask,
217 sizeof(compat_sigset_t));
Martin Schwidefsky399c1d82011-10-30 15:17:10 +0100218 new_ka.sa.sa_mask.sig[0] =
219 set32.sig[0] | (((long)set32.sig[1]) << 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
221
222 if (ret)
223 return -EFAULT;
224 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
225 }
226
227 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
228
229 if (!ret && oact) {
Martin Schwidefsky399c1d82011-10-30 15:17:10 +0100230 set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
231 set32.sig[0] = old_ka.sa.sa_mask.sig[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
233 ret |= __copy_to_user(&oact->sa_mask, &set32,
234 sizeof(compat_sigset_t));
235 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
236 }
237
238 return ret;
239}
240
241asmlinkage long
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200242sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200244 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 stack_t kss, koss;
246 unsigned long ss_sp;
247 int ret, err = 0;
248 mm_segment_t old_fs = get_fs();
249
250 if (uss) {
251 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
252 return -EFAULT;
253 err |= __get_user(ss_sp, &uss->ss_sp);
254 err |= __get_user(kss.ss_size, &uss->ss_size);
255 err |= __get_user(kss.ss_flags, &uss->ss_flags);
256 if (err)
257 return -EFAULT;
Al Viroc2814472005-09-29 00:16:02 +0100258 kss.ss_sp = (void __user *) ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 }
260
261 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100262 ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
263 (stack_t __force __user *) (uoss ? &koss : NULL),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 regs->gprs[15]);
265 set_fs (old_fs);
266
267 if (!ret && uoss) {
268 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
269 return -EFAULT;
270 ss_sp = (unsigned long) koss.ss_sp;
271 err |= __put_user(ss_sp, &uoss->ss_sp);
272 err |= __put_user(koss.ss_size, &uoss->ss_size);
273 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
274 if (err)
275 return -EFAULT;
276 }
277 return ret;
278}
279
280static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
281{
282 _s390_regs_common32 regs32;
283 int err, i;
284
Martin Schwidefskyb50511e2011-10-30 15:16:50 +0100285 regs32.psw.mask = psw32_user_bits |
286 ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER);
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100287 regs32.psw.addr = (__u32) regs->psw.addr |
288 (__u32)(regs->psw.mask & PSW_MASK_BA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 for (i = 0; i < NUM_GPRS; i++)
290 regs32.gprs[i] = (__u32) regs->gprs[i];
291 save_access_regs(current->thread.acrs);
292 memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
293 err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
294 if (err)
295 return err;
296 save_fp_regs(&current->thread.fp_regs);
297 /* s390_fp_regs and _s390_fp_regs32 are the same ! */
298 return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
299 sizeof(_s390_fp_regs32));
300}
301
302static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
303{
304 _s390_regs_common32 regs32;
305 int err, i;
306
307 /* Alwys make any pending restarted system call return -EINTR */
308 current_thread_info()->restart_block.fn = do_no_restart_syscall;
309
310 err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
311 if (err)
312 return err;
Martin Schwidefskyb50511e2011-10-30 15:16:50 +0100313 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100314 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
315 (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
Martin Schwidefsky37a42f92012-11-07 10:44:08 +0100316 /* Check for invalid user address space control. */
317 if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
318 regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
319 (regs->psw.mask & ~PSW_MASK_ASC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
321 for (i = 0; i < NUM_GPRS; i++)
322 regs->gprs[i] = (__u64) regs32.gprs[i];
323 memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
324 restore_access_regs(current->thread.acrs);
325
326 err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
327 sizeof(_s390_fp_regs32));
328 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
329 if (err)
330 return err;
331
332 restore_fp_regs(&current->thread.fp_regs);
Martin Schwidefskyb6ef5bb2011-10-30 15:16:49 +0100333 clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 return 0;
335}
336
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200337static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
338{
339 __u32 gprs_high[NUM_GPRS];
340 int i;
341
342 for (i = 0; i < NUM_GPRS; i++)
343 gprs_high[i] = regs->gprs[i] >> 32;
344
345 return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));
346}
347
348static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
349{
350 __u32 gprs_high[NUM_GPRS];
351 int err, i;
352
353 err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));
354 if (err)
355 return err;
356 for (i = 0; i < NUM_GPRS; i++)
357 *(__u32 *)&regs->gprs[i] = gprs_high[i];
358 return 0;
359}
360
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200361asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200363 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
365 sigset_t set;
366
367 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
368 goto badframe;
369 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
370 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 sigdelsetmask(&set, ~_BLOCKABLE);
Heiko Carstens391c62f2011-08-03 16:44:26 +0200372 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 if (restore_sigregs32(regs, &frame->sregs))
374 goto badframe;
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200375 if (restore_sigregs_gprs_high(regs, frame->gprs_high))
376 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 return regs->gprs[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378badframe:
379 force_sig(SIGSEGV, current);
380 return 0;
381}
382
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200383asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200385 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
387 sigset_t set;
388 stack_t st;
389 __u32 ss_sp;
390 int err;
391 mm_segment_t old_fs = get_fs();
392
393 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
394 goto badframe;
395 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
396 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 sigdelsetmask(&set, ~_BLOCKABLE);
Heiko Carstens391c62f2011-08-03 16:44:26 +0200398 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
400 goto badframe;
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200401 if (restore_sigregs_gprs_high(regs, frame->gprs_high))
402 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
Al Viroc2814472005-09-29 00:16:02 +0100404 st.ss_sp = compat_ptr(ss_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
406 err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
407 if (err)
408 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100410 do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 set_fs (old_fs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 return regs->gprs[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413badframe:
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200414 force_sig(SIGSEGV, current);
415 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416}
417
418/*
419 * Set up a signal frame.
420 */
421
422
423/*
424 * Determine which stack to use..
425 */
426static inline void __user *
427get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
428{
429 unsigned long sp;
430
431 /* Default to using normal stack */
432 sp = (unsigned long) A(regs->gprs[15]);
433
Heiko Carstensde553432008-04-17 07:45:57 +0200434 /* Overflow on alternate signal stack gives SIGSEGV. */
435 if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
436 return (void __user *) -1UL;
437
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 /* This is the X/Open sanctioned signal stack switching. */
439 if (ka->sa.sa_flags & SA_ONSTACK) {
Laurent Meyer28f22372006-04-27 18:40:07 -0700440 if (! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 sp = current->sas_ss_sp + current->sas_ss_size;
442 }
443
444 /* This is the legacy signal stack switching. */
445 else if (!user_mode(regs) &&
446 !(ka->sa.sa_flags & SA_RESTORER) &&
447 ka->sa.sa_restorer) {
448 sp = (unsigned long) ka->sa.sa_restorer;
449 }
450
451 return (void __user *)((sp - frame_size) & -8ul);
452}
453
454static inline int map_signal(int sig)
455{
456 if (current_thread_info()->exec_domain
457 && current_thread_info()->exec_domain->signal_invmap
458 && sig < 32)
459 return current_thread_info()->exec_domain->signal_invmap[sig];
460 else
461 return sig;
462}
463
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800464static int setup_frame32(int sig, struct k_sigaction *ka,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 sigset_t *set, struct pt_regs * regs)
466{
467 sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
468 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
469 goto give_sigsegv;
470
Heiko Carstensde553432008-04-17 07:45:57 +0200471 if (frame == (void __user *) -1UL)
472 goto give_sigsegv;
473
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
475 goto give_sigsegv;
476
477 if (save_sigregs32(regs, &frame->sregs))
478 goto give_sigsegv;
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200479 if (save_sigregs_gprs_high(regs, frame->gprs_high))
480 goto give_sigsegv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
482 goto give_sigsegv;
483
484 /* Set up to return from userspace. If provided, use a stub
485 already in userspace. */
486 if (ka->sa.sa_flags & SA_RESTORER) {
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100487 regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 } else {
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100489 regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100491 (u16 __force __user *)(frame->retcode)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 goto give_sigsegv;
493 }
494
495 /* Set up backchain. */
496 if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
497 goto give_sigsegv;
498
499 /* Set up registers for signal handler */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100500 regs->gprs[15] = (__force __u64) frame;
Martin Schwidefsky37a42f92012-11-07 10:44:08 +0100501 /* Force 31 bit amode and default user address space control. */
502 regs->psw.mask = PSW_MASK_BA |
503 (psw_user_bits & PSW_MASK_ASC) |
504 (regs->psw.mask & ~PSW_MASK_ASC);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100505 regs->psw.addr = (__force __u64) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 regs->gprs[2] = map_signal(sig);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100508 regs->gprs[3] = (__force __u64) &frame->sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 /* We forgot to include these in the sigcontext.
511 To avoid breaking binary compatibility, they are passed as args. */
Martin Schwidefskyaa33c8c2011-12-27 11:27:18 +0100512 if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
513 sig == SIGTRAP || sig == SIGFPE) {
514 /* set extra registers only for synchronous signals */
515 regs->gprs[4] = regs->int_code & 127;
516 regs->gprs[5] = regs->int_parm_long;
517 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
519 /* Place signal number on stack to allow backtrace from handler. */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100520 if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 goto give_sigsegv;
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800522 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
524give_sigsegv:
525 force_sigsegv(sig, current);
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800526 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527}
528
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800529static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 sigset_t *set, struct pt_regs * regs)
531{
532 int err = 0;
533 rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
534 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
535 goto give_sigsegv;
536
Heiko Carstensde553432008-04-17 07:45:57 +0200537 if (frame == (void __user *) -1UL)
538 goto give_sigsegv;
539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (copy_siginfo_to_user32(&frame->info, info))
541 goto give_sigsegv;
542
543 /* Create the ucontext. */
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200544 err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 err |= __put_user(0, &frame->uc.uc_link);
546 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
547 err |= __put_user(sas_ss_flags(regs->gprs[15]),
548 &frame->uc.uc_stack.ss_flags);
549 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
550 err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200551 err |= save_sigregs_gprs_high(regs, frame->gprs_high);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
553 if (err)
554 goto give_sigsegv;
555
556 /* Set up to return from userspace. If provided, use a stub
557 already in userspace. */
558 if (ka->sa.sa_flags & SA_RESTORER) {
Martin Schwidefsky207a0542011-12-27 11:27:30 +0100559 regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 } else {
Martin Schwidefsky207a0542011-12-27 11:27:30 +0100561 regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100563 (u16 __force __user *)(frame->retcode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 }
565
566 /* Set up backchain. */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100567 if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 goto give_sigsegv;
569
570 /* Set up registers for signal handler */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100571 regs->gprs[15] = (__force __u64) frame;
Martin Schwidefsky37a42f92012-11-07 10:44:08 +0100572 /* Force 31 bit amode and default user address space control. */
573 regs->psw.mask = PSW_MASK_BA |
574 (psw_user_bits & PSW_MASK_ASC) |
575 (regs->psw.mask & ~PSW_MASK_ASC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 regs->psw.addr = (__u64) ka->sa.sa_handler;
577
578 regs->gprs[2] = map_signal(sig);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100579 regs->gprs[3] = (__force __u64) &frame->info;
580 regs->gprs[4] = (__force __u64) &frame->uc;
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800581 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583give_sigsegv:
584 force_sigsegv(sig, current);
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800585 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
588/*
589 * OK, we're invoking a handler
590 */
591
Heiko Carstens391c62f2011-08-03 16:44:26 +0200592int handle_signal32(unsigned long sig, struct k_sigaction *ka,
593 siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800595 int ret;
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 /* Set up the stack frame */
598 if (ka->sa.sa_flags & SA_SIGINFO)
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800599 ret = setup_rt_frame32(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 else
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800601 ret = setup_frame32(sig, ka, oldset, regs);
Heiko Carstens391c62f2011-08-03 16:44:26 +0200602 if (ret)
603 return ret;
Matt Flemingad252ff2012-03-11 11:59:33 -0400604 block_sigmask(ka, sig);
Heiko Carstens391c62f2011-08-03 16:44:26 +0200605 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607