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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [m68knommu/] [platform/] [5206e/] [signal.c] - Blame information for rev 199

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

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/arch/m68knommu/platform/5206e/signal.c
3
 *
4
 *  Copyright (C) 1998  D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
5
 *                      Kenneth Albanowski <kjahds@kjahds.com>,
6
 *                      The Silver Hammer Group, Ltd.
7
 *
8
 *  Based on:
9
 *
10
 *  linux/arch/m68k/kernel/signal.c
11
 *
12
 *  Copyright (C) 1991, 1992  Linus Torvalds
13
 *
14
 * This file is subject to the terms and conditions of the GNU General Public
15
 * License.  See the file COPYING in the main directory of this archive
16
 * for more details.
17
 */
18
 
19
/*
20
 * Linux/m68k support by Hamish Macdonald
21
 *
22
 * 68000 and CPU32 support D. Jeff Dionne
23
 * 68060 fixes by Jesper Skov
24
 * 5307  fixes by David W. Miller
25
 * ColdFire support by Greg Ungerer (gerg@moreton.com.au)
26
 */
27
 
28
/*
29
 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
30
 * Atari :-) Current limitation: Only one sigstack can be active at one time.
31
 * If a second signal with SA_STACK set arrives while working on a sigstack,
32
 * SA_STACK is ignored. This behaviour avoids lots of trouble with nested
33
 * signal handlers!
34
 */
35
 
36
#include <linux/config.h>
37
 
38
#include <linux/sched.h>
39
#include <linux/mm.h>
40
#include <linux/kernel.h>
41
#include <linux/signal.h>
42
#include <linux/errno.h>
43
#include <linux/wait.h>
44
#include <linux/ptrace.h>
45
#include <linux/unistd.h>
46
 
47
#include <asm/setup.h>
48
#include <asm/segment.h>
49
#include <asm/pgtable.h>
50
#include <asm/traps.h>
51
 
52
/*
53
#define DEBUG
54
*/
55
 
56
#define offsetof(type, member)  ((size_t)(&((type *)0)->member))
57
 
58
#define _S(nr) (1<<((nr)-1))
59
 
60
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
61
 
62
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
63
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
64
 
65
/*
66
 * atomically swap in the new signal mask, and wait for a signal.
67
 */
68
asmlinkage int do_sigsuspend(struct pt_regs *regs)
69
{
70
        unsigned long oldmask = current->blocked;
71
        unsigned long newmask = regs->d3;
72
 
73
        current->blocked = newmask & _BLOCKABLE;
74
        regs->d0 = -EINTR;
75
        while (1) {
76
                current->state = TASK_INTERRUPTIBLE;
77
                schedule();
78
                if (do_signal(oldmask, regs))
79
                        return -EINTR;
80
        }
81
}
82
 
83
asmlinkage int do_sigreturn(unsigned long __unused)
84
{
85
        struct sigcontext_struct context;
86
        struct pt_regs *regs;
87
        struct switch_stack *sw;
88
        int fsize = 0;
89
        unsigned long fp;
90
        unsigned long usp = rdusp();
91
 
92
#ifdef DEBUG
93
        printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
94
#endif
95
 
96
        /* get stack frame pointer */
97
        sw = (struct switch_stack *) &__unused;
98
        regs = (struct pt_regs *) (sw + 1);
99
 
100
        /* get previous context (including pointer to possible extra junk) */
101
        if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
102
                goto badframe;
103
 
104
        memcpy_fromfs(&context,(void *)usp, sizeof(context));
105
 
106
        fp = usp + sizeof (context);
107
 
108
        /* restore signal mask */
109
        current->blocked = context.sc_mask & _BLOCKABLE;
110
 
111
        /* restore passed registers */
112
        regs->d0 = context.sc_d0;
113
        regs->d1 = context.sc_d1;
114
        regs->a0 = context.sc_a0;
115
        regs->a1 = context.sc_a1;
116
        regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
117
        regs->pc = context.sc_pc;
118
        regs->orig_d0 = -1;             /* disable syscall checks */
119
        wrusp(context.sc_usp);
120
        if (context.sc_usp != fp+fsize) {
121
#ifdef DEBUG
122
                printk("Stack off by %d\n",context.sc_usp - (fp+fsize));
123
#endif
124
                current->flags &= ~PF_ONSIGSTK;
125
        }
126
 
127
        return regs->d0;
128
badframe:
129
        do_exit(SIGSEGV);
130
}
131
 
