Resent-Date: Sun, 18 Jul 1999 19:27:29 +0200 (MET DST)
Date: Sun, 18 Jul 1999 19:25:59 +0200 (MET DST)
From: Roman Zippel <zippel@fh-brandenburg.de>
X-Sender: zippel@zeus
To: Linux/m68k <linux-m68k@lists.linux-m68k.org>
Subject: signal bug fix
Resent-From: linux-m68k@phil.uni-sb.de

Hi,

Below you can find the tested versions of the signal bug fix for 2.0 and
2.2/3. If you want to see the bug yourself, you can try the small program
below if you don't believe me :). After some time it will either be killed
by a SIGILL or a SIGSEGV (in the second case the program will print lots
of '!').
I included also some optimizations for the 2.2 version, if we keep the
return code nicely aligned, we need only to flush 1 cache line. I think
the same can be done for the 030, but I currently have no 030 manual here,
so I kept those two lines in. Jes, if you don't want to include that into
2.2, the significant changes are at line 478 and 797.

bye, Roman

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <asm/sigcontext.h>

void timer_handler(int sig)
{
}

void buserr_handler(int sig, int code, struct sigcontext *sc)
{
	static int oldaddr = 0;

	if (!oldaddr)
		oldaddr = sc->sc_pc;
	else if (oldaddr != sc->sc_pc)
		write(1,"!",1);
}

int main()
{
	struct itimerval timer;
	struct sigaction sig;

	sigemptyset(&sig.sa_mask);
	sig.sa_flags = SA_NODEFER;

	sig.sa_handler = timer_handler;
	sigaction(SIGALRM, &sig, NULL);

	sig.sa_handler = buserr_handler;
	sigaction(SIGSEGV, &sig, NULL);

	timer.it_interval.tv_sec = 0;
	timer.it_interval.tv_usec = 10000;
	timer.it_value.tv_sec = 0;
	timer.it_value.tv_usec = 10000;

	setitimer(ITIMER_REAL, &timer, NULL);

	*(volatile int *)0;
}

--- linux-2.0/arch/m68k/kernel/signal.c.old	Sun Jul 18 18:44:35 1999
+++ linux-2.0/arch/m68k/kernel/signal.c	Sun Jul 18 18:46:45 1999
@@ -92,7 +92,7 @@
 	int fsize = 0;
 	int formatvec = 0;
 	unsigned long fp;
-	unsigned long usp = rdusp();
+	unsigned long usp = rdusp() + 16;
 
 #if 0
 	printk("sys_sigreturn, usp=%08x\n", (unsigned) usp);
@@ -236,8 +236,7 @@
  *	       signum  (parm #1)
  *	       sigcode (parm #2 ; vector number)
  *	       scp     (parm #3 ; sigcontext pointer, pointer to #1 below)
- *	       code1   (addaw #20,sp) ; pop parms and code off stack
- *	       code2   (moveq #119,d0; trap #0) ; sigreturn syscall
+ *	       code    (moveq #119,d0; trap #0) ; sigreturn syscall
  *     #1|     oldmask
  *	 |     old usp
  *	 |     d0      (first saved reg)
@@ -297,10 +296,9 @@
 
 	put_user(regs->vector, tframe); tframe++;
 	/* "scp" parameter.  points to sigcontext */
-	put_user((ulong)(frame+6), tframe); tframe++;
+	put_user((ulong)(frame+5), tframe); tframe++;
 
 /* set up the return code... */
-	put_user(0xdefc0014,tframe); tframe++; /* addaw #20,sp */
 	put_user(0x70774e40,tframe); tframe++; /* moveq #119,d0; trap #0 */
 
 /* Flush caches so the instructions will be correctly executed. (MA) */

--- linux-2.2/arch/m68k/kernel/signal.c.old	Tue Jan 26 22:35:14 1999
+++ linux-2.2/arch/m68k/kernel/signal.c	Sun Jul 18 01:01:50 1999
@@ -156,6 +156,9 @@
 
 /*
  * Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
  */
 
 struct sigframe
@@ -175,9 +178,9 @@
 	int sig;
 	struct siginfo *pinfo;
 	void *puc;
+	char retcode[8];
 	struct siginfo info;
 	struct ucontext uc;
-	char retcode[8];
 };
 
 
@@ -478,7 +481,7 @@
 	struct switch_stack *sw = (struct switch_stack *) &__unused;
 	struct pt_regs *regs = (struct pt_regs *) (sw + 1);
 	unsigned long usp = rdusp();
-	struct sigframe *frame = (struct sigframe *)(usp - 24);
+	struct sigframe *frame = (struct sigframe *)(usp - 4);
 	sigset_t set;
 	int d0;
 
@@ -677,25 +680,6 @@
 				      "cpushl %%bc,(%0)\n\t"
 				      ".chip 68k"
 				      : : "a" (temp));
-		if (((vaddr + 8) ^ vaddr) & ~15) {
-			if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
-				__asm__ __volatile__ (".chip 68040\n\t"
-						      "nop\n\t"
-						      "ptestr (%1)\n\t"
-						      "movec %%mmusr,%0\n\t"
-						      ".chip 68k"
-						      : "=r" (temp)
-						      : "a" (vaddr + 8));
-
-			temp &= PAGE_MASK;
-			temp |= (vaddr + 8) & ~PAGE_MASK;
-
-			__asm__ __volatile__ (".chip 68040\n\t"
-					      "nop\n\t"
-					      "cpushl %%bc,(%0)\n\t"
-					      ".chip 68k"
-					      : : "a" (temp));
-		}
 	}
 	else if (CPU_IS_060) {
 		unsigned long temp;
@@ -708,18 +692,6 @@
 				      "cpushl %%bc,(%0)\n\t"
 				      ".chip 68k"
 				      : : "a" (temp));
-		if (((vaddr + 8) ^ vaddr) & ~15) {
-			if (((vaddr + 8) ^ vaddr) & PAGE_MASK)
-				__asm__ __volatile__ (".chip 68060\n\t"
-						      "plpar (%0)\n\t"
-						      ".chip 68k"
-						      : "=a" (temp)
-						      : "0" (vaddr + 8));
-			__asm__ __volatile__ (".chip 68060\n\t"
-					      "cpushl %%bc,(%0)\n\t"
-					      ".chip 68k"
-					      : : "a" (temp));
-		}
 	}
 	else {
 		/*
@@ -797,11 +769,9 @@
 
 	/* Set up to return from userspace.  */
 	err |= __put_user(frame->retcode, &frame->pretcode);
-	/* addaw #20,sp */
-	err |= __put_user(0xdefc0014, (long *)(frame->retcode + 0));
 	/* moveq #,d0; trap #0 */
 	err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
-			  (long *)(frame->retcode + 4));
+			  (long *)(frame->retcode));
 
 	if (err)
 		goto give_sigsegv;
@@ -881,10 +851,10 @@
 
 	/* Set up to return from userspace.  */
 	err |= __put_user(frame->retcode, &frame->pretcode);
-	/* movel #,d0; trap #0 */
-	err |= __put_user(0x203c, (short *)(frame->retcode + 0));
-	err |= __put_user(__NR_rt_sigreturn, (long *)(frame->retcode + 2));
-	err |= __put_user(0x4e40, (short *)(frame->retcode + 6));
+	/* moveq #,d0; notb d0; trap #0 */
+	err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
+			  (long *)(frame->retcode + 0));
+	err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
 
 	if (err)
 		goto give_sigsegv;

