blob: eacb0d6058a3fed286d3ec63478ba9bf06dbe3e9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Heiko Carstensa53c8fa2012-07-20 11:15:04 +02002 * Copyright IBM Corp. 2000, 2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
4 * Gerhard Tonn (ton@de.ibm.com)
5 *
6 * Copyright (C) 1991, 1992 Linus Torvalds
7 *
8 * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/compat.h>
12#include <linux/sched.h>
13#include <linux/mm.h>
14#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/kernel.h>
16#include <linux/signal.h>
17#include <linux/errno.h>
18#include <linux/wait.h>
19#include <linux/ptrace.h>
20#include <linux/unistd.h>
21#include <linux/stddef.h>
22#include <linux/tty.h>
23#include <linux/personality.h>
24#include <linux/binfmts.h>
25#include <asm/ucontext.h>
26#include <asm/uaccess.h>
27#include <asm/lowcore.h>
David Howellsa0616cd2012-03-28 18:30:02 +010028#include <asm/switch_to.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "compat_linux.h"
30#include "compat_ptrace.h"
Heiko Carstensa8061702008-04-17 07:46:26 +020031#include "entry.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Linus Torvalds1da177e2005-04-16 15:20:36 -070033typedef struct
34{
35 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
36 struct sigcontext32 sc;
37 _sigregs32 sregs;
38 int signo;
Heiko Carstensea2a4d32009-10-06 10:34:13 +020039 __u32 gprs_high[NUM_GPRS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 __u8 retcode[S390_SYSCALL_SIZE];
41} sigframe32;
42
43typedef struct
44{
45 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
46 __u8 retcode[S390_SYSCALL_SIZE];
47 compat_siginfo_t info;
48 struct ucontext32 uc;
Heiko Carstensea2a4d32009-10-06 10:34:13 +020049 __u32 gprs_high[NUM_GPRS];
Linus Torvalds1da177e2005-04-16 15:20:36 -070050} rt_sigframe32;
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
53{
54 int err;
55
56 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
57 return -EFAULT;
58
59 /* If you change siginfo_t structure, please be sure
60 this code is fixed accordingly.
61 It should never copy any pad contained in the structure
62 to avoid security leaks, but must copy the generic
63 3 ints plus the relevant union member.
64 This routine must convert siginfo from 64bit to 32bit as well
65 at the same time. */
66 err = __put_user(from->si_signo, &to->si_signo);
67 err |= __put_user(from->si_errno, &to->si_errno);
68 err |= __put_user((short)from->si_code, &to->si_code);
69 if (from->si_code < 0)
70 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
71 else {
72 switch (from->si_code >> 16) {
73 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
74 case __SI_MESGQ >> 16:
75 err |= __put_user(from->si_int, &to->si_int);
76 /* fallthrough */
77 case __SI_KILL >> 16:
78 err |= __put_user(from->si_pid, &to->si_pid);
79 err |= __put_user(from->si_uid, &to->si_uid);
80 break;
81 case __SI_CHLD >> 16:
82 err |= __put_user(from->si_pid, &to->si_pid);
83 err |= __put_user(from->si_uid, &to->si_uid);
84 err |= __put_user(from->si_utime, &to->si_utime);
85 err |= __put_user(from->si_stime, &to->si_stime);
86 err |= __put_user(from->si_status, &to->si_status);
87 break;
88 case __SI_FAULT >> 16:
89 err |= __put_user((unsigned long) from->si_addr,
90 &to->si_addr);
91 break;
92 case __SI_POLL >> 16:
93 err |= __put_user(from->si_band, &to->si_band);
94 err |= __put_user(from->si_fd, &to->si_fd);
95 break;
96 case __SI_TIMER >> 16:
97 err |= __put_user(from->si_tid, &to->si_tid);
98 err |= __put_user(from->si_overrun, &to->si_overrun);
99 err |= __put_user(from->si_int, &to->si_int);
100 break;
101 default:
102 break;
103 }
104 }
105 return err;
106}
107
108int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
109{
110 int err;
111 u32 tmp;
112
113 if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
114 return -EFAULT;
115
116 err = __get_user(to->si_signo, &from->si_signo);
117 err |= __get_user(to->si_errno, &from->si_errno);
118 err |= __get_user(to->si_code, &from->si_code);
119
120 if (to->si_code < 0)
121 err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
122 else {
123 switch (to->si_code >> 16) {
124 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
125 case __SI_MESGQ >> 16:
126 err |= __get_user(to->si_int, &from->si_int);
127 /* fallthrough */
128 case __SI_KILL >> 16:
129 err |= __get_user(to->si_pid, &from->si_pid);
130 err |= __get_user(to->si_uid, &from->si_uid);
131 break;
132 case __SI_CHLD >> 16:
133 err |= __get_user(to->si_pid, &from->si_pid);
134 err |= __get_user(to->si_uid, &from->si_uid);
135 err |= __get_user(to->si_utime, &from->si_utime);
136 err |= __get_user(to->si_stime, &from->si_stime);
137 err |= __get_user(to->si_status, &from->si_status);
138 break;
139 case __SI_FAULT >> 16:
140 err |= __get_user(tmp, &from->si_addr);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100141 to->si_addr = (void __force __user *)
142 (u64) (tmp & PSW32_ADDR_INSN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 break;
144 case __SI_POLL >> 16:
145 err |= __get_user(to->si_band, &from->si_band);
146 err |= __get_user(to->si_fd, &from->si_fd);
147 break;
148 case __SI_TIMER >> 16:
149 err |= __get_user(to->si_tid, &from->si_tid);
150 err |= __get_user(to->si_overrun, &from->si_overrun);
151 err |= __get_user(to->si_int, &from->si_int);
152 break;
153 default:
154 break;
155 }
156 }
157 return err;
158}
159
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160asmlinkage long
161sys32_sigaction(int sig, const struct old_sigaction32 __user *act,
162 struct old_sigaction32 __user *oact)
163{
164 struct k_sigaction new_ka, old_ka;
165 unsigned long sa_handler, sa_restorer;
166 int ret;
167
168 if (act) {
169 compat_old_sigset_t mask;
170 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
171 __get_user(sa_handler, &act->sa_handler) ||
Heiko Carstens12bae232006-10-27 12:39:22 +0200172 __get_user(sa_restorer, &act->sa_restorer) ||
173 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
174 __get_user(mask, &act->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 return -EFAULT;
176 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
177 new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 siginitset(&new_ka.sa.sa_mask, mask);
179 }
180
181 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
182
183 if (!ret && oact) {
184 sa_handler = (unsigned long) old_ka.sa.sa_handler;
185 sa_restorer = (unsigned long) old_ka.sa.sa_restorer;
186 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
187 __put_user(sa_handler, &oact->sa_handler) ||
Heiko Carstens12bae232006-10-27 12:39:22 +0200188 __put_user(sa_restorer, &oact->sa_restorer) ||
189 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
190 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
193
194 return ret;
195}
196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197asmlinkage long
198sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
199 struct sigaction32 __user *oact, size_t sigsetsize)
200{
201 struct k_sigaction new_ka, old_ka;
202 unsigned long sa_handler;
203 int ret;
204 compat_sigset_t set32;
205
206 /* XXX: Don't preclude handling different sized sigset_t's. */
207 if (sigsetsize != sizeof(compat_sigset_t))
208 return -EINVAL;
209
210 if (act) {
211 ret = get_user(sa_handler, &act->sa_handler);
212 ret |= __copy_from_user(&set32, &act->sa_mask,
213 sizeof(compat_sigset_t));
Martin Schwidefsky399c1d82011-10-30 15:17:10 +0100214 new_ka.sa.sa_mask.sig[0] =
215 set32.sig[0] | (((long)set32.sig[1]) << 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
217
218 if (ret)
219 return -EFAULT;
220 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
221 }
222
223 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
224
225 if (!ret && oact) {
Martin Schwidefsky399c1d82011-10-30 15:17:10 +0100226 set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
227 set32.sig[0] = old_ka.sa.sa_mask.sig[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
229 ret |= __copy_to_user(&oact->sa_mask, &set32,
230 sizeof(compat_sigset_t));
231 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
232 }
233
234 return ret;
235}
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
238{
239 _s390_regs_common32 regs32;
240 int err, i;
241
Martin Schwidefskyb50511e2011-10-30 15:16:50 +0100242 regs32.psw.mask = psw32_user_bits |
243 ((__u32)(regs->psw.mask >> 32) & PSW32_MASK_USER);
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100244 regs32.psw.addr = (__u32) regs->psw.addr |
245 (__u32)(regs->psw.mask & PSW_MASK_BA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 for (i = 0; i < NUM_GPRS; i++)
247 regs32.gprs[i] = (__u32) regs->gprs[i];
248 save_access_regs(current->thread.acrs);
249 memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
250 err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
251 if (err)
252 return err;
253 save_fp_regs(&current->thread.fp_regs);
254 /* s390_fp_regs and _s390_fp_regs32 are the same ! */
255 return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
256 sizeof(_s390_fp_regs32));
257}
258
259static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
260{
261 _s390_regs_common32 regs32;
262 int err, i;
263
264 /* Alwys make any pending restarted system call return -EINTR */
265 current_thread_info()->restart_block.fn = do_no_restart_syscall;
266
267 err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
268 if (err)
269 return err;
Martin Schwidefskyb50511e2011-10-30 15:16:50 +0100270 regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100271 (__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
272 (__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
Martin Schwidefskyfa968ee2012-11-07 10:44:08 +0100273 /* Check for invalid user address space control. */
274 if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
275 regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
276 (regs->psw.mask & ~PSW_MASK_ASC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
278 for (i = 0; i < NUM_GPRS; i++)
279 regs->gprs[i] = (__u64) regs32.gprs[i];
280 memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
281 restore_access_regs(current->thread.acrs);
282
283 err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
284 sizeof(_s390_fp_regs32));
285 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
286 if (err)
287 return err;
288
289 restore_fp_regs(&current->thread.fp_regs);
Martin Schwidefskyb6ef5bb2011-10-30 15:16:49 +0100290 clear_thread_flag(TIF_SYSCALL); /* No longer in a system call */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return 0;
292}
293
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200294static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
295{
296 __u32 gprs_high[NUM_GPRS];
297 int i;
298
299 for (i = 0; i < NUM_GPRS; i++)
300 gprs_high[i] = regs->gprs[i] >> 32;
301
302 return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));
303}
304
305static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
306{
307 __u32 gprs_high[NUM_GPRS];
308 int err, i;
309
310 err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));
311 if (err)
312 return err;
313 for (i = 0; i < NUM_GPRS; i++)
314 *(__u32 *)&regs->gprs[i] = gprs_high[i];
315 return 0;
316}
317
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200318asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200320 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
322 sigset_t set;
323
324 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
325 goto badframe;
326 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
327 goto badframe;
Heiko Carstens391c62f2011-08-03 16:44:26 +0200328 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 if (restore_sigregs32(regs, &frame->sregs))
330 goto badframe;
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200331 if (restore_sigregs_gprs_high(regs, frame->gprs_high))
332 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 return regs->gprs[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334badframe:
335 force_sig(SIGSEGV, current);
336 return 0;
337}
338
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200339asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200341 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
343 sigset_t set;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
346 goto badframe;
347 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
348 goto badframe;
Heiko Carstens391c62f2011-08-03 16:44:26 +0200349 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
351 goto badframe;
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200352 if (restore_sigregs_gprs_high(regs, frame->gprs_high))
353 goto badframe;
Al Viroe2141252012-12-23 03:36:41 -0500354 if (compat_restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 goto badframe;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 return regs->gprs[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357badframe:
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200358 force_sig(SIGSEGV, current);
359 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
362/*
363 * Set up a signal frame.
364 */
365
366
367/*
368 * Determine which stack to use..
369 */
370static inline void __user *
371get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
372{
373 unsigned long sp;
374
375 /* Default to using normal stack */
376 sp = (unsigned long) A(regs->gprs[15]);
377
Heiko Carstensde553432008-04-17 07:45:57 +0200378 /* Overflow on alternate signal stack gives SIGSEGV. */
379 if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
380 return (void __user *) -1UL;
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 /* This is the X/Open sanctioned signal stack switching. */
383 if (ka->sa.sa_flags & SA_ONSTACK) {
Laurent Meyer28f22372006-04-27 18:40:07 -0700384 if (! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 sp = current->sas_ss_sp + current->sas_ss_size;
386 }
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return (void __user *)((sp - frame_size) & -8ul);
389}
390
391static inline int map_signal(int sig)
392{
393 if (current_thread_info()->exec_domain
394 && current_thread_info()->exec_domain->signal_invmap
395 && sig < 32)
396 return current_thread_info()->exec_domain->signal_invmap[sig];
397 else
398 return sig;
399}
400
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800401static int setup_frame32(int sig, struct k_sigaction *ka,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 sigset_t *set, struct pt_regs * regs)
403{
404 sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
405 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
406 goto give_sigsegv;
407
Heiko Carstensde553432008-04-17 07:45:57 +0200408 if (frame == (void __user *) -1UL)
409 goto give_sigsegv;
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
412 goto give_sigsegv;
413
414 if (save_sigregs32(regs, &frame->sregs))
415 goto give_sigsegv;
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200416 if (save_sigregs_gprs_high(regs, frame->gprs_high))
417 goto give_sigsegv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
419 goto give_sigsegv;
420
421 /* Set up to return from userspace. If provided, use a stub
422 already in userspace. */
423 if (ka->sa.sa_flags & SA_RESTORER) {
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100424 regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 } else {
Martin Schwidefskyd4e81b32011-10-30 15:16:51 +0100426 regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100428 (u16 __force __user *)(frame->retcode)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 goto give_sigsegv;
430 }
431
432 /* Set up backchain. */
433 if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
434 goto give_sigsegv;
435
436 /* Set up registers for signal handler */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100437 regs->gprs[15] = (__force __u64) frame;
Martin Schwidefskyfa968ee2012-11-07 10:44:08 +0100438 /* Force 31 bit amode and default user address space control. */
439 regs->psw.mask = PSW_MASK_BA |
440 (psw_user_bits & PSW_MASK_ASC) |
441 (regs->psw.mask & ~PSW_MASK_ASC);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100442 regs->psw.addr = (__force __u64) ka->sa.sa_handler;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443
444 regs->gprs[2] = map_signal(sig);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100445 regs->gprs[3] = (__force __u64) &frame->sc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
447 /* We forgot to include these in the sigcontext.
448 To avoid breaking binary compatibility, they are passed as args. */
Martin Schwidefskyaa33c8c2011-12-27 11:27:18 +0100449 if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
450 sig == SIGTRAP || sig == SIGFPE) {
451 /* set extra registers only for synchronous signals */
452 regs->gprs[4] = regs->int_code & 127;
453 regs->gprs[5] = regs->int_parm_long;
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455
456 /* Place signal number on stack to allow backtrace from handler. */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100457 if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 goto give_sigsegv;
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800459 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461give_sigsegv:
462 force_sigsegv(sig, current);
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800463 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464}
465
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800466static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 sigset_t *set, struct pt_regs * regs)
468{
469 int err = 0;
470 rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
471 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
472 goto give_sigsegv;
473
Heiko Carstensde553432008-04-17 07:45:57 +0200474 if (frame == (void __user *) -1UL)
475 goto give_sigsegv;
476
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 if (copy_siginfo_to_user32(&frame->info, info))
478 goto give_sigsegv;
479
480 /* Create the ucontext. */
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200481 err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 err |= __put_user(0, &frame->uc.uc_link);
Al Viroe2141252012-12-23 03:36:41 -0500483 err |= __compat_save_altstack(&frame->uc.uc_stack, regs->gprs[15]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
Heiko Carstensea2a4d32009-10-06 10:34:13 +0200485 err |= save_sigregs_gprs_high(regs, frame->gprs_high);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
487 if (err)
488 goto give_sigsegv;
489
490 /* Set up to return from userspace. If provided, use a stub
491 already in userspace. */
492 if (ka->sa.sa_flags & SA_RESTORER) {
Martin Schwidefsky207a0542011-12-27 11:27:30 +0100493 regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 } else {
Martin Schwidefsky207a0542011-12-27 11:27:30 +0100495 regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100497 (u16 __force __user *)(frame->retcode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
499
500 /* Set up backchain. */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100501 if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 goto give_sigsegv;
503
504 /* Set up registers for signal handler */
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100505 regs->gprs[15] = (__force __u64) frame;
Martin Schwidefskyfa968ee2012-11-07 10:44:08 +0100506 /* Force 31 bit amode and default user address space control. */
507 regs->psw.mask = PSW_MASK_BA |
508 (psw_user_bits & PSW_MASK_ASC) |
509 (regs->psw.mask & ~PSW_MASK_ASC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 regs->psw.addr = (__u64) ka->sa.sa_handler;
511
512 regs->gprs[2] = map_signal(sig);
Martin Schwidefsky3c52e492011-10-30 15:17:15 +0100513 regs->gprs[3] = (__force __u64) &frame->info;
514 regs->gprs[4] = (__force __u64) &frame->uc;
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800515 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
517give_sigsegv:
518 force_sigsegv(sig, current);
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800519 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
522/*
523 * OK, we're invoking a handler
524 */
525
Al Viroa610d6e2012-05-21 23:42:15 -0400526void handle_signal32(unsigned long sig, struct k_sigaction *ka,
Heiko Carstens391c62f2011-08-03 16:44:26 +0200527 siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528{
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800529 int ret;
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 /* Set up the stack frame */
532 if (ka->sa.sa_flags & SA_SIGINFO)
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800533 ret = setup_rt_frame32(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 else
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800535 ret = setup_frame32(sig, ka, oldset, regs);
Heiko Carstens391c62f2011-08-03 16:44:26 +0200536 if (ret)
Al Viroa610d6e2012-05-21 23:42:15 -0400537 return;
Al Viroefee9842012-04-28 02:04:15 -0400538 signal_delivered(sig, info, ka, regs,
Al Viroa610d6e2012-05-21 23:42:15 -0400539 test_thread_flag(TIF_SINGLE_STEP));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540}
541