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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [kernel/] [signal.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/arch/arm/kernel/signal.c
3
 *
4
 *  Copyright (C) 1995, 1996 Russell King
5
 */
6
 
7
#include <linux/sched.h>
8
#include <linux/mm.h>
9
#include <linux/kernel.h>
10
#include <linux/signal.h>
11
#include <linux/errno.h>
12
#include <linux/wait.h>
13
#include <linux/ptrace.h>
14
#include <linux/unistd.h>
15
 
16
#include <asm/segment.h>
17
#include <asm/pgtable.h>
18
 
19
#define _S(nr) (1<<((nr)-1))
20
 
21
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
22
 
23
#define SWI_SYS_SIGRETURN 0xef900077
24
 
25
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
26
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
27
extern int ptrace_cancel_bpt (struct task_struct *);
28
extern int ptrace_set_bpt (struct task_struct *);
29
 
30
/*
31
 * atomically swap in the new signal mask, and wait for a signal.
32
 */
33
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
34
{
35
    unsigned long mask;
36
    struct pt_regs * regs;
37
    __asm__("mov\t%0,r9\n\t": "=r" (regs));
38
 
39
    mask = current->blocked;
40
    current->blocked = set & _BLOCKABLE;
41
    regs->ARM_r0 = -EINTR;
42
 
43
    while (1) {
44
        current->state = TASK_INTERRUPTIBLE;
45
        schedule();
46
        if (do_signal(mask,regs))
47
            return regs->ARM_r0;
48
    }
49
}
50
 
51
/*
52
 * This sets regs->esp even though we don't actually use sigstacks yet..
53
 */
54
asmlinkage int sys_sigreturn(unsigned long __unused)
55
{
56
    struct pt_regs *regs;
57
    struct sigcontext_struct context;
58
    void *frame;
59
 
60
    __asm__ ("mov\t%0, r9\n\t": "=r" (regs));
61
 
62
    frame = (void *)regs->ARM_sp;
63
 
64
    if (verify_area(VERIFY_READ,frame,sizeof(context))) {
65
        printk("*** Bad stack frame\n");
66
        goto badframe;
67
    }
68
 
69
    memcpy_fromfs(&context,frame,sizeof(context));
70
 
71
    if (context.magic!=0x4B534154) {
72
        printk("Bad stack identifier\n");
73
        goto badframe;
74
    }
75
 
76
    *regs = context.reg;
77
 
78
    current->blocked = context.oldmask & _BLOCKABLE;
79
 
80
    if (!valid_user_regs(regs))
81
        goto badframe;
82
 
83
    /* send SIGTRAP if we're single-stepping */
84
    if (ptrace_cancel_bpt (current))
85
        send_sig (SIGTRAP, current, 1);
86
 
87
    return regs->ARM_r0;
88
badframe:
89
    do_exit(SIGSEGV);
90
    return 0;
91
}
92
 
93
/*
94
 * Set up a signal frame...
95
 */
96
static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
97
        struct pt_regs * regs, int signr, unsigned long oldmask)
98
{
99
    unsigned long * frame;
100
    struct sigcontext_struct context;
101
 
102
    frame = (unsigned long *)(((int)(*fp)) - sizeof(context) - 4);
103
 
104
    if (verify_area (VERIFY_WRITE, frame, sizeof(context)))
105
        do_exit (SIGSEGV);
106
 
107
    context.magic       = 0x4B534154; /* Signature */
108
    context.reg         = *regs;
109
    context.reg.ARM_sp  = (unsigned long)*fp;
110
    context.reg.ARM_pc  = eip;
111
 
112
    context.trap_no     = current->tss.trap_no;
113
    context.error_code  = current->tss.error_code;
114
    context.oldmask     = oldmask;
115
 
116
    memcpy_tofs (frame, &context, sizeof(context));
117
    put_user (SWI_SYS_SIGRETURN, frame + sizeof (context)/4);
118
    /*
119
     * Ensure that the SWI instruction is flushed out of D-cache
120
     */
121
    __flush_entry_to_ram(frame + sizeof (context)/4);
122
 
123
    *fp = frame;
124
    if (current->exec_domain && current->exec_domain->signal_invmap)
125
        regs->ARM_r0 = current->exec_domain->signal_invmap[signr];
126
    else
127
        regs->ARM_r0 = signr;
128
    regs->ARM_lr = ((unsigned long)frame) + sizeof (context);
129
    if (!valid_user_regs(&context.reg))
130
        goto badframe;
131
 
132
    return;
133
 
134
badframe:
135
    do_exit(SIGSEGV);
136
}
137
 
138
/*
139
 * Note that 'init' is a special process: it doesn't get signals it doesn't
140
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
141
 * mistake.
142
 *
143
 * Note that we go through the signals twice: once to check the signals that
144
 * the kernel can handle, and then we build all the user-level signal handling
145
 * stack-frames in one go after that.
146
 */
