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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/arch/m68knommu/kernel/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
 */
25
 
26
/*
27
 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
28
 * Atari :-) Current limitation: Only one sigstack can be active at one time.
29
 * If a second signal with SA_STACK set arrives while working on a sigstack,
30
 * SA_STACK is ignored. This behaviour avoids lots of trouble with nested
31
 * signal handlers!
32
 */
33
 
34
#include <linux/config.h>
35
 
36
#ifdef CONFIG_M68328
37
#define NO_FORMAT_VEC
38
#endif
39
 
40
#include <linux/sched.h>
41
#include <linux/mm.h>
42
#include <linux/kernel.h>
43
#include <linux/signal.h>
44
#include <linux/errno.h>
45
#include <linux/wait.h>
46
#include <linux/ptrace.h>
47
#include <linux/unistd.h>
48
 
49
#include <asm/setup.h>
50
#include <asm/segment.h>
51
#include <asm/pgtable.h>
52
#include <asm/traps.h>
53
 
54
/*
55
#define DEBUG
56
*/
57
 
58
#define offsetof(type, member)  ((size_t)(&((type *)0)->member))
59
 
60
#define _S(nr) (1<<((nr)-1))
61
 
62
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
63
 
64
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
65
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
66
 
67
#ifndef NO_FORMAT_VEC
68
static const int extra_sizes[16] = {
69
  0,
70
  -1, /* sizeof(((struct frame *)0)->un.fmt1), */
71
  sizeof(((struct frame *)0)->un.fmt2),
72
  sizeof(((struct frame *)0)->un.fmt3),
73
  sizeof(((struct frame *)0)->un.fmt4),
74
  -1, /* sizeof(((struct frame *)0)->un.fmt5), */
75
  -1, /* sizeof(((struct frame *)0)->un.fmt6), */
76
  sizeof(((struct frame *)0)->un.fmt7),
77
  -1, /* sizeof(((struct frame *)0)->un.fmt8), */
78
  sizeof(((struct frame *)0)->un.fmt9),
79
  sizeof(((struct frame *)0)->un.fmta),
80
  sizeof(((struct frame *)0)->un.fmtb),
81
  sizeof(((struct frame *)0)->un.fmtc),
82
  -1, /* sizeof(((struct frame *)0)->un.fmtd), */
83
  -1, /* sizeof(((struct frame *)0)->un.fmte), */
84
  -1, /* sizeof(((struct frame *)0)->un.fmtf), */
85
};
86
#endif
87
 
88
/*
89
 * atomically swap in the new signal mask, and wait for a signal.
90
 */
91
asmlinkage int do_sigsuspend(struct pt_regs *regs)
92
{
93
        unsigned long oldmask = current->blocked;
94
        unsigned long newmask = regs->d3;
95
 
96
        current->blocked = newmask & _BLOCKABLE;
97
        regs->d0 = -EINTR;
98
        while (1) {
99
                current->state = TASK_INTERRUPTIBLE;
100
                schedule();
101
                if (do_signal(oldmask, regs))
102
                        return -EINTR;
103
        }
104
}
105
 
