blob: 2d37418c04fbc3602a83cd12caad35e592a889b0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/h8300/kernel/signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11/*
12 * uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp>
13 * and David McCullough <davidm@snapgear.com>
14 *
15 * Based on
16 * Linux/m68k by Hamish Macdonald
17 */
18
19/*
20 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
21 * Atari :-) Current limitation: Only one sigstack can be active at one time.
22 * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
23 * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
24 * signal handlers!
25 */
26
27#include <linux/sched.h>
28#include <linux/mm.h>
29#include <linux/kernel.h>
30#include <linux/signal.h>
31#include <linux/syscalls.h>
32#include <linux/errno.h>
33#include <linux/wait.h>
34#include <linux/ptrace.h>
35#include <linux/unistd.h>
36#include <linux/stddef.h>
37#include <linux/highuid.h>
38#include <linux/personality.h>
39#include <linux/tty.h>
40#include <linux/binfmts.h>
David Howells733e5e42009-09-09 08:30:21 +010041#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43#include <asm/setup.h>
44#include <asm/uaccess.h>
45#include <asm/pgtable.h>
46#include <asm/traps.h>
47#include <asm/ucontext.h>
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049/*
50 * Atomically swap in the new signal mask, and wait for a signal.
51 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070052asmlinkage int
Al Viro7ae4e322012-04-22 01:30:05 -040053sys_sigsuspend(int unused1, int unused2, old_sigset_t mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054{
Al Viro7ae4e322012-04-22 01:30:05 -040055 sigset_t blocked;
56 siginitset(&blocked, mask);
57 return sigsuspend(&blocked);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058}
59
60asmlinkage int
61sys_sigaction(int sig, const struct old_sigaction *act,
62 struct old_sigaction *oact)
63{
64 struct k_sigaction new_ka, old_ka;
65 int ret;
66
67 if (act) {
68 old_sigset_t mask;
69 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
70 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
Al Viro79afd8e2012-04-22 17:21:18 -040071 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
72 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
73 __get_user(mask, &act->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 siginitset(&new_ka.sa.sa_mask, mask);
76 }
77
78 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
79
80 if (!ret && oact) {
81 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
82 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
Al Viro79afd8e2012-04-22 17:21:18 -040083 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
84 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
85 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 }
88
89 return ret;
90}
91
Linus Torvalds1da177e2005-04-16 15:20:36 -070092/*
93 * Do a signal return; undo the signal stack.
94 *
95 * Keep the return code on the stack quadword aligned!
96 * That makes the cache flush below easier.
97 */
98
99struct sigframe
100{
101 long dummy_er0;
102 long dummy_vector;
103#if defined(CONFIG_CPU_H8S)
104 short dummy_exr;
105#endif
106 long dummy_pc;
107 char *pretcode;
108 unsigned char retcode[8];
109 unsigned long extramask[_NSIG_WORDS-1];
110 struct sigcontext sc;
111 int sig;
112} __attribute__((aligned(2),packed));
113
114struct rt_sigframe
115{
116 long dummy_er0;
117 long dummy_vector;
118#if defined(CONFIG_CPU_H8S)
119 short dummy_exr;
120#endif
121 long dummy_pc;
122 char *pretcode;
123 struct siginfo *pinfo;
124 void *puc;
125 unsigned char retcode[8];
126 struct siginfo info;
127 struct ucontext uc;
128 int sig;
129} __attribute__((aligned(2),packed));
130
131static inline int
132restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc,
133 int *pd0)
134{
135 int err = 0;
136 unsigned int ccr;
137 unsigned int usp;
138 unsigned int er0;
139
140 /* Always make any pending restarted system calls return -EINTR */
141 current_thread_info()->restart_block.fn = do_no_restart_syscall;
142
143#define COPY(r) err |= __get_user(regs->r, &usc->sc_##r) /* restore passed registers */
144 COPY(er1);
145 COPY(er2);
146 COPY(er3);
147 COPY(er5);
148 COPY(pc);
149 ccr = regs->ccr & 0x10;
150 COPY(ccr);
151#undef COPY
152 regs->ccr &= 0xef;
153 regs->ccr |= ccr;
154 regs->orig_er0 = -1; /* disable syscall checks */
155 err |= __get_user(usp, &usc->sc_usp);
156 wrusp(usp);
157
158 err |= __get_user(er0, &usc->sc_er0);
159 *pd0 = er0;
160 return err;
161}
162
163asmlinkage int do_sigreturn(unsigned long __unused,...)
164{
165 struct pt_regs *regs = (struct pt_regs *) (&__unused - 1);
166 unsigned long usp = rdusp();
167 struct sigframe *frame = (struct sigframe *)(usp - 4);
168 sigset_t set;
169 int er0;
170
171 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
172 goto badframe;
173 if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
174 (_NSIG_WORDS > 1 &&
175 __copy_from_user(&set.sig[1], &frame->extramask,
176 sizeof(frame->extramask))))
177 goto badframe;
178
Matt Fleming97c47bb2012-05-11 10:58:06 +1000179 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 if (restore_sigcontext(regs, &frame->sc, &er0))
182 goto badframe;
183 return er0;
184
185badframe:
186 force_sig(SIGSEGV, current);
187 return 0;
188}
189
190asmlinkage int do_rt_sigreturn(unsigned long __unused,...)
191{
192 struct pt_regs *regs = (struct pt_regs *) &__unused;
193 unsigned long usp = rdusp();
194 struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
195 sigset_t set;
196 int er0;
197
198 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
199 goto badframe;
200 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
201 goto badframe;
202
Matt Fleming97c47bb2012-05-11 10:58:06 +1000203 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
205 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0))
206 goto badframe;
207
Al Viro6bc43c92012-12-23 02:19:34 -0500208 if (restore_altstack(&frame->uc.uc_stack))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 goto badframe;
210
211 return er0;
212
213badframe:
214 force_sig(SIGSEGV, current);
215 return 0;
216}
217
218static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
219 unsigned long mask)
220{
221 int err = 0;
222
223 err |= __put_user(regs->er0, &sc->sc_er0);
224 err |= __put_user(regs->er1, &sc->sc_er1);
225 err |= __put_user(regs->er2, &sc->sc_er2);
226 err |= __put_user(regs->er3, &sc->sc_er3);
227 err |= __put_user(regs->er4, &sc->sc_er4);
228 err |= __put_user(regs->er5, &sc->sc_er5);
229 err |= __put_user(regs->er6, &sc->sc_er6);
230 err |= __put_user(rdusp(), &sc->sc_usp);
231 err |= __put_user(regs->pc, &sc->sc_pc);
232 err |= __put_user(regs->ccr, &sc->sc_ccr);
233 err |= __put_user(mask, &sc->sc_mask);
234
235 return err;
236}
237
238static inline void *
239get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
240{
241 unsigned long usp;
242
243 /* Default to using normal stack. */
244 usp = rdusp();
245
246 /* This is the X/Open sanctioned signal stack switching. */
247 if (ka->sa.sa_flags & SA_ONSTACK) {
Laurent MEYERd09042d2006-06-23 02:05:36 -0700248 if (!sas_ss_flags(usp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 usp = current->sas_ss_sp + current->sas_ss_size;
250 }
251 return (void *)((usp - frame_size) & -8UL);
252}
253
Al Viro8b6c3302012-04-21 22:42:11 -0400254static int setup_frame (int sig, struct k_sigaction *ka,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 sigset_t *set, struct pt_regs *regs)
256{
257 struct sigframe *frame;
258 int err = 0;
259 int usig;
260 unsigned char *ret;
261
262 frame = get_sigframe(ka, regs, sizeof(*frame));
263
264 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
265 goto give_sigsegv;
266
267 usig = current_thread_info()->exec_domain
268 && current_thread_info()->exec_domain->signal_invmap
269 && sig < 32
270 ? current_thread_info()->exec_domain->signal_invmap[sig]
271 : sig;
272
273 err |= __put_user(usig, &frame->sig);
274 if (err)
275 goto give_sigsegv;
276
277 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
278 if (err)
279 goto give_sigsegv;
280
281 if (_NSIG_WORDS > 1) {
282 err |= copy_to_user(frame->extramask, &set->sig[1],
283 sizeof(frame->extramask));
284 if (err)
285 goto give_sigsegv;
286 }
287
288 ret = frame->retcode;
289 if (ka->sa.sa_flags & SA_RESTORER)
290 ret = (unsigned char *)(ka->sa.sa_restorer);
291 else {
292 /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */
Yoshinori Sato45d464e2008-02-23 15:23:58 -0800293 err |= __put_user(0x1a80f800 + (__NR_sigreturn & 0xff),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 (unsigned long *)(frame->retcode + 0));
295 err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4));
296 }
297
298 /* Set up to return from userspace. */
299 err |= __put_user(ret, &frame->pretcode);
300
301 if (err)
302 goto give_sigsegv;
303
304 /* Set up registers for signal handler */
305 wrusp ((unsigned long) frame);
306 regs->pc = (unsigned long) ka->sa.sa_handler;
307 regs->er0 = (current_thread_info()->exec_domain
308 && current_thread_info()->exec_domain->signal_invmap
309 && sig < 32
310 ? current_thread_info()->exec_domain->signal_invmap[sig]
311 : sig);
312 regs->er1 = (unsigned long)&(frame->sc);
313 regs->er5 = current->mm->start_data; /* GOT base */
314
Al Viro8b6c3302012-04-21 22:42:11 -0400315 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317give_sigsegv:
318 force_sigsegv(sig, current);
Al Viro8b6c3302012-04-21 22:42:11 -0400319 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320}
321
Al Viro8b6c3302012-04-21 22:42:11 -0400322static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 sigset_t *set, struct pt_regs *regs)
324{
325 struct rt_sigframe *frame;
326 int err = 0;
327 int usig;
328 unsigned char *ret;
329
330 frame = get_sigframe(ka, regs, sizeof(*frame));
331
332 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
333 goto give_sigsegv;
334
335 usig = current_thread_info()->exec_domain
336 && current_thread_info()->exec_domain->signal_invmap
337 && sig < 32
338 ? current_thread_info()->exec_domain->signal_invmap[sig]
339 : sig;
340
341 err |= __put_user(usig, &frame->sig);
342 if (err)
343 goto give_sigsegv;
344
345 err |= __put_user(&frame->info, &frame->pinfo);
346 err |= __put_user(&frame->uc, &frame->puc);
347 err |= copy_siginfo_to_user(&frame->info, info);
348 if (err)
349 goto give_sigsegv;
350
351 /* Create the ucontext. */
352 err |= __put_user(0, &frame->uc.uc_flags);
353 err |= __put_user(0, &frame->uc.uc_link);
Al Viro6bc43c92012-12-23 02:19:34 -0500354 err |= __save_altstack(&frame->uc.uc_stack, rdusp());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
356 err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
357 if (err)
358 goto give_sigsegv;
359
360 /* Set up to return from userspace. */
361 ret = frame->retcode;
362 if (ka->sa.sa_flags & SA_RESTORER)
363 ret = (unsigned char *)(ka->sa.sa_restorer);
364 else {
365 /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */
Yoshinori Sato45d464e2008-02-23 15:23:58 -0800366 err |= __put_user(0x1a80f800 + (__NR_sigreturn & 0xff),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 (unsigned long *)(frame->retcode + 0));
368 err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4));
369 }
370 err |= __put_user(ret, &frame->pretcode);
371
372 if (err)
373 goto give_sigsegv;
374
375 /* Set up registers for signal handler */
376 wrusp ((unsigned long) frame);
377 regs->pc = (unsigned long) ka->sa.sa_handler;
378 regs->er0 = (current_thread_info()->exec_domain
379 && current_thread_info()->exec_domain->signal_invmap
380 && sig < 32
381 ? current_thread_info()->exec_domain->signal_invmap[sig]
382 : sig);
383 regs->er1 = (unsigned long)&(frame->info);
384 regs->er2 = (unsigned long)&frame->uc;
385 regs->er5 = current->mm->start_data; /* GOT base */
386
Al Viro8b6c3302012-04-21 22:42:11 -0400387 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388
389give_sigsegv:
390 force_sigsegv(sig, current);
Al Viro8b6c3302012-04-21 22:42:11 -0400391 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392}
393
394/*
395 * OK, we're invoking a handler
396 */
397static void
398handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
Al Virob7f9a112012-05-02 09:59:21 -0400399 struct pt_regs * regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400{
Al Virob7f9a112012-05-02 09:59:21 -0400401 sigset_t *oldset = sigmask_to_save();
Al Viro8b6c3302012-04-21 22:42:11 -0400402 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 /* are we from a system call? */
404 if (regs->orig_er0 >= 0) {
405 switch (regs->er0) {
406 case -ERESTART_RESTARTBLOCK:
407 case -ERESTARTNOHAND:
408 regs->er0 = -EINTR;
409 break;
410
411 case -ERESTARTSYS:
412 if (!(ka->sa.sa_flags & SA_RESTART)) {
413 regs->er0 = -EINTR;
414 break;
415 }
416 /* fallthrough */
417 case -ERESTARTNOINTR:
418 regs->er0 = regs->orig_er0;
419 regs->pc -= 2;
420 }
421 }
422
423 /* set up the stack frame */
424 if (ka->sa.sa_flags & SA_SIGINFO)
Al Viro8b6c3302012-04-21 22:42:11 -0400425 ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 else
Al Viro8b6c3302012-04-21 22:42:11 -0400427 ret = setup_frame(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Al Viroa610d6e2012-05-21 23:42:15 -0400429 if (!ret)
Al Viroefee9842012-04-28 02:04:15 -0400430 signal_delivered(sig, info, ka, regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431}
432
433/*
434 * Note that 'init' is a special process: it doesn't get signals it doesn't
435 * want to handle. Thus you cannot kill init even with a SIGKILL even by
436 * mistake.
437 */
Geert Uytterhoeven87821712012-07-11 14:02:22 -0700438static void do_signal(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
440 siginfo_t info;
441 int signr;
442 struct k_sigaction ka;
443
444 /*
445 * We want the common case to go fast, which
446 * is why we may in certain cases get here from
447 * kernel mode. Just return without doing anything
448 * if so.
449 */
450 if ((regs->ccr & 0x10))
Al Viro7ae4e322012-04-22 01:30:05 -0400451 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 current->thread.esp0 = (unsigned long) regs;
454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
456 if (signr > 0) {
457 /* Whee! Actually deliver the signal. */
Al Virob7f9a112012-05-02 09:59:21 -0400458 handle_signal(signr, &info, &ka, regs);
Al Viro7ae4e322012-04-22 01:30:05 -0400459 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 /* Did we come from a system call? */
462 if (regs->orig_er0 >= 0) {
463 /* Restart the system call - no handlers present */
464 if (regs->er0 == -ERESTARTNOHAND ||
465 regs->er0 == -ERESTARTSYS ||
466 regs->er0 == -ERESTARTNOINTR) {
467 regs->er0 = regs->orig_er0;
468 regs->pc -= 2;
469 }
470 if (regs->er0 == -ERESTART_RESTARTBLOCK){
471 regs->er0 = __NR_restart_syscall;
472 regs->pc -= 2;
473 }
474 }
Al Viro7ae4e322012-04-22 01:30:05 -0400475
476 /* If there's no signal to deliver, we just restore the saved mask. */
Al Viro51a7b442012-05-21 23:33:55 -0400477 restore_saved_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478}
Yoshinori Sato2fea2992007-07-15 23:38:36 -0700479
480asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
481{
Al Viro7ae4e322012-04-22 01:30:05 -0400482 if (thread_info_flags & _TIF_SIGPENDING)
483 do_signal(regs);
David Howellsd0420c82009-09-02 09:14:16 +0100484
485 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
486 clear_thread_flag(TIF_NOTIFY_RESUME);
487 tracehook_notify_resume(regs);
488 }
Yoshinori Sato2fea2992007-07-15 23:38:36 -0700489}