OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [alpha/] [kernel/] [signal.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1622 jcastillo
/*
2
 *  linux/arch/alpha/kernel/signal.c
3
 *
4
 *  Copyright (C) 1995  Linus Torvalds
5
 */
6
 
7
#include <linux/sched.h>
8
#include <linux/kernel.h>
9
#include <linux/signal.h>
10
#include <linux/errno.h>
11
#include <linux/wait.h>
12
#include <linux/ptrace.h>
13
#include <linux/unistd.h>
14
#include <linux/mm.h>
15
 
16
#include <asm/bitops.h>
17
#include <asm/segment.h>
18
 
19
#define _S(nr) (1<<((nr)-1))
20
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
21
 
22
asmlinkage int sys_wait4(int, int *, int, struct rusage *);
23
asmlinkage void ret_from_sys_call(void);
24
asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *,
25
        unsigned long, unsigned long);
26
 
27
extern int ptrace_set_bpt (struct task_struct *child);
28
extern int ptrace_cancel_bpt (struct task_struct *child);
29
 
30
/*
31
 * The OSF/1 sigprocmask calling sequence is different from the
32
 * C sigprocmask() sequence..
33
 *
34
 * how:
35
 * 1 - SIG_BLOCK
36
 * 2 - SIG_UNBLOCK
37
 * 3 - SIG_SETMASK
38
 *
39
 * We change the range to -1 .. 1 in order to let gcc easily
40
 * use the conditional move instructions.
41
 */
42
asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask,
43
        long a2, long a3, long a4, long a5, struct pt_regs regs)
44
{
45
        unsigned long ok, oldmask;
46
        struct task_struct * tsk;
47
 
48
        ok = how-1;             /*  0 .. 2 */
49
        tsk = current;
50
        ok = ok <= 2;
51
        oldmask = -EINVAL;
52
        if (ok) {
53
                long sign;              /* -1 .. 1 */
54
                unsigned long block, unblock;
55
 
56
                oldmask = tsk->blocked;
57
                newmask &= _BLOCKABLE;
58
                sign = how-2;
59
                unblock = oldmask & ~newmask;
60
                block = oldmask | newmask;
61
                if (!sign)
62
                        block = unblock;
63
                regs.r0 = 0;     /* special no error return */
64
                if (sign <= 0)
65
                        newmask = block;
66
                tsk->blocked = newmask;
67
        }
68
        return oldmask;
69
}
70
 
71
/*
72
 * atomically swap in the new signal mask, and wait for a signal.
73
 */
74
asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
75
{
76
        unsigned long oldmask = current->blocked;
77
        current->blocked = mask & _BLOCKABLE;
78
        while (1) {
79
                current->state = TASK_INTERRUPTIBLE;
80
                schedule();
81
                if (do_signal(oldmask,regs, sw, 0, 0))
82
                        return -EINTR;
83
        }
84
}
85
 
86
/*
87
 * Do a signal return; undo the signal stack.
88
 */
89
asmlinkage void do_sigreturn(struct sigcontext_struct * sc,
90
        struct pt_regs * regs, struct switch_stack * sw)
