Root/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c

1/*
2 * arch/ubicom32/kernel/signal.c
3 * Ubicom32 architecture signal handling implementation.
4 *
5 * (C) Copyright 2009, Ubicom, Inc.
6 * Copyright (C) 1991, 1992 Linus Torvalds
7 * Linux/m68k support by Hamish Macdonald
8 * 68060 fixes by Jesper Skov
9 * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
10 * mathemu support by Roman Zippel
11 * ++roman (07/09/96): implemented signal stacks
12 *
13 * This file is part of the Ubicom32 Linux Kernel Port.
14 *
15 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
16 * it and/or modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation, either version 2 of the
18 * License, or (at your option) any later version.
19 *
20 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
21 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
22 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
23 * the GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with the Ubicom32 Linux Kernel Port. If not,
27 * see <http://www.gnu.org/licenses/>.
28 *
29 * Ubicom32 implementation derived from (with many thanks):
30 * arch/m68knommu
31 * arch/blackfin
32 * arch/parisc
33 *
34 * mathemu support by Roman Zippel
35 * (Note: fpstate in the signal context is completely ignored for the emulator
36 * and the internal floating point format is put on stack)
37 *
38 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
39 * Atari :-) Current limitation: Only one sigstack can be active at one time.
40 * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
41 * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
42 * signal handlers!
43 */
44
45#include <linux/module.h>
46#include <linux/sched.h>
47#include <linux/mm.h>
48#include <linux/kernel.h>
49#include <linux/signal.h>
50#include <linux/syscalls.h>
51#include <linux/errno.h>
52#include <linux/wait.h>
53#include <linux/ptrace.h>
54#include <linux/unistd.h>
55#include <linux/stddef.h>
56#include <linux/highuid.h>
57#include <linux/tty.h>
58#include <linux/personality.h>
59#include <linux/binfmts.h>
60
61#include <asm/setup.h>
62#include <asm/uaccess.h>
63#include <asm/pgtable.h>
64#include <asm/traps.h>
65#include <asm/ucontext.h>
66
67#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
68
69/*
70 * asm signal return handlers.
71 */
72void ret_from_user_signal(void);
73void ret_from_user_rt_signal(void);
74asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
75
76/*
77 * Common signal suspend implementation
78 */
79static int signal_suspend(sigset_t *saveset, struct pt_regs *regs)
80{
81    regs->dn[0] = -EINTR;
82    while (1) {
83        current->state = TASK_INTERRUPTIBLE;
84        schedule();
85        if (!do_signal(saveset, regs)) {
86            continue;
87        }
88        /*
89         * If the current frame type is a signal trampoline we are
90         * actually going to call the signal handler so we return the
91         * desired d0 as the return value.
92         */
93        if (regs->frame_type == UBICOM32_FRAME_TYPE_SIGTRAMP) {
94            return regs->dn[0];
95        }
96        return -EINTR;
97    }
98    /*
99     * Should never get here
100     */
101    BUG();
102    return 0;
103}
104
105/*
106 * Atomically swap in the new signal mask, and wait for a signal.
107 */
108asmlinkage int do_sigsuspend(struct pt_regs *regs)
109{
110    old_sigset_t mask = regs->dn[0];
111    sigset_t saveset;
112
113    mask &= _BLOCKABLE;
114    spin_lock_irq(&current->sighand->siglock);
115    saveset = current->blocked;
116    siginitset(&current->blocked, mask);
117    recalc_sigpending();
118    spin_unlock_irq(&current->sighand->siglock);
119
120    /*
121     * Call common handler
122     */
123    return signal_suspend(&saveset, regs);
124}
125
126asmlinkage int
127do_rt_sigsuspend(struct pt_regs *regs)
128{
129    sigset_t *unewset = (sigset_t *)regs->dn[0];
130    size_t sigsetsize = (size_t)regs->dn[1];
131    sigset_t saveset, newset;
132
133    /* XXX: Don't preclude handling different sized sigset_t's. */
134    if (sigsetsize != sizeof(sigset_t))
135        return -EINVAL;
136
137    if (copy_from_user(&newset, unewset, sizeof(newset)))
138        return -EFAULT;
139    sigdelsetmask(&newset, ~_BLOCKABLE);
140
141    spin_lock_irq(&current->sighand->siglock);
142    saveset = current->blocked;
143    current->blocked = newset;
144    recalc_sigpending();
145    spin_unlock_irq(&current->sighand->siglock);
146
147    /*
148     * Call common handler
149     */
150    return signal_suspend(&saveset, regs);
151}
152
153asmlinkage int
154sys_sigaction(int sig, const struct old_sigaction *act,
155          struct old_sigaction *oact)
156{
157    struct k_sigaction new_ka, old_ka;
158    int ret;
159
160    if (act) {
161        old_sigset_t mask;
162        if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
163            __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
164            __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
165            return -EFAULT;
166        __get_user(new_ka.sa.sa_flags, &act->sa_flags);
167        __get_user(mask, &act->sa_mask);
168        siginitset(&new_ka.sa.sa_mask, mask);
169    }
170
171    ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
172
173    if (!ret && oact) {
174        if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
175            __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
176            __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
177            return -EFAULT;
178        __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
179        __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
180    }
181
182    return ret;
183}
184
185asmlinkage int
186do_sys_sigaltstack(struct pt_regs *regs)
187{
188    const stack_t *uss = (stack_t *) regs->dn[0];
189    stack_t *uoss = (stack_t *)regs->dn[1];
190    return do_sigaltstack(uss, uoss, regs->an[7]);
191}
192
193/*
194 * fdpic_func_descriptor describes sa_handler when the application is FDPIC
195 */
196struct fdpic_func_descriptor {
197    unsigned long text;
198    unsigned long GOT;
199};
200
201/*
202 * rt_sigframe is stored on the user stack immediately before (above)
203 * the signal handlers stack.
204 */
205struct rt_sigframe
206{
207    unsigned long syscall_number; /* This holds __NR_rt_sigreturn. */
208    unsigned long restore_all_regs; /* This field gets set to 1 if the frame
209                     * type is TRAP or INTERRUPT. */
210    siginfo_t *info;
211    struct ucontext uc;
212    int sig;
213    void *pretcode;
214};
215
216/*
217 * Do a signal return; undo the signal stack.
218 */
219asmlinkage int do_sigreturn(unsigned long __unused)
220{
221    BUG();
222    return 0;
223}
224
225asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
226{
227    unsigned long usp = regs->an[7];
228    struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
229    sigset_t set;
230
231    if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
232        goto badframe;
233    if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
234        goto badframe;
235
236    sigdelsetmask(&set, ~_BLOCKABLE);
237    spin_lock_irq(&current->sighand->siglock);
238    current->blocked = set;
239    recalc_sigpending();
240    spin_unlock_irq(&current->sighand->siglock);
241
242    if (copy_from_user(regs, &frame->uc.uc_mcontext, sizeof(struct pt_regs)))
243        goto badframe;
244    return regs->dn[0];
245
246badframe:
247    force_sig(SIGSEGV, current);
248    return 0;
249}
250
251static inline void *
252get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
253{
254    unsigned long usp;
255
256    /* Default to using normal stack. */
257    usp = regs->an[7];
258
259    /* This is the X/Open sanctioned signal stack switching. */
260    if (ka->sa.sa_flags & SA_ONSTACK) {
261        if (!sas_ss_flags(usp))
262            usp = current->sas_ss_sp + current->sas_ss_size;
263    }
264    return (void *)((usp - frame_size) & ~0x3);
265}
266
267/*
268 * signal_trampoline: Defined in ubicom32_syscall.S
269 */
270asmlinkage void signal_trampoline(void)__attribute__((naked));
271
272static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
273                sigset_t *set, struct pt_regs *regs)
274{
275    struct rt_sigframe *frame;
276    int err = 0;
277
278    frame = (struct rt_sigframe *) get_sigframe(ka, regs, sizeof(*frame));
279
280    /*
281     * The 'err |=' have been may criticized as bad code style, but I
282     * strongly suspect that we want this code to be fast. So for
283     * now it stays as is.
284     */
285    err |= __put_user( ( (current_thread_info()->exec_domain)
286               && (current_thread_info()->exec_domain->signal_invmap)
287               && (sig < 32) )
288               ? current_thread_info()->exec_domain->signal_invmap[sig]
289               : sig, &frame->sig);
290    err |= __put_user(info, &frame->info);
291
292    /* Create the ucontext. */
293    err |= __put_user(0, &frame->uc.uc_flags);
294    err |= __put_user(0, &frame->uc.uc_link);
295    err |= __put_user((void *)current->sas_ss_sp,
296              &frame->uc.uc_stack.ss_sp);
297    err |= __put_user(sas_ss_flags(regs->an[7]),
298              &frame->uc.uc_stack.ss_flags);
299    err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
300    err |= __put_user(__NR_rt_sigreturn, &frame->syscall_number);
301    if ((regs->frame_type == UBICOM32_FRAME_TYPE_TRAP) ||
302        (regs->frame_type == UBICOM32_FRAME_TYPE_INTERRUPT)) {
303        err |= __put_user(1, &frame->restore_all_regs);
304    } else {
305        err |= __put_user(0, &frame->restore_all_regs);
306    }
307    err |= copy_to_user (&frame->uc.uc_mcontext.sc_regs, regs, sizeof(struct pt_regs));
308    err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
309
310    if (err)
311        goto give_sigsegv;
312
313    /*
314     * Set up registers for signal handler NOTE: Do not modify dn[14], it
315     * contains the userspace tls pointer, so it important that it carries
316     * over to the signal handler.
317     */
318    regs->an[7] = (unsigned long)frame;
319    regs->pc = (unsigned long) signal_trampoline;
320    regs->an[5] = (unsigned long) signal_trampoline;
321    regs->dn[0] = sig;
322    regs->dn[1] = (unsigned long) frame->info;
323    regs->dn[2] = (unsigned int) &frame->uc;
324
325    /*
326     * If this is FDPIC then the signal handler is actually a function
327     * descriptor.
328     */
329    if (current->personality & FDPIC_FUNCPTRS) {
330        struct fdpic_func_descriptor __user *funcptr =
331            (struct fdpic_func_descriptor *) ka->sa.sa_handler;
332        err |= __get_user(regs->dn[3], &funcptr->text);
333        err |= __get_user(regs->an[0], &funcptr->GOT);
334        if (err)
335            goto give_sigsegv;
336
337        /*
338         * The funcdesc must be in a3 as this is required for the lazy
339         * resolver in ld.so, if the application is not FDPIC a3 is not
340         * used.
341         */
342        regs->an[3] = (unsigned long) funcptr;
343
344    } else {
345        regs->dn[3] = (unsigned long)ka->sa.sa_handler;
346        regs->an[0] = 0;
347    }
348
349    regs->frame_type = UBICOM32_FRAME_TYPE_SIGTRAMP;
350
351    return;
352
353give_sigsegv:
354    /* user space exception */
355    force_sigsegv(sig, current);
356}
357
358static inline void
359handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
360{
361    switch (regs->dn[0]) {
362    case -ERESTARTNOHAND:
363        if (!has_handler)
364            goto do_restart;
365        regs->dn[0] = -EINTR;
366        break;
367
368    case -ERESTARTSYS:
369        if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
370            regs->dn[0] = -EINTR;
371            break;
372        }
373    /* fallthrough */
374    case -ERESTARTNOINTR:
375    do_restart:
376        regs->dn[0] = regs->original_dn_0;
377        regs->pc -= 8;
378        regs->an[5] -= 8;
379        break;
380    }
381}
382
383/*
384 * OK, we're invoking a handler
385 */
386static void
387handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
388          sigset_t *oldset, struct pt_regs *regs)
389{
390    /* are we from a system call? */
391    if (regs->frame_type == -1)
392        /* If so, check system call restarting.. */
393        handle_restart(regs, ka, 1);
394
395    /* set up the stack frame */
396    setup_rt_frame(sig, ka, info, oldset, regs);
397
398    if (ka->sa.sa_flags & SA_ONESHOT)
399        ka->sa.sa_handler = SIG_DFL;
400
401    spin_lock_irq(&current->sighand->siglock);
402    sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
403    if (!(ka->sa.sa_flags & SA_NODEFER))
404        sigaddset(&current->blocked,sig);
405    recalc_sigpending();
406    spin_unlock_irq(&current->sighand->siglock);
407}
408
409/*
410 * Note that 'init' is a special process: it doesn't get signals it doesn't
411 * want to handle. Thus you cannot kill init even with a SIGKILL even by
412 * mistake.
413 */
414asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
415{
416    struct k_sigaction ka;
417    siginfo_t info;
418    int signr;
419
420    /*
421     * We want the common case to go fast, which
422     * is why we may in certain cases get here from
423     * kernel mode. Just return without doing anything
424     * if so.
425     */
426    if (!user_mode(regs))
427        return 1;
428
429    if (!oldset)
430        oldset = &current->blocked;
431
432    signr = get_signal_to_deliver(&info, &ka, regs, NULL);
433    if (signr > 0) {
434        /* Whee! Actually deliver the signal. */
435        handle_signal(signr, &ka, &info, oldset, regs);
436        return 1;
437    }
438
439    /* Did we come from a system call? */
440    if (regs->frame_type == -1) {
441        /* Restart the system call - no handlers present */
442        handle_restart(regs, NULL, 0);
443    }
444
445    return 0;
446}
447
448/*
449 * sys_sigreturn()
450 * Return handler for signal clean-up.
451 *
452 * NOTE: Ubicom32 does not use this syscall. Instead we rely
453 * on do_rt_sigreturn().
454 */
455asmlinkage long sys_sigreturn(void)
456{
457    return -ENOSYS;
458}
459

Archive Download this file



interactive