patch-2.4.6 linux/arch/mips/kernel/sysmips.c

Next file: linux/arch/mips/kernel/time.c
Previous file: linux/arch/mips/kernel/sysirix.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c
@@ -7,6 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997, 2000 by Ralf Baechle
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
 #include <linux/mm.h>
@@ -21,6 +22,8 @@
 #include <asm/sysmips.h>
 #include <asm/uaccess.h>
 
+extern asmlinkage void syscall_trace(void);
+
 /*
  * How long a hostname can we get from user space?
  *  -EFAULT if invalid area or too long
@@ -49,7 +52,7 @@
 {
 	int	*p;
 	char	*name;
-	int	flags, tmp, len, retval, errno;
+	int	tmp, len, retval, errno;
 
 	switch(cmd) {
 	case SETNAME: {
@@ -72,8 +75,7 @@
 	}
 
 	case MIPS_ATOMIC_SET: {
-		/* This is broken in case of page faults and SMP ...
-		    Risc/OS faults after maximum 20 tries with EAGAIN.  */
+#ifdef CONFIG_CPU_HAS_LLSC
 		unsigned int tmp;
 
 		p = (int *) arg1;
@@ -81,16 +83,46 @@
 		if (errno)
 			return errno;
 		errno = 0;
-		save_and_cli(flags);
-		errno |= __get_user(tmp, p);
-		errno |= __put_user(arg2, p);
-		restore_flags(flags);
+
+		__asm__(".set\tpush\t\t\t# sysmips(MIPS_ATOMIC, ...)\n\t"
+			".set\tmips2\n\t"
+			".set\tnoat\n\t"
+			"1:\tll\t%0, %4\n\t"
+			"move\t$1, %3\n\t"
+			"2:\tsc\t$1, %1\n\t"
+			"beqz\t$1, 1b\n\t"
+			".set\tpop\n\t"
+			".section\t.fixup,\"ax\"\n"
+			"3:\tli\t%2, 1\t\t\t# error\n\t"
+			".previous\n\t"
+			".section\t__ex_table,\"a\"\n\t"
+			".word\t1b, 3b\n\t"
+			".word\t2b, 3b\n\t"
+			".previous\n\t"
+			: "=&r" (tmp), "=o" (* (u32 *) p), "=r" (errno)
+			: "r" (arg2), "o" (* (u32 *) p), "2" (errno)
+			: "$1");
 
 		if (errno)
-			return tmp;
+			return -EFAULT;
 
-		return tmp;             /* This is broken ...  */ 
-        }
+		/* We're skipping error handling etc.  */
+		if (current->ptrace & PT_TRACESYS)
+			syscall_trace();
+
+		((struct pt_regs *)&cmd)->regs[2] = tmp;
+		((struct pt_regs *)&cmd)->regs[7] = 0;
+
+		__asm__ __volatile__(
+			"move\t$29, %0\n\t"
+			"j\to32_ret_from_sys_call"
+			: /* No outputs */
+			: "r" (&cmd));
+		/* Unreached */
+#else
+	printk("sys_sysmips(MIPS_ATOMIC_SET, ...) not ready for !CONFIG_CPU_HAS_LLSC\n");
+#endif
+	}
 
 	case MIPS_FIXADE:
 		tmp = current->thread.mflags & ~3;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)