blob: 23853814bd174284a3a75c62b88154ac8fb890d3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Paul Mundta23ba432007-11-28 20:19:38 +09002 * arch/sh/kernel/signal_64.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 2000, 2001 Paolo Alberelli
Paul Mundt6ac03432008-12-10 19:26:44 +09005 * Copyright (C) 2003 - 2008 Paul Mundt
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * Copyright (C) 2004 Richard Curnow
7 *
Paul Mundta23ba432007-11-28 20:19:38 +09008 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12#include <linux/rwsem.h>
13#include <linux/sched.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/kernel.h>
17#include <linux/signal.h>
18#include <linux/errno.h>
19#include <linux/wait.h>
20#include <linux/personality.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/ptrace.h>
22#include <linux/unistd.h>
23#include <linux/stddef.h>
Paul Mundtab99c732008-07-30 19:55:30 +090024#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <asm/ucontext.h>
26#include <asm/uaccess.h>
27#include <asm/pgtable.h>
Paul Mundtf7a7b152007-11-10 20:07:57 +090028#include <asm/cacheflush.h>
Adrian Bunk50387b32008-04-13 21:15:38 +030029#include <asm/fpu.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#define REG_RET 9
32#define REG_ARG1 2
33#define REG_ARG2 3
34#define REG_ARG3 4
35#define REG_SP 15
36#define REG_PR 18
37#define REF_REG_RET regs->regs[REG_RET]
38#define REF_REG_SP regs->regs[REG_SP]
39#define DEREF_REG_PR regs->regs[REG_PR]
40
41#define DEBUG_SIG 0
42
Al Viroa610d6e2012-05-21 23:42:15 -040043static void
Paul Mundt8a80a5e2008-09-17 23:14:36 +090044handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
Al Virob7f9a112012-05-02 09:59:21 -040045 struct pt_regs * regs);
Paul Mundt8a80a5e2008-09-17 23:14:36 +090046
Paul Mundt94e2fb32008-12-10 19:46:18 +090047static inline void
48handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
49{
50 /* If we're not from a syscall, bail out */
51 if (regs->syscall_nr < 0)
52 return;
53
54 /* check for system call restart.. */
55 switch (regs->regs[REG_RET]) {
56 case -ERESTART_RESTARTBLOCK:
57 case -ERESTARTNOHAND:
58 no_system_call_restart:
59 regs->regs[REG_RET] = -EINTR;
Paul Mundt94e2fb32008-12-10 19:46:18 +090060 break;
61
62 case -ERESTARTSYS:
63 if (!(sa->sa_flags & SA_RESTART))
64 goto no_system_call_restart;
65 /* fallthrough */
66 case -ERESTARTNOINTR:
67 /* Decode syscall # */
68 regs->regs[REG_RET] = regs->syscall_nr;
69 regs->pc -= 4;
70 break;
71 }
72}
73
Paul Mundtab99c732008-07-30 19:55:30 +090074/*
75 * Note that 'init' is a special process: it doesn't get signals it doesn't
76 * want to handle. Thus you cannot kill init even with a SIGKILL even by
77 * mistake.
78 *
79 * Note that we go through the signals twice: once to check the signals that
80 * the kernel can handle, and then we build all the user-level signal handling
81 * stack-frames in one go after that.
82 */
Al Viro9ef461a2012-04-22 01:16:34 -040083static void do_signal(struct pt_regs *regs)
Paul Mundtab99c732008-07-30 19:55:30 +090084{
85 siginfo_t info;
86 int signr;
87 struct k_sigaction ka;
88
89 /*
90 * We want the common case to go fast, which
91 * is why we may in certain cases get here from
92 * kernel mode. Just return without doing anything
93 * if so.
94 */
95 if (!user_mode(regs))
Al Viro9ef461a2012-04-22 01:16:34 -040096 return;
Paul Mundtab99c732008-07-30 19:55:30 +090097
Paul Mundtab99c732008-07-30 19:55:30 +090098 signr = get_signal_to_deliver(&info, &ka, regs, 0);
Paul Mundtab99c732008-07-30 19:55:30 +090099 if (signr > 0) {
Paul Mundt03f07872009-01-29 11:21:38 +0900100 handle_syscall_restart(regs, &ka.sa);
Paul Mundt94e2fb32008-12-10 19:46:18 +0900101
Paul Mundtab99c732008-07-30 19:55:30 +0900102 /* Whee! Actually deliver the signal. */
Al Viroa610d6e2012-05-21 23:42:15 -0400103 handle_signal(signr, &info, &ka, regs);
Al Viro5754f412012-04-26 23:52:33 -0400104 return;
Paul Mundtab99c732008-07-30 19:55:30 +0900105 }
106
Paul Mundtab99c732008-07-30 19:55:30 +0900107 /* Did we come from a system call? */
108 if (regs->syscall_nr >= 0) {
109 /* Restart the system call - no handlers present */
110 switch (regs->regs[REG_RET]) {
111 case -ERESTARTNOHAND:
112 case -ERESTARTSYS:
113 case -ERESTARTNOINTR:
114 /* Decode Syscall # */
115 regs->regs[REG_RET] = regs->syscall_nr;
116 regs->pc -= 4;
117 break;
118
119 case -ERESTART_RESTARTBLOCK:
120 regs->regs[REG_RET] = __NR_restart_syscall;
121 regs->pc -= 4;
122 break;
123 }
124 }
125
126 /* No signal to deliver -- put the saved sigmask back */
Al Viro51a7b442012-05-21 23:33:55 -0400127 restore_saved_sigmask();
Paul Mundtab99c732008-07-30 19:55:30 +0900128}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130/*
131 * Atomically swap in the new signal mask, and wait for a signal.
132 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133asmlinkage int
Al Viro9ef461a2012-04-22 01:16:34 -0400134sys_sigsuspend(old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Al Viro9ef461a2012-04-22 01:16:34 -0400136 sigset_t blocked;
Matt Fleming5e047fa2012-03-28 15:16:32 -0700137 siginitset(&blocked, mask);
Al Viro9ef461a2012-04-22 01:16:34 -0400138 return sigsuspend(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
141asmlinkage int
142sys_sigaction(int sig, const struct old_sigaction __user *act,
143 struct old_sigaction __user *oact)
144{
145 struct k_sigaction new_ka, old_ka;
146 int ret;
147
148 if (act) {
149 old_sigset_t mask;
150 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
151 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
Al Viroa46808e2012-04-22 16:59:56 -0400152 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
153 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
154 __get_user(mask, &act->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 siginitset(&new_ka.sa.sa_mask, mask);
157 }
158
159 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
160
161 if (!ret && oact) {
162 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
163 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
Al Viroa46808e2012-04-22 16:59:56 -0400164 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
165 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
166 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169
170 return ret;
171}
172
173asmlinkage int
174sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
175 unsigned long r4, unsigned long r5, unsigned long r6,
176 unsigned long r7,
177 struct pt_regs * regs)
178{
179 return do_sigaltstack(uss, uoss, REF_REG_SP);
180}
181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182/*
183 * Do a signal return; undo the signal stack.
184 */
Paul Mundt94e2fb32008-12-10 19:46:18 +0900185struct sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 struct sigcontext sc;
187 unsigned long extramask[_NSIG_WORDS-1];
188 long long retcode[2];
189};
190
Paul Mundt94e2fb32008-12-10 19:46:18 +0900191struct rt_sigframe {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 struct siginfo __user *pinfo;
193 void *puc;
194 struct siginfo info;
195 struct ucontext uc;
196 long long retcode[2];
197};
198
199#ifdef CONFIG_SH_FPU
200static inline int
201restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
202{
203 int err = 0;
204 int fpvalid;
205
206 err |= __get_user (fpvalid, &sc->sc_fpvalid);
207 conditional_used_math(fpvalid);
208 if (! fpvalid)
209 return err;
210
211 if (current == last_task_used_math) {
212 last_task_used_math = NULL;
213 regs->sr |= SR_FD;
214 }
215
Paul Mundt3ef29322010-01-19 15:40:03 +0900216 err |= __copy_from_user(&current->thread.xstate->hardfpu, &sc->sc_fpregs[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 (sizeof(long long) * 32) + (sizeof(int) * 1));
218
219 return err;
220}
221
222static inline int
223setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
224{
225 int err = 0;
226 int fpvalid;
227
228 fpvalid = !!used_math();
229 err |= __put_user(fpvalid, &sc->sc_fpvalid);
230 if (! fpvalid)
231 return err;
232
233 if (current == last_task_used_math) {
Paul Mundt600ee242007-11-19 19:13:38 +0900234 enable_fpu();
Matt Fleming61cc7b02009-12-14 20:12:04 +0000235 save_fpu(current);
Paul Mundt600ee242007-11-19 19:13:38 +0900236 disable_fpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 last_task_used_math = NULL;
238 regs->sr |= SR_FD;
239 }
240
Paul Mundt3ef29322010-01-19 15:40:03 +0900241 err |= __copy_to_user(&sc->sc_fpregs[0], &current->thread.xstate->hardfpu,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 (sizeof(long long) * 32) + (sizeof(int) * 1));
243 clear_used_math();
244
245 return err;
246}
247#else
248static inline int
249restore_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900250{
251 return 0;
252}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253static inline int
254setup_sigcontext_fpu(struct pt_regs *regs, struct sigcontext __user *sc)
Paul Mundtf7a7b152007-11-10 20:07:57 +0900255{
256 return 0;
257}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258#endif
259
260static int
261restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, long long *r2_p)
262{
263 unsigned int err = 0;
264 unsigned long long current_sr, new_sr;
265#define SR_MASK 0xffff8cfd
266
267#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
268
269 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
270 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
271 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
272 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
273 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
274 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
275 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
276 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
277 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
278 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
279 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
280 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
281 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
282 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
283 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
284 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
285 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
286 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
287
288 /* Prevent the signal handler manipulating SR in a way that can
289 crash the kernel. i.e. only allow S, Q, M, PR, SZ, FR to be
290 modified */
291 current_sr = regs->sr;
292 err |= __get_user(new_sr, &sc->sc_sr);
293 regs->sr &= SR_MASK;
294 regs->sr |= (new_sr & ~SR_MASK);
295
296 COPY(pc);
297
298#undef COPY
299
300 /* Must do this last in case it sets regs->sr.fd (i.e. after rest of sr
301 * has been restored above.) */
302 err |= restore_sigcontext_fpu(regs, sc);
303
304 regs->syscall_nr = -1; /* disable syscall checks */
305 err |= __get_user(*r2_p, &sc->sc_regs[REG_RET]);
306 return err;
307}
308
309asmlinkage int sys_sigreturn(unsigned long r2, unsigned long r3,
310 unsigned long r4, unsigned long r5,
311 unsigned long r6, unsigned long r7,
312 struct pt_regs * regs)
313{
314 struct sigframe __user *frame = (struct sigframe __user *) (long) REF_REG_SP;
315 sigset_t set;
316 long long ret;
317
Paul Mundt1bec1572008-09-24 14:37:35 +0900318 /* Always make any pending restarted system calls return -EINTR */
319 current_thread_info()->restart_block.fn = do_no_restart_syscall;
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
322 goto badframe;
323
324 if (__get_user(set.sig[0], &frame->sc.oldmask)
325 || (_NSIG_WORDS > 1
326 && __copy_from_user(&set.sig[1], &frame->extramask,
327 sizeof(frame->extramask))))
328 goto badframe;
329
Matt Fleming5e047fa2012-03-28 15:16:32 -0700330 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 if (restore_sigcontext(regs, &frame->sc, &ret))
333 goto badframe;
334 regs->pc -= 4;
335
336 return (int) ret;
337
338badframe:
339 force_sig(SIGSEGV, current);
340 return 0;
341}
342
343asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
344 unsigned long r4, unsigned long r5,
345 unsigned long r6, unsigned long r7,
346 struct pt_regs * regs)
347{
348 struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
349 sigset_t set;
350 stack_t __user st;
351 long long ret;
352
Paul Mundt1bec1572008-09-24 14:37:35 +0900353 /* Always make any pending restarted system calls return -EINTR */
354 current_thread_info()->restart_block.fn = do_no_restart_syscall;
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
357 goto badframe;
358
359 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
360 goto badframe;
361
Matt Fleming5e047fa2012-03-28 15:16:32 -0700362 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363
364 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ret))
365 goto badframe;
366 regs->pc -= 4;
367
368 if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
369 goto badframe;
370 /* It is more difficult to avoid calling this function than to
371 call it and ignore errors. */
372 do_sigaltstack(&st, NULL, REF_REG_SP);
373
374 return (int) ret;
375
376badframe:
377 force_sig(SIGSEGV, current);
378 return 0;
379}
380
381/*
382 * Set up a signal frame.
383 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384static int
385setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
386 unsigned long mask)
387{
388 int err = 0;
389
390 /* Do this first, otherwise is this sets sr->fd, that value isn't preserved. */
391 err |= setup_sigcontext_fpu(regs, sc);
392
393#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
394
395 COPY(regs[0]); COPY(regs[1]); COPY(regs[2]); COPY(regs[3]);
396 COPY(regs[4]); COPY(regs[5]); COPY(regs[6]); COPY(regs[7]);
397 COPY(regs[8]); COPY(regs[9]); COPY(regs[10]); COPY(regs[11]);
398 COPY(regs[12]); COPY(regs[13]); COPY(regs[14]); COPY(regs[15]);
399 COPY(regs[16]); COPY(regs[17]); COPY(regs[18]); COPY(regs[19]);
400 COPY(regs[20]); COPY(regs[21]); COPY(regs[22]); COPY(regs[23]);
401 COPY(regs[24]); COPY(regs[25]); COPY(regs[26]); COPY(regs[27]);
402 COPY(regs[28]); COPY(regs[29]); COPY(regs[30]); COPY(regs[31]);
403 COPY(regs[32]); COPY(regs[33]); COPY(regs[34]); COPY(regs[35]);
404 COPY(regs[36]); COPY(regs[37]); COPY(regs[38]); COPY(regs[39]);
405 COPY(regs[40]); COPY(regs[41]); COPY(regs[42]); COPY(regs[43]);
406 COPY(regs[44]); COPY(regs[45]); COPY(regs[46]); COPY(regs[47]);
407 COPY(regs[48]); COPY(regs[49]); COPY(regs[50]); COPY(regs[51]);
408 COPY(regs[52]); COPY(regs[53]); COPY(regs[54]); COPY(regs[55]);
409 COPY(regs[56]); COPY(regs[57]); COPY(regs[58]); COPY(regs[59]);
410 COPY(regs[60]); COPY(regs[61]); COPY(regs[62]);
411 COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]);
412 COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]);
413 COPY(sr); COPY(pc);
414
415#undef COPY
416
417 err |= __put_user(mask, &sc->oldmask);
418
419 return err;
420}
421
422/*
423 * Determine which stack to use..
424 */
425static inline void __user *
426get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
427{
Laurent MEYERd09042d2006-06-23 02:05:36 -0700428 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 sp = current->sas_ss_sp + current->sas_ss_size;
430
431 return (void __user *)((sp - frame_size) & -8ul);
432}
433
434void sa_default_restorer(void); /* See comments below */
435void sa_default_rt_restorer(void); /* See comments below */
436
Paul Mundt6ac03432008-12-10 19:26:44 +0900437static int setup_frame(int sig, struct k_sigaction *ka,
438 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 struct sigframe __user *frame;
441 int err = 0;
442 int signal;
443
444 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
445
446 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
447 goto give_sigsegv;
448
449 signal = current_thread_info()->exec_domain
450 && current_thread_info()->exec_domain->signal_invmap
451 && sig < 32
452 ? current_thread_info()->exec_domain->signal_invmap[sig]
453 : sig;
454
455 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
456
457 /* Give up earlier as i386, in case */
458 if (err)
459 goto give_sigsegv;
460
461 if (_NSIG_WORDS > 1) {
462 err |= __copy_to_user(frame->extramask, &set->sig[1],
463 sizeof(frame->extramask)); }
464
465 /* Give up earlier as i386, in case */
466 if (err)
467 goto give_sigsegv;
468
469 /* Set up to return from userspace. If provided, use a stub
470 already in userspace. */
471 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 /*
473 * On SH5 all edited pointers are subject to NEFF
474 */
Paul Mundtc7914832009-08-04 17:14:39 +0900475 DEREF_REG_PR = neff_sign_extend((unsigned long)
476 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 } else {
478 /*
479 * Different approach on SH5.
480 * . Endianness independent asm code gets placed in entry.S .
481 * This is limited to four ASM instructions corresponding
482 * to two long longs in size.
483 * . err checking is done on the else branch only
484 * . flush_icache_range() is called upon __put_user() only
485 * . all edited pointers are subject to NEFF
486 * . being code, linker turns ShMedia bit on, always
487 * dereference index -1.
488 */
Paul Mundtc7914832009-08-04 17:14:39 +0900489 DEREF_REG_PR = neff_sign_extend((unsigned long)
490 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
492 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900493 (void *)((unsigned long)sa_default_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 goto give_sigsegv;
495
496 /* Cohere the trampoline with the I-cache. */
Paul Mundtb6138812007-11-11 15:53:51 +0900497 flush_cache_sigtramp(DEREF_REG_PR-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 }
499
500 /*
501 * Set up registers for signal handler.
502 * All edited pointers are subject to NEFF.
503 */
Paul Mundtc7914832009-08-04 17:14:39 +0900504 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
506
507 /* FIXME:
508 The glibc profiling support for SH-5 needs to be passed a sigcontext
509 so it can retrieve the PC. At some point during 2003 the glibc
510 support was changed to receive the sigcontext through the 2nd
511 argument, but there are still versions of libc.so in use that use
512 the 3rd argument. Until libc.so is stabilised, pass the sigcontext
513 through both 2nd and 3rd arguments.
514 */
515
516 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
517 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->sc;
518
Paul Mundtc7914832009-08-04 17:14:39 +0900519 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520
521 set_fs(USER_DS);
522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 /* Broken %016Lx */
Paul Mundt6ac03432008-12-10 19:26:44 +0900524 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
525 signal, current->comm, current->pid, frame,
526 regs->pc >> 32, regs->pc & 0xffffffff,
527 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Paul Mundt6ac03432008-12-10 19:26:44 +0900529 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
531give_sigsegv:
532 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900533 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534}
535
Paul Mundt6ac03432008-12-10 19:26:44 +0900536static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
537 sigset_t *set, struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538{
539 struct rt_sigframe __user *frame;
540 int err = 0;
541 int signal;
542
543 frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame));
544
545 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
546 goto give_sigsegv;
547
548 signal = current_thread_info()->exec_domain
549 && current_thread_info()->exec_domain->signal_invmap
550 && sig < 32
551 ? current_thread_info()->exec_domain->signal_invmap[sig]
552 : sig;
553
554 err |= __put_user(&frame->info, &frame->pinfo);
555 err |= __put_user(&frame->uc, &frame->puc);
556 err |= copy_siginfo_to_user(&frame->info, info);
557
558 /* Give up earlier as i386, in case */
559 if (err)
560 goto give_sigsegv;
561
562 /* Create the ucontext. */
563 err |= __put_user(0, &frame->uc.uc_flags);
564 err |= __put_user(0, &frame->uc.uc_link);
565 err |= __put_user((void *)current->sas_ss_sp,
566 &frame->uc.uc_stack.ss_sp);
567 err |= __put_user(sas_ss_flags(regs->regs[REG_SP]),
568 &frame->uc.uc_stack.ss_flags);
569 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
570 err |= setup_sigcontext(&frame->uc.uc_mcontext,
571 regs, set->sig[0]);
572 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
573
574 /* Give up earlier as i386, in case */
575 if (err)
576 goto give_sigsegv;
577
578 /* Set up to return from userspace. If provided, use a stub
579 already in userspace. */
580 if (ka->sa.sa_flags & SA_RESTORER) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 /*
582 * On SH5 all edited pointers are subject to NEFF
583 */
Paul Mundtc7914832009-08-04 17:14:39 +0900584 DEREF_REG_PR = neff_sign_extend((unsigned long)
585 ka->sa.sa_restorer | 0x1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 } else {
587 /*
588 * Different approach on SH5.
589 * . Endianness independent asm code gets placed in entry.S .
590 * This is limited to four ASM instructions corresponding
591 * to two long longs in size.
592 * . err checking is done on the else branch only
593 * . flush_icache_range() is called upon __put_user() only
594 * . all edited pointers are subject to NEFF
595 * . being code, linker turns ShMedia bit on, always
596 * dereference index -1.
597 */
Paul Mundtc7914832009-08-04 17:14:39 +0900598 DEREF_REG_PR = neff_sign_extend((unsigned long)
599 frame->retcode | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
601 if (__copy_to_user(frame->retcode,
Paul Mundt091db042008-09-29 19:44:40 +0900602 (void *)((unsigned long)sa_default_rt_restorer & (~1)), 16) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 goto give_sigsegv;
604
Paul Mundtc7914832009-08-04 17:14:39 +0900605 /* Cohere the trampoline with the I-cache. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15);
607 }
608
609 /*
610 * Set up registers for signal handler.
611 * All edited pointers are subject to NEFF.
612 */
Paul Mundtc7914832009-08-04 17:14:39 +0900613 regs->regs[REG_SP] = neff_sign_extend((unsigned long)frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 regs->regs[REG_ARG1] = signal; /* Arg for signal handler */
615 regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->info;
616 regs->regs[REG_ARG3] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext;
Paul Mundtc7914832009-08-04 17:14:39 +0900617 regs->pc = neff_sign_extend((unsigned long)ka->sa.sa_handler);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 set_fs(USER_DS);
620
Paul Mundt6ac03432008-12-10 19:26:44 +0900621 pr_debug("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n",
622 signal, current->comm, current->pid, frame,
623 regs->pc >> 32, regs->pc & 0xffffffff,
624 DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Paul Mundt6ac03432008-12-10 19:26:44 +0900626 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628give_sigsegv:
629 force_sigsegv(sig, current);
Paul Mundt6ac03432008-12-10 19:26:44 +0900630 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631}
632
633/*
634 * OK, we're invoking a handler
635 */
Al Viroa610d6e2012-05-21 23:42:15 -0400636static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
Al Virob7f9a112012-05-02 09:59:21 -0400638 struct pt_regs * regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639{
Al Virob7f9a112012-05-02 09:59:21 -0400640 sigset_t *oldset = sigmask_to_save();
Paul Mundt6ac03432008-12-10 19:26:44 +0900641 int ret;
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 /* Set up the stack frame */
644 if (ka->sa.sa_flags & SA_SIGINFO)
Paul Mundt6ac03432008-12-10 19:26:44 +0900645 ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 else
Paul Mundt6ac03432008-12-10 19:26:44 +0900647 ret = setup_frame(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
Al Viroa610d6e2012-05-21 23:42:15 -0400649 if (ret)
650 return;
Paul Mundt6ac03432008-12-10 19:26:44 +0900651
Al Viroefee9842012-04-28 02:04:15 -0400652 signal_delivered(sig, info, ka, regs,
Al Viroa610d6e2012-05-21 23:42:15 -0400653 test_thread_flag(TIF_SINGLESTEP));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654}
655
Paul Mundtab99c732008-07-30 19:55:30 +0900656asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657{
Paul Mundtab99c732008-07-30 19:55:30 +0900658 if (thread_info_flags & _TIF_SIGPENDING)
Al Viro9ef461a2012-04-22 01:16:34 -0400659 do_signal(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660
Paul Mundtab99c732008-07-30 19:55:30 +0900661 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
662 clear_thread_flag(TIF_NOTIFY_RESUME);
663 tracehook_notify_resume(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}