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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1624 jcastillo
/*
2
 *  linux/arch/mips/kernel/signal.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
#include <linux/sched.h>
7
#include <linux/mm.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
 
15
#include <asm/bitops.h>
16
#include <asm/segment.h>
17
#include <asm/cachectl.h>
18
 
19
#define _S(nr) (1<<((nr)-1))
20
 
21
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
22
 
23
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
24
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
25
 
26
/*
27
 * atomically swap in the new signal mask, and wait for a signal.
28
 */
29
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
30
{
31
        unsigned long mask;
32
        struct pt_regs * regs = (struct pt_regs *) &restart;
33
 
34
        mask = current->blocked;
35
        current->blocked = set & _BLOCKABLE;
36
        regs->reg2 = -EINTR;
37
        while (1) {
38
                current->state = TASK_INTERRUPTIBLE;
39
                schedule();
40
                if (do_signal(mask,regs))
41
                        return -EINTR;
42
        }
43
}
44
 
45
/*
46
 * This sets regs->reg29 even though we don't actually use sigstacks yet..
47
 */
48
asmlinkage int sys_sigreturn(struct pt_regs *regs)
49
{
50
        struct sigcontext_struct *context;
51
 
52
        /*
53
         * We don't support fixing ADEL/ADES exceptions for signal stack frames.
54
         * No big loss - who doesn't care about the alignment of this stack
55
         * really deserves to loose.
56
         */
57
        context = (struct sigcontext_struct *) regs->reg29;
58
        if (verify_area(VERIFY_READ, context, sizeof(struct sigcontext_struct)) ||
59
            (regs->reg29 & 3))
60
                goto badframe;
61
 
62
        current->blocked = context->sc_oldmask & _BLOCKABLE;
63
        regs->reg1  = context->sc_at;
64
        regs->reg2  = context->sc_v0;
65
        regs->reg3  = context->sc_v1;
66
        regs->reg4  = context->sc_a0;
67
        regs->reg5  = context->sc_a1;
68
        regs->reg6  = context->sc_a2;
69
        regs->reg7  = context->sc_a3;
70
        regs->reg8  = context->sc_t0;
71
        regs->reg9  = context->sc_t1;
72
        regs->reg10 = context->sc_t2;
73
        regs->reg11 = context->sc_t3;
74
        regs->reg12 = context->sc_t4;
75
        regs->reg13 = context->sc_t5;
76
        regs->reg14 = context->sc_t6;
77
        regs->reg15 = context->sc_t7;
78
        regs->reg16 = context->sc_s0;
79
        regs->reg17 = context->sc_s1;
80
        regs->reg18 = context->sc_s2;
81
        regs->reg19 = context->sc_s3;
82
        regs->reg20 = context->sc_s4;
83
        regs->reg21 = context->sc_s5;
84
        regs->reg22 = context->sc_s6;
85
        regs->reg23 = context->sc_s7;
86
        regs->reg24 = context->sc_t8;
87
        regs->reg25 = context->sc_t9;
88
        /*
89
         * Skip k0/k1
90
         */
91
        regs->reg28 = context->sc_gp;
92
        regs->reg29 = context->sc_sp;
93
        regs->reg30 = context->sc_fp;
94
        regs->reg31 = context->sc_ra;
95
        regs->cp0_epc = context->sc_epc;
96
        regs->cp0_cause = context->sc_cause;
97
 
98
        /*
99
         * disable syscall checks
100
         */
101
        regs->orig_reg2 = -1;
102
        return context->sc_v0;
103
 
104
badframe:
105
        do_exit(SIGSEGV);
106
}
107
 
108
/*
109
 * Set up a signal frame...
110
 *
111
 * This routine is somewhat complicated by the fact that if the kernel may be
112
 * entered by an exception other than a system call; e.g. a bus error or other
113
 * "bad" exception.  If this is the case, then *all* the context on the kernel
114
 * stack frame must be saved.
115
 *
116
 * For a large number of exceptions, the stack frame format is the same
117
 * as that which will be created when the process traps back to the kernel
118
 * when finished executing the signal handler.  In this case, nothing
119
 * must be done. This information is saved on the user stack and restored
120
 * when the signal handler is returned.
121
 *
122
 * The signal handler will be called with ra pointing to code1 (see below) and
123
 * one parameters in a0 (signum).
124
 *
125
 *     usp ->  [unused]                         ; first free word on stack
126
 *             arg save space                   ; 16 bytes argument save space
127
 *             code1   (addiu sp,#1-offset)     ; syscall number
128
 *             code2   (li v0,__NR_sigreturn)   ; syscall number
129
 *             code3   (syscall)                ; do sigreturn(2)
130
 *     #1|     at, v0, v1, a0, a1, a2, a3       ; All integer registers
131
 *       |     t0, t1, t2, t3, t4, t5, t6, t7   ; except zero, k0 and k1
132
 *       |     s0, s1, s2, s3, s4, s5, s6, s7
133
 *       |     t8, t9, gp, sp, fp, ra;
134
 *       |     epc                              ; old program counter
135
 *       |     cause                            ; CP0 cause register
136
 *       |     oldmask
137
 */
