blob: 0e81b96c642f9cb4736070e9fdcbd453da0f0564 [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
92asmlinkage int
93sys_sigaltstack(const stack_t *uss, stack_t *uoss)
94{
95 return do_sigaltstack(uss, uoss, rdusp());
96}
97
98
99/*
100 * Do a signal return; undo the signal stack.
101 *
102 * Keep the return code on the stack quadword aligned!
103 * That makes the cache flush below easier.
104 */
105
106struct sigframe
107{
108 long dummy_er0;
109 long dummy_vector;
110#if defined(CONFIG_CPU_H8S)
111 short dummy_exr;
112#endif
113 long dummy_pc;
114 char *pretcode;
115 unsigned char retcode[8];
116 unsigned long extramask[_NSIG_WORDS-1];
117 struct sigcontext sc;
118 int sig;
119} __attribute__((aligned(2),packed));
120
121struct rt_sigframe
122{
123 long dummy_er0;
124 long dummy_vector;
125#if defined(CONFIG_CPU_H8S)
126 short dummy_exr;
127#endif
128 long dummy_pc;
129 char *pretcode;
130 struct siginfo *pinfo;
131 void *puc;
132 unsigned char retcode[8];
133 struct siginfo info;
134 struct ucontext uc;
135 int sig;
136} __attribute__((aligned(2),packed));
137
138static inline int
139restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc,
140 int *pd0)
141{
142 int err = 0;
143 unsigned int ccr;
144 unsigned int usp;
145 unsigned int er0;
146
147 /* Always make any pending restarted system calls return -EINTR */
148 current_thread_info()->restart_block.fn = do_no_restart_syscall;
149
150#define COPY(r) err |= __get_user(regs->r, &usc->sc_##r) /* restore passed registers */
151 COPY(er1);
152 COPY(er2);
153 COPY(er3);
154 COPY(er5);
155 COPY(pc);
156 ccr = regs->ccr & 0x10;
157 COPY(ccr);
158#undef COPY
159 regs->ccr &= 0xef;
160 regs->ccr |= ccr;
161 regs->orig_er0 = -1; /* disable syscall checks */
162 err |= __get_user(usp, &usc->sc_usp);
163 wrusp(usp);
164
165 err |= __get_user(er0, &usc->sc_er0);
166 *pd0 = er0;
167 return err;
168}
169
170asmlinkage int do_sigreturn(unsigned long __unused,...)
171{
172 struct pt_regs *regs = (struct pt_regs *) (&__unused - 1);
173 unsigned long usp = rdusp();
174 struct sigframe *frame = (struct sigframe *)(usp - 4);
175 sigset_t set;
176 int er0;
177
178 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
179 goto badframe;
180 if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
181 (_NSIG_WORDS > 1 &&
182 __copy_from_user(&set.sig[1], &frame->extramask,
183 sizeof(frame->extramask))))
184 goto badframe;
185
Matt Fleming97c47bb2012-05-11 10:58:06 +1000186 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
188 if (restore_sigcontext(regs, &frame->sc, &er0))
189 goto badframe;
190 return er0;
191
192badframe:
193 force_sig(SIGSEGV, current);
194 return 0;
195}
196
197asmlinkage int do_rt_sigreturn(unsigned long __unused,...)
198{
199 struct pt_regs *regs = (struct pt_regs *) &__unused;
200 unsigned long usp = rdusp();
201 struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
202 sigset_t set;
203 int er0;
204
205 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
206 goto badframe;
207 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
208 goto badframe;
209
Matt Fleming97c47bb2012-05-11 10:58:06 +1000210 set_current_blocked(&set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
212 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0))
213 goto badframe;
214
215 if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT)
216 goto badframe;
217
218 return er0;
219
220badframe:
221 force_sig(SIGSEGV, current);
222 return 0;
223}
224
225static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
226 unsigned long mask)
227{
228 int err = 0;
229
230 err |= __put_user(regs->er0, &sc->sc_er0);
231 err |= __put_user(regs->er1, &sc->sc_er1);
232 err |= __put_user(regs->er2, &sc->sc_er2);
233 err |= __put_user(regs->er3, &sc->sc_er3);
234 err |= __put_user(regs->er4, &sc->sc_er4);
235 err |= __put_user(regs->er5, &sc->sc_er5);
236 err |= __put_user(regs->er6, &sc->sc_er6);
237 err |= __put_user(rdusp(), &sc->sc_usp);
238 err |= __put_user(regs->pc, &sc->sc_pc);
239 err |= __put_user(regs->ccr, &sc->sc_ccr);
240 err |= __put_user(mask, &sc->sc_mask);
241
242 return err;
243}
244
245static inline void *
246get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
247{
248 unsigned long usp;
249
250 /* Default to using normal stack. */
251 usp = rdusp();
252
253 /* This is the X/Open sanctioned signal stack switching. */
254 if (ka->sa.sa_flags & SA_ONSTACK) {
Laurent MEYERd09042d2006-06-23 02:05:36 -0700255 if (!sas_ss_flags(usp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 usp = current->sas_ss_sp + current->sas_ss_size;
257 }
258 return (void *)((usp - frame_size) & -8UL);
259}
260
Al Viro8b6c3302012-04-21 22:42:11 -0400261static int setup_frame (int sig, struct k_sigaction *ka,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 sigset_t *set, struct pt_regs *regs)
263{
264 struct sigframe *frame;
265 int err = 0;
266 int usig;
267 unsigned char *ret;
268
269 frame = get_sigframe(ka, regs, sizeof(*frame));
270
271 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
272 goto give_sigsegv;
273
274 usig = current_thread_info()->exec_domain
275 && current_thread_info()->exec_domain->signal_invmap
276 && sig < 32
277 ? current_thread_info()->exec_domain->signal_invmap[sig]
278 : sig;
279
280 err |= __put_user(usig, &frame->sig);
281 if (err)
282 goto give_sigsegv;
283
284 err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
285 if (err)
286 goto give_sigsegv;
287
288 if (_NSIG_WORDS > 1) {
289 err |= copy_to_user(frame->extramask, &set->sig[1],
290 sizeof(frame->extramask));
291 if (err)
292 goto give_sigsegv;
293 }
294
295 ret = frame->retcode;
296 if (ka->sa.sa_flags & SA_RESTORER)
297 ret = (unsigned char *)(ka->sa.sa_restorer);
298 else {
299 /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */
Yoshinori Sato45d464e2008-02-23 15:23:58 -0800300 err |= __put_user(0x1a80f800 + (__NR_sigreturn & 0xff),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 (unsigned long *)(frame->retcode + 0));
302 err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4));
303 }
304
305 /* Set up to return from userspace. */
306 err |= __put_user(ret, &frame->pretcode);
307
308 if (err)
309 goto give_sigsegv;
310
311 /* Set up registers for signal handler */
312 wrusp ((unsigned long) frame);
313 regs->pc = (unsigned long) ka->sa.sa_handler;
314 regs->er0 = (current_thread_info()->exec_domain
315 && current_thread_info()->exec_domain->signal_invmap
316 && sig < 32
317 ? current_thread_info()->exec_domain->signal_invmap[sig]
318 : sig);
319 regs->er1 = (unsigned long)&(frame->sc);
320 regs->er5 = current->mm->start_data; /* GOT base */
321
Al Viro8b6c3302012-04-21 22:42:11 -0400322 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324give_sigsegv:
325 force_sigsegv(sig, current);
Al Viro8b6c3302012-04-21 22:42:11 -0400326 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Al Viro8b6c3302012-04-21 22:42:11 -0400329static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 sigset_t *set, struct pt_regs *regs)
331{
332 struct rt_sigframe *frame;
333 int err = 0;
334 int usig;
335 unsigned char *ret;
336
337 frame = get_sigframe(ka, regs, sizeof(*frame));
338
339 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
340 goto give_sigsegv;
341
342 usig = current_thread_info()->exec_domain
343 && current_thread_info()->exec_domain->signal_invmap
344 && sig < 32
345 ? current_thread_info()->exec_domain->signal_invmap[sig]
346 : sig;
347
348 err |= __put_user(usig, &frame->sig);
349 if (err)
350 goto give_sigsegv;
351
352 err |= __put_user(&frame->info, &frame->pinfo);
353 err |= __put_user(&frame->uc, &frame->puc);
354 err |= copy_siginfo_to_user(&frame->info, info);
355 if (err)
356 goto give_sigsegv;
357
358 /* Create the ucontext. */
359 err |= __put_user(0, &frame->uc.uc_flags);
360 err |= __put_user(0, &frame->uc.uc_link);
361 err |= __put_user((void *)current->sas_ss_sp,
362 &frame->uc.uc_stack.ss_sp);
363 err |= __put_user(sas_ss_flags(rdusp()),
364 &frame->uc.uc_stack.ss_flags);
365 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
366 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
367 err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
368 if (err)
369 goto give_sigsegv;
370
371 /* Set up to return from userspace. */
372 ret = frame->retcode;
373 if (ka->sa.sa_flags & SA_RESTORER)
374 ret = (unsigned char *)(ka->sa.sa_restorer);
375 else {
376 /* sub.l er0,er0; mov.b #__NR_sigreturn,r0l; trapa #0 */
Yoshinori Sato45d464e2008-02-23 15:23:58 -0800377 err |= __put_user(0x1a80f800 + (__NR_sigreturn & 0xff),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 (unsigned long *)(frame->retcode + 0));
379 err |= __put_user(0x5700, (unsigned short *)(frame->retcode + 4));
380 }
381 err |= __put_user(ret, &frame->pretcode);
382
383 if (err)
384 goto give_sigsegv;
385
386 /* Set up registers for signal handler */
387 wrusp ((unsigned long) frame);
388 regs->pc = (unsigned long) ka->sa.sa_handler;
389 regs->er0 = (current_thread_info()->exec_domain
390 && current_thread_info()->exec_domain->signal_invmap
391 && sig < 32
392 ? current_thread_info()->exec_domain->signal_invmap[sig]
393 : sig);
394 regs->er1 = (unsigned long)&(frame->info);
395 regs->er2 = (unsigned long)&frame->uc;
396 regs->er5 = current->mm->start_data; /* GOT base */
397
Al Viro8b6c3302012-04-21 22:42:11 -0400398 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399
400give_sigsegv:
401 force_sigsegv(sig, current);
Al Viro8b6c3302012-04-21 22:42:11 -0400402 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
404
405/*
406 * OK, we're invoking a handler
407 */
408static void
409handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
Al Virob7f9a112012-05-02 09:59:21 -0400410 struct pt_regs * regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
Al Virob7f9a112012-05-02 09:59:21 -0400412 sigset_t *oldset = sigmask_to_save();
Al Viro8b6c3302012-04-21 22:42:11 -0400413 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 /* are we from a system call? */
415 if (regs->orig_er0 >= 0) {
416 switch (regs->er0) {
417 case -ERESTART_RESTARTBLOCK:
418 case -ERESTARTNOHAND:
419 regs->er0 = -EINTR;
420 break;
421
422 case -ERESTARTSYS:
423 if (!(ka->sa.sa_flags & SA_RESTART)) {
424 regs->er0 = -EINTR;
425 break;
426 }
427 /* fallthrough */
428 case -ERESTARTNOINTR:
429 regs->er0 = regs->orig_er0;
430 regs->pc -= 2;
431 }
432 }
433
434 /* set up the stack frame */
435 if (ka->sa.sa_flags & SA_SIGINFO)
Al Viro8b6c3302012-04-21 22:42:11 -0400436 ret = setup_rt_frame(sig, ka, info, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 else
Al Viro8b6c3302012-04-21 22:42:11 -0400438 ret = setup_frame(sig, ka, oldset, regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
Al Viroa610d6e2012-05-21 23:42:15 -0400440 if (!ret)
Al Viroefee9842012-04-28 02:04:15 -0400441 signal_delivered(sig, info, ka, regs, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442}
443
444/*
445 * Note that 'init' is a special process: it doesn't get signals it doesn't
446 * want to handle. Thus you cannot kill init even with a SIGKILL even by
447 * mistake.
448 */
Geert Uytterhoeven87821712012-07-11 14:02:22 -0700449static void do_signal(struct pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
451 siginfo_t info;
452 int signr;
453 struct k_sigaction ka;
454
455 /*
456 * We want the common case to go fast, which
457 * is why we may in certain cases get here from
458 * kernel mode. Just return without doing anything
459 * if so.
460 */
461 if ((regs->ccr & 0x10))
Al Viro7ae4e322012-04-22 01:30:05 -0400462 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 current->thread.esp0 = (unsigned long) regs;
465
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
467 if (signr > 0) {
468 /* Whee! Actually deliver the signal. */
Al Virob7f9a112012-05-02 09:59:21 -0400469 handle_signal(signr, &info, &ka, regs);
Al Viro7ae4e322012-04-22 01:30:05 -0400470 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 /* Did we come from a system call? */
473 if (regs->orig_er0 >= 0) {
474 /* Restart the system call - no handlers present */
475 if (regs->er0 == -ERESTARTNOHAND ||
476 regs->er0 == -ERESTARTSYS ||
477 regs->er0 == -ERESTARTNOINTR) {
478 regs->er0 = regs->orig_er0;
479 regs->pc -= 2;
480 }
481 if (regs->er0 == -ERESTART_RESTARTBLOCK){
482 regs->er0 = __NR_restart_syscall;
483 regs->pc -= 2;
484 }
485 }
Al Viro7ae4e322012-04-22 01:30:05 -0400486
487 /* If there's no signal to deliver, we just restore the saved mask. */
Al Viro51a7b442012-05-21 23:33:55 -0400488 restore_saved_sigmask();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489}
Yoshinori Sato2fea2992007-07-15 23:38:36 -0700490
491asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
492{
Al Viro7ae4e322012-04-22 01:30:05 -0400493 if (thread_info_flags & _TIF_SIGPENDING)
494 do_signal(regs);
David Howellsd0420c82009-09-02 09:14:16 +0100495
496 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
497 clear_thread_flag(TIF_NOTIFY_RESUME);
498 tracehook_notify_resume(regs);
499 }
Yoshinori Sato2fea2992007-07-15 23:38:36 -0700500}