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

Subversion Repositories or1k

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

powered by: WebSVN 2.1.0

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