147
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
148
{
149
        unsigned long orig_signal;
150
        unsigned long mask = ~current->blocked;
151
        unsigned long handler_signal = 0;
152
        unsigned long *frame = NULL;
153
        unsigned long eip = 0;
154
        unsigned long signr;
155
        struct sigaction * sa;
156
        unsigned long *pcinstr = (unsigned long *)(instruction_pointer(regs)-4);
157
        int swiinstr = 0, single_stepping;
158
 
159
        single_stepping = ptrace_cancel_bpt (current);
160
 
161
        if (verify_area(VERIFY_READ, pcinstr, 4) == 0 &&
162
            (get_user(pcinstr) & 0x0f000000) == 0x0f000000)
163
                swiinstr = 1;
164
 
165
        while ((signr = current->signal & mask)) {
166
                orig_signal = current->signal;
167
                eip = signr;
168
                for (signr = 0; signr < 32; signr++)
169
 
170
                if (eip & (1 << signr)) {
171
                        current->signal &= ~(1 << signr);
172
                        break;
173
                }
174
                sa = current->sig->action + signr;
175
                signr++;
176
 
177
                if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
178
                        current->exit_code = signr;
179
                        current->state = TASK_STOPPED;
180
                        notify_parent(current, SIGCHLD);
181
                        schedule();
182
                        single_stepping |= ptrace_cancel_bpt (current);
183
 
184
                        if (!(signr = current->exit_code))
185
                                continue;
186
 
187
                        current->exit_code = 0;
188
 
189
                        if (signr == SIGSTOP)
190
                                continue;
191
 
192
                        if (_S(signr) & current->blocked) {
193
                                current->signal |= _S(signr);
194
                                continue;
195
                        }
196
                        sa = current->sig->action + signr - 1;
197
                }
198
                if (sa->sa_handler == SIG_IGN) {
199
                        if (signr != SIGCHLD)
200
                                continue;
201
                        /* check for SIGCHLD: it's special */
202
                        while (sys_waitpid(-1,NULL,WNOHANG) > 0)
203
                                /* nothing */;
204
                        continue;
205
                }
206
                if (sa->sa_handler == SIG_DFL) {
207
                        if (current->pid == 1)
208
                                continue;
209
 
210
                        switch (signr) {
211
                        case SIGCONT: case SIGCHLD: case SIGWINCH:
212
                                continue;
213
 
214
                        case SIGTSTP: case SIGTTIN: case SIGTTOU:
215
                                if (is_orphaned_pgrp (current->pgrp))
216
                                        continue;
217
 
218
                        case SIGSTOP:
219
                                if (current->flags & PF_PTRACED)
220
                                        continue;
221
 
222
                                current->state = TASK_STOPPED;
223
                                current->exit_code = signr;
224
                                if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
225
                                    SA_NOCLDSTOP))
226
                                        notify_parent(current, SIGCHLD);
227
                                schedule();
228
                                single_stepping |= ptrace_cancel_bpt (current);
229
                                continue;
230
 
231
                        case SIGBUS:  case SIGQUIT: case SIGILL:
232
                        case SIGTRAP: case SIGIOT:  case SIGFPE:
233
                        case SIGSEGV:
234
                                if (current->binfmt && current->binfmt->core_dump) {
235
                                        if (current->binfmt->core_dump(signr, regs))
236
                                                signr |= 0x80;
237
                                }
238
                                /* fall through */
239
                        default:
240
                                current->signal |= _S(signr & 0x7f);
241
                                do_exit(signr);
242
                        }
243
                }
244
                /*
245
                 * OK, we're invoking a handler
246
                 */
247
                if (swiinstr && (regs->ARM_r0 == -ERESTARTNOHAND ||
248
                            (regs->ARM_r0 == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART))))
249
                        regs->ARM_r0 = -EINTR;
250
                handler_signal |= 1 << (signr-1);
251
                mask &= ~sa->sa_mask;
252
        }
253
 
254
        if (swiinstr &&
255
            (regs->ARM_r0 == -ERESTARTNOHAND ||
256
             regs->ARM_r0 == -ERESTARTSYS ||
257
             regs->ARM_r0 == -ERESTARTNOINTR)) {
258
                regs->ARM_r0 = regs->ARM_ORIG_r0;
259
                regs->ARM_pc -= 4;
260
        }
261
 
262
        if (!handler_signal) {          /* no handler will be called - return 0 */
263
                if (single_stepping)
264
                        ptrace_set_bpt (current);
265
                return 0;
266
        }
267
 
268
        eip = regs->ARM_pc;
269
        frame = (unsigned long *) regs->ARM_sp;
270
        signr = 1;
271
        sa = current->sig->action;
272
        for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
273
                if (mask > handler_signal)
274
                        break;
275
                if (!(mask & handler_signal))
276
                        continue;
277
                setup_frame(sa,&frame,eip,regs,signr,oldmask);
278
                eip = (unsigned long) sa->sa_handler;
279
                if (sa->sa_flags & SA_ONESHOT)
280
                        sa->sa_handler = NULL;
281
/* force a supervisor-mode page-in of the signal handler to reduce races */
282
                        current->blocked |= sa->sa_mask;
283
                        oldmask |= sa->sa_mask;
284
        }
285
        regs->ARM_sp = (unsigned long) frame;
286
        regs->ARM_pc = eip;             /* "return" to the first handler */
287
        current->tss.trap_no = current->tss.error_code = 0;
288
        if (single_stepping)
289
                ptrace_set_bpt (current);
290
        return 1;
291
}

powered by: WebSVN 2.1.0

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