summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/signal.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /arch/ppc/kernel/signal.c
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'arch/ppc/kernel/signal.c')
-rw-r--r--arch/ppc/kernel/signal.c126
1 files changed, 85 insertions, 41 deletions
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 18a0a10d9..ba8864251 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -3,16 +3,20 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Adapted for PowerPC by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
*/
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
@@ -26,7 +30,9 @@ asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
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();
mask = current->blocked;
current->blocked = set & _BLOCKABLE;
regs->gpr[3] = -EINTR;
@@ -37,25 +43,32 @@ printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, reg
current->state = TASK_INTERRUPTIBLE;
schedule();
if (do_signal(mask,regs))
- return -EINTR;
+ goto out;
}
+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;
+ int signo, ret;
+
+ lock_kernel();
+#if 1
+ if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
+ || (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' */
- if (sc == (struct sigcontext_struct *)(int_regs))
- { /* Last stacked signal */
+ 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));
@@ -72,16 +85,24 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
regs->nip -= 4; /* Back up & retry system call */
regs->result = 0;
}
- return (regs->result);
- } else
- { /* More signals to go */
+ 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;
- return (sc->signal);
+ ret = sc->signal;
}
+ goto out;
+
+badframe:
+ /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
+ regs,current->comm,current->pid);*/
+ do_exit(SIGSEGV);
+out:
+ unlock_kernel();
+ return ret;
}
@@ -96,27 +117,24 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
*/
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
{
- unsigned long mask = ~current->blocked;
+ unsigned long mask;
unsigned long handler_signal = 0;
unsigned long *frame = NULL;
- unsigned long *trampoline;
- unsigned long *regs_ptr;
+ unsigned long *trampoline, *regs_ptr;
unsigned long nip = 0;
unsigned long signr;
- int bitno;
struct sigcontext_struct *sc;
struct sigaction * sa;
- int s = _disable_interrupts();
+ int bitno, s, ret;
+
+ 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;
- }
+ if (signr & (1<<bitno))
+ break;
signr = bitno;
-#endif
+
current->signal &= ~(1<<signr); /* Clear bit */
sa = current->sig->action + signr;
signr++;
@@ -157,7 +175,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
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;
@@ -174,27 +192,33 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
do_exit(signr);
}
}
- /*
- * OK, we're invoking a handler
- */
+
+ /* handle signal */
if ((int)regs->orig_gpr3 >= 0) {
if ((int)regs->result == -ERESTARTNOHAND ||
- ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+ ((int)regs->result == -ERESTARTSYS &&
+ !(sa->sa_flags & SA_RESTART)))
(int)regs->result = -EINTR;
}
handler_signal |= 1 << (signr-1);
mask &= ~sa->sa_mask;
}
+ ret = 0;
if (!handler_signal) /* no handler will be called - return 0 */
- {
- _enable_interrupts(s);
- return 0;
- }
+ goto out;
+
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
+
/* 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 ))
+ goto badframe;
+#endif
trampoline[0] = 0x38007777; /* li r0,0x7777 */
trampoline[1] = 0x44000002; /* sc */
frame -= sizeof(*regs) / sizeof(long);
@@ -202,12 +226,19 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
memcpy(regs_ptr, regs, sizeof(*regs));
signr = 1;
sa = current->sig->action;
+
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
if (mask > handler_signal)
break;
if (!(mask & handler_signal))
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 */
@@ -226,14 +257,27 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
regs->link = (unsigned long)trampoline;
regs->nip = nip;
regs->gpr[1] = (unsigned long)sc;
- /* 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 */
+
+ /* 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();
- _enable_interrupts(s);
- return 1;
+ ret = 1;
+ goto out;
+
+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
+ do_exit(SIGSEGV);
+
+out:
+ unlock_kernel();
+ return ret;
}