106
asmlinkage int do_sigreturn(unsigned long __unused)
107
{
108
        struct sigcontext_struct context;
109
        struct pt_regs *regs;
110
        struct switch_stack *sw;
111
        int fsize = 0;
112
#ifndef NO_FORMAT_VEC
113
        int formatvec = 0;
114
#endif
115
        unsigned long fp;
116
        unsigned long usp = rdusp();
117
 
118
#ifdef DEBUG
119
        printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
120
#endif
121
 
122
        /* get stack frame pointer */
123
        sw = (struct switch_stack *) &__unused;
124
        regs = (struct pt_regs *) (sw + 1);
125
 
126
        /* get previous context (including pointer to possible extra junk) */
127
        if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
128
                goto badframe;
129
 
130
        memcpy_fromfs(&context,(void *)usp, sizeof(context));
131
 
132
        fp = usp + sizeof (context);
133
 
134
        /* restore signal mask */
135
        current->blocked = context.sc_mask & _BLOCKABLE;
136
 
137
        /* restore passed registers */
138
        regs->d0 = context.sc_d0;
139
        regs->d1 = context.sc_d1;
140
        regs->a0 = context.sc_a0;
141
        regs->a1 = context.sc_a1;
142
        regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
143
        regs->pc = context.sc_pc;
144
        regs->orig_d0 = -1;             /* disable syscall checks */
145
        wrusp(context.sc_usp);
146
#ifndef NO_FORMAT_VEC
147
        formatvec = context.sc_formatvec;
148
        regs->format = formatvec >> 12;
149
        regs->vector = formatvec & 0xfff;
150
 
151
        fsize = extra_sizes[regs->format];
152
        if (fsize < 0) {
153
                /*
154
                 * user process trying to return with weird frame format
155
                 */
156
#ifdef DEBUG
157
                printk("user process returning with weird frame format\n");
158
#endif
159
                goto badframe;
160
        }
161
#endif /* !NO_FORMAT_VEC */
162
        if (context.sc_usp != fp+fsize) {
163
#ifdef DEBUG
164
                printk("Stack off by %d\n",context.sc_usp - (fp+fsize));
165
#endif
166
                current->flags &= ~PF_ONSIGSTK;
167
        }
168
#ifndef NO_FORMAT_VEC   
169
        /* OK.  Make room on the supervisor stack for the extra junk,
170
         * if necessary.
171
         */
172
 
173
        if (fsize) {
174
                if (verify_area(VERIFY_READ, (void *)fp, fsize))
175
                        goto badframe;
176
 
177
#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
178
                __asm__ __volatile__
179
                        ("movel %0,%/a0\n\t"
180
                         "subl %1,%/a0\n\t"     /* make room on stack */
181
                         "movel %/a0,%/sp\n\t"  /* set stack pointer */
182
                         /* move switch_stack and pt_regs */
183
                         "1: movel %0@+,%/a0@+\n\t"
184
                         "   dbra %2,1b\n\t"
185
                         "lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt stuff */
186
                         "lsrl  #2,%1\n\t"
187
                         "subql #1,%1\n\t"
188
                         "2: movesl %4@+,%2\n\t"
189
                         "   movel %2,%/a0@+\n\t"
190
                         "   dbra %1,2b\n\t"
191
                         "bral " SYMBOL_NAME_STR(ret_from_signal)
192
                         : /* no outputs, it doesn't ever return */
193
                         : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
194
                           "n" (frame_offset), "a" (fp)
195
                         : "a0");
196
#undef frame_offset
197
                goto badframe;
198
                /* NOTREACHED */
199
        }
200
#endif /* NO_FORMAT_VEC */
201
 
202
        return regs->d0;
203
badframe:
204
        do_exit(SIGSEGV);
205
}
206
 
207
/*
208
 * Set up a signal frame...
209
 *
210
 * This routine is somewhat complicated by the fact that if the
211
 * kernel may be entered by an exception other than a system call;
212
 * e.g. a bus error or other "bad" exception.  If this is the case,
213
 * then *all* the context on the kernel stack frame must be saved.
214
 *
215
 * For a large number of exceptions, the stack frame format is the same
216
 * as that which will be created when the process traps back to the kernel
217
 * when finished executing the signal handler.  In this case, nothing
218
 * must be done.  This is exception frame format "0".  For exception frame
219
 * formats "2", "9", "A" and "B", the extra information on the frame must
220
 * be saved.  This information is saved on the user stack and restored
221
 * when the signal handler is returned.
222
 *
223
 * The format of the user stack when executing the signal handler is:
224
 *
225
 *     usp ->  RETADDR (points to code below)
226
 *             signum  (parm #1)
227
 *             sigcode (parm #2 ; vector number)
228
 *             scp     (parm #3 ; sigcontext pointer, pointer to #1 below)
229
 *             code1   (addaw #20,sp) ; pop parms and code off stack
230
 *             code2   (moveq #119,d0; trap #0) ; sigreturn syscall
231
 *     #1|     oldmask
232
 *       |     old usp
233
 *       |     d0      (first saved reg)
234
 *       |     d1
235
 *       |     a0
236
 *       |     a1
237
 *       |     sr      (saved status register)
238
 *       |     pc      (old pc; one to return to)
239
 * ----->|     forvec  (format and vector word of old supervisor stack frame)
240
 *       |     floating point context
241
 *
242
 * These are optionally followed by some extra stuff, depending on the
243
 * stack frame interrupted. This is 1 longword for format "2", 3
244
 * longwords for format "9", 6 longwords for format "A", and 21
245
 * longwords for format "B".
246
 *
247
 * everything after ------> is not present if the processor does not push a vector
248
 * format.  Only 68000 and the new 68000 modular core are like this
249
 */