132
/*
133
 * Set up a signal frame...
134
 *
135
 * This routine is somewhat complicated by the fact that if the
136
 * kernel may be entered by an exception other than a system call;
137
 * e.g. a bus error or other "bad" exception.  If this is the case,
138
 * then *all* the context on the kernel stack frame must be saved.
139
 *
140
 * For a large number of exceptions, the stack frame format is the same
141
 * as that which will be created when the process traps back to the kernel
142
 * when finished executing the signal handler.  In this case, nothing
143
 * must be done.  This is exception frame format "0".  For exception frame
144
 * formats "2", "9", "A" and "B", the extra information on the frame must
145
 * be saved.  This information is saved on the user stack and restored
146
 * when the signal handler is returned.
147
 *
148
 * The format of the user stack when executing the signal handler is:
149
 *
150
 *     usp ->  RETADDR (points to code below)
151
 *             signum  (parm #1)
152
 *             sigcode (parm #2 ; vector number)
153
 *             scp     (parm #3 ; sigcontext pointer, pointer to #1 below)
154
 *             code1   (addaw #20,sp) ; pop parms and code off stack
155
 *             code2   (moveq #119,d0; trap #0) ; sigreturn syscall
156
 *             slot1   (spare slots for ill-timed exception frame)
157
 *             slot2
158
 *     #1|     oldmask
159
 *       |     old usp
160
 *       |     d0      (first saved reg)
161
 *       |     d1
162
 *       |     a0
163
 *       |     a1
164
 *       |     sr      (saved status register)
165
 *       |     pc      (old pc; one to return to)
166
 * ----->|     forvec  (format and vector word of old supervisor stack frame)
167
 *       |     floating point context
168
 *
169
 * These are optionally followed by some extra stuff, depending on the
170
 * stack frame interrupted. This is 1 longword for format "2", 3
171
 * longwords for format "9", 6 longwords for format "A", and 21
172
 * longwords for format "B".
173
 *
174
 * everything after ------> is not present if the processor does not push a vector
175
 * format.  Only 68000 and the new 68000 modular core are like this
176
 */
177
 
178
#define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 8 + fs/4)
179
 
180
static void setup_frame (struct sigaction * sa, struct pt_regs *regs,
181
                         int signr, unsigned long oldmask)
182
{
183
        struct sigcontext_struct context;
184
        unsigned long *frame, *tframe;
185
        int stackOdd;
186
#define fsize 0
187
 
188
        frame = (unsigned long *)rdusp();
189
        stackOdd = !!(frame[-2] & 0x20000000);
190
        if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) {
191
                frame = (unsigned long *)sa->sa_restorer;
192
                current->flags |= PF_ONSIGSTK;
193
        }
194
#ifdef DEBUG
195
printk("setup_frame: usp %.8x\n",frame);
196
#endif
197
        frame -= UFRAME_SIZE(fsize);
198
#ifdef DEBUG
199
printk("setup_frame: frame %.8x\n",frame);
200
#endif
201
        if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
202
                do_exit(SIGSEGV);
203
        if (fsize) {
204
                memcpy_tofs (frame + UFRAME_SIZE(0), regs + 1, fsize);
205
                regs->stkadj = fsize;
206
        }
207
 
208
/* set up the "normal" stack seen by the signal handler */
209
        tframe = frame;
210
 
211
        /* return address points to code on stack */
212
        put_user((ulong)(frame+4), tframe); tframe++;
213
        if (current->exec_domain && current->exec_domain->signal_invmap)
214
            put_user(current->exec_domain->signal_invmap[signr], tframe);
215
        else
216
            put_user(signr, tframe);
217
        tframe++;
218
        tframe++;
219
        /* "scp" parameter.  points to sigcontext */
220
        put_user((ulong)(frame+6), tframe); tframe++;
221
 
222
        /* set up the return code... */
223
        /* Digestable ColdFire code :-) */
224
        if (!stackOdd)    /* moveq #28,d0; addal d0,sp */