91
{
92
        unsigned long mask;
93
        int i;
94
 
95
        /* verify that it's a good sigcontext before using it */
96
        if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
97
                do_exit(SIGSEGV);
98
        if (get_fs_quad(&sc->sc_ps) != 8)
99
                do_exit(SIGSEGV);
100
        mask = get_fs_quad(&sc->sc_mask);
101
        if (mask & ~_BLOCKABLE)
102
                do_exit(SIGSEGV);
103
 
104
        /* ok, looks fine, start restoring */
105
        wrusp(get_fs_quad(sc->sc_regs+30));
106
        regs->pc = get_fs_quad(&sc->sc_pc);
107
        sw->r26 = (unsigned long) ret_from_sys_call;
108
        current->blocked = mask;
109
 
110
        regs->r0  = get_fs_quad(sc->sc_regs+0);
111
        regs->r1  = get_fs_quad(sc->sc_regs+1);
112
        regs->r2  = get_fs_quad(sc->sc_regs+2);
113
        regs->r3  = get_fs_quad(sc->sc_regs+3);
114
        regs->r4  = get_fs_quad(sc->sc_regs+4);
115
        regs->r5  = get_fs_quad(sc->sc_regs+5);
116
        regs->r6  = get_fs_quad(sc->sc_regs+6);
117
        regs->r7  = get_fs_quad(sc->sc_regs+7);
118
        regs->r8  = get_fs_quad(sc->sc_regs+8);
119
        sw->r9    = get_fs_quad(sc->sc_regs+9);
120
        sw->r10   = get_fs_quad(sc->sc_regs+10);
121
        sw->r11   = get_fs_quad(sc->sc_regs+11);
122
        sw->r12   = get_fs_quad(sc->sc_regs+12);
123
        sw->r13   = get_fs_quad(sc->sc_regs+13);
124
        sw->r14   = get_fs_quad(sc->sc_regs+14);
125
        sw->r15   = get_fs_quad(sc->sc_regs+15);
126
        regs->r16 = get_fs_quad(sc->sc_regs+16);
127
        regs->r17 = get_fs_quad(sc->sc_regs+17);
128
        regs->r18 = get_fs_quad(sc->sc_regs+18);
129
        regs->r19 = get_fs_quad(sc->sc_regs+19);
130
        regs->r20 = get_fs_quad(sc->sc_regs+20);
131
        regs->r21 = get_fs_quad(sc->sc_regs+21);
132
        regs->r22 = get_fs_quad(sc->sc_regs+22);
133
        regs->r23 = get_fs_quad(sc->sc_regs+23);
134
        regs->r24 = get_fs_quad(sc->sc_regs+24);
135
        regs->r25 = get_fs_quad(sc->sc_regs+25);
136
        regs->r26 = get_fs_quad(sc->sc_regs+26);
137
        regs->r27 = get_fs_quad(sc->sc_regs+27);
138
        regs->r28 = get_fs_quad(sc->sc_regs+28);
139
        regs->gp  = get_fs_quad(sc->sc_regs+29);
140
        for (i = 0; i < 31; i++)
141
                sw->fp[i] = get_fs_quad(sc->sc_fpregs+i);
142
 
143
        /* send SIGTRAP if we're single-stepping: */
144
        if (ptrace_cancel_bpt (current))
145
                send_sig(SIGTRAP, current, 1);
146
}
147
 
148
/*
149
 * Set up a signal frame...
150
 */
151
static void setup_frame(struct sigaction * sa,
152
                        struct pt_regs * regs,
153
                        struct switch_stack * sw, int signr,
154
                        unsigned long oldmask)
