|
From: Andy P. <at...@us...> - 2001-08-27 23:39:31
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel
In directory usw-pr-cvs1:/tmp/cvs-serv3881
Modified Files:
signal.c
Log Message:
Add trampoline code to make user signal handlers work.
Index: signal.c
===================================================================
RCS file: /cvsroot/linux-vax/kernel-2.4/arch/vax/kernel/signal.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- signal.c 2001/08/17 20:20:41 1.4
+++ signal.c 2001/08/27 23:39:28 1.5
@@ -40,7 +40,7 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
+int do_signal(sigset_t *oldset, struct pt_regs *regs);
int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
{
@@ -96,7 +96,7 @@
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(0, &saveset, regs))
+ if (do_signal(&saveset, regs))
return -EINTR;
}
}
@@ -128,7 +128,7 @@
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(0, &saveset, regs))
+ if (do_signal(&saveset, regs))
return -EINTR;
}
}
@@ -178,12 +178,13 @@
*/
struct sigframe {
- char *pretcode;
+ int sig;
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
- unsigned char retcode[8]; /* trampoline code */
+ unsigned char retcode[20]; /* trampoline code */
};
+/* FIXME: this dont work ... */
struct rt_sigframe {
char *pretcode;
struct siginfo *pinfo;
@@ -241,7 +242,7 @@
if (((long)frame) & 3)
goto badframe;
- if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask)
|| (_NSIG_WORDS > 1
@@ -267,6 +268,8 @@
return 0;
}
+
+/* FIXME: _rt_ stuff is completely unchecked + probably does not work */
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe *frame = (struct rt_sigframe *)(regs->sp);
@@ -342,7 +345,7 @@
}
/* make sure the frame is dword-aligned */
-
+
sp &= ~3;
return (void *)(sp - frame_size);
@@ -360,14 +363,20 @@
sigset_t *set, struct pt_regs * regs)
{
struct sigframe *frame;
- unsigned long return_ip;
int err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
-
+
+
+#ifdef DEBUG_SIG
+ printk("setup_frame: pid %d, sig %d, regs %p, frame %p, sigaction %p\n",current->pid,sig,regs,frame,ka);
+ show_regs(regs);
+#endif
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;
+ /* write the signal onto the stack */
+ err |= __put_user(sig, (unsigned int *)&frame->sig);
err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
if (err)
goto give_sigsegv;
@@ -381,27 +390,127 @@
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
+
+ /* We do this differently to other ports. Each function has a two byte RSM.
+ * (due to the calling convention). Each sighandler will expect to be
+ * CALLS'd and will RET from that. So we cant just muck about with PC's on the
+ * stack like the i386. So we use the trampoline code on the stack a bit more.
+ * The easiest way to skip around all this is to calls the signal
+ * handler, and then either calls the restorer, or chmk to sys_sigreturn */
+
+ /* CALLS $1, */
+ err |= __put_user(0xfb, (char *)(frame->retcode+0));
+ err |= __put_user(0x01, (char *)(frame->retcode+1));
+ /* (absolute address)*/
+ err |= __put_user(0x9f, (char *)(frame->retcode+2));
+ /* sighandler */
+ err |= __put_user(((unsigned long) ka->sa.sa_handler), (unsigned long *)(frame->retcode + 3));
+
if (ka->sa.sa_flags & SA_RESTORER) {
- return_ip = (unsigned long)ka->sa.sa_restorer;
+ /* CALLS $0,*/
+ err |= __put_user(0xfb, (char *)(frame->retcode+7));
+ err |= __put_user(0x00, (char *)(frame->retcode+8));
+ /* (absolute address)*/
+ err |= __put_user(0x9f, (char *)(frame->retcode+9));
+ /* restorer */
+ err |= __put_user(((unsigned long) ka->sa.sa_restorer), (unsigned long *)(frame->retcode + 10));
+ /* plus a halt */
+ err |= __put_user(0x00, (char *)(frame->retcode+14));
} else {
- /* trampoline - the desired return ip is the retcode itself */
- return_ip = (unsigned long)&frame->retcode;
- /* This is chmk __NR_sigreturn; */
- /* TODO: check byteorder */
- err |= __put_user(0xbc8f, (short *)(frame->retcode+0));
- err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
+ /* perform a syscall to sys_sigreturn. First set up the
+ * argument list to avoid confusing it */
+
+ /* pushl $0x0 */
+ err |= __put_user(0xdd, (char *)(frame->retcode+7));
+ err |= __put_user(0x00, (char *)(frame->retcode+8));
+ /* movl sp, ap */
+ err |= __put_user(0xd0, (char *)(frame->retcode+9));
+ err |= __put_user(0x5e, (char *)(frame->retcode+10));
+ err |= __put_user(0x5c, (char *)(frame->retcode+11));
+ /* chmk __NR_sigreturn; */
+ err |= __put_user(0xbc, (char *)(frame->retcode+12));
+ err |= __put_user(0x8f, (char *)(frame->retcode+13));
+ err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+14));
+ /* plus a halt */
+ err |= __put_user(0x00, (char *)(frame->retcode+16));
}
- err |= __put_user(return_ip, &frame->pretcode);
-
if (err)
goto give_sigsegv;
+#ifdef DEBUG_SIG
+ printk("setup_frame: pid %d, frame->retcode %p, sa_handler %p\n",current->pid,frame->retcode,ka->sa.sa_handler);
+#endif
/* Set up registers for signal handler */
-
- regs->pc = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */
- regs->sp = frame;
-
+
+ regs->pc = (unsigned long) frame->retcode; /* what we enter NOW */
+ regs->fp = regs->sp;
+ regs->sp = frame;
+ __mtpr(frame,PR_USP); /* and into to the register, ready for REI */
+
+#ifdef DEBUG_SIG
+ printk("setup_frame: pid %d, regs->pc %8lx, regs->sp %8lx, regs->ap %8lx\n",current->pid,regs->pc,regs->sp,regs->ap);
+ {
+ unsigned char c[4];
+ __get_user(c[0], (char *)&frame->sig);
+ __get_user(c[1], (char *)&frame->sig+1);
+ __get_user(c[2], (char *)&frame->sig+2);
+ __get_user(c[3], (char *)&frame->sig+3);
+ printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n",
+ &frame->sig, c[0],
+ &frame->sig+1, c[1],
+ &frame->sig+2, c[2],
+ &frame->sig+3, c[3]);
+ }
+ {
+ unsigned char c[4];
+ __get_user(c[0], (char *)frame->retcode);
+ __get_user(c[1], (char *)frame->retcode+1);
+ __get_user(c[2], (char *)frame->retcode+2);
+ __get_user(c[3], (char *)frame->retcode+3);
+ printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n",
+ frame->retcode, c[0],
+ frame->retcode+1, c[1],
+ frame->retcode+2, c[2],
+ frame->retcode+3, c[3]);
+ }
+ {
+ unsigned char c[4];
+ __get_user(c[0], (char *)frame->retcode+4);
+ __get_user(c[1], (char *)frame->retcode+5);
+ __get_user(c[2], (char *)frame->retcode+6);
+ __get_user(c[3], (char *)frame->retcode+7);
+ printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n",
+ frame->retcode+4, c[0],
+ frame->retcode+5, c[1],
+ frame->retcode+6, c[2],
+ frame->retcode+7, c[3]);
+ }
+ {
+ unsigned char c[4];
+ __get_user(c[0], (char *)frame->retcode+8);
+ __get_user(c[1], (char *)frame->retcode+9);
+ __get_user(c[2], (char *)frame->retcode+10);
+ __get_user(c[3], (char *)frame->retcode+11);
+ printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n",
+ frame->retcode+8, c[0],
+ frame->retcode+9, c[1],
+ frame->retcode+10, c[2],
+ frame->retcode+11, c[3]);
+ }
+ {
+ unsigned char c[4];
+ __get_user(c[0], (char *)frame->retcode+12);
+ __get_user(c[1], (char *)frame->retcode+13);
+ __get_user(c[2], (char *)frame->retcode+14);
+ __get_user(c[3], (char *)frame->retcode+15);
+ printk("setup_frame: %p %1x %p %1x %p %1x %p %1x\n",
+ frame->retcode+12, c[0],
+ frame->retcode+13, c[1],
+ frame->retcode+14, c[2],
+ frame->retcode+15, c[3]);
+ }
+#endif
return;
give_sigsegv:
@@ -410,6 +519,7 @@
force_sig(SIGSEGV, current);
}
+/* FIXME: this is bogus */
static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs)
{
@@ -504,7 +614,10 @@
}
/* Set up the stack frame */
- if (ka->sa.sa_flags & SA_SIGINFO)
+#ifdef DEBUG_SIG
+ printk("handle_signal: setup_frame(sig=%d,ka=%p,oldset=%d,regs=%p)\n",sig,ka,oldset,regs);
+#endif
+ if (ka->sa.sa_flags & SA_SIGINFO)
setup_rt_frame(sig, ka, info, oldset, regs);
else
setup_frame(sig, ka, oldset, regs);
@@ -526,11 +639,11 @@
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
+int do_signal(sigset_t *oldset, struct pt_regs *regs)
{
siginfo_t info;
struct k_sigaction *ka;
-
+ int canrestart;
/*
* We want the common case to go fast, which
* is why we may in certain cases get here from
@@ -540,16 +653,24 @@
if (!user_mode(regs))
return 1;
+ /* FIXME: */
+ canrestart=0;
+#ifdef DEBUG_SIG
+ printk("do_signal: pid %d,canrestart %d, current->sigpending %d,current->blocked %d ", current->pid,canrestart,current->sigpending,current->blocked);
+#endif
if (!oldset)
oldset = ¤t->blocked;
+
for (;;) {
unsigned long signr;
spin_lock_irq(¤t->sigmask_lock);
signr = dequeue_signal(¤t->blocked, &info);
spin_unlock_irq(¤t->sigmask_lock);
-
+#ifdef DEBUG_SIG
+ printk(" sig %d\n",signr);
+#endif
if (!signr)
break;
@@ -589,6 +710,9 @@
if (ka->sa.sa_handler == SIG_IGN) {
if (signr != SIGCHLD)
continue;
+#ifdef DEBUG_SIG
+ printk("do_signal: waiting for sigchld\n");
+#endif
/* Check for SIGCHLD: it's special. */
while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
/* nothing */;
@@ -597,7 +721,9 @@
if (ka->sa.sa_handler == SIG_DFL) {
int exit_code = signr;
-
+#ifdef DEBUG_SIG
+ printk("do_signal: invoking default handler for sig %d\n",signr);
+#endif
/* Init gets no signals it doesn't want. */
if (current->pid == 1)
continue;
@@ -631,11 +757,16 @@
sigaddset(¤t->pending.signal, signr);
recalc_sigpending(current);
current->flags |= PF_SIGNALED;
+#ifdef DEBUG_SIG
+ printk("handle_sig: do_exit exit_code=%d\n",exit_code);
+#endif
do_exit(exit_code);
/* NOTREACHED */
}
}
-
+#ifdef DEBUG_SIG
+ printk("do_signal: handle_signal(canrestart=%d,signr=%d,info=%p,ka->sa.sa_handler=%p)\n",canrestart,signr,info,ka->sa.sa_handler);
+#endif
/* Whee! Actually deliver the signal. */
handle_signal(canrestart, signr, ka, &info, oldset, regs);
return 1;
|