blob: c5f3d823d42b7f6cdb47217a2c826c3a35d3650b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/parisc/kernel/signal.c: Architecture-specific signal
3 * handling support.
4 *
5 * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
6 * Copyright (C) 2000 Linuxcare, Inc.
7 *
8 * Based on the ia64, i386, and alpha versions.
9 *
10 * Like the IA-64, we are a recent enough port (we are *starting*
11 * with glibc2.2) that we do not need to support the old non-realtime
12 * Linux signals. Therefore we don't. HP/UX signals will go in
13 * arch/parisc/hpux/signal.c when we figure out how to do them.
14 */
15
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/kernel.h>
20#include <linux/signal.h>
21#include <linux/errno.h>
22#include <linux/wait.h>
23#include <linux/ptrace.h>
Kyle McMartinecf02de2009-04-27 00:29:53 -040024#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/unistd.h>
26#include <linux/stddef.h>
27#include <linux/compat.h>
28#include <linux/elf.h>
David Howells733e5e42009-09-09 08:30:21 +010029#include <linux/tracehook.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <asm/ucontext.h>
31#include <asm/rt_sigframe.h>
32#include <asm/uaccess.h>
33#include <asm/pgalloc.h>
34#include <asm/cacheflush.h>
Sam Ravnborg0013a852005-09-09 20:57:26 +020035#include <asm/asm-offsets.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#ifdef CONFIG_COMPAT
38#include <linux/compat.h>
39#include "signal32.h"
40#endif
41
42#define DEBUG_SIG 0
43#define DEBUG_SIG_LEVEL 2
44
45#if DEBUG_SIG
46#define DBG(LEVEL, ...) \
47 ((DEBUG_SIG_LEVEL >= LEVEL) \
48 ? printk(__VA_ARGS__) : (void) 0)
49#else
50#define DBG(LEVEL, ...)
51#endif
52
53
54#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
55
56/* gcc will complain if a pointer is cast to an integer of different
57 * size. If you really need to do this (and we do for an ELF32 user
58 * application in an ELF64 kernel) then you have to do a cast to an
59 * integer of the same size first. The A() macro accomplishes
60 * this. */
61#define A(__x) ((unsigned long)(__x))
62
Linus Torvalds1da177e2005-04-16 15:20:36 -070063/*
64 * Atomically swap in the new signal mask, and wait for a signal.
65 */
Helge Dellera8f44e32007-01-28 14:58:52 +010066#ifdef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#include "sys32.h"
68#endif
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/*
71 * Do a signal return - restore sigcontext.
72 */
73
74/* Trampoline for calling rt_sigreturn() */
75#define INSN_LDI_R25_0 0x34190000 /* ldi 0,%r25 (in_syscall=0) */
76#define INSN_LDI_R25_1 0x34190002 /* ldi 1,%r25 (in_syscall=1) */
77#define INSN_LDI_R20 0x3414015a /* ldi __NR_rt_sigreturn,%r20 */
78#define INSN_BLE_SR2_R0 0xe4008200 /* be,l 0x100(%sr2,%r0),%sr0,%r31 */
79#define INSN_NOP 0x08000240 /* nop */
80/* For debugging */
81#define INSN_DIE_HORRIBLY 0x68000ccc /* stw %r0,0x666(%sr0,%r0) */
82
83static long
84restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
85{
86 long err = 0;
87
88 err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr));
89 err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
90 err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq));
91 err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq));
92 err |= __get_user(regs->sar, &sc->sc_sar);
93 DBG(2,"restore_sigcontext: iaoq is 0x%#lx / 0x%#lx\n",
94 regs->iaoq[0],regs->iaoq[1]);
95 DBG(2,"restore_sigcontext: r28 is %ld\n", regs->gr[28]);
96 return err;
97}
98
99void
100sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
101{
102 struct rt_sigframe __user *frame;
103 struct siginfo si;
104 sigset_t set;
105 unsigned long usp = (regs->gr[30] & ~(0x01UL));
106 unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
Helge Dellera8f44e32007-01-28 14:58:52 +0100107#ifdef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 compat_sigset_t compat_set;
109 struct compat_rt_sigframe __user * compat_frame;
110
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000111 if (is_compat_task())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
113#endif
114
115
116 /* Unwind the user stack to get the rt_sigframe structure. */
117 frame = (struct rt_sigframe __user *)
118 (usp - sigframe_size);
119 DBG(2,"sys_rt_sigreturn: frame is %p\n", frame);
120
Helge Dellera8f44e32007-01-28 14:58:52 +0100121#ifdef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 compat_frame = (struct compat_rt_sigframe __user *)frame;
123
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000124 if (is_compat_task()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 DBG(2,"sys_rt_sigreturn: ELF32 process.\n");
126 if (__copy_from_user(&compat_set, &compat_frame->uc.uc_sigmask, sizeof(compat_set)))
127 goto give_sigsegv;
128 sigset_32to64(&set,&compat_set);
129 } else
130#endif
131 {
132 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
133 goto give_sigsegv;
134 }
135
136 sigdelsetmask(&set, ~_BLOCKABLE);
137 spin_lock_irq(&current->sighand->siglock);
138 current->blocked = set;
139 recalc_sigpending();
140 spin_unlock_irq(&current->sighand->siglock);
141
142 /* Good thing we saved the old gr[30], eh? */
Helge Dellera8f44e32007-01-28 14:58:52 +0100143#ifdef CONFIG_64BIT
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000144 if (is_compat_task()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 DBG(1,"sys_rt_sigreturn: compat_frame->uc.uc_mcontext 0x%p\n",
146 &compat_frame->uc.uc_mcontext);
147// FIXME: Load upper half from register file
148 if (restore_sigcontext32(&compat_frame->uc.uc_mcontext,
149 &compat_frame->regs, regs))
150 goto give_sigsegv;
151 DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n",
152 usp, &compat_frame->uc.uc_stack);
153 if (do_sigaltstack32(&compat_frame->uc.uc_stack, NULL, usp) == -EFAULT)
154 goto give_sigsegv;
155 } else
156#endif
157 {
158 DBG(1,"sys_rt_sigreturn: frame->uc.uc_mcontext 0x%p\n",
159 &frame->uc.uc_mcontext);
160 if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
161 goto give_sigsegv;
162 DBG(1,"sys_rt_sigreturn: usp %#08lx stack 0x%p\n",
163 usp, &frame->uc.uc_stack);
164 if (do_sigaltstack(&frame->uc.uc_stack, NULL, usp) == -EFAULT)
165 goto give_sigsegv;
166 }
167
168
169
170 /* If we are on the syscall path IAOQ will not be restored, and
171 * if we are on the interrupt path we must not corrupt gr31.
172 */
173 if (in_syscall)
174 regs->gr[31] = regs->iaoq[0];
175#if DEBUG_SIG
176 DBG(1,"sys_rt_sigreturn: returning to %#lx, DUMPING REGS:\n", regs->iaoq[0]);
177 show_regs(regs);
178#endif
179 return;
180
181give_sigsegv:
182 DBG(1,"sys_rt_sigreturn: Sending SIGSEGV\n");
183 si.si_signo = SIGSEGV;
184 si.si_errno = 0;
185 si.si_code = SI_KERNEL;
Pavel Emelyanovb4888932007-10-18 23:40:14 -0700186 si.si_pid = task_pid_vnr(current);
David Howells25e15732008-11-14 10:38:38 +1100187 si.si_uid = current_uid();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 si.si_addr = &frame->uc;
189 force_sig_info(SIGSEGV, &si, current);
190 return;
191}
192
193/*
194 * Set up a signal frame.
195 */
196
197static inline void __user *
198get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
199{
200 /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we
201 don't use the parameter it doesn't matter */
202
203 DBG(1,"get_sigframe: ka = %#lx, sp = %#lx, frame_size = %#lx\n",
204 (unsigned long)ka, sp, frame_size);
205
Laurent MEYERd09042d2006-06-23 02:05:36 -0700206 if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 sp = current->sas_ss_sp; /* Stacks grow up! */
208
209 DBG(1,"get_sigframe: Returning sp = %#lx\n", (unsigned long)sp);
210 return (void __user *) sp; /* Stacks grow up. Fun. */
211}
212
213static long
214setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, int in_syscall)
215
216{
217 unsigned long flags = 0;
218 long err = 0;
219
220 if (on_sig_stack((unsigned long) sc))
221 flags |= PARISC_SC_FLAG_ONSTACK;
222 if (in_syscall) {
223 flags |= PARISC_SC_FLAG_IN_SYSCALL;
224 /* regs->iaoq is undefined in the syscall return path */
225 err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]);
226 err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]);
227 err |= __put_user(regs->sr[3], &sc->sc_iasq[0]);
228 err |= __put_user(regs->sr[3], &sc->sc_iasq[1]);
229 DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (in syscall)\n",
230 regs->gr[31], regs->gr[31]+4);
231 } else {
232 err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
233 err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
234 DBG(1,"setup_sigcontext: iaoq %#lx / %#lx (not in syscall)\n",
235 regs->iaoq[0], regs->iaoq[1]);
236 }
237
238 err |= __put_user(flags, &sc->sc_flags);
239 err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr));
240 err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
241 err |= __put_user(regs->sar, &sc->sc_sar);
242 DBG(1,"setup_sigcontext: r28 is %ld\n", regs->gr[28]);
243
244 return err;
245}
246
247static long
248setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
249 sigset_t *set, struct pt_regs *regs, int in_syscall)
250{
251 struct rt_sigframe __user *frame;
252 unsigned long rp, usp;
253 unsigned long haddr, sigframe_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 int err = 0;
Helge Dellera8f44e32007-01-28 14:58:52 +0100255#ifdef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 compat_int_t compat_val;
257 struct compat_rt_sigframe __user * compat_frame;
258 compat_sigset_t compat_set;
259#endif
260
261 usp = (regs->gr[30] & ~(0x01UL));
262 /*FIXME: frame_size parameter is unused, remove it. */
263 frame = get_sigframe(ka, usp, sizeof(*frame));
264
265 DBG(1,"SETUP_RT_FRAME: START\n");
266 DBG(1,"setup_rt_frame: frame %p info %p\n", frame, info);
267
268
Helge Dellera8f44e32007-01-28 14:58:52 +0100269#ifdef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270
271 compat_frame = (struct compat_rt_sigframe __user *)frame;
272
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000273 if (is_compat_task()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
Kyle McMartinf671c452006-01-15 14:10:29 -0500275 err |= copy_siginfo_to_user32(&compat_frame->info, info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 DBG(1,"SETUP_RT_FRAME: 1\n");
277 compat_val = (compat_int_t)current->sas_ss_sp;
278 err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp);
279 DBG(1,"SETUP_RT_FRAME: 2\n");
280 compat_val = (compat_int_t)current->sas_ss_size;
281 err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_size);
282 DBG(1,"SETUP_RT_FRAME: 3\n");
283 compat_val = sas_ss_flags(regs->gr[30]);
284 err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_flags);
285 DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &compat_frame->uc);
286 DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &compat_frame->uc.uc_mcontext);
287 err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext,
288 &compat_frame->regs, regs, in_syscall);
289 sigset_64to32(&compat_set,set);
290 err |= __copy_to_user(&compat_frame->uc.uc_sigmask, &compat_set, sizeof(compat_set));
291 } else
292#endif
293 {
294 DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &frame->info);
295 err |= copy_siginfo_to_user(&frame->info, info);
296 err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
297 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
298 err |= __put_user(sas_ss_flags(regs->gr[30]),
299 &frame->uc.uc_stack.ss_flags);
300 DBG(1,"setup_rt_frame: frame->uc = 0x%p\n", &frame->uc);
301 DBG(1,"setup_rt_frame: frame->uc.uc_mcontext = 0x%p\n", &frame->uc.uc_mcontext);
302 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);
303 /* FIXME: Should probably be converted aswell for the compat case */
304 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
305 }
306
307 if (err)
308 goto give_sigsegv;
309
310 /* Set up to return from userspace. If provided, use a stub
311 already in userspace. The first words of tramp are used to
312 save the previous sigrestartblock trampoline that might be
313 on the stack. We start the sigreturn trampoline at
314 SIGRESTARTBLOCK_TRAMP+X. */
315 err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0,
316 &frame->tramp[SIGRESTARTBLOCK_TRAMP+0]);
317 err |= __put_user(INSN_LDI_R20,
318 &frame->tramp[SIGRESTARTBLOCK_TRAMP+1]);
319 err |= __put_user(INSN_BLE_SR2_R0,
320 &frame->tramp[SIGRESTARTBLOCK_TRAMP+2]);
321 err |= __put_user(INSN_NOP, &frame->tramp[SIGRESTARTBLOCK_TRAMP+3]);
322
323#if DEBUG_SIG
324 /* Assert that we're flushing in the correct space... */
325 {
326 int sid;
327 asm ("mfsp %%sr3,%0" : "=r" (sid));
328 DBG(1,"setup_rt_frame: Flushing 64 bytes at space %#x offset %p\n",
329 sid, frame->tramp);
330 }
331#endif
332
333 flush_user_dcache_range((unsigned long) &frame->tramp[0],
334 (unsigned long) &frame->tramp[TRAMP_SIZE]);
335 flush_user_icache_range((unsigned long) &frame->tramp[0],
336 (unsigned long) &frame->tramp[TRAMP_SIZE]);
337
Paulius Zaleckasefad798b2008-02-03 15:42:53 +0200338 /* TRAMP Words 0-4, Length 5 = SIGRESTARTBLOCK_TRAMP
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 * TRAMP Words 5-9, Length 4 = SIGRETURN_TRAMP
340 * So the SIGRETURN_TRAMP is at the end of SIGRESTARTBLOCK_TRAMP
341 */
342 rp = (unsigned long) &frame->tramp[SIGRESTARTBLOCK_TRAMP];
343
344 if (err)
345 goto give_sigsegv;
346
347 haddr = A(ka->sa.sa_handler);
348 /* The sa_handler may be a pointer to a function descriptor */
Helge Dellera8f44e32007-01-28 14:58:52 +0100349#ifdef CONFIG_64BIT
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000350 if (is_compat_task()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351#endif
352 if (haddr & PA_PLABEL_FDESC) {
353 Elf32_Fdesc fdesc;
354 Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3);
355
356 err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
357
358 if (err)
359 goto give_sigsegv;
360
361 haddr = fdesc.addr;
362 regs->gr[19] = fdesc.gp;
363 }
Helge Dellera8f44e32007-01-28 14:58:52 +0100364#ifdef CONFIG_64BIT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 } else {
366 Elf64_Fdesc fdesc;
367 Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3);
368
369 err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
370
371 if (err)
372 goto give_sigsegv;
373
374 haddr = fdesc.addr;
375 regs->gr[19] = fdesc.gp;
376 DBG(1,"setup_rt_frame: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n",
377 haddr, regs->gr[19], in_syscall);
378 }
379#endif
380
381 /* The syscall return path will create IAOQ values from r31.
382 */
383 sigframe_size = PARISC_RT_SIGFRAME_SIZE;
Helge Dellera8f44e32007-01-28 14:58:52 +0100384#ifdef CONFIG_64BIT
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000385 if (is_compat_task())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
387#endif
388 if (in_syscall) {
389 regs->gr[31] = haddr;
Helge Dellera8f44e32007-01-28 14:58:52 +0100390#ifdef CONFIG_64BIT
Kyle McMartindf570b92006-08-27 11:04:26 -0400391 if (!test_thread_flag(TIF_32BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 sigframe_size |= 1;
393#endif
394 } else {
395 unsigned long psw = USER_PSW;
Helge Dellera8f44e32007-01-28 14:58:52 +0100396#ifdef CONFIG_64BIT
Kyle McMartindf570b92006-08-27 11:04:26 -0400397 if (!test_thread_flag(TIF_32BIT))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 psw |= PSW_W;
399#endif
400
401 /* If we are singlestepping, arrange a trap to be delivered
402 when we return to userspace. Note the semantics -- we
403 should trap before the first insn in the handler is
404 executed. Ref:
405 http://sources.redhat.com/ml/gdb/2004-11/msg00245.html
406 */
407 if (pa_psw(current)->r) {
408 pa_psw(current)->r = 0;
409 psw |= PSW_R;
410 mtctl(-1, 0);
411 }
412
413 regs->gr[0] = psw;
414 regs->iaoq[0] = haddr | 3;
415 regs->iaoq[1] = regs->iaoq[0] + 4;
416 }
417
418 regs->gr[2] = rp; /* userland return pointer */
419 regs->gr[26] = sig; /* signal number */
420
Helge Dellera8f44e32007-01-28 14:58:52 +0100421#ifdef CONFIG_64BIT
Kyle McMartina3ea84f2006-06-16 19:10:02 +0000422 if (is_compat_task()) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
424 regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */
425 } else
426#endif
427 {
428 regs->gr[25] = A(&frame->info); /* siginfo pointer */
429 regs->gr[24] = A(&frame->uc); /* ucontext pointer */
430 }
431
432 DBG(1,"setup_rt_frame: making sigreturn frame: %#lx + %#lx = %#lx\n",
433 regs->gr[30], sigframe_size,
434 regs->gr[30] + sigframe_size);
435 /* Raise the user stack pointer to make a proper call frame. */
436 regs->gr[30] = (A(frame) + sigframe_size);
437
438
439 DBG(1,"setup_rt_frame: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
440 current->comm, current->pid, frame, regs->gr[30],
441 regs->iaoq[0], regs->iaoq[1], rp);
442
443 return 1;
444
445give_sigsegv:
446 DBG(1,"setup_rt_frame: sending SIGSEGV\n");
Randolph Chung40c72f22005-10-21 22:49:47 -0400447 force_sigsegv(sig, current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return 0;
449}
450
451/*
452 * OK, we're invoking a handler.
453 */
454
455static long
456handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
457 sigset_t *oldset, struct pt_regs *regs, int in_syscall)
458{
459 DBG(1,"handle_signal: sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p\n",
460 sig, ka, info, oldset, regs);
461
462 /* Set up the stack frame */
463 if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
464 return 0;
465
Steven Rostedt69be8f12005-08-29 11:44:09 -0400466 spin_lock_irq(&current->sighand->siglock);
467 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
468 if (!(ka->sa.sa_flags & SA_NODEFER))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 sigaddset(&current->blocked,sig);
Steven Rostedt69be8f12005-08-29 11:44:09 -0400470 recalc_sigpending();
471 spin_unlock_irq(&current->sighand->siglock);
Kyle McMartinecf02de2009-04-27 00:29:53 -0400472
473 tracehook_signal_handler(sig, info, ka, regs, 0);
474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 return 1;
476}
477
Kyle McMartin2b163b72007-01-15 00:36:26 -0500478static inline void
479syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
480{
481 /* Check the return code */
482 switch (regs->gr[28]) {
483 case -ERESTART_RESTARTBLOCK:
484 current_thread_info()->restart_block.fn =
485 do_no_restart_syscall;
486 case -ERESTARTNOHAND:
487 DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
488 regs->gr[28] = -EINTR;
489 break;
490
491 case -ERESTARTSYS:
492 if (!(ka->sa.sa_flags & SA_RESTART)) {
493 DBG(1,"ERESTARTSYS: putting -EINTR\n");
494 regs->gr[28] = -EINTR;
495 break;
496 }
497 /* fallthrough */
498 case -ERESTARTNOINTR:
499 /* A syscall is just a branch, so all
500 * we have to do is fiddle the return pointer.
501 */
502 regs->gr[31] -= 8; /* delayed branching */
503 /* Preserve original r28. */
504 regs->gr[28] = regs->orig_r28;
505 break;
506 }
507}
508
509static inline void
510insert_restart_trampoline(struct pt_regs *regs)
511{
512 switch(regs->gr[28]) {
513 case -ERESTART_RESTARTBLOCK: {
514 /* Restart the system call - no handlers present */
515 unsigned int *usp = (unsigned int *)regs->gr[30];
516
517 /* Setup a trampoline to restart the syscall
518 * with __NR_restart_syscall
519 *
520 * 0: <return address (orig r31)>
521 * 4: <2nd half for 64-bit>
522 * 8: ldw 0(%sp), %r31
523 * 12: be 0x100(%sr2, %r0)
524 * 16: ldi __NR_restart_syscall, %r20
525 */
526#ifdef CONFIG_64BIT
527 put_user(regs->gr[31] >> 32, &usp[0]);
528 put_user(regs->gr[31] & 0xffffffff, &usp[1]);
529 put_user(0x0fc010df, &usp[2]);
530#else
531 put_user(regs->gr[31], &usp[0]);
532 put_user(0x0fc0109f, &usp[2]);
533#endif
534 put_user(0xe0008200, &usp[3]);
535 put_user(0x34140000, &usp[4]);
536
537 /* Stack is 64-byte aligned, and we only need
538 * to flush 1 cache line.
539 * Flushing one cacheline is cheap.
540 * "sync" on bigger (> 4 way) boxes is not.
541 */
Kyle McMartincf39cc32008-04-15 18:36:38 -0400542 flush_user_dcache_range(regs->gr[30], regs->gr[30] + 4);
543 flush_user_icache_range(regs->gr[30], regs->gr[30] + 4);
Kyle McMartin2b163b72007-01-15 00:36:26 -0500544
545 regs->gr[31] = regs->gr[30] + 8;
546 /* Preserve original r28. */
547 regs->gr[28] = regs->orig_r28;
548
549 return;
550 }
551 case -ERESTARTNOHAND:
552 case -ERESTARTSYS:
553 case -ERESTARTNOINTR: {
554 /* Hooray for delayed branching. We don't
555 * have to restore %r20 (the system call
556 * number) because it gets loaded in the delay
557 * slot of the branch external instruction.
558 */
559 regs->gr[31] -= 8;
560 /* Preserve original r28. */
561 regs->gr[28] = regs->orig_r28;
562
563 return;
564 }
565 default:
566 break;
567 }
568}
569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570/*
571 * Note that 'init' is a special process: it doesn't get signals it doesn't
572 * want to handle. Thus you cannot kill init even with a SIGKILL even by
573 * mistake.
574 *
575 * We need to be able to restore the syscall arguments (r21-r26) to
576 * restart syscalls. Thus, the syscall path should save them in the
577 * pt_regs structure (it's okay to do so since they are caller-save
578 * registers). As noted below, the syscall number gets restored for
579 * us due to the magic of delayed branching.
580 */
Kyle McMartin4650f0a2007-01-08 16:28:06 -0500581asmlinkage void
582do_signal(struct pt_regs *regs, long in_syscall)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 siginfo_t info;
585 struct k_sigaction ka;
586 int signr;
Kyle McMartin4650f0a2007-01-08 16:28:06 -0500587 sigset_t *oldset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
589 DBG(1,"\ndo_signal: oldset=0x%p, regs=0x%p, sr7 %#lx, in_syscall=%d\n",
590 oldset, regs, regs->sr[7], in_syscall);
591
592 /* Everyone else checks to see if they are in kernel mode at
593 this point and exits if that's the case. I'm not sure why
594 we would be called in that case, but for some reason we
595 are. */
596
Kyle McMartin4650f0a2007-01-08 16:28:06 -0500597 if (test_thread_flag(TIF_RESTORE_SIGMASK))
598 oldset = &current->saved_sigmask;
599 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 oldset = &current->blocked;
601
602 DBG(1,"do_signal: oldset %08lx / %08lx\n",
603 oldset->sig[0], oldset->sig[1]);
604
605
606 /* May need to force signal if handle_signal failed to deliver */
607 while (1) {
608
609 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
610 DBG(3,"do_signal: signr = %d, regs->gr[28] = %ld\n", signr, regs->gr[28]);
611
612 if (signr <= 0)
613 break;
614
615 /* Restart a system call if necessary. */
Kyle McMartin2b163b72007-01-15 00:36:26 -0500616 if (in_syscall)
617 syscall_restart(regs, &ka);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 /* Whee! Actually deliver the signal. If the
620 delivery failed, we need to continue to iterate in
621 this loop so we can deliver the SIGSEGV... */
Kyle McMartin2b163b72007-01-15 00:36:26 -0500622 if (handle_signal(signr, &info, &ka, oldset,
623 regs, in_syscall)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 DBG(1,KERN_DEBUG "do_signal: Exit (success), regs->gr[28] = %ld\n",
625 regs->gr[28]);
Kyle McMartin4650f0a2007-01-08 16:28:06 -0500626 if (test_thread_flag(TIF_RESTORE_SIGMASK))
627 clear_thread_flag(TIF_RESTORE_SIGMASK);
628 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
630 }
631 /* end of while(1) looping forever if we can't force a signal */
632
633 /* Did we come from a system call? */
Kyle McMartin2b163b72007-01-15 00:36:26 -0500634 if (in_syscall)
635 insert_restart_trampoline(regs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 DBG(1,"do_signal: Exit (not delivered), regs->gr[28] = %ld\n",
638 regs->gr[28]);
639
Kyle McMartin4650f0a2007-01-08 16:28:06 -0500640 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
641 clear_thread_flag(TIF_RESTORE_SIGMASK);
642 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
643 }
644
645 return;
646}
647
648void do_notify_resume(struct pt_regs *regs, long in_syscall)
649{
650 if (test_thread_flag(TIF_SIGPENDING) ||
651 test_thread_flag(TIF_RESTORE_SIGMASK))
652 do_signal(regs, in_syscall);
David Howellsd0420c82009-09-02 09:14:16 +0100653
654 if (test_thread_flag(TIF_NOTIFY_RESUME)) {
655 clear_thread_flag(TIF_NOTIFY_RESUME);
656 tracehook_notify_resume(regs);
David Howellsee18d642009-09-02 09:14:21 +0100657 if (current->replacement_session_keyring)
658 key_replace_session_keyring();
David Howellsd0420c82009-09-02 09:14:16 +0100659 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}