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), ®s->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 |
|
|
}
|