138
 
139
struct sc {
140
        unsigned long   ass[4];
141
        unsigned int    code[4];
142
        struct sigcontext_struct scc;
143
};
144
#define scc_offset ((size_t)&((struct sc *)0)->scc)
145
 
146
static void setup_frame(struct sigaction * sa, struct sc **fp,
147
                        unsigned long pc, struct pt_regs *regs,
148
                        int signr, unsigned long oldmask)
149
{
150
        struct sc *frame;
151
 
152
        frame = *fp;
153
        frame--;
154
 
155
        /*
156
         * We don't support fixing ADEL/ADES exceptions for signal stack frames.
157
         * No big loss - who doesn't care about the alignment of this stack
158
         * really deserves to loose.
159
         */
160
        if (verify_area(VERIFY_WRITE, frame, sizeof (struct sc)) ||
161
            ((unsigned long)frame & 3))
162
                do_exit(SIGSEGV);
163
 
164
        /*
165
         * Set up the return code ...
166
         *
167
         *         .set    noreorder
168
         *         addiu   sp,24
169
         *         li      v0,__NR_sigreturn
170
         *         syscall
171
         *         .set    reorder
172
         */
173
        frame->code[0] = 0x27bd0000 + scc_offset;
174
        frame->code[1] = 0x24020000 + __NR_sigreturn;
175
        frame->code[2] = 0x0000000c;
176
 
177
        /*
178
         * Flush caches so that the instructions will be correctly executed.
179
         */
180
        sys_cacheflush (frame->code, sizeof (frame->code), ICACHE);
181
 
182
        /*
183
         * Set up the "normal" sigcontext_struct
184
         */
185
        frame->scc.sc_at = regs->reg1;          /* Assembler temporary */
186
        frame->scc.sc_v0 = regs->reg2;          /* Result registers */
187
        frame->scc.sc_v1 = regs->reg3;
188
        frame->scc.sc_a0 = regs->reg4;          /* Argument registers */
189
        frame->scc.sc_a1 = regs->reg5;
190
        frame->scc.sc_a2 = regs->reg6;
191
        frame->scc.sc_a3 = regs->reg7;
192
 
193
        frame->scc.sc_t0 = regs->reg8;          /* Caller saved */
194
        frame->scc.sc_t1 = regs->reg9;
195
        frame->scc.sc_t2 = regs->reg10;
196
        frame->scc.sc_t3 = regs->reg11;
197
        frame->scc.sc_t4 = regs->reg12;
198
        frame->scc.sc_t5 = regs->reg13;
199
        frame->scc.sc_t6 = regs->reg14;
200
        frame->scc.sc_t7 = regs->reg15;
201
 
202
        frame->scc.sc_s0 = regs->reg16;         /* Callee saved */
203
        frame->scc.sc_s1 = regs->reg17;
204
        frame->scc.sc_s2 = regs->reg18;
205
        frame->scc.sc_s3 = regs->reg19;
206
        frame->scc.sc_s4 = regs->reg20;
207
        frame->scc.sc_s5 = regs->reg21;
208
        frame->scc.sc_s6 = regs->reg22;
209
        frame->scc.sc_s7 = regs->reg23;
210
 
211
        frame->scc.sc_t8 = regs->reg24;         /* Caller saved */
212
        frame->scc.sc_t9 = regs->reg25;
213
 
214
        /*
215
         * Don't copy k0/k1
216
         */
217
        frame->scc.sc_gp = regs->reg28;         /* global pointer / s8 */
218
        frame->scc.sc_sp = regs->reg29;         /* old stack pointer */
219
        frame->scc.sc_fp = regs->reg30;         /* old frame pointer */
220
        frame->scc.sc_ra = regs->reg31;         /* old return address */
221
 
222
        frame->scc.sc_epc = regs->cp0_epc;      /* Program counter */
223
        frame->scc.sc_cause = regs->cp0_cause;  /* c0_epc register */
224
 
225
        frame->scc.sc_oldmask = oldmask;
226
        *fp = frame;
227
 
228
        regs->reg4 = signr;             /* argument for handler */
229
}
230
 
