aboutsummaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/signal.c
diff options
context:
space:
mode:
authorChris Metcalf <cmetcalf@tilera.com>2010-05-28 23:09:12 -0400
committerChris Metcalf <cmetcalf@tilera.com>2010-06-04 17:11:18 -0400
commit867e359b97c970a60626d5d76bbe2a8fadbf38fb (patch)
treec5ccbb7f5172e8555977119608ecb1eee3cc37e3 /arch/tile/kernel/signal.c
parent5360bd776f73d0a7da571d72a09a03f237e99900 (diff)
arch/tile: core support for Tilera 32-bit chips.
This change is the core kernel support for TILEPro and TILE64 chips. No driver support (except the console driver) is included yet. This includes the relevant Linux headers in asm/; the low-level low-level "Tile architecture" headers in arch/, which are shared with the hypervisor, etc., and are build-system agnostic; and the relevant hypervisor headers in hv/. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Reviewed-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/tile/kernel/signal.c')
-rw-r--r--arch/tile/kernel/signal.c359
1 files changed, 359 insertions, 0 deletions
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
new file mode 100644
index 000000000000..7ea85eb85242
--- /dev/null
+++ b/arch/tile/kernel/signal.c
@@ -0,0 +1,359 @@
1/*
2 * Copyright (C) 1991, 1992 Linus Torvalds
3 * Copyright 2010 Tilera Corporation. All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation, version 2.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12 * NON INFRINGEMENT. See the GNU General Public License for
13 * more details.
14 */
15
16#include <linux/sched.h>
17#include <linux/mm.h>
18#include <linux/smp.h>
19#include <linux/smp_lock.h>
20#include <linux/kernel.h>
21#include <linux/signal.h>
22#include <linux/errno.h>
23#include <linux/wait.h>
24#include <linux/unistd.h>
25#include <linux/stddef.h>
26#include <linux/personality.h>
27#include <linux/suspend.h>
28#include <linux/ptrace.h>
29#include <linux/elf.h>
30#include <linux/compat.h>
31#include <linux/syscalls.h>
32#include <linux/uaccess.h>
33#include <asm/processor.h>
34#include <asm/ucontext.h>
35#include <asm/sigframe.h>
36#include <arch/interrupts.h>
37
38#define DEBUG_SIG 0
39
40#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
41
42
43/* Caller before callee in this file; other callee is in assembler */
44void do_signal(struct pt_regs *regs);
45
46int _sys_sigaltstack(const stack_t __user *uss,
47 stack_t __user *uoss, struct pt_regs *regs)
48{
49 return do_sigaltstack(uss, uoss, regs->sp);
50}
51
52
53/*
54 * Do a signal return; undo the signal stack.
55 */
56
57int restore_sigcontext(struct pt_regs *regs,
58 struct sigcontext __user *sc, long *pr0)
59{
60 int err = 0;
61 int i;
62
63 /* Always make any pending restarted system calls return -EINTR */
64 current_thread_info()->restart_block.fn = do_no_restart_syscall;
65
66 for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
67 err |= __get_user(((long *)regs)[i],
68 &((long *)(&sc->regs))[i]);
69
70 regs->faultnum = INT_SWINT_1_SIGRETURN;
71
72 err |= __get_user(*pr0, &sc->regs.regs[0]);
73 return err;
74}
75
76int _sys_rt_sigreturn(struct pt_regs *regs)
77{
78 struct rt_sigframe __user *frame =
79 (struct rt_sigframe __user *)(regs->sp);
80 sigset_t set;
81 long r0;
82
83 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
84 goto badframe;
85 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
86 goto badframe;
87
88 sigdelsetmask(&set, ~_BLOCKABLE);
89 spin_lock_irq(&current->sighand->siglock);
90 current->blocked = set;
91 recalc_sigpending();
92 spin_unlock_irq(&current->sighand->siglock);
93
94 if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
95 goto badframe;
96
97 if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
98 goto badframe;
99
100 return r0;
101
102badframe:
103 force_sig(SIGSEGV, current);
104 return 0;
105}
106
107/*
108 * Set up a signal frame.
109 */
110
111int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
112{
113 int i, err = 0;
114
115 for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
116 err |= __put_user(((long *)regs)[i],
117 &((long *)(&sc->regs))[i]);
118
119 return err;
120}
121
122/*
123 * Determine which stack to use..
124 */
125static inline void __user *get_sigframe(struct k_sigaction *ka,
126 struct pt_regs *regs,
127 size_t frame_size)
128{
129 unsigned long sp;
130
131 /* Default to using normal stack */
132 sp = regs->sp;
133
134 /*
135 * If we are on the alternate signal stack and would overflow
136 * it, don't. Return an always-bogus address instead so we
137 * will die with SIGSEGV.
138 */
139 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
140 return (void __user *) -1L;
141
142 /* This is the X/Open sanctioned signal stack switching. */
143 if (ka->sa.sa_flags & SA_ONSTACK) {
144 if (sas_ss_flags(sp) == 0)
145 sp = current->sas_ss_sp + current->sas_ss_size;
146 }
147
148 sp -= frame_size;
149 /*
150 * Align the stack pointer according to the TILE ABI,
151 * i.e. so that on function entry (sp & 15) == 0.
152 */
153 sp &= -16UL;
154 return (void __user *) sp;
155}
156
157static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
158 sigset_t *set, struct pt_regs *regs)
159{
160 unsigned long restorer;
161 struct rt_sigframe __user *frame;
162 int err = 0;
163 int usig;
164
165 frame = get_sigframe(ka, regs, sizeof(*frame));
166
167 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
168 goto give_sigsegv;
169
170 usig = current_thread_info()->exec_domain
171 && current_thread_info()->exec_domain->signal_invmap
172 && sig < 32
173 ? current_thread_info()->exec_domain->signal_invmap[sig]
174 : sig;
175
176 /* Always write at least the signal number for the stack backtracer. */
177 if (ka->sa.sa_flags & SA_SIGINFO) {
178 /* At sigreturn time, restore the callee-save registers too. */
179 err |= copy_siginfo_to_user(&frame->info, info);
180 regs->flags |= PT_FLAGS_RESTORE_REGS;
181 } else {
182 err |= __put_user(info->si_signo, &frame->info.si_signo);
183 }
184
185 /* Create the ucontext. */
186 err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
187 err |= __put_user(0, &frame->uc.uc_flags);
188 err |= __put_user(0, &frame->uc.uc_link);
189 err |= __put_user((void *)(current->sas_ss_sp),
190 &frame->uc.uc_stack.ss_sp);
191 err |= __put_user(sas_ss_flags(regs->sp),
192 &frame->uc.uc_stack.ss_flags);
193 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
194 err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
195 err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
196 if (err)
197 goto give_sigsegv;
198
199 restorer = VDSO_BASE;
200 if (ka->sa.sa_flags & SA_RESTORER)
201 restorer = (unsigned long) ka->sa.sa_restorer;
202
203 /*
204 * Set up registers for signal handler.
205 * Registers that we don't modify keep the value they had from
206 * user-space at the time we took the signal.
207 */
208 regs->pc = (unsigned long) ka->sa.sa_handler;
209 regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
210 regs->sp = (unsigned long) frame;
211 regs->lr = restorer;
212 regs->regs[0] = (unsigned long) usig;
213
214 if (ka->sa.sa_flags & SA_SIGINFO) {
215 /* Need extra arguments, so mark to restore caller-saves. */
216 regs->regs[1] = (unsigned long) &frame->info;
217 regs->regs[2] = (unsigned long) &frame->uc;
218 regs->flags |= PT_FLAGS_CALLER_SAVES;
219 }
220
221 /*
222 * Notify any tracer that was single-stepping it.
223 * The tracer may want to single-step inside the
224 * handler too.
225 */
226 if (test_thread_flag(TIF_SINGLESTEP))
227 ptrace_notify(SIGTRAP);
228
229 return 0;
230
231give_sigsegv:
232 force_sigsegv(sig, current);
233 return -EFAULT;
234}
235
236/*
237 * OK, we're invoking a handler
238 */
239
240static int handle_signal(unsigned long sig, siginfo_t *info,
241 struct k_sigaction *ka, sigset_t *oldset,
242 struct pt_regs *regs)
243{
244 int ret;
245
246
247 /* Are we from a system call? */
248 if (regs->faultnum == INT_SWINT_1) {
249 /* If so, check system call restarting.. */
250 switch (regs->regs[0]) {
251 case -ERESTART_RESTARTBLOCK:
252 case -ERESTARTNOHAND:
253 regs->regs[0] = -EINTR;
254 break;
255
256 case -ERESTARTSYS:
257 if (!(ka->sa.sa_flags & SA_RESTART)) {
258 regs->regs[0] = -EINTR;
259 break;
260 }
261 /* fallthrough */
262 case -ERESTARTNOINTR:
263 /* Reload caller-saves to restore r0..r5 and r10. */
264 regs->flags |= PT_FLAGS_CALLER_SAVES;
265 regs->regs[0] = regs->orig_r0;
266 regs->pc -= 8;
267 }
268 }
269
270 /* Set up the stack frame */
271#ifdef CONFIG_COMPAT
272 if (is_compat_task())
273 ret = compat_setup_rt_frame(sig, ka, info, oldset, regs);
274 else
275#endif
276 ret = setup_rt_frame(sig, ka, info, oldset, regs);
277 if (ret == 0) {
278 /* This code is only called from system calls or from
279 * the work_pending path in the return-to-user code, and
280 * either way we can re-enable interrupts unconditionally.
281 */
282 spin_lock_irq(&current->sighand->siglock);
283 sigorsets(&current->blocked,
284 &current->blocked, &ka->sa.sa_mask);
285 if (!(ka->sa.sa_flags & SA_NODEFER))
286 sigaddset(&current->blocked, sig);
287 recalc_sigpending();
288 spin_unlock_irq(&current->sighand->siglock);
289 }
290
291 return ret;
292}
293
294/*
295 * Note that 'init' is a special process: it doesn't get signals it doesn't
296 * want to handle. Thus you cannot kill init even with a SIGKILL even by
297 * mistake.
298 */
299void do_signal(struct pt_regs *regs)
300{
301 siginfo_t info;
302 int signr;
303 struct k_sigaction ka;
304 sigset_t *oldset;
305
306 /*
307 * i386 will check if we're coming from kernel mode and bail out
308 * here. In my experience this just turns weird crashes into
309 * weird spin-hangs. But if we find a case where this seems
310 * helpful, we can reinstate the check on "!user_mode(regs)".
311 */
312
313 if (current_thread_info()->status & TS_RESTORE_SIGMASK)
314 oldset = &current->saved_sigmask;
315 else
316 oldset = &current->blocked;
317
318 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
319 if (signr > 0) {
320 /* Whee! Actually deliver the signal. */
321 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
322 /*
323 * A signal was successfully delivered; the saved
324 * sigmask will have been stored in the signal frame,
325 * and will be restored by sigreturn, so we can simply
326 * clear the TS_RESTORE_SIGMASK flag.
327 */
328 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
329 }
330
331 return;
332 }
333
334 /* Did we come from a system call? */
335 if (regs->faultnum == INT_SWINT_1) {
336 /* Restart the system call - no handlers present */
337 switch (regs->regs[0]) {
338 case -ERESTARTNOHAND:
339 case -ERESTARTSYS:
340 case -ERESTARTNOINTR:
341 regs->flags |= PT_FLAGS_CALLER_SAVES;
342 regs->regs[0] = regs->orig_r0;
343 regs->pc -= 8;
344 break;
345
346 case -ERESTART_RESTARTBLOCK:
347 regs->flags |= PT_FLAGS_CALLER_SAVES;
348 regs->regs[TREG_SYSCALL_NR] = __NR_restart_syscall;
349 regs->pc -= 8;
350 break;
351 }
352 }
353
354 /* If there's no signal to deliver, just put the saved sigmask back. */
355 if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
356 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
357 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
358 }
359}