250
 
251
#define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4)
252
 
253
static void setup_frame (struct sigaction * sa, struct pt_regs *regs,
254
                         int signr, unsigned long oldmask)
255
{
256
        struct sigcontext_struct context;
257
        unsigned long *frame, *tframe;
258
#ifndef NO_FORMAT_VEC
259
        int fsize = extra_sizes[regs->format];
260
 
261
        if (fsize < 0) {
262
#ifdef DEBUG
263
                printk ("setup_frame: Unknown frame format %#x\n",
264
                        regs->format);
265
#endif
266
                do_exit(SIGSEGV);
267
        }
268
#else /* !NO_FORMAT_VEC */
269
#define fsize 0
270
#endif /* !NO_FORMAT_VEC */
271
 
272
        frame = (unsigned long *)rdusp();
273
        if (!(current->flags & PF_ONSIGSTK) && (sa->sa_flags & SA_STACK)) {
274
                frame = (unsigned long *)sa->sa_restorer;
275
                current->flags |= PF_ONSIGSTK;
276
        }
277
#ifdef DEBUG
278
printk("setup_frame: usp %.8x\n",frame);
279
#endif
280
        frame -= UFRAME_SIZE(fsize);
281
#ifdef DEBUG
282
printk("setup_frame: frame %.8x\n",frame);
283
#endif
284
        if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
285
                do_exit(SIGSEGV);
286
        if (fsize) {
287
                memcpy_tofs (frame + UFRAME_SIZE(0), regs + 1, fsize);
288
                regs->stkadj = fsize;
289
        }
290
 
291
/* set up the "normal" stack seen by the signal handler */
292
        tframe = frame;
293
 
294
        /* return address points to code on stack */
295
        put_user((ulong)(frame+4), tframe); tframe++;
296
        if (current->exec_domain && current->exec_domain->signal_invmap)
297
            put_user(current->exec_domain->signal_invmap[signr], tframe);
298
        else
299
            put_user(signr, tframe);
300
        tframe++;
301
        /* dummy if NO_FORMAT_VEC */
302
#ifndef NO_FORMAT_VEC
303
        put_user(regs->vector, tframe);
304
#endif
305
        tframe++;
306
        /* "scp" parameter.  points to sigcontext */
307
        put_user((ulong)(frame+6), tframe); tframe++;
308
 
309
/* set up the return code... */
310
        put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
311
        put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
312
 
313
/* setup and copy the sigcontext structure */
314
        context.sc_mask       = oldmask;
315
        context.sc_usp        = rdusp();
316
        context.sc_d0         = regs->d0;
317
        context.sc_d1         = regs->d1;
318
        context.sc_a0         = regs->a0;
319
        context.sc_a1         = regs->a1;
320
        context.sc_sr         = regs->sr;
321
        context.sc_pc         = regs->pc;
322
#ifndef NO_FORMAT_VEC
323
        context.sc_formatvec  = (regs->format << 12 | regs->vector);
324
#endif
325
 
326
        memcpy_tofs (tframe, &context, sizeof(context));
327
#ifdef DEBUG
328
printk("setup_frame: top tframe %.8x\n",tframe + sizeof(context));
329
#endif
330
 
331
#ifndef NO_FORMAT_VEC
332
        /*
333
         * no matter what frame format we were using before, we
334
         * will do the "RTE" using a normal 4 word frame.
335
         */
336
        regs->format = 0;
337
#endif
338
 
339
        /* Set up registers for signal handler */
340
        wrusp ((unsigned long) frame);
341
        regs->pc = (unsigned long) sa->sa_handler;
342
 
343
        /* Prepare to skip over the extra stuff in the exception frame.  */
344
        if (regs->stkadj) {
345
                struct pt_regs *tregs =
346
                        (struct pt_regs *)((ulong)regs + regs->stkadj);
347
 
348
#ifdef DEBUG
349
                printk("Performing stackadjust=%04x\n", regs->stkadj);
350
#endif
351
 
352
                /* This must be copied with decreasing addresses to
353
                   handle overlaps.  */
354
#ifndef NO_FORMAT_VEC
355
                tregs->vector = regs->vector;
356
                tregs->format = regs->format;
357
#endif
358
                tregs->pc = regs->pc;
359
                tregs->sr = regs->sr;
360
        }
361
}
362
 
