12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ac689eb7SJonas Bonn /*
3ac689eb7SJonas Bonn * OpenRISC signal.c
4ac689eb7SJonas Bonn *
5ac689eb7SJonas Bonn * Linux architectural port borrowing liberally from similar works of
6ac689eb7SJonas Bonn * others. All original copyrights apply as per the original source
7ac689eb7SJonas Bonn * declaration.
8ac689eb7SJonas Bonn *
9ac689eb7SJonas Bonn * Modifications for the OpenRISC architecture:
10ac689eb7SJonas Bonn * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
11ac689eb7SJonas Bonn * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
12ac689eb7SJonas Bonn */
13ac689eb7SJonas Bonn
14ac689eb7SJonas Bonn #include <linux/sched.h>
15ac689eb7SJonas Bonn #include <linux/mm.h>
16ac689eb7SJonas Bonn #include <linux/smp.h>
17ac689eb7SJonas Bonn #include <linux/kernel.h>
18ac689eb7SJonas Bonn #include <linux/signal.h>
19ac689eb7SJonas Bonn #include <linux/errno.h>
20ac689eb7SJonas Bonn #include <linux/wait.h>
21ac689eb7SJonas Bonn #include <linux/ptrace.h>
22ac689eb7SJonas Bonn #include <linux/unistd.h>
23ac689eb7SJonas Bonn #include <linux/stddef.h>
2403248addSEric W. Biederman #include <linux/resume_user_mode.h>
25ac689eb7SJonas Bonn
26ac689eb7SJonas Bonn #include <asm/processor.h>
2710f67dbfSJonas Bonn #include <asm/syscall.h>
28ac689eb7SJonas Bonn #include <asm/ucontext.h>
297c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
30ac689eb7SJonas Bonn
31ac689eb7SJonas Bonn struct rt_sigframe {
32ac689eb7SJonas Bonn struct siginfo info;
33ac689eb7SJonas Bonn struct ucontext uc;
34ac689eb7SJonas Bonn unsigned char retcode[16]; /* trampoline code */
35ac689eb7SJonas Bonn };
36ac689eb7SJonas Bonn
371c4de499SStafford Horne asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs);
381c4de499SStafford Horne
391c4de499SStafford Horne asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags,
401c4de499SStafford Horne int syscall);
411c4de499SStafford Horne
restore_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc)4210f67dbfSJonas Bonn static int restore_sigcontext(struct pt_regs *regs,
4310f67dbfSJonas Bonn struct sigcontext __user *sc)
44ac689eb7SJonas Bonn {
4510f67dbfSJonas Bonn int err = 0;
46ac689eb7SJonas Bonn
4710f67dbfSJonas Bonn /* Always make any pending restarted system calls return -EINTR */
48f56141e3SAndy Lutomirski current->restart_block.fn = do_no_restart_syscall;
49ac689eb7SJonas Bonn
50d7cb6667SJonas Bonn /*
51d7cb6667SJonas Bonn * Restore the regs from &sc->regs.
5296d4f267SLinus Torvalds * (sc is already checked since the sigframe was
53ac689eb7SJonas Bonn * checked in sys_sigreturn previously)
54ac689eb7SJonas Bonn */
5510f67dbfSJonas Bonn err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
5610f67dbfSJonas Bonn err |= __copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long));
5710f67dbfSJonas Bonn err |= __copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long));
58dceaafd6SStafford Horne err |= __copy_from_user(®s->fpcsr, &sc->fpcsr, sizeof(unsigned long));
59ac689eb7SJonas Bonn
60ac689eb7SJonas Bonn /* make sure the SM-bit is cleared so user-mode cannot fool us */
61ac689eb7SJonas Bonn regs->sr &= ~SPR_SR_SM;
62ac689eb7SJonas Bonn
6310f67dbfSJonas Bonn regs->orig_gpr11 = -1; /* Avoid syscall restart checks */
6410f67dbfSJonas Bonn
65ac689eb7SJonas Bonn /* TODO: the other ports use regs->orig_XX to disable syscall checks
66ac689eb7SJonas Bonn * after this completes, but we don't use that mechanism. maybe we can
67ac689eb7SJonas Bonn * use it now ?
68ac689eb7SJonas Bonn */
69ac689eb7SJonas Bonn
70ac689eb7SJonas Bonn return err;
71ac689eb7SJonas Bonn }
72ac689eb7SJonas Bonn
_sys_rt_sigreturn(struct pt_regs * regs)73ac689eb7SJonas Bonn asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
74ac689eb7SJonas Bonn {
75d9959664SStafford Horne struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->sp;
76ac689eb7SJonas Bonn sigset_t set;
77ac689eb7SJonas Bonn
78ac689eb7SJonas Bonn /*
79ac689eb7SJonas Bonn * Since we stacked the signal on a dword boundary,
80ac689eb7SJonas Bonn * then frame should be dword aligned here. If it's
81ac689eb7SJonas Bonn * not, then the user is trying to mess with us.
82ac689eb7SJonas Bonn */
83d9959664SStafford Horne if (((unsigned long)frame) & 3)
84ac689eb7SJonas Bonn goto badframe;
85ac689eb7SJonas Bonn
8696d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame)))
87ac689eb7SJonas Bonn goto badframe;
88ac689eb7SJonas Bonn if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
89ac689eb7SJonas Bonn goto badframe;
90ac689eb7SJonas Bonn
91d8d4b20dSMatt Fleming set_current_blocked(&set);
92ac689eb7SJonas Bonn
93ac689eb7SJonas Bonn if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
94ac689eb7SJonas Bonn goto badframe;
95ac689eb7SJonas Bonn
96faec5a96SAl Viro if (restore_altstack(&frame->uc.uc_stack))
97d26654e5SAl Viro goto badframe;
98ac689eb7SJonas Bonn
99ac689eb7SJonas Bonn return regs->gpr[11];
100ac689eb7SJonas Bonn
101ac689eb7SJonas Bonn badframe:
1023cf5d076SEric W. Biederman force_sig(SIGSEGV);
103ac689eb7SJonas Bonn return 0;
104ac689eb7SJonas Bonn }
105ac689eb7SJonas Bonn
106ac689eb7SJonas Bonn /*
107ac689eb7SJonas Bonn * Set up a signal frame.
108ac689eb7SJonas Bonn */
109ac689eb7SJonas Bonn
setup_sigcontext(struct pt_regs * regs,struct sigcontext __user * sc)11010f67dbfSJonas Bonn static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
111ac689eb7SJonas Bonn {
112ac689eb7SJonas Bonn int err = 0;
113ac689eb7SJonas Bonn
114d7cb6667SJonas Bonn /* copy the regs */
11510f67dbfSJonas Bonn /* There should be no need to save callee-saved registers here...
11610f67dbfSJonas Bonn * ...but we save them anyway. Revisit this
11710f67dbfSJonas Bonn */
118d7cb6667SJonas Bonn err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
119d7cb6667SJonas Bonn err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long));
120d7cb6667SJonas Bonn err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long));
121dceaafd6SStafford Horne err |= __copy_to_user(&sc->fpcsr, ®s->fpcsr, sizeof(unsigned long));
122ac689eb7SJonas Bonn
123ac689eb7SJonas Bonn return err;
124ac689eb7SJonas Bonn }
125ac689eb7SJonas Bonn
align_sigframe(unsigned long sp)126ac689eb7SJonas Bonn static inline unsigned long align_sigframe(unsigned long sp)
127ac689eb7SJonas Bonn {
128ac689eb7SJonas Bonn return sp & ~3UL;
129ac689eb7SJonas Bonn }
130ac689eb7SJonas Bonn
131ac689eb7SJonas Bonn /*
132ac689eb7SJonas Bonn * Work out where the signal frame should go. It's either on the user stack
133ac689eb7SJonas Bonn * or the alternate stack.
134ac689eb7SJonas Bonn */
135ac689eb7SJonas Bonn
get_sigframe(struct ksignal * ksig,struct pt_regs * regs,size_t frame_size)1368e2beafaSRichard Weinberger static inline void __user *get_sigframe(struct ksignal *ksig,
137ac689eb7SJonas Bonn struct pt_regs *regs, size_t frame_size)
138ac689eb7SJonas Bonn {
139ac689eb7SJonas Bonn unsigned long sp = regs->sp;
140ac689eb7SJonas Bonn
141ac689eb7SJonas Bonn /* redzone */
142ac689eb7SJonas Bonn sp -= STACK_FRAME_OVERHEAD;
1438e2beafaSRichard Weinberger sp = sigsp(sp, ksig);
144ac689eb7SJonas Bonn sp = align_sigframe(sp - frame_size);
145ac689eb7SJonas Bonn
146ac689eb7SJonas Bonn return (void __user *)sp;
147ac689eb7SJonas Bonn }
148ac689eb7SJonas Bonn
149ac689eb7SJonas Bonn /* grab and setup a signal frame.
150ac689eb7SJonas Bonn *
151ac689eb7SJonas Bonn * basically we stack a lot of state info, and arrange for the
152ac689eb7SJonas Bonn * user-mode program to return to the kernel using either a
153ac689eb7SJonas Bonn * trampoline which performs the syscall sigreturn, or a provided
154ac689eb7SJonas Bonn * user-mode trampoline.
155ac689eb7SJonas Bonn */
setup_rt_frame(struct ksignal * ksig,sigset_t * set,struct pt_regs * regs)156548dafe8SRichard Weinberger static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
157548dafe8SRichard Weinberger struct pt_regs *regs)
158ac689eb7SJonas Bonn {
159d9959664SStafford Horne struct rt_sigframe __user *frame;
160ac689eb7SJonas Bonn unsigned long return_ip;
161ac689eb7SJonas Bonn int err = 0;
162ac689eb7SJonas Bonn
1638e2beafaSRichard Weinberger frame = get_sigframe(ksig, regs, sizeof(*frame));
164548dafe8SRichard Weinberger
16596d4f267SLinus Torvalds if (!access_ok(frame, sizeof(*frame)))
166548dafe8SRichard Weinberger return -EFAULT;
167ac689eb7SJonas Bonn
16810f67dbfSJonas Bonn /* Create siginfo. */
169548dafe8SRichard Weinberger if (ksig->ka.sa.sa_flags & SA_SIGINFO)
170548dafe8SRichard Weinberger err |= copy_siginfo_to_user(&frame->info, &ksig->info);
171ac689eb7SJonas Bonn
17210f67dbfSJonas Bonn /* Create the ucontext. */
173ac689eb7SJonas Bonn err |= __put_user(0, &frame->uc.uc_flags);
174ac689eb7SJonas Bonn err |= __put_user(NULL, &frame->uc.uc_link);
175faec5a96SAl Viro err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
17610f67dbfSJonas Bonn err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
177ac689eb7SJonas Bonn
178ac689eb7SJonas Bonn err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
179ac689eb7SJonas Bonn
180ac689eb7SJonas Bonn if (err)
181548dafe8SRichard Weinberger return -EFAULT;
182ac689eb7SJonas Bonn
183ac689eb7SJonas Bonn /* trampoline - the desired return ip is the retcode itself */
184ac689eb7SJonas Bonn return_ip = (unsigned long)&frame->retcode;
18510f67dbfSJonas Bonn /* This is:
18610f67dbfSJonas Bonn l.ori r11,r0,__NR_sigreturn
18710f67dbfSJonas Bonn l.sys 1
18810f67dbfSJonas Bonn */
189d9959664SStafford Horne err |= __put_user(0xa960, (short __user *)(frame->retcode + 0));
190d9959664SStafford Horne err |= __put_user(__NR_rt_sigreturn, (short __user *)(frame->retcode + 2));
191d9959664SStafford Horne err |= __put_user(0x20000001, (unsigned long __user *)(frame->retcode + 4));
192d9959664SStafford Horne err |= __put_user(0x15000000, (unsigned long __user *)(frame->retcode + 8));
193ac689eb7SJonas Bonn
194ac689eb7SJonas Bonn if (err)
195548dafe8SRichard Weinberger return -EFAULT;
196ac689eb7SJonas Bonn
197ac689eb7SJonas Bonn /* Set up registers for signal handler */
198548dafe8SRichard Weinberger regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */
199ac689eb7SJonas Bonn regs->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
200548dafe8SRichard Weinberger regs->gpr[3] = (unsigned long)ksig->sig; /* arg 1: signo */
201ac689eb7SJonas Bonn regs->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
202ac689eb7SJonas Bonn regs->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
203ac689eb7SJonas Bonn
204ac689eb7SJonas Bonn /* actually move the usp to reflect the stacked frame */
205ac689eb7SJonas Bonn regs->sp = (unsigned long)frame;
206ac689eb7SJonas Bonn
207e933c70dSMatt Fleming return 0;
208ac689eb7SJonas Bonn }
209ac689eb7SJonas Bonn
21039974d08SAl Viro static inline void
handle_signal(struct ksignal * ksig,struct pt_regs * regs)211548dafe8SRichard Weinberger handle_signal(struct ksignal *ksig, struct pt_regs *regs)
212ac689eb7SJonas Bonn {
213e933c70dSMatt Fleming int ret;
214e933c70dSMatt Fleming
215548dafe8SRichard Weinberger ret = setup_rt_frame(ksig, sigmask_to_save(), regs);
216ac689eb7SJonas Bonn
217548dafe8SRichard Weinberger signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
218ac689eb7SJonas Bonn }
219ac689eb7SJonas Bonn
220ac689eb7SJonas Bonn /*
221ac689eb7SJonas Bonn * Note that 'init' is a special process: it doesn't get signals it doesn't
222ac689eb7SJonas Bonn * want to handle. Thus you cannot kill init even with a SIGKILL even by
223ac689eb7SJonas Bonn * mistake.
224ac689eb7SJonas Bonn *
225ac689eb7SJonas Bonn * Also note that the regs structure given here as an argument, is the latest
226ac689eb7SJonas Bonn * pushed pt_regs. It may or may not be the same as the first pushed registers
227ac689eb7SJonas Bonn * when the initial usermode->kernelmode transition took place. Therefore
228ac689eb7SJonas Bonn * we can use user_mode(regs) to see if we came directly from kernel or user
229ac689eb7SJonas Bonn * mode below.
230ac689eb7SJonas Bonn */
231ac689eb7SJonas Bonn
do_signal(struct pt_regs * regs,int syscall)232*af1fc740SStafford Horne static int do_signal(struct pt_regs *regs, int syscall)
233ac689eb7SJonas Bonn {
234548dafe8SRichard Weinberger struct ksignal ksig;
23510f67dbfSJonas Bonn unsigned long continue_addr = 0;
23610f67dbfSJonas Bonn unsigned long restart_addr = 0;
23710f67dbfSJonas Bonn unsigned long retval = 0;
238ac689eb7SJonas Bonn int restart = 0;
239ac689eb7SJonas Bonn
24010f67dbfSJonas Bonn if (syscall) {
24110f67dbfSJonas Bonn continue_addr = regs->pc;
24210f67dbfSJonas Bonn restart_addr = continue_addr - 4;
24310f67dbfSJonas Bonn retval = regs->gpr[11];
24410f67dbfSJonas Bonn
24510f67dbfSJonas Bonn /*
24610f67dbfSJonas Bonn * Setup syscall restart here so that a debugger will
24710f67dbfSJonas Bonn * see the already changed PC.
24810f67dbfSJonas Bonn */
24910f67dbfSJonas Bonn switch (retval) {
250ac689eb7SJonas Bonn case -ERESTART_RESTARTBLOCK:
25110f67dbfSJonas Bonn restart = -2;
252df561f66SGustavo A. R. Silva fallthrough;
253ac689eb7SJonas Bonn case -ERESTARTNOHAND:
254ac689eb7SJonas Bonn case -ERESTARTSYS:
255ac689eb7SJonas Bonn case -ERESTARTNOINTR:
25610f67dbfSJonas Bonn restart++;
25710f67dbfSJonas Bonn regs->gpr[11] = regs->orig_gpr11;
25810f67dbfSJonas Bonn regs->pc = restart_addr;
259ac689eb7SJonas Bonn break;
260ac689eb7SJonas Bonn }
26110f67dbfSJonas Bonn }
262ac689eb7SJonas Bonn
26310f67dbfSJonas Bonn /*
264548dafe8SRichard Weinberger * Get the signal to deliver. During the call to get_signal the
265548dafe8SRichard Weinberger * debugger may change all our registers so we may need to revert
266548dafe8SRichard Weinberger * the decision to restart the syscall; specifically, if the PC is
267548dafe8SRichard Weinberger * changed, don't restart the syscall.
26810f67dbfSJonas Bonn */
269548dafe8SRichard Weinberger if (get_signal(&ksig)) {
27010f67dbfSJonas Bonn if (unlikely(restart) && regs->pc == restart_addr) {
27110f67dbfSJonas Bonn if (retval == -ERESTARTNOHAND ||
27210f67dbfSJonas Bonn retval == -ERESTART_RESTARTBLOCK
27310f67dbfSJonas Bonn || (retval == -ERESTARTSYS
274548dafe8SRichard Weinberger && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
27510f67dbfSJonas Bonn /* No automatic restart */
276ac689eb7SJonas Bonn regs->gpr[11] = -EINTR;
27710f67dbfSJonas Bonn regs->pc = continue_addr;
278ac689eb7SJonas Bonn }
279ac689eb7SJonas Bonn }
280548dafe8SRichard Weinberger handle_signal(&ksig, regs);
28110f67dbfSJonas Bonn } else {
28210f67dbfSJonas Bonn /* no handler */
28310f67dbfSJonas Bonn restore_saved_sigmask();
28410f67dbfSJonas Bonn /*
28510f67dbfSJonas Bonn * Restore pt_regs PC as syscall restart will be handled by
28610f67dbfSJonas Bonn * kernel without return to userspace
28710f67dbfSJonas Bonn */
28810f67dbfSJonas Bonn if (unlikely(restart) && regs->pc == restart_addr) {
28910f67dbfSJonas Bonn regs->pc = continue_addr;
29010f67dbfSJonas Bonn return restart;
29110f67dbfSJonas Bonn }
292ac689eb7SJonas Bonn }
293ac689eb7SJonas Bonn
29410f67dbfSJonas Bonn return 0;
295ac689eb7SJonas Bonn }
296ac689eb7SJonas Bonn
29710f67dbfSJonas Bonn asmlinkage int
do_work_pending(struct pt_regs * regs,unsigned int thread_flags,int syscall)29810f67dbfSJonas Bonn do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
299ac689eb7SJonas Bonn {
30010f67dbfSJonas Bonn do {
30110f67dbfSJonas Bonn if (likely(thread_flags & _TIF_NEED_RESCHED)) {
30210f67dbfSJonas Bonn schedule();
30310f67dbfSJonas Bonn } else {
30410f67dbfSJonas Bonn if (unlikely(!user_mode(regs)))
30510f67dbfSJonas Bonn return 0;
30610f67dbfSJonas Bonn local_irq_enable();
307e181c0aaSJens Axboe if (thread_flags & (_TIF_SIGPENDING|_TIF_NOTIFY_SIGNAL)) {
30810f67dbfSJonas Bonn int restart = do_signal(regs, syscall);
30910f67dbfSJonas Bonn if (unlikely(restart)) {
31010f67dbfSJonas Bonn /*
31110f67dbfSJonas Bonn * Restart without handlers.
31210f67dbfSJonas Bonn * Deal with it without leaving
31310f67dbfSJonas Bonn * the kernel space.
31410f67dbfSJonas Bonn */
31510f67dbfSJonas Bonn return restart;
31610f67dbfSJonas Bonn }
31710f67dbfSJonas Bonn syscall = 0;
31810f67dbfSJonas Bonn } else {
31903248addSEric W. Biederman resume_user_mode_work(regs);
320ac689eb7SJonas Bonn }
321ac689eb7SJonas Bonn }
32210f67dbfSJonas Bonn local_irq_disable();
3234ea7ce0aSMark Rutland thread_flags = read_thread_flags();
32410f67dbfSJonas Bonn } while (thread_flags & _TIF_WORK_MASK);
32510f67dbfSJonas Bonn return 0;
32610f67dbfSJonas Bonn }
327