231
/*
232
 * Note that 'init' is a special process: it doesn't get signals it doesn't
233
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
234
 * mistake.
235
 *
236
 * Note that we go through the signals twice: once to check the signals that
237
 * the kernel can handle, and then we build all the user-level signal handling
238
 * stack-frames in one go after that.
239
 */
240
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
241
{
242
        unsigned long mask = ~current->blocked;
243
        unsigned long handler_signal = 0;
244
        struct sc *frame = NULL;
245
        unsigned long pc = 0;
246
        unsigned long signr;
247
        struct sigaction * sa;
248
 
249
        while ((signr = current->signal & mask)) {
250
                signr = ffz(~signr);
251
                clear_bit(signr, &current->signal);
252
                sa = current->sig->action + signr;
253
                signr++;
254
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
255
                        current->exit_code = signr;
256
                        current->state = TASK_STOPPED;
257
                        notify_parent(current);
258
                        schedule();
259
                        if (!(signr = current->exit_code))
260
                                continue;
261
                        current->exit_code = 0;
262
                        if (signr == SIGSTOP)
263
                                continue;
264
                        if (_S(signr) & current->blocked) {
265
                                current->signal |= _S(signr);
266
                                continue;
267
                        }
268
                        sa = current->sig->action + signr - 1;
269
                }
270
                if (sa->sa_handler == SIG_IGN) {
271
                        if (signr != SIGCHLD)
272
                                continue;
273
                        /* check for SIGCHLD: it's special */
274
                        while (sys_waitpid(-1,NULL,WNOHANG) > 0)
275
                                /* nothing */;
276
                        continue;
277
                }
278
                if (sa->sa_handler == SIG_DFL) {
279
                        if (current->pid == 1)
280
                                continue;
281
                        switch (signr) {
282
                        case SIGCONT: case SIGCHLD: case SIGWINCH:
283
                                continue;
284
 
285
                        case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
286
                                if (current->flags & PF_PTRACED)
287
                                        continue;
288
                                current->state = TASK_STOPPED;
289
                                current->exit_code = signr;
290
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
291
                                                SA_NOCLDSTOP))
292
                                        notify_parent(current);
293
                                schedule();
294
                                continue;
295
 
296
                        case SIGQUIT: case SIGILL: case SIGTRAP:
297
                        case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
298
                                if (current->binfmt && current->binfmt->core_dump) {
299
                                        if (current->binfmt->core_dump(signr, regs))
300
                                                signr |= 0x80;
301
                                }
302
                                /* fall through */
303
                        default:
304
                                current->signal |= _S(signr & 0x7f);
305
                                current->flags |= PF_SIGNALED;
306
                                do_exit(signr);
307
                        }
308
                }
309
                /*
310
                 * OK, we're invoking a handler
311
                 */
312
                if (regs->orig_reg2 >= 0) {
313
                        if (regs->reg2 == -ERESTARTNOHAND ||
314
                           (regs->reg2 == -ERESTARTSYS &&
315
                            !(sa->sa_flags & SA_RESTART)))
316
                                regs->reg2 = -EINTR;
317
                }
318
                handler_signal |= 1 << (signr-1);
319
                mask &= ~sa->sa_mask;
320
        }
321
        /*
322
         * Who's code doesn't conform to the restartable syscall convention
323
         * dies here!!!  The li instruction, a single machine instruction,
324
         * must directly be followed by the syscall instruction.
325
         */
326
        if (regs->orig_reg2 >= 0 &&
327
            (regs->reg2 == -ERESTARTNOHAND ||
328
             regs->reg2 == -ERESTARTSYS ||
329
             regs->reg2 == -ERESTARTNOINTR))
330
        {
331
                regs->reg2 = regs->orig_reg2;
332
                regs->cp0_epc -= 8;
333
        }
334
        if (!handler_signal)            /* no handler will be called - return 0 */
335
                return 0;
336
        pc = regs->cp0_epc;
337
        frame = (struct sc *) regs->reg29;
338
        signr = 1;
339
        sa = current->sig->action;
340
        for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
341
                if (mask > handler_signal)
342
                        break;
343
                if (!(mask & handler_signal))
344
                        continue;
345
                setup_frame(sa, &frame, pc, regs, signr, oldmask);
346
                pc = (unsigned long) sa->sa_handler;
347
                if (sa->sa_flags & SA_ONESHOT)
348
                        sa->sa_handler = NULL;
349
                current->blocked |= sa->sa_mask;
350
                oldmask |= sa->sa_mask;
351
        }
352
        regs->reg29 = (unsigned long) frame;            /* Stack pointer */
353
        regs->reg31 = (unsigned long) frame->code;      /* Return address */
354
        regs->cp0_epc = pc;             /* "return" to the first handler */
355
 
356
        return 1;
357
}

powered by: WebSVN 2.1.0

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