363
/*
364
 * OK, we're invoking a handler
365
 */
366
static void handle_signal(unsigned long signr, struct sigaction *sa,
367
                          unsigned long oldmask, struct pt_regs *regs)
368
{
369
#ifdef DEBUG
370
        printk("Entering handle_signal, signr=%d\n", signr);
371
#endif
372
        /* are we from a system call? */
373
        if (regs->orig_d0 >= 0) {
374
                /* If so, check system call restarting.. */
375
                switch (regs->d0) {
376
                        case -ERESTARTNOHAND:
377
                                regs->d0 = -EINTR;
378
                                break;
379
 
380
                        case -ERESTARTSYS:
381
                                if (!(sa->sa_flags & SA_RESTART)) {
382
                                        regs->d0 = -EINTR;
383
                                        break;
384
                                }
385
                /* fallthrough */
386
                        case -ERESTARTNOINTR:
387
                                regs->d0 = regs->orig_d0;
388
                                regs->pc -= 2;
389
                }
390
        }
391
 
392
        /* set up the stack frame */
393
        setup_frame(sa, regs, signr, oldmask);
394
 
395
        if (sa->sa_flags & SA_ONESHOT)
396
                sa->sa_handler = NULL;
397
        if (!(sa->sa_flags & SA_NOMASK))
398
                current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
399
}
400
 
401
/*
402
 * Note that 'init' is a special process: it doesn't get signals it doesn't
403
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
404
 * mistake.
405
 *
406
 * Note that we go through the signals twice: once to check the signals
407
 * that the kernel can handle, and then we build all the user-level signal
408
 * handling stack-frames in one go after that.
409
 */
