xref: /openbmc/linux/arch/csky/kernel/signal.c (revision d4fd6347)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/signal.h>
4 #include <linux/uaccess.h>
5 #include <linux/syscalls.h>
6 #include <linux/tracehook.h>
7 
8 #include <asm/traps.h>
9 #include <asm/ucontext.h>
10 #include <asm/vdso.h>
11 
12 #include <abi/regdef.h>
13 
14 #ifdef CONFIG_CPU_HAS_FPU
15 #include <abi/fpu.h>
16 static int restore_fpu_state(struct sigcontext __user *sc)
17 {
18 	int err = 0;
19 	struct user_fp user_fp;
20 
21 	err = __copy_from_user(&user_fp, &sc->sc_user_fp, sizeof(user_fp));
22 
23 	restore_from_user_fp(&user_fp);
24 
25 	return err;
26 }
27 
28 static int save_fpu_state(struct sigcontext __user *sc)
29 {
30 	struct user_fp user_fp;
31 
32 	save_to_user_fp(&user_fp);
33 
34 	return __copy_to_user(&sc->sc_user_fp, &user_fp, sizeof(user_fp));
35 }
36 #else
37 #define restore_fpu_state(sigcontext)	(0)
38 #define save_fpu_state(sigcontext)	(0)
39 #endif
40 
41 struct rt_sigframe {
42 	struct siginfo info;
43 	struct ucontext uc;
44 };
45 
46 static long restore_sigcontext(struct pt_regs *regs,
47 	struct sigcontext __user *sc)
48 {
49 	int err = 0;
50 
51 	/* sc_pt_regs is structured the same as the start of pt_regs */
52 	err |= __copy_from_user(regs, &sc->sc_pt_regs, sizeof(struct pt_regs));
53 
54 	/* Restore the floating-point state. */
55 	err |= restore_fpu_state(sc);
56 
57 	return err;
58 }
59 
60 SYSCALL_DEFINE0(rt_sigreturn)
61 {
62 	struct pt_regs *regs = current_pt_regs();
63 	struct rt_sigframe __user *frame;
64 	struct task_struct *task;
65 	sigset_t set;
66 
67 	/* Always make any pending restarted system calls return -EINTR */
68 	current->restart_block.fn = do_no_restart_syscall;
69 
70 	frame = (struct rt_sigframe __user *)regs->usp;
71 
72 	if (!access_ok(frame, sizeof(*frame)))
73 		goto badframe;
74 
75 	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
76 		goto badframe;
77 
78 	set_current_blocked(&set);
79 
80 	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
81 		goto badframe;
82 
83 	if (restore_altstack(&frame->uc.uc_stack))
84 		goto badframe;
85 
86 	return regs->a0;
87 
88 badframe:
89 	task = current;
90 	force_sig(SIGSEGV, task);
91 	return 0;
92 }
93 
94 static int setup_sigcontext(struct rt_sigframe __user *frame,
95 	struct pt_regs *regs)
96 {
97 	struct sigcontext __user *sc = &frame->uc.uc_mcontext;
98 	int err = 0;
99 
100 	err |= __copy_to_user(&sc->sc_pt_regs, regs, sizeof(struct pt_regs));
101 	err |= save_fpu_state(sc);
102 
103 	return err;
104 }
105 
106 static inline void __user *get_sigframe(struct ksignal *ksig,
107 	struct pt_regs *regs, size_t framesize)
108 {
109 	unsigned long sp;
110 	/* Default to using normal stack */
111 	sp = regs->usp;
112 
113 	/*
114 	 * If we are on the alternate signal stack and would overflow it, don't.
115 	 * Return an always-bogus address instead so we will die with SIGSEGV.
116 	 */
117 	if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize)))
118 		return (void __user __force *)(-1UL);
119 
120 	/* This is the X/Open sanctioned signal stack switching. */
121 	sp = sigsp(sp, ksig) - framesize;
122 
123 	/* Align the stack frame. */
124 	sp &= -8UL;
125 
126 	return (void __user *)sp;
127 }
128 
129 static int
130 setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
131 {
132 	struct rt_sigframe *frame;
133 	int err = 0;
134 	struct csky_vdso *vdso = current->mm->context.vdso;
135 
136 	frame = get_sigframe(ksig, regs, sizeof(*frame));
137 	if (!access_ok(frame, sizeof(*frame)))
138 		return -EFAULT;
139 
140 	err |= copy_siginfo_to_user(&frame->info, &ksig->info);
141 
142 	/* Create the ucontext. */
143 	err |= __put_user(0, &frame->uc.uc_flags);
144 	err |= __put_user(NULL, &frame->uc.uc_link);
145 	err |= __save_altstack(&frame->uc.uc_stack, regs->usp);
146 	err |= setup_sigcontext(frame, regs);
147 	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
148 	if (err)
149 		return -EFAULT;
150 
151 	/* Set up to return from userspace. */
152 	regs->lr = (unsigned long)(vdso->rt_signal_retcode);
153 
154 	/*
155 	 * Set up registers for signal handler.
156 	 * Registers that we don't modify keep the value they had from
157 	 * user-space at the time we took the signal.
158 	 * We always pass siginfo and mcontext, regardless of SA_SIGINFO,
159 	 * since some things rely on this (e.g. glibc's debug/segfault.c).
160 	 */
161 	regs->pc  = (unsigned long)ksig->ka.sa.sa_handler;
162 	regs->usp = (unsigned long)frame;
163 	regs->a0  = ksig->sig;				/* a0: signal number */
164 	regs->a1  = (unsigned long)(&(frame->info));	/* a1: siginfo pointer */
165 	regs->a2  = (unsigned long)(&(frame->uc));	/* a2: ucontext pointer */
166 
167 	return 0;
168 }
169 
170 static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
171 {
172 	sigset_t *oldset = sigmask_to_save();
173 	int ret;
174 
175 	/* Are we from a system call? */
176 	if (in_syscall(regs)) {
177 		/* Avoid additional syscall restarting via ret_from_exception */
178 		forget_syscall(regs);
179 
180 		/* If so, check system call restarting.. */
181 		switch (regs->a0) {
182 		case -ERESTART_RESTARTBLOCK:
183 		case -ERESTARTNOHAND:
184 			regs->a0 = -EINTR;
185 			break;
186 
187 		case -ERESTARTSYS:
188 			if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {
189 				regs->a0 = -EINTR;
190 				break;
191 			}
192 			/* fallthrough */
193 		case -ERESTARTNOINTR:
194 			regs->a0 = regs->orig_a0;
195 			regs->pc -= TRAP0_SIZE;
196 			break;
197 		}
198 	}
199 
200 	/* Set up the stack frame */
201 	ret = setup_rt_frame(ksig, oldset, regs);
202 
203 	signal_setup_done(ret, ksig, 0);
204 }
205 
206 static void do_signal(struct pt_regs *regs)
207 {
208 	struct ksignal ksig;
209 
210 	if (get_signal(&ksig)) {
211 		/* Actually deliver the signal */
212 		handle_signal(&ksig, regs);
213 		return;
214 	}
215 
216 	/* Did we come from a system call? */
217 	if (in_syscall(regs)) {
218 		/* Avoid additional syscall restarting via ret_from_exception */
219 		forget_syscall(regs);
220 
221 		/* Restart the system call - no handlers present */
222 		switch (regs->a0) {
223 		case -ERESTARTNOHAND:
224 		case -ERESTARTSYS:
225 		case -ERESTARTNOINTR:
226 			regs->a0 = regs->orig_a0;
227 			regs->pc -= TRAP0_SIZE;
228 			break;
229 		case -ERESTART_RESTARTBLOCK:
230 			regs->a0 = regs->orig_a0;
231 			regs_syscallid(regs) = __NR_restart_syscall;
232 			regs->pc -= TRAP0_SIZE;
233 			break;
234 		}
235 	}
236 
237 	/*
238 	 * If there is no signal to deliver, we just put the saved
239 	 * sigmask back.
240 	 */
241 	restore_saved_sigmask();
242 }
243 
244 /*
245  * notification of userspace execution resumption
246  * - triggered by the _TIF_WORK_MASK flags
247  */
248 asmlinkage void do_notify_resume(struct pt_regs *regs,
249 	unsigned long thread_info_flags)
250 {
251 	/* Handle pending signal delivery */
252 	if (thread_info_flags & _TIF_SIGPENDING)
253 		do_signal(regs);
254 
255 	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
256 		clear_thread_flag(TIF_NOTIFY_RESUME);
257 		tracehook_notify_resume(regs);
258 	}
259 }
260