1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
3a53c8fabSHeiko Carstens * Copyright IBM Corp. 1999, 2006
41da177e4SLinus Torvalds * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Based on Intel version
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
111da177e4SLinus Torvalds */
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #include <linux/sched.h>
1468db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
151da177e4SLinus Torvalds #include <linux/mm.h>
161da177e4SLinus Torvalds #include <linux/smp.h>
171da177e4SLinus Torvalds #include <linux/kernel.h>
181da177e4SLinus Torvalds #include <linux/signal.h>
19c1971eaeSSven Schnelle #include <linux/entry-common.h>
201da177e4SLinus Torvalds #include <linux/errno.h>
211da177e4SLinus Torvalds #include <linux/wait.h>
221da177e4SLinus Torvalds #include <linux/ptrace.h>
231da177e4SLinus Torvalds #include <linux/unistd.h>
241da177e4SLinus Torvalds #include <linux/stddef.h>
251da177e4SLinus Torvalds #include <linux/tty.h>
261da177e4SLinus Torvalds #include <linux/personality.h>
271da177e4SLinus Torvalds #include <linux/binfmts.h>
2826689452SHeiko Carstens #include <linux/syscalls.h>
297757591aSHeiko Carstens #include <linux/compat.h>
301da177e4SLinus Torvalds #include <asm/ucontext.h>
317c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
321da177e4SLinus Torvalds #include <asm/lowcore.h>
33a0616cdeSDavid Howells #include <asm/switch_to.h>
34df29a744SSven Schnelle #include <asm/vdso.h>
35a806170eSHeiko Carstens #include "entry.h"
361da177e4SLinus Torvalds
3780703617SMartin Schwidefsky /*
3880703617SMartin Schwidefsky * Layout of an old-style signal-frame:
3980703617SMartin Schwidefsky * -----------------------------------------
4080703617SMartin Schwidefsky * | save area (_SIGNAL_FRAMESIZE) |
4180703617SMartin Schwidefsky * -----------------------------------------
4280703617SMartin Schwidefsky * | struct sigcontext |
4380703617SMartin Schwidefsky * | oldmask |
4480703617SMartin Schwidefsky * | _sigregs * |
4580703617SMartin Schwidefsky * -----------------------------------------
4680703617SMartin Schwidefsky * | _sigregs with |
4780703617SMartin Schwidefsky * | _s390_regs_common |
4880703617SMartin Schwidefsky * | _s390_fp_regs |
4980703617SMartin Schwidefsky * -----------------------------------------
5080703617SMartin Schwidefsky * | int signo |
5180703617SMartin Schwidefsky * -----------------------------------------
5280703617SMartin Schwidefsky * | _sigregs_ext with |
5380703617SMartin Schwidefsky * | gprs_high 64 byte (opt) |
5480703617SMartin Schwidefsky * | vxrs_low 128 byte (opt) |
5580703617SMartin Schwidefsky * | vxrs_high 256 byte (opt) |
5680703617SMartin Schwidefsky * | reserved 128 byte (opt) |
5780703617SMartin Schwidefsky * -----------------------------------------
5880703617SMartin Schwidefsky * | __u16 svc_insn |
5980703617SMartin Schwidefsky * -----------------------------------------
6080703617SMartin Schwidefsky * The svc_insn entry with the sigreturn system call opcode does not
6180703617SMartin Schwidefsky * have a fixed position and moves if gprs_high or vxrs exist.
6280703617SMartin Schwidefsky * Future extensions will be added to _sigregs_ext.
6380703617SMartin Schwidefsky */
6480703617SMartin Schwidefsky struct sigframe
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
671da177e4SLinus Torvalds struct sigcontext sc;
681da177e4SLinus Torvalds _sigregs sregs;
691da177e4SLinus Torvalds int signo;
7080703617SMartin Schwidefsky _sigregs_ext sregs_ext;
7180703617SMartin Schwidefsky __u16 svc_insn; /* Offset of svc_insn is NOT fixed! */
7280703617SMartin Schwidefsky };
731da177e4SLinus Torvalds
7480703617SMartin Schwidefsky /*
7580703617SMartin Schwidefsky * Layout of an rt signal-frame:
7680703617SMartin Schwidefsky * -----------------------------------------
7780703617SMartin Schwidefsky * | save area (_SIGNAL_FRAMESIZE) |
7880703617SMartin Schwidefsky * -----------------------------------------
7980703617SMartin Schwidefsky * | svc __NR_rt_sigreturn 2 byte |
8080703617SMartin Schwidefsky * -----------------------------------------
8180703617SMartin Schwidefsky * | struct siginfo |
8280703617SMartin Schwidefsky * -----------------------------------------
8380703617SMartin Schwidefsky * | struct ucontext_extended with |
8480703617SMartin Schwidefsky * | unsigned long uc_flags |
8580703617SMartin Schwidefsky * | struct ucontext *uc_link |
8680703617SMartin Schwidefsky * | stack_t uc_stack |
8780703617SMartin Schwidefsky * | _sigregs uc_mcontext with |
8880703617SMartin Schwidefsky * | _s390_regs_common |
8980703617SMartin Schwidefsky * | _s390_fp_regs |
9080703617SMartin Schwidefsky * | sigset_t uc_sigmask |
9180703617SMartin Schwidefsky * | _sigregs_ext uc_mcontext_ext |
9280703617SMartin Schwidefsky * | gprs_high 64 byte (opt) |
9380703617SMartin Schwidefsky * | vxrs_low 128 byte (opt) |
9480703617SMartin Schwidefsky * | vxrs_high 256 byte (opt)|
9580703617SMartin Schwidefsky * | reserved 128 byte (opt) |
9680703617SMartin Schwidefsky * -----------------------------------------
9780703617SMartin Schwidefsky * Future extensions will be added to _sigregs_ext.
9880703617SMartin Schwidefsky */
9980703617SMartin Schwidefsky struct rt_sigframe
1001da177e4SLinus Torvalds {
1011da177e4SLinus Torvalds __u8 callee_used_stack[__SIGNAL_FRAMESIZE];
10280703617SMartin Schwidefsky __u16 svc_insn;
1031da177e4SLinus Torvalds struct siginfo info;
10480703617SMartin Schwidefsky struct ucontext_extended uc;
10580703617SMartin Schwidefsky };
10680703617SMartin Schwidefsky
10780703617SMartin Schwidefsky /* Store registers needed to create the signal frame */
store_sigregs(void)10880703617SMartin Schwidefsky static void store_sigregs(void)
10980703617SMartin Schwidefsky {
11080703617SMartin Schwidefsky save_access_regs(current->thread.acrs);
111d0164ee2SHendrik Brueckner save_fpu_regs();
11280703617SMartin Schwidefsky }
11380703617SMartin Schwidefsky
11480703617SMartin Schwidefsky /* Load registers after signal return */
load_sigregs(void)11580703617SMartin Schwidefsky static void load_sigregs(void)
11680703617SMartin Schwidefsky {
11780703617SMartin Schwidefsky restore_access_regs(current->thread.acrs);
11880703617SMartin Schwidefsky }
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds /* Returns non-zero on fault. */
save_sigregs(struct pt_regs * regs,_sigregs __user * sregs)1211da177e4SLinus Torvalds static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
1221da177e4SLinus Torvalds {
1236837a8c3SGerald Schaefer _sigregs user_sregs;
1241da177e4SLinus Torvalds
1251da177e4SLinus Torvalds /* Copy a 'clean' PSW mask to the user to avoid leaking
1261da177e4SLinus Torvalds information about whether PER is currently on. */
127e258d719SMartin Schwidefsky user_sregs.regs.psw.mask = PSW_USER_BITS |
1285ebf250dSHeiko Carstens (regs->psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
129b05e3703SMartin Schwidefsky user_sregs.regs.psw.addr = regs->psw.addr;
130b05e3703SMartin Schwidefsky memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs));
1316837a8c3SGerald Schaefer memcpy(&user_sregs.regs.acrs, current->thread.acrs,
1324725c860SMartin Schwidefsky sizeof(user_sregs.regs.acrs));
133904818e2SHendrik Brueckner fpregs_store(&user_sregs.fpregs, ¤t->thread.fpu);
134f8544ec4SHeiko Carstens if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs)))
135f8544ec4SHeiko Carstens return -EFAULT;
136f8544ec4SHeiko Carstens return 0;
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds
restore_sigregs(struct pt_regs * regs,_sigregs __user * sregs)1391da177e4SLinus Torvalds static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
1401da177e4SLinus Torvalds {
1416837a8c3SGerald Schaefer _sigregs user_sregs;
1421da177e4SLinus Torvalds
1430ecf337fSHeiko Carstens /* Always make any pending restarted system call return -EINTR */
144f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall;
1451da177e4SLinus Torvalds
1464725c860SMartin Schwidefsky if (__copy_from_user(&user_sregs, sregs, sizeof(user_sregs)))
147f8544ec4SHeiko Carstens return -EFAULT;
1484725c860SMartin Schwidefsky
1495ebf250dSHeiko Carstens if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI))
1505ebf250dSHeiko Carstens return -EINVAL;
1515ebf250dSHeiko Carstens
1524084eb77SHendrik Brueckner /* Test the floating-point-control word. */
1534084eb77SHendrik Brueckner if (test_fp_ctl(user_sregs.fpregs.fpc))
1544725c860SMartin Schwidefsky return -EINVAL;
1554725c860SMartin Schwidefsky
156e258d719SMartin Schwidefsky /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */
157aa7e04b3SHendrik Brueckner regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) |
1585ebf250dSHeiko Carstens (user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI));
159fa968ee2SMartin Schwidefsky /* Check for invalid user address space control. */
160e258d719SMartin Schwidefsky if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME)
161e258d719SMartin Schwidefsky regs->psw.mask = PSW_ASC_PRIMARY |
162fa968ee2SMartin Schwidefsky (regs->psw.mask & ~PSW_MASK_ASC);
163d4e81b35SMartin Schwidefsky /* Check for invalid amode */
164d4e81b35SMartin Schwidefsky if (regs->psw.mask & PSW_MASK_EA)
165d4e81b35SMartin Schwidefsky regs->psw.mask |= PSW_MASK_BA;
166d4e81b35SMartin Schwidefsky regs->psw.addr = user_sregs.regs.psw.addr;
167b05e3703SMartin Schwidefsky memcpy(®s->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
1686837a8c3SGerald Schaefer memcpy(¤t->thread.acrs, &user_sregs.regs.acrs,
1694725c860SMartin Schwidefsky sizeof(current->thread.acrs));
1701da177e4SLinus Torvalds
171904818e2SHendrik Brueckner fpregs_load(&user_sregs.fpregs, ¤t->thread.fpu);
1721da177e4SLinus Torvalds
173d3a73acbSMartin Schwidefsky clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */
1741da177e4SLinus Torvalds return 0;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds
17780703617SMartin Schwidefsky /* Returns non-zero on fault. */
save_sigregs_ext(struct pt_regs * regs,_sigregs_ext __user * sregs_ext)17880703617SMartin Schwidefsky static int save_sigregs_ext(struct pt_regs *regs,
17980703617SMartin Schwidefsky _sigregs_ext __user *sregs_ext)
18080703617SMartin Schwidefsky {
18180703617SMartin Schwidefsky __u64 vxrs[__NUM_VXRS_LOW];
18280703617SMartin Schwidefsky int i;
18380703617SMartin Schwidefsky
18480703617SMartin Schwidefsky /* Save vector registers to signal stack */
185b5510d9bSHendrik Brueckner if (MACHINE_HAS_VX) {
18680703617SMartin Schwidefsky for (i = 0; i < __NUM_VXRS_LOW; i++)
187*a02d584eSHeiko Carstens vxrs[i] = current->thread.fpu.vxrs[i].low;
18880703617SMartin Schwidefsky if (__copy_to_user(&sregs_ext->vxrs_low, vxrs,
18980703617SMartin Schwidefsky sizeof(sregs_ext->vxrs_low)) ||
19080703617SMartin Schwidefsky __copy_to_user(&sregs_ext->vxrs_high,
191904818e2SHendrik Brueckner current->thread.fpu.vxrs + __NUM_VXRS_LOW,
19280703617SMartin Schwidefsky sizeof(sregs_ext->vxrs_high)))
19380703617SMartin Schwidefsky return -EFAULT;
19480703617SMartin Schwidefsky }
19580703617SMartin Schwidefsky return 0;
19680703617SMartin Schwidefsky }
19780703617SMartin Schwidefsky
restore_sigregs_ext(struct pt_regs * regs,_sigregs_ext __user * sregs_ext)19880703617SMartin Schwidefsky static int restore_sigregs_ext(struct pt_regs *regs,
19980703617SMartin Schwidefsky _sigregs_ext __user *sregs_ext)
20080703617SMartin Schwidefsky {
20180703617SMartin Schwidefsky __u64 vxrs[__NUM_VXRS_LOW];
20280703617SMartin Schwidefsky int i;
20380703617SMartin Schwidefsky
20480703617SMartin Schwidefsky /* Restore vector registers from signal stack */
205b5510d9bSHendrik Brueckner if (MACHINE_HAS_VX) {
20680703617SMartin Schwidefsky if (__copy_from_user(vxrs, &sregs_ext->vxrs_low,
20780703617SMartin Schwidefsky sizeof(sregs_ext->vxrs_low)) ||
208904818e2SHendrik Brueckner __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW,
20980703617SMartin Schwidefsky &sregs_ext->vxrs_high,
21080703617SMartin Schwidefsky sizeof(sregs_ext->vxrs_high)))
21180703617SMartin Schwidefsky return -EFAULT;
21280703617SMartin Schwidefsky for (i = 0; i < __NUM_VXRS_LOW; i++)
213*a02d584eSHeiko Carstens current->thread.fpu.vxrs[i].low = vxrs[i];
21480703617SMartin Schwidefsky }
21580703617SMartin Schwidefsky return 0;
21680703617SMartin Schwidefsky }
21780703617SMartin Schwidefsky
SYSCALL_DEFINE0(sigreturn)21826689452SHeiko Carstens SYSCALL_DEFINE0(sigreturn)
2191da177e4SLinus Torvalds {
22003ff9a23SMartin Schwidefsky struct pt_regs *regs = task_pt_regs(current);
22180703617SMartin Schwidefsky struct sigframe __user *frame =
22280703617SMartin Schwidefsky (struct sigframe __user *) regs->gprs[15];
2231da177e4SLinus Torvalds sigset_t set;
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE))
2261da177e4SLinus Torvalds goto badframe;
227391c62feSHeiko Carstens set_current_blocked(&set);
228d0164ee2SHendrik Brueckner save_fpu_regs();
2291da177e4SLinus Torvalds if (restore_sigregs(regs, &frame->sregs))
2301da177e4SLinus Torvalds goto badframe;
23180703617SMartin Schwidefsky if (restore_sigregs_ext(regs, &frame->sregs_ext))
23280703617SMartin Schwidefsky goto badframe;
23380703617SMartin Schwidefsky load_sigregs();
2341da177e4SLinus Torvalds return regs->gprs[2];
2351da177e4SLinus Torvalds badframe:
2363cf5d076SEric W. Biederman force_sig(SIGSEGV);
2371da177e4SLinus Torvalds return 0;
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds
SYSCALL_DEFINE0(rt_sigreturn)24026689452SHeiko Carstens SYSCALL_DEFINE0(rt_sigreturn)
2411da177e4SLinus Torvalds {
24203ff9a23SMartin Schwidefsky struct pt_regs *regs = task_pt_regs(current);
24380703617SMartin Schwidefsky struct rt_sigframe __user *frame =
24480703617SMartin Schwidefsky (struct rt_sigframe __user *)regs->gprs[15];
2451da177e4SLinus Torvalds sigset_t set;
2461da177e4SLinus Torvalds
2471da177e4SLinus Torvalds if (__copy_from_user(&set.sig, &frame->uc.uc_sigmask, sizeof(set)))
2481da177e4SLinus Torvalds goto badframe;
249391c62feSHeiko Carstens set_current_blocked(&set);
250e214125aSAl Viro if (restore_altstack(&frame->uc.uc_stack))
2514e3df37eSCedric Le Goater goto badframe;
252d0164ee2SHendrik Brueckner save_fpu_regs();
25380703617SMartin Schwidefsky if (restore_sigregs(regs, &frame->uc.uc_mcontext))
25480703617SMartin Schwidefsky goto badframe;
25580703617SMartin Schwidefsky if (restore_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
25680703617SMartin Schwidefsky goto badframe;
25780703617SMartin Schwidefsky load_sigregs();
2581da177e4SLinus Torvalds return regs->gprs[2];
2591da177e4SLinus Torvalds badframe:
2603cf5d076SEric W. Biederman force_sig(SIGSEGV);
2611da177e4SLinus Torvalds return 0;
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds
2641da177e4SLinus Torvalds /*
2651da177e4SLinus Torvalds * Determine which stack to use..
2661da177e4SLinus Torvalds */
2671da177e4SLinus Torvalds static inline void __user *
get_sigframe(struct k_sigaction * ka,struct pt_regs * regs,size_t frame_size)2681da177e4SLinus Torvalds get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds unsigned long sp;
2711da177e4SLinus Torvalds
2721da177e4SLinus Torvalds /* Default to using normal stack */
2731da177e4SLinus Torvalds sp = regs->gprs[15];
2741da177e4SLinus Torvalds
275de553438SHeiko Carstens /* Overflow on alternate signal stack gives SIGSEGV. */
276de553438SHeiko Carstens if (on_sig_stack(sp) && !on_sig_stack((sp - frame_size) & -8UL))
277de553438SHeiko Carstens return (void __user *) -1UL;
278de553438SHeiko Carstens
2791da177e4SLinus Torvalds /* This is the X/Open sanctioned signal stack switching. */
2801da177e4SLinus Torvalds if (ka->sa.sa_flags & SA_ONSTACK) {
2811da177e4SLinus Torvalds if (! sas_ss_flags(sp))
2821da177e4SLinus Torvalds sp = current->sas_ss_sp + current->sas_ss_size;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds
2851da177e4SLinus Torvalds return (void __user *)((sp - frame_size) & -8ul);
2861da177e4SLinus Torvalds }
2871da177e4SLinus Torvalds
setup_frame(int sig,struct k_sigaction * ka,sigset_t * set,struct pt_regs * regs)28854dfe5ddSHeiko Carstens static int setup_frame(int sig, struct k_sigaction *ka,
2891da177e4SLinus Torvalds sigset_t *set, struct pt_regs * regs)
2901da177e4SLinus Torvalds {
29180703617SMartin Schwidefsky struct sigframe __user *frame;
29280703617SMartin Schwidefsky struct sigcontext sc;
29380703617SMartin Schwidefsky unsigned long restorer;
29480703617SMartin Schwidefsky size_t frame_size;
2951da177e4SLinus Torvalds
29680703617SMartin Schwidefsky /*
29780703617SMartin Schwidefsky * gprs_high are only present for a 31-bit task running on
29880703617SMartin Schwidefsky * a 64-bit kernel (see compat_signal.c) but the space for
29980703617SMartin Schwidefsky * gprs_high need to be allocated if vector registers are
30080703617SMartin Schwidefsky * included in the signal frame on a 31-bit system.
30180703617SMartin Schwidefsky */
30280703617SMartin Schwidefsky frame_size = sizeof(*frame) - sizeof(frame->sregs_ext);
30380703617SMartin Schwidefsky if (MACHINE_HAS_VX)
30480703617SMartin Schwidefsky frame_size += sizeof(frame->sregs_ext);
30580703617SMartin Schwidefsky frame = get_sigframe(ka, regs, frame_size);
306de553438SHeiko Carstens if (frame == (void __user *) -1UL)
307067bf2d4SRichard Weinberger return -EFAULT;
308de553438SHeiko Carstens
3091da177e4SLinus Torvalds /* Set up backchain. */
3101da177e4SLinus Torvalds if (__put_user(regs->gprs[15], (addr_t __user *) frame))
311067bf2d4SRichard Weinberger return -EFAULT;
3121da177e4SLinus Torvalds
31380703617SMartin Schwidefsky /* Create struct sigcontext on the signal stack */
31480703617SMartin Schwidefsky memcpy(&sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE);
31580703617SMartin Schwidefsky sc.sregs = (_sigregs __user __force *) &frame->sregs;
31680703617SMartin Schwidefsky if (__copy_to_user(&frame->sc, &sc, sizeof(frame->sc)))
31780703617SMartin Schwidefsky return -EFAULT;
31880703617SMartin Schwidefsky
31980703617SMartin Schwidefsky /* Store registers needed to create the signal frame */
32080703617SMartin Schwidefsky store_sigregs();
32180703617SMartin Schwidefsky
32280703617SMartin Schwidefsky /* Create _sigregs on the signal stack */
32380703617SMartin Schwidefsky if (save_sigregs(regs, &frame->sregs))
32480703617SMartin Schwidefsky return -EFAULT;
32580703617SMartin Schwidefsky
32680703617SMartin Schwidefsky /* Place signal number on stack to allow backtrace from handler. */
32780703617SMartin Schwidefsky if (__put_user(regs->gprs[2], (int __user *) &frame->signo))
32880703617SMartin Schwidefsky return -EFAULT;
32980703617SMartin Schwidefsky
33080703617SMartin Schwidefsky /* Create _sigregs_ext on the signal stack */
33180703617SMartin Schwidefsky if (save_sigregs_ext(regs, &frame->sregs_ext))
33280703617SMartin Schwidefsky return -EFAULT;
33380703617SMartin Schwidefsky
33480703617SMartin Schwidefsky /* Set up to return from userspace. If provided, use a stub
33580703617SMartin Schwidefsky already in userspace. */
336df29a744SSven Schnelle if (ka->sa.sa_flags & SA_RESTORER)
337fecc868aSHeiko Carstens restorer = (unsigned long) ka->sa.sa_restorer;
338df29a744SSven Schnelle else
339df29a744SSven Schnelle restorer = VDSO64_SYMBOL(current, sigreturn);
34080703617SMartin Schwidefsky
3411da177e4SLinus Torvalds /* Set up registers for signal handler */
34280703617SMartin Schwidefsky regs->gprs[14] = restorer;
3431da177e4SLinus Torvalds regs->gprs[15] = (unsigned long) frame;
344fa968ee2SMartin Schwidefsky /* Force default amode and default user address space control. */
345fa968ee2SMartin Schwidefsky regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
346e258d719SMartin Schwidefsky (PSW_USER_BITS & PSW_MASK_ASC) |
347fa968ee2SMartin Schwidefsky (regs->psw.mask & ~PSW_MASK_ASC);
348fecc868aSHeiko Carstens regs->psw.addr = (unsigned long) ka->sa.sa_handler;
3491da177e4SLinus Torvalds
3506a32591aSRichard Weinberger regs->gprs[2] = sig;
3511da177e4SLinus Torvalds regs->gprs[3] = (unsigned long) &frame->sc;
3521da177e4SLinus Torvalds
3531da177e4SLinus Torvalds /* We forgot to include these in the sigcontext.
3541da177e4SLinus Torvalds To avoid breaking binary compatibility, they are passed as args. */
355aa33c8cbSMartin Schwidefsky if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL ||
356aa33c8cbSMartin Schwidefsky sig == SIGTRAP || sig == SIGFPE) {
357aa33c8cbSMartin Schwidefsky /* set extra registers only for synchronous signals */
358aa33c8cbSMartin Schwidefsky regs->gprs[4] = regs->int_code & 127;
359aa33c8cbSMartin Schwidefsky regs->gprs[5] = regs->int_parm_long;
360ef280c85SMartin Schwidefsky regs->gprs[6] = current->thread.last_break;
361aa33c8cbSMartin Schwidefsky }
362067bf2d4SRichard Weinberger return 0;
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds
setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)365067bf2d4SRichard Weinberger static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
366067bf2d4SRichard Weinberger struct pt_regs *regs)
3671da177e4SLinus Torvalds {
36880703617SMartin Schwidefsky struct rt_sigframe __user *frame;
36980703617SMartin Schwidefsky unsigned long uc_flags, restorer;
37080703617SMartin Schwidefsky size_t frame_size;
3711da177e4SLinus Torvalds
37280703617SMartin Schwidefsky frame_size = sizeof(struct rt_sigframe) - sizeof(_sigregs_ext);
37380703617SMartin Schwidefsky /*
37480703617SMartin Schwidefsky * gprs_high are only present for a 31-bit task running on
37580703617SMartin Schwidefsky * a 64-bit kernel (see compat_signal.c) but the space for
37680703617SMartin Schwidefsky * gprs_high need to be allocated if vector registers are
37780703617SMartin Schwidefsky * included in the signal frame on a 31-bit system.
37880703617SMartin Schwidefsky */
37980703617SMartin Schwidefsky uc_flags = 0;
38080703617SMartin Schwidefsky if (MACHINE_HAS_VX) {
38180703617SMartin Schwidefsky frame_size += sizeof(_sigregs_ext);
38280703617SMartin Schwidefsky uc_flags |= UC_VXRS;
38380703617SMartin Schwidefsky }
38480703617SMartin Schwidefsky frame = get_sigframe(&ksig->ka, regs, frame_size);
385de553438SHeiko Carstens if (frame == (void __user *) -1UL)
386067bf2d4SRichard Weinberger return -EFAULT;
387de553438SHeiko Carstens
3881da177e4SLinus Torvalds /* Set up backchain. */
3891da177e4SLinus Torvalds if (__put_user(regs->gprs[15], (addr_t __user *) frame))
390067bf2d4SRichard Weinberger return -EFAULT;
3911da177e4SLinus Torvalds
39280703617SMartin Schwidefsky /* Set up to return from userspace. If provided, use a stub
39380703617SMartin Schwidefsky already in userspace. */
394df29a744SSven Schnelle if (ksig->ka.sa.sa_flags & SA_RESTORER)
395fecc868aSHeiko Carstens restorer = (unsigned long) ksig->ka.sa.sa_restorer;
396df29a744SSven Schnelle else
397df29a744SSven Schnelle restorer = VDSO64_SYMBOL(current, rt_sigreturn);
39880703617SMartin Schwidefsky
39980703617SMartin Schwidefsky /* Create siginfo on the signal stack */
40080703617SMartin Schwidefsky if (copy_siginfo_to_user(&frame->info, &ksig->info))
40180703617SMartin Schwidefsky return -EFAULT;
40280703617SMartin Schwidefsky
40380703617SMartin Schwidefsky /* Store registers needed to create the signal frame */
40480703617SMartin Schwidefsky store_sigregs();
40580703617SMartin Schwidefsky
40680703617SMartin Schwidefsky /* Create ucontext on the signal stack. */
40780703617SMartin Schwidefsky if (__put_user(uc_flags, &frame->uc.uc_flags) ||
40880703617SMartin Schwidefsky __put_user(NULL, &frame->uc.uc_link) ||
40980703617SMartin Schwidefsky __save_altstack(&frame->uc.uc_stack, regs->gprs[15]) ||
41080703617SMartin Schwidefsky save_sigregs(regs, &frame->uc.uc_mcontext) ||
41180703617SMartin Schwidefsky __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)) ||
41280703617SMartin Schwidefsky save_sigregs_ext(regs, &frame->uc.uc_mcontext_ext))
41380703617SMartin Schwidefsky return -EFAULT;
41480703617SMartin Schwidefsky
4151da177e4SLinus Torvalds /* Set up registers for signal handler */
41680703617SMartin Schwidefsky regs->gprs[14] = restorer;
4171da177e4SLinus Torvalds regs->gprs[15] = (unsigned long) frame;
418fa968ee2SMartin Schwidefsky /* Force default amode and default user address space control. */
419fa968ee2SMartin Schwidefsky regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
420e258d719SMartin Schwidefsky (PSW_USER_BITS & PSW_MASK_ASC) |
421fa968ee2SMartin Schwidefsky (regs->psw.mask & ~PSW_MASK_ASC);
422fecc868aSHeiko Carstens regs->psw.addr = (unsigned long) ksig->ka.sa.sa_handler;
4231da177e4SLinus Torvalds
4246a32591aSRichard Weinberger regs->gprs[2] = ksig->sig;
4251da177e4SLinus Torvalds regs->gprs[3] = (unsigned long) &frame->info;
4261da177e4SLinus Torvalds regs->gprs[4] = (unsigned long) &frame->uc;
427ef280c85SMartin Schwidefsky regs->gprs[5] = current->thread.last_break;
42854dfe5ddSHeiko Carstens return 0;
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds
handle_signal(struct ksignal * ksig,sigset_t * oldset,struct pt_regs * regs)431067bf2d4SRichard Weinberger static void handle_signal(struct ksignal *ksig, sigset_t *oldset,
432391c62feSHeiko Carstens struct pt_regs *regs)
4331da177e4SLinus Torvalds {
43454dfe5ddSHeiko Carstens int ret;
43554dfe5ddSHeiko Carstens
4361da177e4SLinus Torvalds /* Set up the stack frame */
437067bf2d4SRichard Weinberger if (ksig->ka.sa.sa_flags & SA_SIGINFO)
438067bf2d4SRichard Weinberger ret = setup_rt_frame(ksig, oldset, regs);
4391da177e4SLinus Torvalds else
440067bf2d4SRichard Weinberger ret = setup_frame(ksig->sig, &ksig->ka, oldset, regs);
441067bf2d4SRichard Weinberger
442067bf2d4SRichard Weinberger signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLE_STEP));
44354dfe5ddSHeiko Carstens }
44454dfe5ddSHeiko Carstens
4451da177e4SLinus Torvalds /*
4461da177e4SLinus Torvalds * Note that 'init' is a special process: it doesn't get signals it doesn't
4471da177e4SLinus Torvalds * want to handle. Thus you cannot kill init even with a SIGKILL even by
4481da177e4SLinus Torvalds * mistake.
4491da177e4SLinus Torvalds *
4501da177e4SLinus Torvalds * Note that we go through the signals twice: once to check the signals that
4511da177e4SLinus Torvalds * the kernel can handle, and then we build all the user-level signal handling
4521da177e4SLinus Torvalds * stack-frames in one go after that.
4531da177e4SLinus Torvalds */
45456e62a73SSven Schnelle
arch_do_signal_or_restart(struct pt_regs * regs)4558ba62d37SEric W. Biederman void arch_do_signal_or_restart(struct pt_regs *regs)
4561da177e4SLinus Torvalds {
457067bf2d4SRichard Weinberger struct ksignal ksig;
458b7f9a11aSAl Viro sigset_t *oldset = sigmask_to_save();
4591da177e4SLinus Torvalds
46020b40a79SMartin Schwidefsky /*
46120b40a79SMartin Schwidefsky * Get signal to deliver. When running under ptrace, at this point
46220b40a79SMartin Schwidefsky * the debugger may change all our registers, including the system
46320b40a79SMartin Schwidefsky * call information.
46420b40a79SMartin Schwidefsky */
465f8fc82b4SMartin Schwidefsky current->thread.system_call =
466d3a73acbSMartin Schwidefsky test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0;
4671da177e4SLinus Torvalds
4688ba62d37SEric W. Biederman if (get_signal(&ksig)) {
4691da177e4SLinus Torvalds /* Whee! Actually deliver the signal. */
470f8fc82b4SMartin Schwidefsky if (current->thread.system_call) {
471f8fc82b4SMartin Schwidefsky regs->int_code = current->thread.system_call;
47220b40a79SMartin Schwidefsky /* Check for system call restarting. */
47320b40a79SMartin Schwidefsky switch (regs->gprs[2]) {
47420b40a79SMartin Schwidefsky case -ERESTART_RESTARTBLOCK:
47520b40a79SMartin Schwidefsky case -ERESTARTNOHAND:
47620b40a79SMartin Schwidefsky regs->gprs[2] = -EINTR;
47720b40a79SMartin Schwidefsky break;
47820b40a79SMartin Schwidefsky case -ERESTARTSYS:
479067bf2d4SRichard Weinberger if (!(ksig.ka.sa.sa_flags & SA_RESTART)) {
48020b40a79SMartin Schwidefsky regs->gprs[2] = -EINTR;
48120b40a79SMartin Schwidefsky break;
48254dfe5ddSHeiko Carstens }
4832c7749b9SJoe Perches fallthrough;
48420b40a79SMartin Schwidefsky case -ERESTARTNOINTR:
48520b40a79SMartin Schwidefsky regs->gprs[2] = regs->orig_gpr2;
486ccf45cafSMartin Schwidefsky regs->psw.addr =
487ccf45cafSMartin Schwidefsky __rewind_psw(regs->psw,
488aa33c8cbSMartin Schwidefsky regs->int_code >> 16);
48920b40a79SMartin Schwidefsky break;
49020b40a79SMartin Schwidefsky }
491d9ae6772SMartin Schwidefsky }
49220b40a79SMartin Schwidefsky /* No longer in a system call */
493d3a73acbSMartin Schwidefsky clear_pt_regs_flag(regs, PIF_SYSCALL);
494df29a744SSven Schnelle
4959d6d99e3SHeiko Carstens rseq_signal_deliver(&ksig, regs);
496a610d6e6SAl Viro if (is_compat_task())
497067bf2d4SRichard Weinberger handle_signal32(&ksig, oldset, regs);
498a610d6e6SAl Viro else
499067bf2d4SRichard Weinberger handle_signal(&ksig, oldset, regs);
50054dfe5ddSHeiko Carstens return;
50154dfe5ddSHeiko Carstens }
50254dfe5ddSHeiko Carstens
50320b40a79SMartin Schwidefsky /* No handlers present - check for system call restart */
504d3a73acbSMartin Schwidefsky clear_pt_regs_flag(regs, PIF_SYSCALL);
505f8fc82b4SMartin Schwidefsky if (current->thread.system_call) {
506f8fc82b4SMartin Schwidefsky regs->int_code = current->thread.system_call;
50720b40a79SMartin Schwidefsky switch (regs->gprs[2]) {
50820b40a79SMartin Schwidefsky case -ERESTART_RESTARTBLOCK:
50920b40a79SMartin Schwidefsky /* Restart with sys_restart_syscall */
510df29a744SSven Schnelle regs->gprs[2] = regs->orig_gpr2;
511df29a744SSven Schnelle current->restart_block.arch_data = regs->psw.addr;
512df29a744SSven Schnelle if (is_compat_task())
513df29a744SSven Schnelle regs->psw.addr = VDSO32_SYMBOL(current, restart_syscall);
514df29a744SSven Schnelle else
515df29a744SSven Schnelle regs->psw.addr = VDSO64_SYMBOL(current, restart_syscall);
516df29a744SSven Schnelle if (test_thread_flag(TIF_SINGLE_STEP))
517df29a744SSven Schnelle clear_thread_flag(TIF_PER_TRAP);
518df29a744SSven Schnelle break;
51920b40a79SMartin Schwidefsky case -ERESTARTNOHAND:
52020b40a79SMartin Schwidefsky case -ERESTARTSYS:
52120b40a79SMartin Schwidefsky case -ERESTARTNOINTR:
52220b40a79SMartin Schwidefsky regs->gprs[2] = regs->orig_gpr2;
523df29a744SSven Schnelle regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
52439efd4ecSMartin Schwidefsky if (test_thread_flag(TIF_SINGLE_STEP))
52556e62a73SSven Schnelle clear_thread_flag(TIF_PER_TRAP);
526b6ef5bb3SMartin Schwidefsky break;
52720b40a79SMartin Schwidefsky }
52820b40a79SMartin Schwidefsky }
52920b40a79SMartin Schwidefsky
53054dfe5ddSHeiko Carstens /*
53154dfe5ddSHeiko Carstens * If there's no signal to deliver, we just put the saved sigmask back.
53254dfe5ddSHeiko Carstens */
53351a7b448SAl Viro restore_saved_sigmask();
5341da177e4SLinus Torvalds }
535