410
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs)
411
{
412
        unsigned long mask = ~current->blocked;
413
        unsigned long signr;
414
        struct sigaction * sa;
415
 
416
        current->tss.esp0 = (unsigned long) regs;
417
 
418
        /* If the process is traced, all signals are passed to the debugger. */
419
        if (current->flags & PF_PTRACED)
420
                mask = ~0UL;
421
        while ((signr = current->signal & mask) != 0) {
422
                signr = ffz(~signr);
423
                clear_bit(signr, &current->signal);
424
                sa = current->sig->action + signr;
425
                signr++;
426
 
427
#ifdef DEBUG
428
                printk("Signal %d: ", sa->sa_handler);
429
#endif
430
 
431
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
432
                        current->exit_code = signr;
433
                        current->state = TASK_STOPPED;
434
 
435
                        /* Did we come from a system call? */
436
                        if (regs->orig_d0 >= 0) {
437
                                /* Restart the system call */
438
                                if (regs->d0 == -ERESTARTNOHAND ||
439
                                    regs->d0 == -ERESTARTSYS ||
440
                                    regs->d0 == -ERESTARTNOINTR) {
441
                                        regs->d0 = regs->orig_d0;
442
                                        regs->pc -= 2;
443
                                }
444
                        }
445
                        notify_parent(current, SIGCHLD);
446
                        schedule();
447
                        if (!(signr = current->exit_code)) {
448
                        discard_frame:
449
#ifndef NO_FORMAT_VEC
450
                            /* Make sure that a faulted bus cycle
451
                               isn't restarted (only needed on the
452
                               68030).  */
453
                            if (regs->format == 10 || regs->format == 11) {
454
                                regs->stkadj = extra_sizes[regs->format];
455
                                regs->format = 0;
456
                            }
457
#endif /* !NO_FORMAT_VEC */
458
                            continue;
459
                        }
460
                        current->exit_code = 0;
461
                        if (signr == SIGSTOP)
462
                                goto discard_frame;
463
                        if (_S(signr) & current->blocked) {
464
                                current->signal |= _S(signr);
465
                                mask &= ~_S(signr);
466
                                continue;
467
                        }
468
                        sa = current->sig->action + signr - 1;
469
                }
470
                if (sa->sa_handler == SIG_IGN) {
471
#ifdef DEBUG
472
                        printk("Ignoring.\n");
473
#endif
474
                        if (signr != SIGCHLD)
475
                                continue;
476
                        /* check for SIGCHLD: it's special */
477
                        while (sys_waitpid(-1,NULL,WNOHANG) > 0)
478
                                /* nothing */;
479
                        continue;
480
                }
481
                if (sa->sa_handler == SIG_DFL) {
482
#ifdef DEBUG
483
                        printk("Default.\n");
484
#endif
485
                        if (current->pid == 1)
486
                                continue;
487
                        switch (signr) {
488
                        case SIGCONT: case SIGCHLD: case SIGWINCH:
489
                                continue;
490
 
491
                        case SIGTSTP: case SIGTTIN: case SIGTTOU:
492
                                if (is_orphaned_pgrp(current->pgrp))
493
                                        continue;
494
                        case SIGSTOP:
495
                                if (current->flags & PF_PTRACED)
496
                                        continue;
497
                                current->state = TASK_STOPPED;
498
                                current->exit_code = signr;
499
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
500
                                      SA_NOCLDSTOP))
501
                                        notify_parent(current, SIGCHLD);
502
                                schedule();
503
                                continue;
504
 
505
                        case SIGQUIT: case SIGILL: case SIGTRAP:
506
                        case SIGIOT: case SIGFPE: case SIGSEGV:
507
                                if (current->binfmt && current->binfmt->core_dump) {
508
                                    if (current->binfmt->core_dump(signr, regs))
509
                                        signr |= 0x80;
510
                                }
511
                                /* fall through */
512
                        default:
513
                                current->signal |= _S(signr & 0x7f);
514
                                current->flags |= PF_SIGNALED;
515
                                do_exit(signr);
516
                        }
517
                }
518
                handle_signal(signr, sa, oldmask, regs);
519
                return 1;
520
        }
521
 
522
        /* Did we come from a system call? */
523
        if (regs->orig_d0 >= 0) {
524
                /* Restart the system call - no handlers present */
525
                if (regs->d0 == -ERESTARTNOHAND ||
526
                    regs->d0 == -ERESTARTSYS ||
527
                    regs->d0 == -ERESTARTNOINTR) {
528
                        regs->d0 = regs->orig_d0;
529
                        regs->pc -= 2;
530
                }
531
        }
532
 
533
        /* If we are about to discard some frame stuff we must copy
534
           over the remaining frame. */
535
        if (regs->stkadj) {
536
                struct pt_regs *tregs =
537
                  (struct pt_regs *) ((ulong) regs + regs->stkadj);
538
#if defined(DEBUG) || 1
539
        printk("!!!!!!!!!!!!!! stkadj !!!\n");
540
#endif
541
                /* This must be copied with decreasing addresses to
542
                   handle overlaps.  */
543
#ifndef NO_FORMAT_VEC
544
                tregs->vector = regs->vector;
545
                tregs->format = regs->format;
546
#endif
547
                tregs->pc = regs->pc;
548
                tregs->sr = regs->sr;
549
        }
550
        return 0;
551
}

powered by: WebSVN 2.1.0

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