To: linux-m68k@lists.linux-m68k.org
Subject: L68K: copy_to_user exception processing bug
X-Yow: Life is selling REVOLUTIONARY HAIR PRODUCTS!
From: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
Date: 24 Jun 1998 10:22:54 +0200
Sender: owner-linux-m68k@phil.uni-sb.de

The exception processing in copy_to_user for an invalid user address is
even more tricky than i thought.  Due to instruction prefetch and caching
it is possible that the stacked pc is as much as two instructions away
from the moves instruction in the copying loop.  That means that the
exception table must be extended even more.  If you want to try it out
yourself, here is a small test program:

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>

int main ()
{
  int psize = getpagesize ();
  void *page = mmap (0, psize * 2, PROT_READ|PROT_WRITE,
		     MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
  int ret;
  if (page == MAP_FAILED)
    {
      perror ("mmap");
      exit (1);
    }
  if (munmap (page + psize, psize) < 0)
    {
      perror ("munmap");
      exit (1);
    }
  printf ("%p\n", page);
  ret = read (0, page + 3, 2 * psize);
  if (ret == -1)
    perror ("read");
  else
    printf ("read: %d Bytes\n", ret);
  return 0;
}


Redirect stdin from a file that is bigger than one page, and experiment
with the offset into the page as passed to read().  Depending on this
offset the access fault will happen at different places inside the
copy_to_user macro.  For example, an offset of three means that the loop
at the beginning will just be finished when the fault address is written
to.  But the CPU has already executed both the subq and the branch
instruction from the pipeline before it asks the bus controller to fetch
the next instruction, and only then it processes the pending access fault.
That's probably the main reason why the m680x0 is generally faster than
the ix86. :-)

Andreas.

----------------------------------------------------------------------
--- linux/include/asm-m68k/uaccess.h.~1~	Mon Apr 14 19:34:59 1997
+++ linux/include/asm-m68k/uaccess.h	Wed Jun 24 00:57:49 1998
@@ -200,6 +200,7 @@
 	 "5:\n"
 	 ".section .fixup,\"ax\"\n"
 	 "   .even\n"
+	 "60:addql #1,%2\n"
 	 "6: lsll #2,%2\n"
 	 "   addl %4,%2\n"
 	 "   jra 5b\n"
@@ -210,9 +211,11 @@
 	 ".previous\n"
 	 ".section __ex_table,\"a\"\n"
 	 "   .align 4\n"
+	 "   .long 1b,60b\n"
 	 "   .long 22b,6b\n"
 	 "   .long 2b,6b\n"
 	 "   .long 24b,7b\n"
+	 "   .long 3b,60b\n"
 	 "   .long 4b,7b\n"
 	 "   .long 25b,8b\n"
 	 "   .long 5b,8b\n"
@@ -458,16 +461,20 @@
 	 "31: movesl %%d0,(%0)+\n"			\
 	 "11: subql #1,%2\n"				\
 	 "    jne 10b\n"				\
+	 "41:\n"					\
 	 ".section .fixup,\"ax\"\n"			\
 	 "   .even\n"					\
+	 "22: addql #1,%2\n"				\
 	 "12: lsll #2,%2\n"				\
 	 fixup "\n"					\
 	 "    jra 13f\n"				\
 	 ".previous\n"					\
 	 ".section __ex_table,\"a\"\n"			\
 	 "    .align 4\n"				\
+	 "    .long 10b,22b\n"				\
 	 "    .long 31b,12b\n"				\
 	 "    .long 11b,12b\n"				\
+	 "    .long 41b,22b\n"				\
 	 ".previous\n"					\
 	 copy "\n"					\
 	 "13:"						\
@@ -803,6 +810,7 @@
 	 "5:\n"
 	 ".section .fixup,\"ax\"\n"
 	 "   .even\n"
+	 "61:addql #1,%1\n"
 	 "6: lsll #2,%1\n"
 	 "   addl %2,%1\n"
 	 "   jra 5b\n"
@@ -813,8 +821,9 @@
 	 ".previous\n"
 	 ".section __ex_table,\"a\"\n"
 	 "   .align 4\n"
-	 "   .long 1b,6b\n"
+	 "   .long 1b,61b\n"
 	 "   .long 2b,6b\n"
+	 "   .long 3b,61b\n"
 	 "   .long 24b,7b\n"
 	 "   .long 4b,7b\n"
 	 "   .long 25b,8b\n"

-- 
Andreas Schwab                                      "And now for something
schwab@issan.informatik.uni-dortmund.de              completely different"
schwab@gnu.org