225
                put_user(0x701cdfc0,tframe);
226
        else              /* moveq #30,d0; addal d0,sp */
227
                put_user(0x701edfc0,tframe);
228
        tframe++;
229
 
230
        put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
231
        /*
232
         * Leave 2 empty slots between code and stack frame. If a real
233
         * interrupt comes in just before trap call we need space for
234
         * new exception frame (so it doesn't clobber code!)
235
         */
236
        put_user(0,tframe); tframe++; /* space for exception vector */
237
        put_user(0,tframe); tframe++; /* space for return address */
238
 
239
/* setup and copy the sigcontext structure */
240
        context.sc_mask       = oldmask;
241
        context.sc_usp        = rdusp();
242
        context.sc_d0         = regs->d0;
243
        context.sc_d1         = regs->d1;
244
        context.sc_a0         = regs->a0;
245
        context.sc_a1         = regs->a1;
246
        context.sc_sr         = regs->sr;
247
        context.sc_pc         = regs->pc;
248
 
249
        memcpy_tofs (tframe, &context, sizeof(context));
250
#ifdef DEBUG
251
printk("setup_frame: top tframe %.8x\n",tframe + sizeof(context));
252
#endif
253
 
254
        /* Set up registers for signal handler */
255
        wrusp ((unsigned long) frame);
256
        regs->pc = (unsigned long) sa->sa_handler;
257
 
258
        /* Prepare to skip over the extra stuff in the exception frame.  */
259
        if (regs->stkadj) {
260
                struct pt_regs *tregs =
261
                        (struct pt_regs *)((ulong)regs + regs->stkadj);
262
 
263
#ifdef DEBUG
264
                printk("Performing stackadjust=%04x\n", regs->stkadj);
265
#endif
266
 
267
                /* This must be copied with decreasing addresses to
268
                   handle overlaps.  */
269
                tregs->pc = regs->pc;
270
                tregs->sr = regs->sr;
271
        }
272
}
273
 
274
/*
275
 * OK, we're invoking a handler
276
 */
277
static void handle_signal(unsigned long signr, struct sigaction *sa,
278
                          unsigned long oldmask, struct pt_regs *regs)
279
{
280
#ifdef DEBUG
281
        printk("Entering handle_signal, signr=%d\n", signr);
282
#endif
283
        /* are we from a system call? */
284
        if (regs->orig_d0 >= 0) {
285
                /* If so, check system call restarting.. */
286
                switch (regs->d0) {
287
                        case -ERESTARTNOHAND:
288
                                regs->d0 = -EINTR;
289
                                break;
290
 
291
                        case -ERESTARTSYS:
292
                                if (!(sa->sa_flags & SA_RESTART)) {
293
                                        regs->d0 = -EINTR;
294
                                        break;
295
                                }
296
                /* fallthrough */
297
                        case -ERESTARTNOINTR:
298
                                regs->d0 = regs->orig_d0;
299
                                regs->pc -= 2;
300
                }
301
        }
302
 
303
        /* set up the stack frame */
304
        setup_frame(sa, regs, signr, oldmask);
305
 
306
        if (sa->sa_flags & SA_ONESHOT)
307
                sa->sa_handler = NULL;
308
        if (!(sa->sa_flags & SA_NOMASK))
309
                current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
310
}
311
 
312
/*
313
 * Note that 'init' is a special process: it doesn't get signals it doesn't
314
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
315
 * mistake.
316
 *
317
 * Note that we go through the signals twice: once to check the signals
318
 * that the kernel can handle, and then we build all the user-level signal
319
 * handling stack-frames in one go after that.
320
 */