155
{
156
        int i;
157
        unsigned long oldsp;
158
        struct sigcontext_struct * sc;
159
 
160
        oldsp = rdusp();
161
        sc = ((struct sigcontext_struct *) oldsp) - 1;
162
 
163
        /* check here if we would need to switch stacks.. */
164
        if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
165
                do_exit(SIGSEGV);
166
 
167
        wrusp((unsigned long) sc);
168
 
169
        put_fs_quad(oldmask, &sc->sc_mask);
170
        put_fs_quad(8, &sc->sc_ps);
171
        put_fs_quad(regs->pc, &sc->sc_pc);
172
        put_fs_quad(oldsp, sc->sc_regs+30);
173
 
174
        put_fs_quad(regs->r0 , sc->sc_regs+0);
175
        put_fs_quad(regs->r1 , sc->sc_regs+1);
176
        put_fs_quad(regs->r2 , sc->sc_regs+2);
177
        put_fs_quad(regs->r3 , sc->sc_regs+3);
178
        put_fs_quad(regs->r4 , sc->sc_regs+4);
179
        put_fs_quad(regs->r5 , sc->sc_regs+5);
180
        put_fs_quad(regs->r6 , sc->sc_regs+6);
181
        put_fs_quad(regs->r7 , sc->sc_regs+7);
182
        put_fs_quad(regs->r8 , sc->sc_regs+8);
183
        put_fs_quad(sw->r9   , sc->sc_regs+9);
184
        put_fs_quad(sw->r10  , sc->sc_regs+10);
185
        put_fs_quad(sw->r11  , sc->sc_regs+11);
186
        put_fs_quad(sw->r12  , sc->sc_regs+12);
187
        put_fs_quad(sw->r13  , sc->sc_regs+13);
188
        put_fs_quad(sw->r14  , sc->sc_regs+14);
189
        put_fs_quad(sw->r15  , sc->sc_regs+15);
190
        put_fs_quad(regs->r16, sc->sc_regs+16);
191
        put_fs_quad(regs->r17, sc->sc_regs+17);
192
        put_fs_quad(regs->r18, sc->sc_regs+18);
193
        put_fs_quad(regs->r19, sc->sc_regs+19);
194
        put_fs_quad(regs->r20, sc->sc_regs+20);
195
        put_fs_quad(regs->r21, sc->sc_regs+21);
196
        put_fs_quad(regs->r22, sc->sc_regs+22);
197
        put_fs_quad(regs->r23, sc->sc_regs+23);
198
        put_fs_quad(regs->r24, sc->sc_regs+24);
199
        put_fs_quad(regs->r25, sc->sc_regs+25);
200
        put_fs_quad(regs->r26, sc->sc_regs+26);
201
        put_fs_quad(regs->r27, sc->sc_regs+27);
202
        put_fs_quad(regs->r28, sc->sc_regs+28);
203
        put_fs_quad(regs->gp , sc->sc_regs+29);
204
        for (i = 0; i < 31; i++)
205
                put_fs_quad(sw->fp[i], sc->sc_fpregs+i);
206
        put_fs_quad(regs->trap_a0, &sc->sc_traparg_a0);
207
        put_fs_quad(regs->trap_a1, &sc->sc_traparg_a1);
208
        put_fs_quad(regs->trap_a2, &sc->sc_traparg_a2);
209
 
210
        /*
211
         * The following is:
212
         *
213
         * bis $30,$30,$16
214
         * addq $31,0x67,$0
215
         * call_pal callsys
216
         *
217
         * ie, "sigreturn(stack-pointer)"
218
         */
219
        put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0);
220
        put_fs_quad(0x0000000000000083, sc->sc_retcode+1);
221
        imb();
222
 
223
        /* "return" to the handler */
224
        regs->r27 = regs->pc = (unsigned long) sa->sa_handler;
225
        regs->r26 = (unsigned long) sc->sc_retcode;
226
        regs->r16 = signr;              /* a0: signal number */
227
        regs->r17 = 0;                   /* a1: exception code; see gentrap.h */
228
        regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */
229
}
230
 
231
/*
232
 * OK, we're invoking a handler
233
 */
234
static inline void handle_signal(unsigned long signr, struct sigaction *sa,
235
        unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw)
236
{
237
        setup_frame(sa,regs,sw,signr,oldmask);
238
 
239
        if (sa->sa_flags & SA_ONESHOT)
240
                sa->sa_handler = NULL;
241
        if (!(sa->sa_flags & SA_NOMASK))
242
                current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
243
}
244
 
245
static inline void syscall_restart(unsigned long r0, unsigned long r19,
246
        struct pt_regs * regs, struct sigaction * sa)
247
{
248
        switch (regs->r0) {
249
                case ERESTARTNOHAND:
250
                no_system_call_restart:
251
                        regs->r0 = EINTR;
252
                        break;
253
                case ERESTARTSYS:
254
                        if (!(sa->sa_flags & SA_RESTART))
255
                                goto no_system_call_restart;
256
                /* fallthrough */
257
                case ERESTARTNOINTR:
258
                        regs->r0 = r0;  /* reset v0 and a3 and replay syscall */
259
                        regs->r19 = r19;
260
                        regs->pc -= 4;
261
        }
262
}
263
 
264
 
