blob: b537cb0e9b55f607652f217f802ac7c2d8358d0b [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>
30#include "compat_linux.h"
31#include "compat_ptrace.h"
Heiko Carstensa8061702008-04-17 07:46:26 +020032#include "entry.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35
36typedef struct
37{
38 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
39 struct sigcontext32 sc;
40 _sigregs32 sregs;
41 int signo;
42 __u8 retcode[S390_SYSCALL_SIZE];
43} sigframe32;
44
45typedef struct
46{
47 __u8 callee_used_stack[__SIGNAL_FRAMESIZE32];
48 __u8 retcode[S390_SYSCALL_SIZE];
49 compat_siginfo_t info;
50 struct ucontext32 uc;
51} rt_sigframe32;
52
Linus Torvalds1da177e2005-04-16 15:20:36 -070053int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
54{
55 int err;
56
57 if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
58 return -EFAULT;
59
60 /* If you change siginfo_t structure, please be sure
61 this code is fixed accordingly.
62 It should never copy any pad contained in the structure
63 to avoid security leaks, but must copy the generic
64 3 ints plus the relevant union member.
65 This routine must convert siginfo from 64bit to 32bit as well
66 at the same time. */
67 err = __put_user(from->si_signo, &to->si_signo);
68 err |= __put_user(from->si_errno, &to->si_errno);
69 err |= __put_user((short)from->si_code, &to->si_code);
70 if (from->si_code < 0)
71 err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
72 else {
73 switch (from->si_code >> 16) {
74 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
75 case __SI_MESGQ >> 16:
76 err |= __put_user(from->si_int, &to->si_int);
77 /* fallthrough */
78 case __SI_KILL >> 16:
79 err |= __put_user(from->si_pid, &to->si_pid);
80 err |= __put_user(from->si_uid, &to->si_uid);
81 break;
82 case __SI_CHLD >> 16:
83 err |= __put_user(from->si_pid, &to->si_pid);
84 err |= __put_user(from->si_uid, &to->si_uid);
85 err |= __put_user(from->si_utime, &to->si_utime);
86 err |= __put_user(from->si_stime, &to->si_stime);
87 err |= __put_user(from->si_status, &to->si_status);
88 break;
89 case __SI_FAULT >> 16:
90 err |= __put_user((unsigned long) from->si_addr,
91 &to->si_addr);
92 break;
93 case __SI_POLL >> 16:
94 err |= __put_user(from->si_band, &to->si_band);
95 err |= __put_user(from->si_fd, &to->si_fd);
96 break;
97 case __SI_TIMER >> 16:
98 err |= __put_user(from->si_tid, &to->si_tid);
99 err |= __put_user(from->si_overrun, &to->si_overrun);
100 err |= __put_user(from->si_int, &to->si_int);
101 break;
102 default:
103 break;
104 }
105 }
106 return err;
107}
108
109int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
110{
111 int err;
112 u32 tmp;
113
114 if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t)))
115 return -EFAULT;
116
117 err = __get_user(to->si_signo, &from->si_signo);
118 err |= __get_user(to->si_errno, &from->si_errno);
119 err |= __get_user(to->si_code, &from->si_code);
120
121 if (to->si_code < 0)
122 err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
123 else {
124 switch (to->si_code >> 16) {
125 case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
126 case __SI_MESGQ >> 16:
127 err |= __get_user(to->si_int, &from->si_int);
128 /* fallthrough */
129 case __SI_KILL >> 16:
130 err |= __get_user(to->si_pid, &from->si_pid);
131 err |= __get_user(to->si_uid, &from->si_uid);
132 break;
133 case __SI_CHLD >> 16:
134 err |= __get_user(to->si_pid, &from->si_pid);
135 err |= __get_user(to->si_uid, &from->si_uid);
136 err |= __get_user(to->si_utime, &from->si_utime);
137 err |= __get_user(to->si_stime, &from->si_stime);
138 err |= __get_user(to->si_status, &from->si_status);
139 break;
140 case __SI_FAULT >> 16:
141 err |= __get_user(tmp, &from->si_addr);
Al Viroc2814472005-09-29 00:16:02 +0100142 to->si_addr = (void __user *)(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));
214 switch (_NSIG_WORDS) {
215 case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6]
216 | (((long)set32.sig[7]) << 32);
217 case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4]
218 | (((long)set32.sig[5]) << 32);
219 case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2]
220 | (((long)set32.sig[3]) << 32);
221 case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0]
222 | (((long)set32.sig[1]) << 32);
223 }
224 ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
225
226 if (ret)
227 return -EFAULT;
228 new_ka.sa.sa_handler = (__sighandler_t) sa_handler;
229 }
230
231 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
232
233 if (!ret && oact) {
234 switch (_NSIG_WORDS) {
235 case 4:
236 set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32);
237 set32.sig[6] = old_ka.sa.sa_mask.sig[3];
238 case 3:
239 set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32);
240 set32.sig[4] = old_ka.sa.sa_mask.sig[2];
241 case 2:
242 set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32);
243 set32.sig[2] = old_ka.sa.sa_mask.sig[1];
244 case 1:
245 set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32);
246 set32.sig[0] = old_ka.sa.sa_mask.sig[0];
247 }
248 ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler);
249 ret |= __copy_to_user(&oact->sa_mask, &set32,
250 sizeof(compat_sigset_t));
251 ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
252 }
253
254 return ret;
255}
256
257asmlinkage long
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200258sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200260 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 stack_t kss, koss;
262 unsigned long ss_sp;
263 int ret, err = 0;
264 mm_segment_t old_fs = get_fs();
265
266 if (uss) {
267 if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
268 return -EFAULT;
269 err |= __get_user(ss_sp, &uss->ss_sp);
270 err |= __get_user(kss.ss_size, &uss->ss_size);
271 err |= __get_user(kss.ss_flags, &uss->ss_flags);
272 if (err)
273 return -EFAULT;
Al Viroc2814472005-09-29 00:16:02 +0100274 kss.ss_sp = (void __user *) ss_sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 }
276
277 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100278 ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
279 (stack_t __force __user *) (uoss ? &koss : NULL),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 regs->gprs[15]);
281 set_fs (old_fs);
282
283 if (!ret && uoss) {
284 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
285 return -EFAULT;
286 ss_sp = (unsigned long) koss.ss_sp;
287 err |= __put_user(ss_sp, &uoss->ss_sp);
288 err |= __put_user(koss.ss_size, &uoss->ss_size);
289 err |= __put_user(koss.ss_flags, &uoss->ss_flags);
290 if (err)
291 return -EFAULT;
292 }
293 return ret;
294}
295
296static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
297{
298 _s390_regs_common32 regs32;
299 int err, i;
300
Gerald Schaeferc1821c22007-02-05 21:18:17 +0100301 regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 (__u32)(regs->psw.mask >> 32));
303 regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
304 for (i = 0; i < NUM_GPRS; i++)
305 regs32.gprs[i] = (__u32) regs->gprs[i];
306 save_access_regs(current->thread.acrs);
307 memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
308 err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
309 if (err)
310 return err;
311 save_fp_regs(&current->thread.fp_regs);
312 /* s390_fp_regs and _s390_fp_regs32 are the same ! */
313 return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
314 sizeof(_s390_fp_regs32));
315}
316
317static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
318{
319 _s390_regs_common32 regs32;
320 int err, i;
321
322 /* Alwys make any pending restarted system call return -EINTR */
323 current_thread_info()->restart_block.fn = do_no_restart_syscall;
324
325 err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
326 if (err)
327 return err;
328 regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
329 (__u64)regs32.psw.mask << 32);
330 regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
331 for (i = 0; i < NUM_GPRS; i++)
332 regs->gprs[i] = (__u64) regs32.gprs[i];
333 memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
334 restore_access_regs(current->thread.acrs);
335
336 err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
337 sizeof(_s390_fp_regs32));
338 current->thread.fp_regs.fpc &= FPC_VALID_MASK;
339 if (err)
340 return err;
341
342 restore_fp_regs(&current->thread.fp_regs);
Martin Schwidefsky59da2132008-11-27 11:05:55 +0100343 regs->svcnr = 0; /* disable syscall checks */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 return 0;
345}
346
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200347asmlinkage long sys32_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200349 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];
351 sigset_t set;
352
353 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
354 goto badframe;
355 if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))
356 goto badframe;
357
358 sigdelsetmask(&set, ~_BLOCKABLE);
359 spin_lock_irq(&current->sighand->siglock);
360 current->blocked = set;
361 recalc_sigpending();
362 spin_unlock_irq(&current->sighand->siglock);
363
364 if (restore_sigregs32(regs, &frame->sregs))
365 goto badframe;
366
367 return regs->gprs[2];
368
369badframe:
370 force_sig(SIGSEGV, current);
371 return 0;
372}
373
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200374asmlinkage long sys32_rt_sigreturn(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200376 struct pt_regs *regs = task_pt_regs(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];
378 sigset_t set;
379 stack_t st;
380 __u32 ss_sp;
381 int err;
382 mm_segment_t old_fs = get_fs();
383
384 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
385 goto badframe;
386 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
387 goto badframe;
388
389 sigdelsetmask(&set, ~_BLOCKABLE);
390 spin_lock_irq(&current->sighand->siglock);
391 current->blocked = set;
392 recalc_sigpending();
393 spin_unlock_irq(&current->sighand->siglock);
394
395 if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
396 goto badframe;
397
398 err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
Al Viroc2814472005-09-29 00:16:02 +0100399 st.ss_sp = compat_ptr(ss_sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
401 err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
402 if (err)
403 goto badframe;
404
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 set_fs (KERNEL_DS);
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100406 do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 set_fs (old_fs);
408
409 return regs->gprs[2];
410
411badframe:
Martin Schwidefsky03ff9a22007-04-27 16:01:40 +0200412 force_sig(SIGSEGV, current);
413 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414}
415
416/*
417 * Set up a signal frame.
418 */
419
420
421/*
422 * Determine which stack to use..
423 */
424static inline void __user *
425get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
426{
427 unsigned long sp;
428
429 /* Default to using normal stack */
430 sp = (unsigned long) A(regs->gprs[15]);
431
Heiko Carstensde553432008-04-17 07:45:57 +0200432 /* Overflow on alternate signal stack gives SIGSEGV. */
433 if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
434 return (void __user *) -1UL;
435
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 /* This is the X/Open sanctioned signal stack switching. */
437 if (ka->sa.sa_flags & SA_ONSTACK) {
Laurent Meyer28f22372006-04-27 18:40:07 -0700438 if (! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 sp = current->sas_ss_sp + current->sas_ss_size;
440 }
441
442 /* This is the legacy signal stack switching. */
443 else if (!user_mode(regs) &&
444 !(ka->sa.sa_flags & SA_RESTORER) &&
445 ka->sa.sa_restorer) {
446 sp = (unsigned long) ka->sa.sa_restorer;
447 }
448
449 return (void __user *)((sp - frame_size) & -8ul);
450}
451
452static inline int map_signal(int sig)
453{
454 if (current_thread_info()->exec_domain
455 && current_thread_info()->exec_domain->signal_invmap
456 && sig < 32)
457 return current_thread_info()->exec_domain->signal_invmap[sig];
458 else
459 return sig;
460}
461
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800462static int setup_frame32(int sig, struct k_sigaction *ka,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 sigset_t *set, struct pt_regs * regs)
464{
465 sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32));
466 if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32)))
467 goto give_sigsegv;
468
Heiko Carstensde553432008-04-17 07:45:57 +0200469 if (frame == (void __user *) -1UL)
470 goto give_sigsegv;
471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32))
473 goto give_sigsegv;
474
475 if (save_sigregs32(regs, &frame->sregs))
476 goto give_sigsegv;
477 if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
478 goto give_sigsegv;
479
480 /* Set up to return from userspace. If provided, use a stub
481 already in userspace. */
482 if (ka->sa.sa_flags & SA_RESTORER) {
483 regs->gprs[14] = (__u64) ka->sa.sa_restorer;
484 } else {
485 regs->gprs[14] = (__u64) frame->retcode;
486 if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
487 (u16 __user *)(frame->retcode)))
488 goto give_sigsegv;
489 }
490
491 /* Set up backchain. */
492 if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
493 goto give_sigsegv;
494
495 /* Set up registers for signal handler */
496 regs->gprs[15] = (__u64) frame;
497 regs->psw.addr = (__u64) ka->sa.sa_handler;
498
499 regs->gprs[2] = map_signal(sig);
500 regs->gprs[3] = (__u64) &frame->sc;
501
502 /* We forgot to include these in the sigcontext.
503 To avoid breaking binary compatibility, they are passed as args. */
504 regs->gprs[4] = current->thread.trap_no;
505 regs->gprs[5] = current->thread.prot_addr;
506
507 /* Place signal number on stack to allow backtrace from handler. */
508 if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
509 goto give_sigsegv;
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800510 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512give_sigsegv:
513 force_sigsegv(sig, current);
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800514 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515}
516
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800517static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 sigset_t *set, struct pt_regs * regs)
519{
520 int err = 0;
521 rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32));
522 if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32)))
523 goto give_sigsegv;
524
Heiko Carstensde553432008-04-17 07:45:57 +0200525 if (frame == (void __user *) -1UL)
526 goto give_sigsegv;
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 if (copy_siginfo_to_user32(&frame->info, info))
529 goto give_sigsegv;
530
531 /* Create the ucontext. */
532 err |= __put_user(0, &frame->uc.uc_flags);
533 err |= __put_user(0, &frame->uc.uc_link);
534 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
535 err |= __put_user(sas_ss_flags(regs->gprs[15]),
536 &frame->uc.uc_stack.ss_flags);
537 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
538 err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
539 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
540 if (err)
541 goto give_sigsegv;
542
543 /* Set up to return from userspace. If provided, use a stub
544 already in userspace. */
545 if (ka->sa.sa_flags & SA_RESTORER) {
546 regs->gprs[14] = (__u64) ka->sa.sa_restorer;
547 } else {
548 regs->gprs[14] = (__u64) frame->retcode;
549 err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
550 (u16 __user *)(frame->retcode));
551 }
552
553 /* Set up backchain. */
554 if (__put_user(regs->gprs[15], (unsigned int __user *) frame))
555 goto give_sigsegv;
556
557 /* Set up registers for signal handler */
558 regs->gprs[15] = (__u64) frame;
559 regs->psw.addr = (__u64) ka->sa.sa_handler;
560
561 regs->gprs[2] = map_signal(sig);
562 regs->gprs[3] = (__u64) &frame->info;
563 regs->gprs[4] = (__u64) &frame->uc;
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800564 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566give_sigsegv:
567 force_sigsegv(sig, current);
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800568 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569}
570
571/*
572 * OK, we're invoking a handler
573 */
574
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800575int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576handle_signal32(unsigned long sig, struct k_sigaction *ka,
577 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
578{
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800579 int ret;
580
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 /* Set up the stack frame */
582 if (ka->sa.sa_flags & SA_SIGINFO)
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800583 ret = setup_rt_frame32(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 else
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800585 ret = setup_frame32(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
Heiko Carstens54dfe5d2006-02-01 03:06:38 -0800587 if (ret == 0) {
588 spin_lock_irq(&current->sighand->siglock);
589 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
590 if (!(ka->sa.sa_flags & SA_NODEFER))
591 sigaddset(&current->blocked,sig);
592 recalc_sigpending();
593 spin_unlock_irq(&current->sighand->siglock);
594 }
595 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596}
597