321
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
322
{
323
        unsigned long mask = ~current->blocked;
324
        unsigned long signr;
325
        struct sigaction * sa;
326
 
327
        current->tss.esp0 = (unsigned long) regs;
328
 
329
        /* If the process is traced, all signals are passed to the debugger. */
330
        if (current->flags & PF_PTRACED)
331
                mask = ~0UL;
332
        while ((signr = current->signal & mask) != 0) {
333
                signr = ffz(~signr);
334
                clear_bit(signr, &current->signal);
335
                sa = current->sig->action + signr;
336
#ifdef DEBUG
337
                printk("Signal %d, Handler %d: ", signr, sa->sa_handler);
338
#endif
339
                signr++;
340
 
341
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
342
                        current->exit_code = signr;
343
                        current->state = TASK_STOPPED;
344
 
345
                        /* Did we come from a system call? */
346
                        if (regs->orig_d0 >= 0) {
347
                                /* Restart the system call */
348
                                if (regs->d0 == -ERESTARTNOHAND ||
349
                                    regs->d0 == -ERESTARTSYS ||
350
                                    regs->d0 == -ERESTARTNOINTR) {
351
                                        regs->d0 = regs->orig_d0;
352
                                        regs->pc -= 2;
353
                                }
354
                        }
355
                        notify_parent(current, SIGCHLD);
356
                        schedule();
357
                        if (!(signr = current->exit_code)) {
358
                            discard_frame:
359
                            continue;
360
                        }
361
                        current->exit_code = 0;
362
                        if (signr == SIGSTOP)
363
                                goto discard_frame;
364
                        if (_S(signr) & current->blocked) {
365
                                current->signal |= _S(signr);
366
                                mask &= ~_S(signr);
367
                                continue;
368
                        }
369
                        sa = current->sig->action + signr - 1;
370
                }
371
                if (sa->sa_handler == SIG_IGN) {
372
#ifdef DEBUG
373
                        printk("Ignoring.\n");
374
#endif
375
                        if (signr != SIGCHLD)
376
                                continue;
377
                        /* check for SIGCHLD: it's special */
378
                        while (sys_waitpid(-1,NULL,WNOHANG) > 0)
379
                                /* nothing */;
380
                        continue;
381
                }
382
                if (sa->sa_handler == SIG_DFL) {
383
#ifdef DEBUG
384
                        printk("Default.\n");
385
#endif
386
                        if (current->pid == 1)
387
                                continue;
388
                        switch (signr) {
389
                        case SIGCONT: case SIGCHLD: case SIGWINCH:
390
                                continue;
391
 
392
                        case SIGTSTP: case SIGTTIN: case SIGTTOU:
393
                                if (is_orphaned_pgrp(current->pgrp))
394
                                        continue;
395
                        case SIGSTOP:
396
                                if (current->flags & PF_PTRACED)
397
                                        continue;
398
                                current->state = TASK_STOPPED;
399
                                current->exit_code = signr;
400
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
401
                                      SA_NOCLDSTOP))
402
                                        notify_parent(current, SIGCHLD);
403
                                schedule();
404
                                continue;
405
 
406
                        case SIGQUIT: case SIGILL: case SIGTRAP:
407
                        case SIGIOT: case SIGFPE: case SIGSEGV:
408
                                if (current->binfmt && current->binfmt->core_dump) {
409
                                    if (current->binfmt->core_dump(signr, regs))
410
                                        signr |= 0x80;
411
                                }
412
                                /* fall through */
413
                        default:
414
                                current->signal |= _S(signr & 0x7f);
415
                                current->flags |= PF_SIGNALED;
416
                                do_exit(signr);
417
                        }
418
                }
419
                handle_signal(signr, sa, oldmask, regs);
420
                return 1;
421
        }
422
 
423
        /* Did we come from a system call? */
424
        if (regs->orig_d0 >= 0) {
425
                /* Restart the system call - no handlers present */
426
                if (regs->d0 == -ERESTARTNOHAND ||
427
                    regs->d0 == -ERESTARTSYS ||
428
                    regs->d0 == -ERESTARTNOINTR) {
429
                        regs->d0 = regs->orig_d0;
430
                        regs->pc -= 2;
431
                }
432
        }
433
 
434
        /* If we are about to discard some frame stuff we must copy
435
           over the remaining frame. */
436
        if (regs->stkadj) {
437
                struct pt_regs *tregs =
438
                  (struct pt_regs *) ((ulong) regs + regs->stkadj);
439
#ifdef DEBUG
440
        printk("!!!!!!!!!!!!!! stkadj !!!\n");
441
#endif
442
                /* This must be copied with decreasing addresses to
443
                   handle overlaps.  */
444
                tregs->pc = regs->pc;
445
                tregs->sr = regs->sr;
446
        }
447
        return 0;
448
}

powered by: WebSVN 2.1.0

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