265
/*
266
 * Note that 'init' is a special process: it doesn't get signals it doesn't
267
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
268
 * mistake.
269
 *
270
 * Note that we go through the signals twice: once to check the signals that
271
 * the kernel can handle, and then we build all the user-level signal handling
272
 * stack-frames in one go after that.
273
 *
274
 * "r0" and "r19" are the registers we need to restore for system call
275
 * restart. "r0" is also used as an indicator whether we can restart at
276
 * all (if we get here from anything but a syscall return, it will be 0)
277
 */
278
asmlinkage int do_signal(unsigned long oldmask,
279
        struct pt_regs * regs,
280
        struct switch_stack * sw,
281
        unsigned long r0, unsigned long r19)
282
{
283
        unsigned long mask = ~current->blocked;
284
        unsigned long signr, single_stepping;
285
        struct sigaction * sa;
286
 
287
        single_stepping = ptrace_cancel_bpt(current);
288
 
289
        while ((signr = current->signal & mask) != 0) {
290
                signr = ffz(~signr);
291
                clear_bit(signr, &current->signal);
292
                sa = current->sig->action + signr;
293
                signr++;
294
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
295
                        current->exit_code = signr;
296
                        current->state = TASK_STOPPED;
297
                        notify_parent(current, SIGCHLD);
298
                        schedule();
299
                        single_stepping |= ptrace_cancel_bpt(current);
300
                        if (!(signr = current->exit_code))
301
                                continue;
302
                        current->exit_code = 0;
303
                        if (signr == SIGSTOP)
304
                                continue;
305
                        if (_S(signr) & current->blocked) {
306
                                current->signal |= _S(signr);
307
                                continue;
308
                        }
309
                        sa = current->sig->action + signr - 1;
310
                }
311
                if (sa->sa_handler == SIG_IGN) {
312
                        if (signr != SIGCHLD)
313
                                continue;
314
                        /* check for SIGCHLD: it's special */
315
                        while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
316
                                /* nothing */;
317
                        continue;
318
                }
319
                if (sa->sa_handler == SIG_DFL) {
320
                        if (current->pid == 1)
321
                                continue;
322
                        switch (signr) {
323
                        case SIGCONT: case SIGCHLD: case SIGWINCH:
324
                                continue;
325
 
326
                        case SIGTSTP: case SIGTTIN: case SIGTTOU:
327
                                if (is_orphaned_pgrp(current->pgrp))
328
                                        continue;
329
                        case SIGSTOP:
330
                                if (current->flags & PF_PTRACED)
331
                                        continue;
332
                                current->state = TASK_STOPPED;
333
                                current->exit_code = signr;
334
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
335
                                                SA_NOCLDSTOP))
336
                                        notify_parent(current, SIGCHLD);
337
                                schedule();
338
                                single_stepping |= ptrace_cancel_bpt(current);
339
                                continue;
340
 
341
                        case SIGQUIT: case SIGILL: case SIGTRAP:
342
                        case SIGABRT: case SIGFPE: case SIGSEGV:
343
                                if (current->binfmt && current->binfmt->core_dump) {
344
                                        if (current->binfmt->core_dump(signr, regs))
345
                                                signr |= 0x80;
346
                                }
347
                                /* fall through */
348
                        default:
349
                                current->signal |= _S(signr & 0x7f);
350
                                current->flags |= PF_SIGNALED;
351
                                do_exit(signr);
352
                        }
353
                }
354
                if (r0)
355
                        syscall_restart(r0, r19, regs, sa);
356
                handle_signal(signr, sa, oldmask, regs, sw);
357
                if (single_stepping) {
358
                        ptrace_set_bpt(current);        /* re-set breakpoint */
359
                }
360
                return 1;
361
        }
362
        if (r0 &&
363
            (regs->r0 == ERESTARTNOHAND ||
364
             regs->r0 == ERESTARTSYS ||
365
             regs->r0 == ERESTARTNOINTR)) {
366
                regs->r0 = r0;  /* reset v0 and a3 and replay syscall */
367
                regs->r19 = r19;
368
                regs->pc -= 4;
369
        }
370
        if (single_stepping) {
371
                ptrace_set_bpt(current);        /* re-set breakpoint */
372
        }
373
        return 0;
374
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.