patch-2.1.48 linux/arch/ppc/kernel/signal.c
Next file: linux/arch/ppc/kernel/strcase.c
Previous file: linux/arch/ppc/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 362
- Date:
Thu Jul 31 13:09:17 1997
- Orig file:
v2.1.47/linux/arch/ppc/kernel/signal.c
- Orig date:
Sun Jan 26 02:07:05 1997
diff -u --recursive --new-file v2.1.47/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
@@ -1,9 +1,17 @@
/*
* linux/arch/ppc/kernel/signal.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Adapted for PowerPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/signal.c"
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
#include <linux/sched.h>
@@ -22,6 +30,12 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define DEBUG_SIGNALS
+#undef DEBUG_SIGNALS
+
+#define PAUSE_AFTER_SIGNAL
+#undef PAUSE_AFTER_SIGNAL
+
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
@@ -30,79 +44,85 @@
asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
{
unsigned long mask;
- int ret = -EINTR;
- lock_kernel();
+ spin_lock_irq(¤t->sigmask_lock);
mask = current->blocked;
current->blocked = set & _BLOCKABLE;
+ spin_unlock_irq(¤t->sigmask_lock);
+
regs->gpr[3] = -EINTR;
-#if 0
+#ifdef DEBUG_SIGNALS
printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);
#endif
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(mask,regs))
- goto out;
+ if (do_signal(mask,regs)) {
+ /*
+ * If a signal handler needs to be called,
+ * do_signal() has set R3 to the signal number (the
+ * first argument of the signal handler), so don't
+ * overwrite that with EINTR !
+ * In the other cases, do_signal() doesn't touch
+ * R3, so it's still set to -EINTR (see above).
+ */
+ return regs->gpr[3];
+ }
}
-out:
- unlock_kernel();
- return ret;
}
+/*
+ * This sets regs->esp even though we don't actually use sigstacks yet..
+ */
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
struct sigcontext_struct *sc;
struct pt_regs *int_regs;
int signo, ret;
- lock_kernel();
#if 1
if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
- || (regs->gpr[1] >=KERNELBASE))
+ || (regs->gpr[1] >= KERNELBASE))
goto badframe;
#endif
- sc = (struct sigcontext_struct *)regs->gpr[1];
- current->blocked = sc->oldmask & _BLOCKABLE;
- int_regs = sc->regs;
- signo = sc->signal;
- sc++; /* Pop signal 'context' */
+ sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
+ get_user(current->blocked, &sc->oldmask);
+ current->blocked &= _BLOCKABLE;
+ get_user(int_regs, &sc->regs);
+ get_user(signo, &sc->signal);
+ sc++; /* Pop signal 'context' */
+#ifdef DEBUG_SIGNALS
+printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+#endif
if (sc == (struct sigcontext_struct *)(int_regs)) {
/* Last stacked signal */
-#if 0
- /* This doesn't work - it blows away the return address! */
memcpy(regs, int_regs, sizeof(*regs));
-#else
- /* Don't mess up 'my' stack frame */
- memcpy(®s->gpr, &int_regs->gpr, sizeof(*regs)-sizeof(regs->_overhead));
-#endif
- if ((int)regs->orig_gpr3 >= 0 &&
+ if (regs->trap == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
- (int)regs->result == -ERESTARTNOINTR))
- {
+ (int)regs->result == -ERESTARTNOINTR)) {
regs->gpr[3] = regs->orig_gpr3;
regs->nip -= 4; /* Back up & retry system call */
regs->result = 0;
}
- ret = (regs->result);
- } else { /* More signals to go */
- regs->gpr[1] = (unsigned long)sc;
- regs->gpr[3] = sc->signal;
- regs->gpr[4] = sc->regs;
- regs->link = (unsigned long)((sc->regs)+1);
- regs->nip = sc->handler;
- ret = sc->signal;
+ ret = regs->result;
+ } else {
+ /* More signals to go */
+ regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+ get_user(regs->gpr[3], &sc->signal);
+ get_user(int_regs, (struct pt_regs **) &sc->regs);
+ regs->gpr[4] = (unsigned long) int_regs;
+ regs->link = (unsigned long) (int_regs+1);
+ get_user(regs->nip, &sc->handler);
+ ret = regs->gpr[3];
}
- goto out;
+ return ret;
badframe:
- /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
- regs,current->comm,current->pid);*/
+ lock_kernel();
do_exit(SIGSEGV);
-out:
unlock_kernel();
- return ret;
+ return -EFAULT;
}
@@ -120,21 +140,24 @@
unsigned long mask;
unsigned long handler_signal = 0;
unsigned long *frame = NULL;
- unsigned long *trampoline, *regs_ptr;
+ unsigned long *trampoline;
+ unsigned long *regs_ptr;
unsigned long nip = 0;
unsigned long signr;
struct sigcontext_struct *sc;
struct sigaction * sa;
- int bitno, s, ret;
+ int bitno;
- lock_kernel();
mask = ~current->blocked;
while ((signr = current->signal & mask)) {
+#if 0
+ signr = ffz(~signr); /* Compute bit # */
+#else
for (bitno = 0; bitno < 32; bitno++)
if (signr & (1<<bitno))
break;
signr = bitno;
-
+#endif
current->signal &= ~(1<<signr); /* Clear bit */
sa = current->sig->action + signr;
signr++;
@@ -150,6 +173,8 @@
continue;
if (_S(signr) & current->blocked) {
current->signal |= _S(signr);
+ spin_lock_irq(¤t->sigmask_lock);
+ spin_unlock_irq(¤t->sigmask_lock);
continue;
}
sa = current->sig->action + signr - 1;
@@ -169,32 +194,45 @@
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ SA_NOCLDSTOP))
notify_parent(current);
schedule();
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
+ spin_lock_irq(¤t->sigmask_lock);
current->signal |= _S(signr & 0x7f);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ current->flags |= PF_SIGNALED;
+
+ lock_kernel(); /* 8-( */
do_exit(signr);
+ unlock_kernel();
}
}
-
- /* handle signal */
- if ((int)regs->orig_gpr3 >= 0) {
+ /*
+ * OK, we're invoking a handler
+ */
+ if (regs->trap == 0x0C00 /* System Call! */) {
if ((int)regs->result == -ERESTARTNOHAND ||
((int)regs->result == -ERESTARTSYS &&
!(sa->sa_flags & SA_RESTART)))
@@ -203,9 +241,18 @@
handler_signal |= 1 << (signr-1);
mask &= ~sa->sa_mask;
}
- ret = 0;
- if (!handler_signal) /* no handler will be called - return 0 */
- goto out;
+
+ if (regs->trap == 0x0C00 /* System Call! */ &&
+ ((int)regs->result == -ERESTARTNOHAND ||
+ (int)regs->result == -ERESTARTSYS ||
+ (int)regs->result == -ERESTARTNOINTR)) {
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4; /* Back up & retry system call */
+ regs->result = 0;
+ }
+
+ if (!handler_signal) /* no handler will be called - return 0 */
+ return 0;
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
@@ -213,20 +260,18 @@
/* Build trampoline code on stack */
frame -= 2;
trampoline = frame;
-#if 1
/* verify stack is valid for writing regs struct */
if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
- || (frame >= KERNELBASE ))
+ || ((unsigned long) frame >= KERNELBASE ))
goto badframe;
-#endif
- trampoline[0] = 0x38007777; /* li r0,0x7777 */
- trampoline[1] = 0x44000002; /* sc */
+ put_user(0x38007777UL, trampoline); /* li r0,0x7777 */
+ put_user(0x44000002UL, trampoline+1); /* sc */
frame -= sizeof(*regs) / sizeof(long);
regs_ptr = frame;
- memcpy(regs_ptr, regs, sizeof(*regs));
+ copy_to_user(regs_ptr, regs, sizeof(*regs));
signr = 1;
sa = current->sig->action;
-
+
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
if (mask > handler_signal)
break;
@@ -234,50 +279,39 @@
continue;
frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-#if 1
if (verify_area(VERIFY_WRITE,(void *)frame,
sizeof(struct sigcontext_struct)/sizeof(long)))
goto badframe;
-#endif
sc = (struct sigcontext_struct *)frame;
nip = (unsigned long) sa->sa_handler;
-#if 0 /* Old compiler */
- nip = *(unsigned long *)nip;
-#endif
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- sc->handler = nip;
- sc->oldmask = current->blocked;
- sc->regs = (unsigned long)regs_ptr;
- sc->signal = signr;
+ put_user(nip, &sc->handler);
+ put_user(oldmask, &sc->oldmask); /* was current->blocked */
+ put_user(regs_ptr, &sc->regs);
+ put_user(signr, &sc->signal);
current->blocked |= sa->sa_mask;
regs->gpr[3] = signr;
regs->gpr[4] = (unsigned long)regs_ptr;
}
regs->link = (unsigned long)trampoline;
regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc;
+ regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
- /* The DATA cache must be flushed here to insure coherency
- * between the DATA & INSTRUCTION caches. Since we just
- * created an instruction stream using the DATA [cache] space
- * and since the instruction cache will not look in the DATA
- * cache for new data, we have to force the data to go on to
- * memory and flush the instruction cache to force it to look
- * there. The following function performs this magic
- */
- flush_instruction_cache();
- ret = 1;
- goto out;
+ /* The DATA cache must be flushed here to insure coherency */
+ /* between the DATA & INSTRUCTION caches. Since we just */
+ /* created an instruction stream using the DATA [cache] space */
+ /* and since the instruction cache will not look in the DATA */
+ /* cache for new data, we have to force the data to go on to */
+ /* memory and flush the instruction cache to force it to look */
+ /* there. The following function performs this magic */
+ store_cache_range((unsigned long) trampoline,
+ (unsigned long) (trampoline + 2));
+ return 1;
badframe:
-#if 0
- printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
- signr, frame, regs, current->comm, current->pid);
-#endif
+ lock_kernel();
do_exit(SIGSEGV);
-
-out:
unlock_kernel();
- return ret;
+ return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov