/*
|
/*
|
* linux/arch/m68k/kernel/signal.c
|
* linux/arch/m68k/kernel/signal.c
|
*
|
*
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
*
|
*
|
* This file is subject to the terms and conditions of the GNU General Public
|
* This file is subject to the terms and conditions of the GNU General Public
|
* License. See the file COPYING in the main directory of this archive
|
* License. See the file COPYING in the main directory of this archive
|
* for more details.
|
* for more details.
|
*/
|
*/
|
|
|
/*
|
/*
|
* 680x0 support by Hamish Macdonald
|
* 680x0 support by Hamish Macdonald
|
*/
|
*/
|
|
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/mm.h>
|
#include <linux/mm.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/signal.h>
|
#include <linux/signal.h>
|
#include <linux/errno.h>
|
#include <linux/errno.h>
|
#include <linux/wait.h>
|
#include <linux/wait.h>
|
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
|
|
#include <asm/segment.h>
|
#include <asm/segment.h>
|
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
#include <asm/traps.h>
|
#include <asm/traps.h>
|
#include <asm/bootinfo.h>
|
#include <asm/bootinfo.h>
|
|
|
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
|
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
|
|
|
#define _S(nr) (1<<((nr)-1))
|
#define _S(nr) (1<<((nr)-1))
|
|
|
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
|
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
|
|
|
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
|
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
|
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
|
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
|
|
|
static const int extra_sizes[16] = {
|
static const int extra_sizes[16] = {
|
0,
|
0,
|
-1, /* sizeof(((struct frame *)0)->un.fmt1), */
|
-1, /* sizeof(((struct frame *)0)->un.fmt1), */
|
sizeof(((struct frame *)0)->un.fmt2),
|
sizeof(((struct frame *)0)->un.fmt2),
|
sizeof(((struct frame *)0)->un.fmt3),
|
sizeof(((struct frame *)0)->un.fmt3),
|
sizeof(((struct frame *)0)->un.fmt4),
|
sizeof(((struct frame *)0)->un.fmt4),
|
-1, /* sizeof(((struct frame *)0)->un.fmt5), */
|
-1, /* sizeof(((struct frame *)0)->un.fmt5), */
|
-1, /* sizeof(((struct frame *)0)->un.fmt6), */
|
-1, /* sizeof(((struct frame *)0)->un.fmt6), */
|
sizeof(((struct frame *)0)->un.fmt7),
|
sizeof(((struct frame *)0)->un.fmt7),
|
-1, /* sizeof(((struct frame *)0)->un.fmt8), */
|
-1, /* sizeof(((struct frame *)0)->un.fmt8), */
|
sizeof(((struct frame *)0)->un.fmt9),
|
sizeof(((struct frame *)0)->un.fmt9),
|
sizeof(((struct frame *)0)->un.fmta),
|
sizeof(((struct frame *)0)->un.fmta),
|
sizeof(((struct frame *)0)->un.fmtb),
|
sizeof(((struct frame *)0)->un.fmtb),
|
-1, /* sizeof(((struct frame *)0)->un.fmtc), */
|
-1, /* sizeof(((struct frame *)0)->un.fmtc), */
|
-1, /* sizeof(((struct frame *)0)->un.fmtd), */
|
-1, /* sizeof(((struct frame *)0)->un.fmtd), */
|
-1, /* sizeof(((struct frame *)0)->un.fmte), */
|
-1, /* sizeof(((struct frame *)0)->un.fmte), */
|
-1, /* sizeof(((struct frame *)0)->un.fmtf), */
|
-1, /* sizeof(((struct frame *)0)->un.fmtf), */
|
};
|
};
|
|
|
/*
|
/*
|
* atomically swap in the new signal mask, and wait for a signal.
|
* atomically swap in the new signal mask, and wait for a signal.
|
*/
|
*/
|
asmlinkage int do_sigsuspend(struct pt_regs *regs)
|
asmlinkage int do_sigsuspend(struct pt_regs *regs)
|
{
|
{
|
unsigned long oldmask = current->blocked;
|
unsigned long oldmask = current->blocked;
|
unsigned long newmask = regs->d3;
|
unsigned long newmask = regs->d3;
|
|
|
current->blocked = newmask & _BLOCKABLE;
|
current->blocked = newmask & _BLOCKABLE;
|
regs->d0 = -EINTR;
|
regs->d0 = -EINTR;
|
while (1) {
|
while (1) {
|
current->state = TASK_INTERRUPTIBLE;
|
current->state = TASK_INTERRUPTIBLE;
|
schedule();
|
schedule();
|
if (do_signal(oldmask, regs))
|
if (do_signal(oldmask, regs))
|
return -EINTR;
|
return -EINTR;
|
}
|
}
|
}
|
}
|
|
|
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
|
static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
|
|
|
/*
|
/*
|
* This sets regs->usp even though we don't actually use sigstacks yet..
|
* This sets regs->usp even though we don't actually use sigstacks yet..
|
*/
|
*/
|
asmlinkage int do_sigreturn(unsigned long __unused)
|
asmlinkage int do_sigreturn(unsigned long __unused)
|
{
|
{
|
struct sigcontext_struct context;
|
struct sigcontext_struct context;
|
struct frame * regs;
|
struct frame * regs;
|
struct switch_stack *sw;
|
struct switch_stack *sw;
|
int fsize = 0;
|
int fsize = 0;
|
int formatvec = 0;
|
int formatvec = 0;
|
unsigned long fp;
|
unsigned long fp;
|
unsigned long usp = rdusp();
|
unsigned long usp = rdusp();
|
|
|
#if 0
|
#if 0
|
printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
|
printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
|
#endif
|
#endif
|
|
|
/* get stack frame pointer */
|
/* get stack frame pointer */
|
sw = (struct switch_stack *) &__unused;
|
sw = (struct switch_stack *) &__unused;
|
regs = (struct frame *) (sw + 1);
|
regs = (struct frame *) (sw + 1);
|
|
|
/* get previous context (including pointer to possible extra junk) */
|
/* get previous context (including pointer to possible extra junk) */
|
if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
|
if (verify_area(VERIFY_READ, (void *)usp, sizeof(context)))
|
goto badframe;
|
goto badframe;
|
|
|
memcpy_fromfs(&context,(void *)usp, sizeof(context));
|
memcpy_fromfs(&context,(void *)usp, sizeof(context));
|
|
|
fp = usp + sizeof (context);
|
fp = usp + sizeof (context);
|
|
|
/* restore signal mask */
|
/* restore signal mask */
|
current->blocked = context.sc_mask & _BLOCKABLE;
|
current->blocked = context.sc_mask & _BLOCKABLE;
|
|
|
/* restore passed registers */
|
/* restore passed registers */
|
regs->ptregs.d0 = context.sc_d0;
|
regs->ptregs.d0 = context.sc_d0;
|
regs->ptregs.d1 = context.sc_d1;
|
regs->ptregs.d1 = context.sc_d1;
|
regs->ptregs.a0 = context.sc_a0;
|
regs->ptregs.a0 = context.sc_a0;
|
regs->ptregs.a1 = context.sc_a1;
|
regs->ptregs.a1 = context.sc_a1;
|
regs->ptregs.sr = (regs->ptregs.sr & 0xff00)|(context.sc_sr & 0xff);
|
regs->ptregs.sr = (regs->ptregs.sr & 0xff00)|(context.sc_sr & 0xff);
|
regs->ptregs.pc = context.sc_pc;
|
regs->ptregs.pc = context.sc_pc;
|
|
|
wrusp(context.sc_usp);
|
wrusp(context.sc_usp);
|
formatvec = context.sc_formatvec;
|
formatvec = context.sc_formatvec;
|
regs->ptregs.format = formatvec >> 12;
|
regs->ptregs.format = formatvec >> 12;
|
regs->ptregs.vector = formatvec & 0xfff;
|
regs->ptregs.vector = formatvec & 0xfff;
|
if (context.sc_fpstate[0])
|
if (context.sc_fpstate[0])
|
{
|
{
|
/* Verify the frame format. */
|
/* Verify the frame format. */
|
if (context.sc_fpstate[0] != fpu_version){
|
if (context.sc_fpstate[0] != fpu_version){
|
#if DEBUG
|
#if DEBUG
|
printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
|
printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
|
context.sc_fpcntl);
|
context.sc_fpcntl);
|
printk("Wrong fpu: sc_fpstate[0]=%02x fpu_version=%02x\n",
|
printk("Wrong fpu: sc_fpstate[0]=%02x fpu_version=%02x\n",
|
(unsigned) context.sc_fpstate[0], (unsigned) fpu_version);
|
(unsigned) context.sc_fpstate[0], (unsigned) fpu_version);
|
{
|
{
|
int i;
|
int i;
|
printk("Saved fp_state: ");
|
printk("Saved fp_state: ");
|
for (i = 0; i < 216; i++){
|
for (i = 0; i < 216; i++){
|
printk("%02x ", context.sc_fpstate[i]);
|
printk("%02x ", context.sc_fpstate[i]);
|
}
|
}
|
printk("\n");
|
printk("\n");
|
}
|
}
|
#endif
|
#endif
|
goto badframe;
|
goto badframe;
|
}
|
}
|
if (boot_info.cputype & FPU_68881)
|
if (boot_info.cputype & FPU_68881)
|
{
|
{
|
if (context.sc_fpstate[1] != 0x18
|
if (context.sc_fpstate[1] != 0x18
|
&& context.sc_fpstate[1] != 0xb4)
|
&& context.sc_fpstate[1] != 0xb4)
|
goto badframe;
|
goto badframe;
|
}
|
}
|
else if (boot_info.cputype & FPU_68882)
|
else if (boot_info.cputype & FPU_68882)
|
{
|
{
|
if (context.sc_fpstate[1] != 0x38
|
if (context.sc_fpstate[1] != 0x38
|
&& context.sc_fpstate[1] != 0xd4){
|
&& context.sc_fpstate[1] != 0xd4){
|
#if 0
|
#if 0
|
printk("Wrong 68882 fpu-state\n");
|
printk("Wrong 68882 fpu-state\n");
|
#endif
|
#endif
|
goto badframe;
|
goto badframe;
|
}
|
}
|
}
|
}
|
else if (boot_info.cputype & FPU_68040)
|
else if (boot_info.cputype & FPU_68040)
|
{
|
{
|
if (!((context.sc_fpstate[1] == 0x00)|| \
|
if (!((context.sc_fpstate[1] == 0x00)|| \
|
(context.sc_fpstate[1] == 0x28)|| \
|
(context.sc_fpstate[1] == 0x28)|| \
|
(context.sc_fpstate[1] == 0x60))){
|
(context.sc_fpstate[1] == 0x60))){
|
#if 0
|
#if 0
|
printk("Wrong 68040 fpu-state\n");
|
printk("Wrong 68040 fpu-state\n");
|
#endif
|
#endif
|
goto badframe;
|
goto badframe;
|
}
|
}
|
}
|
}
|
else if (boot_info.cputype & FPU_68060)
|
else if (boot_info.cputype & FPU_68060)
|
{
|
{
|
if (!((context.sc_fpstate[1] == 0x00)|| \
|
if (!((context.sc_fpstate[1] == 0x00)|| \
|
(context.sc_fpstate[1] == 0x60)|| \
|
(context.sc_fpstate[1] == 0x60)|| \
|
(context.sc_fpstate[1] == 0xe0))){
|
(context.sc_fpstate[1] == 0xe0))){
|
#if 0
|
#if 0
|
printk("Wrong 68060 fpu-state\n");
|
printk("Wrong 68060 fpu-state\n");
|
#endif
|
#endif
|
goto badframe;
|
goto badframe;
|
}
|
}
|
}
|
}
|
__asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t"
|
__asm__ volatile ("fmovemx %0,%/fp0-%/fp1\n\t"
|
"fmoveml %1,%/fpcr/%/fpsr/%/fpiar"
|
"fmoveml %1,%/fpcr/%/fpsr/%/fpiar"
|
: /* no outputs */
|
: /* no outputs */
|
: "m" (*context.sc_fpregs),
|
: "m" (*context.sc_fpregs),
|
"m" (*context.sc_fpcntl));
|
"m" (*context.sc_fpcntl));
|
}
|
}
|
__asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate));
|
__asm__ volatile ("frestore %0" : : "m" (*context.sc_fpstate));
|
|
|
fsize = extra_sizes[regs->ptregs.format];
|
fsize = extra_sizes[regs->ptregs.format];
|
if (fsize < 0) {
|
if (fsize < 0) {
|
/*
|
/*
|
* user process trying to return with weird frame format
|
* user process trying to return with weird frame format
|
*/
|
*/
|
#if DEBUG
|
#if DEBUG
|
printk("user process returning with weird frame format\n");
|
printk("user process returning with weird frame format\n");
|
#endif
|
#endif
|
goto badframe;
|
goto badframe;
|
}
|
}
|
|
|
/* OK. Make room on the supervisor stack for the extra junk,
|
/* OK. Make room on the supervisor stack for the extra junk,
|
* if necessary.
|
* if necessary.
|
*/
|
*/
|
|
|
if (fsize) {
|
if (fsize) {
|
if (verify_area(VERIFY_READ, (void *)fp, fsize))
|
if (verify_area(VERIFY_READ, (void *)fp, fsize))
|
goto badframe;
|
goto badframe;
|
|
|
#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
|
#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("movel %0,%/a0\n\t"
|
("movel %0,%/a0\n\t"
|
"subl %1,%/a0\n\t" /* make room on stack */
|
"subl %1,%/a0\n\t" /* make room on stack */
|
"movel %/a0,%/sp\n\t" /* set stack pointer */
|
"movel %/a0,%/sp\n\t" /* set stack pointer */
|
/* move switch_stack and pt_regs */
|
/* move switch_stack and pt_regs */
|
"1: movel %0@+,%/a0@+\n\t"
|
"1: movel %0@+,%/a0@+\n\t"
|
" dbra %2,1b\n\t"
|
" dbra %2,1b\n\t"
|
"lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt stuff */
|
"lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt stuff */
|
"lsrl #2,%1\n\t"
|
"lsrl #2,%1\n\t"
|
"subql #1,%1\n\t"
|
"subql #1,%1\n\t"
|
"2: movesl %4@+,%2\n\t"
|
"2: movesl %4@+,%2\n\t"
|
" movel %2,%/a0@+\n\t"
|
" movel %2,%/a0@+\n\t"
|
" dbra %1,2b\n\t"
|
" dbra %1,2b\n\t"
|
"bral " SYMBOL_NAME_STR(ret_from_signal)
|
"bral " SYMBOL_NAME_STR(ret_from_signal)
|
: /* no outputs, it doesn't ever return */
|
: /* no outputs, it doesn't ever return */
|
: "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
|
: "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
|
"n" (frame_offset), "a" (fp)
|
"n" (frame_offset), "a" (fp)
|
: "a0");
|
: "a0");
|
#undef frame_offset
|
#undef frame_offset
|
goto badframe;
|
goto badframe;
|
/* NOTREACHED */
|
/* NOTREACHED */
|
}
|
}
|
|
|
return regs->ptregs.d0;
|
return regs->ptregs.d0;
|
badframe:
|
badframe:
|
do_exit(SIGSEGV);
|
do_exit(SIGSEGV);
|
}
|
}
|
|
|
/*
|
/*
|
* Set up a signal frame...
|
* Set up a signal frame...
|
*
|
*
|
* This routine is somewhat complicated by the fact that if the
|
* This routine is somewhat complicated by the fact that if the
|
* kernel may be entered by an exception other than a system call;
|
* kernel may be entered by an exception other than a system call;
|
* e.g. a bus error or other "bad" exception. If this is the case,
|
* e.g. a bus error or other "bad" exception. If this is the case,
|
* then *all* the context on the kernel stack frame must be saved.
|
* then *all* the context on the kernel stack frame must be saved.
|
*
|
*
|
* For a large number of exceptions, the stack frame format is the same
|
* For a large number of exceptions, the stack frame format is the same
|
* as that which will be created when the process traps back to the kernel
|
* as that which will be created when the process traps back to the kernel
|
* when finished executing the signal handler. In this case, nothing
|
* when finished executing the signal handler. In this case, nothing
|
* must be done. This is exception frame format "0". For exception frame
|
* must be done. This is exception frame format "0". For exception frame
|
* formats "2", "9", "A" and "B", the extra information on the frame must
|
* formats "2", "9", "A" and "B", the extra information on the frame must
|
* be saved. This information is saved on the user stack and restored
|
* be saved. This information is saved on the user stack and restored
|
* when the signal handler is returned.
|
* when the signal handler is returned.
|
*
|
*
|
* The format of the user stack when executing the signal handler is:
|
* The format of the user stack when executing the signal handler is:
|
*
|
*
|
* usp -> RETADDR (points to code below)
|
* usp -> RETADDR (points to code below)
|
* signum (parm #1)
|
* signum (parm #1)
|
* sigcode (parm #2 ; vector number)
|
* sigcode (parm #2 ; vector number)
|
* scp (parm #3 ; sigcontext pointer, pointer to #1 below)
|
* scp (parm #3 ; sigcontext pointer, pointer to #1 below)
|
* code1 (addaw #20,sp) ; pop parms and code off stack
|
* code1 (addaw #20,sp) ; pop parms and code off stack
|
* code2 (moveq #119,d0; trap #0) ; sigreturn syscall
|
* code2 (moveq #119,d0; trap #0) ; sigreturn syscall
|
* #1| oldmask
|
* #1| oldmask
|
* | old usp
|
* | old usp
|
* | d0 (first saved reg)
|
* | d0 (first saved reg)
|
* | d1
|
* | d1
|
* | a0
|
* | a0
|
* | a1
|
* | a1
|
* | sr (saved status register)
|
* | sr (saved status register)
|
* | pc (old pc; one to return to)
|
* | pc (old pc; one to return to)
|
* | forvec (format and vector word of old supervisor stack frame)
|
* | forvec (format and vector word of old supervisor stack frame)
|
* | floating point context
|
* | floating point context
|
*
|
*
|
* These are optionally followed by some extra stuff, depending on the
|
* These are optionally followed by some extra stuff, depending on the
|
* stack frame interrupted. This is 1 longword for format "2", 3
|
* stack frame interrupted. This is 1 longword for format "2", 3
|
* longwords for format "9", 6 longwords for format "A", and 21
|
* longwords for format "9", 6 longwords for format "A", and 21
|
* longwords for format "B".
|
* longwords for format "B".
|
*/
|
*/
|
|
|
#define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4)
|
#define UFRAME_SIZE(fs) (sizeof(struct sigcontext_struct)/4 + 6 + fs/4)
|
|
|
static void setup_frame (struct sigaction * sa, unsigned long **fp,
|
static void setup_frame (struct sigaction * sa, unsigned long **fp,
|
unsigned long pc, struct frame *regs, int
|
unsigned long pc, struct frame *regs, int
|
signr, unsigned long oldmask)
|
signr, unsigned long oldmask)
|
{
|
{
|
struct sigcontext_struct context;
|
struct sigcontext_struct context;
|
unsigned long *frame, *tframe;
|
unsigned long *frame, *tframe;
|
int fsize = extra_sizes[regs->ptregs.format];
|
int fsize = extra_sizes[regs->ptregs.format];
|
|
|
if (fsize < 0) {
|
if (fsize < 0) {
|
printk ("setup_frame: Unknown frame format %#x\n",
|
printk ("setup_frame: Unknown frame format %#x\n",
|
regs->ptregs.format);
|
regs->ptregs.format);
|
do_exit(SIGSEGV);
|
do_exit(SIGSEGV);
|
}
|
}
|
frame = *fp - UFRAME_SIZE(fsize);
|
frame = *fp - UFRAME_SIZE(fsize);
|
if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
|
if (verify_area(VERIFY_WRITE,frame,UFRAME_SIZE(fsize)*4))
|
do_exit(SIGSEGV);
|
do_exit(SIGSEGV);
|
if (fsize) {
|
if (fsize) {
|
memcpy_tofs (frame + UFRAME_SIZE(0), ®s->un, fsize);
|
memcpy_tofs (frame + UFRAME_SIZE(0), ®s->un, fsize);
|
regs->ptregs.stkadj = fsize;
|
regs->ptregs.stkadj = fsize;
|
}
|
}
|
|
|
/* set up the "normal" stack seen by the signal handler */
|
/* set up the "normal" stack seen by the signal handler */
|
tframe = frame;
|
tframe = frame;
|
|
|
/* return address points to code on stack */
|
/* return address points to code on stack */
|
put_user((ulong)(frame+4), tframe); tframe++;
|
put_user((ulong)(frame+4), tframe); tframe++;
|
if (current->exec_domain && current->exec_domain->signal_invmap)
|
if (current->exec_domain && current->exec_domain->signal_invmap)
|
put_user(current->exec_domain->signal_invmap[signr], tframe);
|
put_user(current->exec_domain->signal_invmap[signr], tframe);
|
else
|
else
|
put_user(signr, tframe);
|
put_user(signr, tframe);
|
tframe++;
|
tframe++;
|
|
|
put_user(regs->ptregs.vector, tframe); tframe++;
|
put_user(regs->ptregs.vector, tframe); tframe++;
|
/* "scp" parameter. points to sigcontext */
|
/* "scp" parameter. points to sigcontext */
|
put_user((ulong)(frame+6), tframe); tframe++;
|
put_user((ulong)(frame+6), tframe); tframe++;
|
|
|
/* set up the return code... */
|
/* set up the return code... */
|
put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
|
put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
|
put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
|
put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
|
|
|
/* Flush caches so the instructions will be correctly executed. (MA) */
|
/* Flush caches so the instructions will be correctly executed. (MA) */
|
cache_push_v ((unsigned long)frame, (int)tframe - (int)frame);
|
cache_push_v ((unsigned long)frame, (int)tframe - (int)frame);
|
|
|
/* setup and copy the sigcontext structure */
|
/* setup and copy the sigcontext structure */
|
context.sc_mask = oldmask;
|
context.sc_mask = oldmask;
|
context.sc_usp = (unsigned long)*fp;
|
context.sc_usp = (unsigned long)*fp;
|
context.sc_d0 = regs->ptregs.d0;
|
context.sc_d0 = regs->ptregs.d0;
|
context.sc_d1 = regs->ptregs.d1;
|
context.sc_d1 = regs->ptregs.d1;
|
context.sc_a0 = regs->ptregs.a0;
|
context.sc_a0 = regs->ptregs.a0;
|
context.sc_a1 = regs->ptregs.a1;
|
context.sc_a1 = regs->ptregs.a1;
|
context.sc_sr = regs->ptregs.sr;
|
context.sc_sr = regs->ptregs.sr;
|
context.sc_pc = pc;
|
context.sc_pc = pc;
|
context.sc_formatvec = (regs->ptregs.format << 12 |
|
context.sc_formatvec = (regs->ptregs.format << 12 |
|
regs->ptregs.vector);
|
regs->ptregs.vector);
|
#if DEBUG
|
#if DEBUG
|
printk("formatvec: %02x\n", (unsigned) context.sc_formatvec);
|
printk("formatvec: %02x\n", (unsigned) context.sc_formatvec);
|
#endif
|
#endif
|
__asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
|
__asm__ volatile ("fsave %0" : : "m" (*context.sc_fpstate) : "memory");
|
if (context.sc_fpstate[0])
|
if (context.sc_fpstate[0])
|
{
|
{
|
fpu_version = context.sc_fpstate[0];
|
fpu_version = context.sc_fpstate[0];
|
#if DEBUG
|
#if DEBUG
|
{
|
{
|
int i;
|
int i;
|
printk("Saved fp_state: ");
|
printk("Saved fp_state: ");
|
for (i = 0; i < 216; i++){
|
for (i = 0; i < 216; i++){
|
printk("%02x ", context.sc_fpstate[i]);
|
printk("%02x ", context.sc_fpstate[i]);
|
}
|
}
|
printk("\n");
|
printk("\n");
|
}
|
}
|
printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
|
printk("fpregs=%08x fpcntl=%08x\n", context.sc_fpregs,
|
context.sc_fpcntl);
|
context.sc_fpcntl);
|
#endif
|
#endif
|
__asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
|
__asm__ volatile ("fmovemx %/fp0-%/fp1,%0\n\t"
|
"fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
|
"fmoveml %/fpcr/%/fpsr/%/fpiar,%1"
|
: /* no outputs */
|
: /* no outputs */
|
: "m" (*context.sc_fpregs),
|
: "m" (*context.sc_fpregs),
|
"m" (*context.sc_fpcntl)
|
"m" (*context.sc_fpcntl)
|
: "memory");
|
: "memory");
|
}
|
}
|
#if DEBUG
|
#if DEBUG
|
{
|
{
|
int i;
|
int i;
|
printk("Saved fp_state: ");
|
printk("Saved fp_state: ");
|
for (i = 0; i < 216; i++){
|
for (i = 0; i < 216; i++){
|
printk("%02x ", context.sc_fpstate[i]);
|
printk("%02x ", context.sc_fpstate[i]);
|
}
|
}
|
printk("\n");
|
printk("\n");
|
}
|
}
|
#endif
|
#endif
|
memcpy_tofs (tframe, &context, sizeof(context));
|
memcpy_tofs (tframe, &context, sizeof(context));
|
/*
|
/*
|
* no matter what frame format we were using before, we
|
* no matter what frame format we were using before, we
|
* will do the "RTE" using a normal 4 word frame.
|
* will do the "RTE" using a normal 4 word frame.
|
*/
|
*/
|
regs->ptregs.format = 0;
|
regs->ptregs.format = 0;
|
|
|
/* "return" new usp to caller */
|
/* "return" new usp to caller */
|
*fp = frame;
|
*fp = frame;
|
}
|
}
|
|
|
/*
|
/*
|
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
* Note that 'init' is a special process: it doesn't get signals it doesn't
|
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
* want to handle. Thus you cannot kill init even with a SIGKILL even by
|
* mistake.
|
* mistake.
|
*
|
*
|
* Note that we go through the signals twice: once to check the signals
|
* Note that we go through the signals twice: once to check the signals
|
* that the kernel can handle, and then we build all the user-level signal
|
* that the kernel can handle, and then we build all the user-level signal
|
* handling stack-frames in one go after that.
|
* handling stack-frames in one go after that.
|
*/
|
*/
|
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
|
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs_in)
|
{
|
{
|
unsigned long mask = ~current->blocked;
|
unsigned long mask = ~current->blocked;
|
unsigned long handler_signal = 0;
|
unsigned long handler_signal = 0;
|
unsigned long *frame = NULL;
|
unsigned long *frame = NULL;
|
unsigned long pc = 0;
|
unsigned long pc = 0;
|
unsigned long signr;
|
unsigned long signr;
|
struct frame *regs = (struct frame *)regs_in;
|
struct frame *regs = (struct frame *)regs_in;
|
struct sigaction * sa;
|
struct sigaction * sa;
|
|
|
current->tss.esp0 = (unsigned long) regs;
|
current->tss.esp0 = (unsigned long) regs;
|
|
|
while ((signr = current->signal & mask)) {
|
while ((signr = current->signal & mask)) {
|
__asm__("bfffo %2,#0,#0,%1\n\t"
|
__asm__("bfffo %2,#0,#0,%1\n\t"
|
"bfclr %0,%1,#1\n\t"
|
"bfclr %0,%1,#1\n\t"
|
"eorw #31,%1"
|
"eorw #31,%1"
|
:"=m" (current->signal),"=r" (signr)
|
:"=m" (current->signal),"=r" (signr)
|
:"1" (signr));
|
:"1" (signr));
|
sa = current->sig->action + signr;
|
sa = current->sig->action + signr;
|
signr++;
|
signr++;
|
|
|
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
|
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
|
current->exit_code = signr;
|
current->exit_code = signr;
|
current->state = TASK_STOPPED;
|
current->state = TASK_STOPPED;
|
notify_parent(current);
|
notify_parent(current);
|
schedule();
|
schedule();
|
if (!(signr = current->exit_code)) {
|
if (!(signr = current->exit_code)) {
|
discard_frame:
|
discard_frame:
|
/* Make sure that a faulted bus cycle
|
/* Make sure that a faulted bus cycle
|
isn't restarted. */
|
isn't restarted. */
|
switch (regs->ptregs.format) {
|
switch (regs->ptregs.format) {
|
case 7:
|
case 7:
|
case 9:
|
case 9:
|
case 10:
|
case 10:
|
case 11:
|
case 11:
|
regs->ptregs.stkadj = extra_sizes[regs->ptregs.format];
|
regs->ptregs.stkadj = extra_sizes[regs->ptregs.format];
|
regs->ptregs.format = 0;
|
regs->ptregs.format = 0;
|
break;
|
break;
|
}
|
}
|
continue;
|
continue;
|
}
|
}
|
current->exit_code = 0;
|
current->exit_code = 0;
|
if (signr == SIGSTOP)
|
if (signr == SIGSTOP)
|
goto discard_frame;
|
goto discard_frame;
|
if (_S(signr) & current->blocked) {
|
if (_S(signr) & current->blocked) {
|
current->signal |= _S(signr);
|
current->signal |= _S(signr);
|
continue;
|
continue;
|
}
|
}
|
sa = current->sig->action + signr - 1;
|
sa = current->sig->action + signr - 1;
|
}
|
}
|
if (sa->sa_handler == SIG_IGN) {
|
if (sa->sa_handler == SIG_IGN) {
|
if (signr != SIGCHLD)
|
if (signr != SIGCHLD)
|
continue;
|
continue;
|
/* check for SIGCHLD: it's special */
|
/* check for SIGCHLD: it's special */
|
while (sys_waitpid(-1,NULL,WNOHANG) > 0)
|
while (sys_waitpid(-1,NULL,WNOHANG) > 0)
|
/* nothing */;
|
/* nothing */;
|
continue;
|
continue;
|
}
|
}
|
if (sa->sa_handler == SIG_DFL) {
|
if (sa->sa_handler == SIG_DFL) {
|
if (current->pid == 1)
|
if (current->pid == 1)
|
continue;
|
continue;
|
switch (signr) {
|
switch (signr) {
|
case SIGCONT: case SIGCHLD: case SIGWINCH:
|
case SIGCONT: case SIGCHLD: case SIGWINCH:
|
continue;
|
continue;
|
|
|
case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
|
case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
|
if (current->flags & PF_PTRACED)
|
if (current->flags & PF_PTRACED)
|
continue;
|
continue;
|
current->state = TASK_STOPPED;
|
current->state = TASK_STOPPED;
|
current->exit_code = signr;
|
current->exit_code = signr;
|
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
|
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
|
SA_NOCLDSTOP))
|
SA_NOCLDSTOP))
|
notify_parent(current);
|
notify_parent(current);
|
schedule();
|
schedule();
|
continue;
|
continue;
|
|
|
case SIGQUIT: case SIGILL: case SIGTRAP:
|
case SIGQUIT: case SIGILL: case SIGTRAP:
|
case SIGIOT: case SIGFPE: case SIGSEGV:
|
case SIGIOT: case SIGFPE: case SIGSEGV:
|
if (current->binfmt && current->binfmt->core_dump) {
|
if (current->binfmt && current->binfmt->core_dump) {
|
if (current->binfmt->core_dump(signr, (struct pt_regs *)regs))
|
if (current->binfmt->core_dump(signr, (struct pt_regs *)regs))
|
signr |= 0x80;
|
signr |= 0x80;
|
}
|
}
|
/* fall through */
|
/* fall through */
|
default:
|
default:
|
current->signal |= _S(signr & 0x7f);
|
current->signal |= _S(signr & 0x7f);
|
do_exit(signr);
|
do_exit(signr);
|
}
|
}
|
}
|
}
|
/*
|
/*
|
* OK, we're invoking a handler
|
* OK, we're invoking a handler
|
*/
|
*/
|
if (regs->ptregs.orig_d0 >= 0) {
|
if (regs->ptregs.orig_d0 >= 0) {
|
if (regs->ptregs.d0 == -ERESTARTNOHAND ||
|
if (regs->ptregs.d0 == -ERESTARTNOHAND ||
|
(regs->ptregs.d0 == -ERESTARTSYS &&
|
(regs->ptregs.d0 == -ERESTARTSYS &&
|
!(sa->sa_flags & SA_RESTART)))
|
!(sa->sa_flags & SA_RESTART)))
|
regs->ptregs.d0 = -EINTR;
|
regs->ptregs.d0 = -EINTR;
|
}
|
}
|
handler_signal |= 1 << (signr-1);
|
handler_signal |= 1 << (signr-1);
|
mask &= ~sa->sa_mask;
|
mask &= ~sa->sa_mask;
|
}
|
}
|
if (regs->ptregs.orig_d0 >= 0 &&
|
if (regs->ptregs.orig_d0 >= 0 &&
|
(regs->ptregs.d0 == -ERESTARTNOHAND ||
|
(regs->ptregs.d0 == -ERESTARTNOHAND ||
|
regs->ptregs.d0 == -ERESTARTSYS ||
|
regs->ptregs.d0 == -ERESTARTSYS ||
|
regs->ptregs.d0 == -ERESTARTNOINTR)) {
|
regs->ptregs.d0 == -ERESTARTNOINTR)) {
|
regs->ptregs.d0 = regs->ptregs.orig_d0;
|
regs->ptregs.d0 = regs->ptregs.orig_d0;
|
regs->ptregs.pc -= 2;
|
regs->ptregs.pc -= 2;
|
}
|
}
|
if (!handler_signal) /* no handler will be called - return 0 */
|
if (!handler_signal) /* no handler will be called - return 0 */
|
{
|
{
|
/* If we are about to discard some frame stuff we must
|
/* If we are about to discard some frame stuff we must
|
copy over the remaining frame. */
|
copy over the remaining frame. */
|
if (regs->ptregs.stkadj)
|
if (regs->ptregs.stkadj)
|
{
|
{
|
struct frame *tregs =
|
struct frame *tregs =
|
(struct frame *) ((ulong) regs + regs->ptregs.stkadj);
|
(struct frame *) ((ulong) regs + regs->ptregs.stkadj);
|
|
|
/* This must be copied with decreasing addresses to
|
/* This must be copied with decreasing addresses to
|
handle overlaps. */
|
handle overlaps. */
|
tregs->ptregs.vector = regs->ptregs.vector;
|
tregs->ptregs.vector = regs->ptregs.vector;
|
tregs->ptregs.format = regs->ptregs.format;
|
tregs->ptregs.format = regs->ptregs.format;
|
tregs->ptregs.pc = regs->ptregs.pc;
|
tregs->ptregs.pc = regs->ptregs.pc;
|
tregs->ptregs.sr = regs->ptregs.sr;
|
tregs->ptregs.sr = regs->ptregs.sr;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
pc = regs->ptregs.pc;
|
pc = regs->ptregs.pc;
|
frame = (unsigned long *)rdusp();
|
frame = (unsigned long *)rdusp();
|
signr = 1;
|
signr = 1;
|
sa = current->sig->action;
|
sa = current->sig->action;
|
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
|
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
|
if (mask > handler_signal)
|
if (mask > handler_signal)
|
break;
|
break;
|
if (!(mask & handler_signal))
|
if (!(mask & handler_signal))
|
continue;
|
continue;
|
setup_frame(sa,&frame,pc,regs,signr,oldmask);
|
setup_frame(sa,&frame,pc,regs,signr,oldmask);
|
pc = (unsigned long) sa->sa_handler;
|
pc = (unsigned long) sa->sa_handler;
|
if (sa->sa_flags & SA_ONESHOT)
|
if (sa->sa_flags & SA_ONESHOT)
|
sa->sa_handler = NULL;
|
sa->sa_handler = NULL;
|
/* force a supervisor-mode page-in of the signal handler to reduce races */
|
/* force a supervisor-mode page-in of the signal handler to reduce races */
|
__asm__ __volatile__("movesb %0,%/d0": :"m" (*(char *)pc):"d0");
|
__asm__ __volatile__("movesb %0,%/d0": :"m" (*(char *)pc):"d0");
|
current->blocked |= sa->sa_mask;
|
current->blocked |= sa->sa_mask;
|
oldmask |= sa->sa_mask;
|
oldmask |= sa->sa_mask;
|
}
|
}
|
wrusp((unsigned long)frame);
|
wrusp((unsigned long)frame);
|
regs->ptregs.pc = pc;
|
regs->ptregs.pc = pc;
|
|
|
/*
|
/*
|
* if setup_frame saved some extra frame junk, we need to
|
* if setup_frame saved some extra frame junk, we need to
|
* skip over that stuff when doing the RTE. This means we have
|
* skip over that stuff when doing the RTE. This means we have
|
* to move the machine portion of the stack frame to where the
|
* to move the machine portion of the stack frame to where the
|
* "RTE" instruction expects it. The signal that we need to
|
* "RTE" instruction expects it. The signal that we need to
|
* do this is that regs->stkadj is nonzero.
|
* do this is that regs->stkadj is nonzero.
|
*/
|
*/
|
if (regs->ptregs.stkadj) {
|
if (regs->ptregs.stkadj) {
|
struct frame *tregs =
|
struct frame *tregs =
|
(struct frame *)((ulong)regs + regs->ptregs.stkadj);
|
(struct frame *)((ulong)regs + regs->ptregs.stkadj);
|
#if DEBUG
|
#if DEBUG
|
printk("Performing stackadjust=%04x\n", (unsigned)
|
printk("Performing stackadjust=%04x\n", (unsigned)
|
regs->ptregs.stkadj);
|
regs->ptregs.stkadj);
|
#endif
|
#endif
|
/* This must be copied with decreasing addresses to
|
/* This must be copied with decreasing addresses to
|
handle overlaps. */
|
handle overlaps. */
|
tregs->ptregs.vector = regs->ptregs.vector;
|
tregs->ptregs.vector = regs->ptregs.vector;
|
tregs->ptregs.format = regs->ptregs.format;
|
tregs->ptregs.format = regs->ptregs.format;
|
tregs->ptregs.pc = regs->ptregs.pc;
|
tregs->ptregs.pc = regs->ptregs.pc;
|
tregs->ptregs.sr = regs->ptregs.sr;
|
tregs->ptregs.sr = regs->ptregs.sr;
|
}
|
}
|
|
|
return 1;
|
return 1;
|
}
|
}
|
|
|