>>>>> On Wed, 01 Sep 2004 09:51:16 +0100, Richard Sandiford
>>>>> <rsandifo@redhat.com> said:
>> Is this a get_user's problem or gcc's?
rsandifo> The latter. gcc is putting the empty asm:
rsandifo> __asm__ ("":"=r" (__gu_val));
rsandifo> into the delay slot of the call.
Thank you for the detailed explanation.
rsandifo> FWIW, I don't think the bug is specific to 3.3 or 3.4. It
rsandifo> could probably trigger for other gcc versions too. It is
rsandifo> highly dependent on scheduling though.
Yes, this problem was originally found on gcc 3.2.
rsandifo> The attached 3.4.x patch fixes the problem there, but if you
rsandifo> want to work around it for old versions, just avoid using
rsandifo> empty asms if you can, or make them volatile if you can't.
Thank you. I create a patch for kernel with this workaround.
# This patch assumes gcc 3.5 will be free from this problem :-)
Could you apply, Ralf?
diff -u linux-mips-cvs/include/asm-mips/paccess.h
linux-mips/include/asm-mips/paccess.h
--- linux-mips-cvs/include/asm-mips/paccess.h Mon Nov 24 20:22:01 2003
+++ linux-mips/include/asm-mips/paccess.h Wed Sep 1 22:49:30 2004
@@ -15,6 +15,7 @@
#include <linux/config.h>
#include <linux/errno.h>
+#include <asm/war.h>
#ifdef CONFIG_MIPS32
#define __PA_ADDR ".word"
@@ -37,7 +38,7 @@
long __gu_err; \
__typeof(*(ptr)) __gu_val; \
unsigned long __gu_addr; \
- __asm__("":"=r" (__gu_val)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__gu_val)); \
__gu_addr = (unsigned long) (ptr); \
__asm__("":"=r" (__gu_err)); \
switch (size) { \
@@ -78,7 +79,7 @@
long __pu_addr; \
__pu_val = (x); \
__pu_addr = (long) (ptr); \
- __asm__("":"=r" (__pu_err)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__pu_err)); \
switch (size) { \
case 1: __put_dbe_asm("sb"); break; \
case 2: __put_dbe_asm("sh"); break; \
diff -u linux-mips-cvs/include/asm-mips/uaccess.h
linux-mips/include/asm-mips/uaccess.h
--- linux-mips-cvs/include/asm-mips/uaccess.h Wed Mar 31 20:21:59 2004
+++ linux-mips/include/asm-mips/uaccess.h Wed Sep 1 23:24:15 2004
@@ -13,6 +13,7 @@
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/thread_info.h>
+#include <asm/war.h>
/*
* The fs value determines whether argument validity checking should be
@@ -235,9 +236,9 @@
__typeof(*(ptr)) __gu_val; \
long __gu_addr; \
might_sleep(); \
- __asm__("":"=r" (__gu_val)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__gu_val)); \
__gu_addr = (long) (ptr); \
- __asm__("":"=r" (__gu_err)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__gu_err)); \
switch (size) { \
case 1: __get_user_asm("lb"); break; \
case 2: __get_user_asm("lh"); break; \
@@ -253,9 +254,9 @@
__typeof__(*(ptr)) __gu_val; \
long __gu_addr; \
might_sleep(); \
- __asm__("":"=r" (__gu_val)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__gu_val)); \
__gu_addr = (long) (ptr); \
- __asm__("":"=r" (__gu_err)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__gu_err)); \
if (access_ok(VERIFY_READ,__gu_addr,size)) { \
switch (size) { \
case 1: __get_user_asm("lb"); break; \
@@ -329,7 +330,7 @@
might_sleep(); \
__pu_val = (x); \
__pu_addr = (long) (ptr); \
- __asm__("":"=r" (__pu_err)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__pu_err)); \
switch (size) { \
case 1: __put_user_asm("sb"); break; \
case 2: __put_user_asm("sh"); break; \
@@ -348,7 +349,7 @@
might_sleep(); \
__pu_val = (x); \
__pu_addr = (long) (ptr); \
- __asm__("":"=r" (__pu_err)); \
+ __asm__ GCC_ASM_PROTECT_DSLOT ("":"=r" (__pu_err)); \
if (access_ok(VERIFY_WRITE, __pu_addr, size)) { \
switch (size) { \
case 1: __put_user_asm("sb"); break; \
diff -u linux-mips-cvs/include/asm-mips/war.h linux-mips/include/asm-mips/war.h
--- linux-mips-cvs/include/asm-mips/war.h Sat Aug 21 00:34:12 2004
+++ linux-mips/include/asm-mips/war.h Wed Sep 1 23:22:29 2004
@@ -221,4 +221,10 @@
#define R10000_LLSC_WAR 0
#endif
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 4))
+#define GCC_ASM_PROTECT_DSLOT
+#else
+#define GCC_ASM_PROTECT_DSLOT __volatile__
+#endif
+
#endif /* _ASM_WAR_H */
|