1 |
199 |
simons |
/*
|
2 |
|
|
* linux/arch/m68knommu/platform/5307/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, ¤t->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 |
|
|
}
|