* [PATCH] x86: Add support for 64bit get_user() on x86-32
@ 2012-12-12 11:34 ville.syrjala
2012-12-12 16:15 ` H. Peter Anvin
2013-02-07 16:53 ` Ville Syrjälä
0 siblings, 2 replies; 39+ messages in thread
From: ville.syrjala @ 2012-12-12 11:34 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
Linus Torvalds, Ville Syrjälä,
Jamie Lokier
From: Ville Syrjälä <ville.syrjala@linux.intel.com>
Implement __get_user_8() for x86-32. It will return the
64bit result in edx:eax register pair, and ecx is used
to pass in the address and return the error value.
For consistency, change the register assignment for all
other __get_user_x() variants, so that address is passed in
ecx/rcx, the error value is returned in ecx/rcx, and eax/rax
contains the actual value.
This is a partial refresh of a patch [1] by Jamie Lokier from
2004. Only the minimal changes to implement 64bit get_user()
were picked from the original patch.
[1] http://article.gmane.org/gmane.linux.kernel/198823
Cc: Jamie Lokier <jamie@shareable.org>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
arch/x86/include/asm/uaccess.h | 17 ++++++--
arch/x86/kernel/i386_ksyms_32.c | 1 +
arch/x86/lib/getuser.S | 82 ++++++++++++++++++++++++++------------
3 files changed, 69 insertions(+), 31 deletions(-)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 7ccf8d1..3f4387e 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -127,7 +127,7 @@ extern int __get_user_bad(void);
#define __get_user_x(size, ret, x, ptr) \
asm volatile("call __get_user_" #size \
- : "=a" (ret), "=d" (x) \
+ : "=c" (ret), "=a" (x) \
: "0" (ptr)) \
/* Careful: we have to cast the result to the type of the pointer
@@ -151,8 +151,11 @@ extern int __get_user_bad(void);
* On error, the variable @x is set to zero.
*/
#ifdef CONFIG_X86_32
-#define __get_user_8(__ret_gu, __val_gu, ptr) \
- __get_user_x(X, __ret_gu, __val_gu, ptr)
+#define __get_user_8(ret, x, ptr) \
+ asm volatile("call __get_user_8" \
+ : "=c" (ret), "=A" (x) \
+ : "0" (ptr)) \
+
#else
#define __get_user_8(__ret_gu, __val_gu, ptr) \
__get_user_x(8, __ret_gu, __val_gu, ptr)
@@ -162,6 +165,7 @@ extern int __get_user_bad(void);
({ \
int __ret_gu; \
unsigned long __val_gu; \
+ unsigned long long __val_gu8; \
__chk_user_ptr(ptr); \
might_fault(); \
switch (sizeof(*(ptr))) { \
@@ -175,13 +179,16 @@ extern int __get_user_bad(void);
__get_user_x(4, __ret_gu, __val_gu, ptr); \
break; \
case 8: \
- __get_user_8(__ret_gu, __val_gu, ptr); \
+ __get_user_8(__ret_gu, __val_gu8, ptr); \
break; \
default: \
__get_user_x(X, __ret_gu, __val_gu, ptr); \
break; \
} \
- (x) = (__typeof__(*(ptr)))__val_gu; \
+ if (sizeof(*(ptr)) == 8) \
+ (x) = (__typeof__(*(ptr)))__val_gu8; \
+ else \
+ (x) = (__typeof__(*(ptr)))__val_gu; \
__ret_gu; \
})
diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c
index 9c3bd4a..0fa6912 100644
--- a/arch/x86/kernel/i386_ksyms_32.c
+++ b/arch/x86/kernel/i386_ksyms_32.c
@@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
EXPORT_SYMBOL(__get_user_1);
EXPORT_SYMBOL(__get_user_2);
EXPORT_SYMBOL(__get_user_4);
+EXPORT_SYMBOL(__get_user_8);
EXPORT_SYMBOL(__put_user_1);
EXPORT_SYMBOL(__put_user_2);
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 156b9c8..38afef0 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -14,12 +14,11 @@
/*
* __get_user_X
*
- * Inputs: %[r|e]ax contains the address.
- * The register is modified, but all changes are undone
- * before returning because the C code doesn't know about it.
+ * Inputs: %[r|e]cx contains the address.
*
- * Outputs: %[r|e]ax is error code (0 or -EFAULT)
- * %[r|e]dx contains zero-extended value
+ * Outputs: %[r|e]cx is error code (0 or -EFAULT)
+ * %[r|e]ax contains zero-extended value
+ * %edx contains the high bits of the value for __get_user_8 on x86-32
*
*
* These functions should not modify any other registers,
@@ -38,12 +37,12 @@
.text
ENTRY(__get_user_1)
CFI_STARTPROC
- GET_THREAD_INFO(%_ASM_DX)
- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+ GET_THREAD_INFO(%_ASM_AX)
+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
jae bad_get_user
ASM_STAC
-1: movzb (%_ASM_AX),%edx
- xor %eax,%eax
+1: movzb (%_ASM_CX),%eax
+ xor %ecx,%ecx
ASM_CLAC
ret
CFI_ENDPROC
@@ -51,14 +50,14 @@ ENDPROC(__get_user_1)
ENTRY(__get_user_2)
CFI_STARTPROC
- add $1,%_ASM_AX
+ add $1,%_ASM_CX
jc bad_get_user
- GET_THREAD_INFO(%_ASM_DX)
- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+ GET_THREAD_INFO(%_ASM_AX)
+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
jae bad_get_user
ASM_STAC
-2: movzwl -1(%_ASM_AX),%edx
- xor %eax,%eax
+2: movzwl -1(%_ASM_CX),%eax
+ xor %ecx,%ecx
ASM_CLAC
ret
CFI_ENDPROC
@@ -66,14 +65,14 @@ ENDPROC(__get_user_2)
ENTRY(__get_user_4)
CFI_STARTPROC
- add $3,%_ASM_AX
+ add $3,%_ASM_CX
jc bad_get_user
- GET_THREAD_INFO(%_ASM_DX)
- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+ GET_THREAD_INFO(%_ASM_AX)
+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
jae bad_get_user
ASM_STAC
-3: mov -3(%_ASM_AX),%edx
- xor %eax,%eax
+3: mov -3(%_ASM_CX),%eax
+ xor %ecx,%ecx
ASM_CLAC
ret
CFI_ENDPROC
@@ -82,14 +81,30 @@ ENDPROC(__get_user_4)
#ifdef CONFIG_X86_64
ENTRY(__get_user_8)
CFI_STARTPROC
- add $7,%_ASM_AX
+ add $7,%_ASM_CX
jc bad_get_user
- GET_THREAD_INFO(%_ASM_DX)
- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
+ GET_THREAD_INFO(%_ASM_AX)
+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
jae bad_get_user
ASM_STAC
-4: movq -7(%_ASM_AX),%_ASM_DX
- xor %eax,%eax
+4: movq -7(%_ASM_CX),%_ASM_AX
+ xor %ecx,%ecx
+ ASM_CLAC
+ ret
+ CFI_ENDPROC
+ENDPROC(__get_user_8)
+#else
+ENTRY(__get_user_8)
+ CFI_STARTPROC
+ add $7,%_ASM_CX
+ jc bad_get_user_8
+ GET_THREAD_INFO(%_ASM_AX)
+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
+ jae bad_get_user_8
+ ASM_STAC
+4: mov -7(%_ASM_CX),%eax
+5: mov -3(%_ASM_CX),%edx
+ xor %ecx,%ecx
ASM_CLAC
ret
CFI_ENDPROC
@@ -98,16 +113,31 @@ ENDPROC(__get_user_8)
bad_get_user:
CFI_STARTPROC
- xor %edx,%edx
- mov $(-EFAULT),%_ASM_AX
+ xor %eax,%eax
+ mov $(-EFAULT),%_ASM_CX
ASM_CLAC
ret
CFI_ENDPROC
END(bad_get_user)
+#ifdef CONFIG_X86_32
+bad_get_user_8:
+ CFI_STARTPROC
+ xor %eax,%eax
+ xor %edx,%edx
+ mov $(-EFAULT),%_ASM_CX
+ ASM_CLAC
+ ret
+ CFI_ENDPROC
+END(bad_get_user_8)
+#endif
+
_ASM_EXTABLE(1b,bad_get_user)
_ASM_EXTABLE(2b,bad_get_user)
_ASM_EXTABLE(3b,bad_get_user)
#ifdef CONFIG_X86_64
_ASM_EXTABLE(4b,bad_get_user)
+#else
+ _ASM_EXTABLE(4b,bad_get_user_8)
+ _ASM_EXTABLE(5b,bad_get_user_8)
#endif
--
1.7.8.6
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2012-12-12 11:34 [PATCH] x86: Add support for 64bit get_user() on x86-32 ville.syrjala
@ 2012-12-12 16:15 ` H. Peter Anvin
2012-12-12 16:32 ` Ville Syrjälä
2013-02-07 16:53 ` Ville Syrjälä
1 sibling, 1 reply; 39+ messages in thread
From: H. Peter Anvin @ 2012-12-12 16:15 UTC (permalink / raw)
To: ville.syrjala, linux-kernel
Cc: x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds, Jamie Lokier
Can we worry about this after the merge window?
ville.syrjala@linux.intel.com wrote:
>From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
>Implement __get_user_8() for x86-32. It will return the
>64bit result in edx:eax register pair, and ecx is used
>to pass in the address and return the error value.
>
>For consistency, change the register assignment for all
>other __get_user_x() variants, so that address is passed in
>ecx/rcx, the error value is returned in ecx/rcx, and eax/rax
>contains the actual value.
>
>This is a partial refresh of a patch [1] by Jamie Lokier from
>2004. Only the minimal changes to implement 64bit get_user()
>were picked from the original patch.
>
>[1] http://article.gmane.org/gmane.linux.kernel/198823
>
>Cc: Jamie Lokier <jamie@shareable.org>
>Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>---
> arch/x86/include/asm/uaccess.h | 17 ++++++--
> arch/x86/kernel/i386_ksyms_32.c | 1 +
>arch/x86/lib/getuser.S | 82
>++++++++++++++++++++++++++------------
> 3 files changed, 69 insertions(+), 31 deletions(-)
>
>diff --git a/arch/x86/include/asm/uaccess.h
>b/arch/x86/include/asm/uaccess.h
>index 7ccf8d1..3f4387e 100644
>--- a/arch/x86/include/asm/uaccess.h
>+++ b/arch/x86/include/asm/uaccess.h
>@@ -127,7 +127,7 @@ extern int __get_user_bad(void);
>
> #define __get_user_x(size, ret, x, ptr) \
> asm volatile("call __get_user_" #size \
>- : "=a" (ret), "=d" (x) \
>+ : "=c" (ret), "=a" (x) \
> : "0" (ptr)) \
>
> /* Careful: we have to cast the result to the type of the pointer
>@@ -151,8 +151,11 @@ extern int __get_user_bad(void);
> * On error, the variable @x is set to zero.
> */
> #ifdef CONFIG_X86_32
>-#define __get_user_8(__ret_gu, __val_gu, ptr) \
>- __get_user_x(X, __ret_gu, __val_gu, ptr)
>+#define __get_user_8(ret, x, ptr) \
>+ asm volatile("call __get_user_8" \
>+ : "=c" (ret), "=A" (x) \
>+ : "0" (ptr)) \
>+
> #else
> #define __get_user_8(__ret_gu, __val_gu, ptr) \
> __get_user_x(8, __ret_gu, __val_gu, ptr)
>@@ -162,6 +165,7 @@ extern int __get_user_bad(void);
> ({ \
> int __ret_gu; \
> unsigned long __val_gu; \
>+ unsigned long long __val_gu8; \
> __chk_user_ptr(ptr); \
> might_fault(); \
> switch (sizeof(*(ptr))) { \
>@@ -175,13 +179,16 @@ extern int __get_user_bad(void);
> __get_user_x(4, __ret_gu, __val_gu, ptr); \
> break; \
> case 8: \
>- __get_user_8(__ret_gu, __val_gu, ptr); \
>+ __get_user_8(__ret_gu, __val_gu8, ptr); \
> break; \
> default: \
> __get_user_x(X, __ret_gu, __val_gu, ptr); \
> break; \
> } \
>- (x) = (__typeof__(*(ptr)))__val_gu; \
>+ if (sizeof(*(ptr)) == 8) \
>+ (x) = (__typeof__(*(ptr)))__val_gu8; \
>+ else \
>+ (x) = (__typeof__(*(ptr)))__val_gu; \
> __ret_gu; \
> })
>
>diff --git a/arch/x86/kernel/i386_ksyms_32.c
>b/arch/x86/kernel/i386_ksyms_32.c
>index 9c3bd4a..0fa6912 100644
>--- a/arch/x86/kernel/i386_ksyms_32.c
>+++ b/arch/x86/kernel/i386_ksyms_32.c
>@@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
> EXPORT_SYMBOL(__get_user_1);
> EXPORT_SYMBOL(__get_user_2);
> EXPORT_SYMBOL(__get_user_4);
>+EXPORT_SYMBOL(__get_user_8);
>
> EXPORT_SYMBOL(__put_user_1);
> EXPORT_SYMBOL(__put_user_2);
>diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
>index 156b9c8..38afef0 100644
>--- a/arch/x86/lib/getuser.S
>+++ b/arch/x86/lib/getuser.S
>@@ -14,12 +14,11 @@
> /*
> * __get_user_X
> *
>- * Inputs: %[r|e]ax contains the address.
>- * The register is modified, but all changes are undone
>- * before returning because the C code doesn't know about it.
>+ * Inputs: %[r|e]cx contains the address.
> *
>- * Outputs: %[r|e]ax is error code (0 or -EFAULT)
>- * %[r|e]dx contains zero-extended value
>+ * Outputs: %[r|e]cx is error code (0 or -EFAULT)
>+ * %[r|e]ax contains zero-extended value
>+ * %edx contains the high bits of the value for __get_user_8 on
>x86-32
> *
> *
> * These functions should not modify any other registers,
>@@ -38,12 +37,12 @@
> .text
> ENTRY(__get_user_1)
> CFI_STARTPROC
>- GET_THREAD_INFO(%_ASM_DX)
>- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>+ GET_THREAD_INFO(%_ASM_AX)
>+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
>-1: movzb (%_ASM_AX),%edx
>- xor %eax,%eax
>+1: movzb (%_ASM_CX),%eax
>+ xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
>@@ -51,14 +50,14 @@ ENDPROC(__get_user_1)
>
> ENTRY(__get_user_2)
> CFI_STARTPROC
>- add $1,%_ASM_AX
>+ add $1,%_ASM_CX
> jc bad_get_user
>- GET_THREAD_INFO(%_ASM_DX)
>- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>+ GET_THREAD_INFO(%_ASM_AX)
>+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
>-2: movzwl -1(%_ASM_AX),%edx
>- xor %eax,%eax
>+2: movzwl -1(%_ASM_CX),%eax
>+ xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
>@@ -66,14 +65,14 @@ ENDPROC(__get_user_2)
>
> ENTRY(__get_user_4)
> CFI_STARTPROC
>- add $3,%_ASM_AX
>+ add $3,%_ASM_CX
> jc bad_get_user
>- GET_THREAD_INFO(%_ASM_DX)
>- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>+ GET_THREAD_INFO(%_ASM_AX)
>+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
>-3: mov -3(%_ASM_AX),%edx
>- xor %eax,%eax
>+3: mov -3(%_ASM_CX),%eax
>+ xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
>@@ -82,14 +81,30 @@ ENDPROC(__get_user_4)
> #ifdef CONFIG_X86_64
> ENTRY(__get_user_8)
> CFI_STARTPROC
>- add $7,%_ASM_AX
>+ add $7,%_ASM_CX
> jc bad_get_user
>- GET_THREAD_INFO(%_ASM_DX)
>- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>+ GET_THREAD_INFO(%_ASM_AX)
>+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
>-4: movq -7(%_ASM_AX),%_ASM_DX
>- xor %eax,%eax
>+4: movq -7(%_ASM_CX),%_ASM_AX
>+ xor %ecx,%ecx
>+ ASM_CLAC
>+ ret
>+ CFI_ENDPROC
>+ENDPROC(__get_user_8)
>+#else
>+ENTRY(__get_user_8)
>+ CFI_STARTPROC
>+ add $7,%_ASM_CX
>+ jc bad_get_user_8
>+ GET_THREAD_INFO(%_ASM_AX)
>+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
>+ jae bad_get_user_8
>+ ASM_STAC
>+4: mov -7(%_ASM_CX),%eax
>+5: mov -3(%_ASM_CX),%edx
>+ xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
>@@ -98,16 +113,31 @@ ENDPROC(__get_user_8)
>
> bad_get_user:
> CFI_STARTPROC
>- xor %edx,%edx
>- mov $(-EFAULT),%_ASM_AX
>+ xor %eax,%eax
>+ mov $(-EFAULT),%_ASM_CX
> ASM_CLAC
> ret
> CFI_ENDPROC
> END(bad_get_user)
>
>+#ifdef CONFIG_X86_32
>+bad_get_user_8:
>+ CFI_STARTPROC
>+ xor %eax,%eax
>+ xor %edx,%edx
>+ mov $(-EFAULT),%_ASM_CX
>+ ASM_CLAC
>+ ret
>+ CFI_ENDPROC
>+END(bad_get_user_8)
>+#endif
>+
> _ASM_EXTABLE(1b,bad_get_user)
> _ASM_EXTABLE(2b,bad_get_user)
> _ASM_EXTABLE(3b,bad_get_user)
> #ifdef CONFIG_X86_64
> _ASM_EXTABLE(4b,bad_get_user)
>+#else
>+ _ASM_EXTABLE(4b,bad_get_user_8)
>+ _ASM_EXTABLE(5b,bad_get_user_8)
> #endif
--
Sent from my mobile phone. Please excuse brevity and lack of formatting.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2012-12-12 16:15 ` H. Peter Anvin
@ 2012-12-12 16:32 ` Ville Syrjälä
2012-12-12 16:45 ` H. Peter Anvin
0 siblings, 1 reply; 39+ messages in thread
From: Ville Syrjälä @ 2012-12-12 16:32 UTC (permalink / raw)
To: H. Peter Anvin
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier
On Wed, Dec 12, 2012 at 08:15:12AM -0800, H. Peter Anvin wrote:
> Can we worry about this after the merge window?
Sure. The only use I have for this is in my drm/kms atomic
modeset/pageflip patch set, and that's not 3.8 material.
>
> ville.syrjala@linux.intel.com wrote:
>
> >From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> >Implement __get_user_8() for x86-32. It will return the
> >64bit result in edx:eax register pair, and ecx is used
> >to pass in the address and return the error value.
> >
> >For consistency, change the register assignment for all
> >other __get_user_x() variants, so that address is passed in
> >ecx/rcx, the error value is returned in ecx/rcx, and eax/rax
> >contains the actual value.
> >
> >This is a partial refresh of a patch [1] by Jamie Lokier from
> >2004. Only the minimal changes to implement 64bit get_user()
> >were picked from the original patch.
> >
> >[1] http://article.gmane.org/gmane.linux.kernel/198823
> >
> >Cc: Jamie Lokier <jamie@shareable.org>
> >Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >---
> > arch/x86/include/asm/uaccess.h | 17 ++++++--
> > arch/x86/kernel/i386_ksyms_32.c | 1 +
> >arch/x86/lib/getuser.S | 82
> >++++++++++++++++++++++++++------------
> > 3 files changed, 69 insertions(+), 31 deletions(-)
> >
> >diff --git a/arch/x86/include/asm/uaccess.h
> >b/arch/x86/include/asm/uaccess.h
> >index 7ccf8d1..3f4387e 100644
> >--- a/arch/x86/include/asm/uaccess.h
> >+++ b/arch/x86/include/asm/uaccess.h
> >@@ -127,7 +127,7 @@ extern int __get_user_bad(void);
> >
> > #define __get_user_x(size, ret, x, ptr) \
> > asm volatile("call __get_user_" #size \
> >- : "=a" (ret), "=d" (x) \
> >+ : "=c" (ret), "=a" (x) \
> > : "0" (ptr)) \
> >
> > /* Careful: we have to cast the result to the type of the pointer
> >@@ -151,8 +151,11 @@ extern int __get_user_bad(void);
> > * On error, the variable @x is set to zero.
> > */
> > #ifdef CONFIG_X86_32
> >-#define __get_user_8(__ret_gu, __val_gu, ptr) \
> >- __get_user_x(X, __ret_gu, __val_gu, ptr)
> >+#define __get_user_8(ret, x, ptr) \
> >+ asm volatile("call __get_user_8" \
> >+ : "=c" (ret), "=A" (x) \
> >+ : "0" (ptr)) \
> >+
> > #else
> > #define __get_user_8(__ret_gu, __val_gu, ptr) \
> > __get_user_x(8, __ret_gu, __val_gu, ptr)
> >@@ -162,6 +165,7 @@ extern int __get_user_bad(void);
> > ({ \
> > int __ret_gu; \
> > unsigned long __val_gu; \
> >+ unsigned long long __val_gu8; \
> > __chk_user_ptr(ptr); \
> > might_fault(); \
> > switch (sizeof(*(ptr))) { \
> >@@ -175,13 +179,16 @@ extern int __get_user_bad(void);
> > __get_user_x(4, __ret_gu, __val_gu, ptr); \
> > break; \
> > case 8: \
> >- __get_user_8(__ret_gu, __val_gu, ptr); \
> >+ __get_user_8(__ret_gu, __val_gu8, ptr); \
> > break; \
> > default: \
> > __get_user_x(X, __ret_gu, __val_gu, ptr); \
> > break; \
> > } \
> >- (x) = (__typeof__(*(ptr)))__val_gu; \
> >+ if (sizeof(*(ptr)) == 8) \
> >+ (x) = (__typeof__(*(ptr)))__val_gu8; \
> >+ else \
> >+ (x) = (__typeof__(*(ptr)))__val_gu; \
> > __ret_gu; \
> > })
> >
> >diff --git a/arch/x86/kernel/i386_ksyms_32.c
> >b/arch/x86/kernel/i386_ksyms_32.c
> >index 9c3bd4a..0fa6912 100644
> >--- a/arch/x86/kernel/i386_ksyms_32.c
> >+++ b/arch/x86/kernel/i386_ksyms_32.c
> >@@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
> > EXPORT_SYMBOL(__get_user_1);
> > EXPORT_SYMBOL(__get_user_2);
> > EXPORT_SYMBOL(__get_user_4);
> >+EXPORT_SYMBOL(__get_user_8);
> >
> > EXPORT_SYMBOL(__put_user_1);
> > EXPORT_SYMBOL(__put_user_2);
> >diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
> >index 156b9c8..38afef0 100644
> >--- a/arch/x86/lib/getuser.S
> >+++ b/arch/x86/lib/getuser.S
> >@@ -14,12 +14,11 @@
> > /*
> > * __get_user_X
> > *
> >- * Inputs: %[r|e]ax contains the address.
> >- * The register is modified, but all changes are undone
> >- * before returning because the C code doesn't know about it.
> >+ * Inputs: %[r|e]cx contains the address.
> > *
> >- * Outputs: %[r|e]ax is error code (0 or -EFAULT)
> >- * %[r|e]dx contains zero-extended value
> >+ * Outputs: %[r|e]cx is error code (0 or -EFAULT)
> >+ * %[r|e]ax contains zero-extended value
> >+ * %edx contains the high bits of the value for __get_user_8 on
> >x86-32
> > *
> > *
> > * These functions should not modify any other registers,
> >@@ -38,12 +37,12 @@
> > .text
> > ENTRY(__get_user_1)
> > CFI_STARTPROC
> >- GET_THREAD_INFO(%_ASM_DX)
> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> >+ GET_THREAD_INFO(%_ASM_AX)
> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> > jae bad_get_user
> > ASM_STAC
> >-1: movzb (%_ASM_AX),%edx
> >- xor %eax,%eax
> >+1: movzb (%_ASM_CX),%eax
> >+ xor %ecx,%ecx
> > ASM_CLAC
> > ret
> > CFI_ENDPROC
> >@@ -51,14 +50,14 @@ ENDPROC(__get_user_1)
> >
> > ENTRY(__get_user_2)
> > CFI_STARTPROC
> >- add $1,%_ASM_AX
> >+ add $1,%_ASM_CX
> > jc bad_get_user
> >- GET_THREAD_INFO(%_ASM_DX)
> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> >+ GET_THREAD_INFO(%_ASM_AX)
> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> > jae bad_get_user
> > ASM_STAC
> >-2: movzwl -1(%_ASM_AX),%edx
> >- xor %eax,%eax
> >+2: movzwl -1(%_ASM_CX),%eax
> >+ xor %ecx,%ecx
> > ASM_CLAC
> > ret
> > CFI_ENDPROC
> >@@ -66,14 +65,14 @@ ENDPROC(__get_user_2)
> >
> > ENTRY(__get_user_4)
> > CFI_STARTPROC
> >- add $3,%_ASM_AX
> >+ add $3,%_ASM_CX
> > jc bad_get_user
> >- GET_THREAD_INFO(%_ASM_DX)
> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> >+ GET_THREAD_INFO(%_ASM_AX)
> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> > jae bad_get_user
> > ASM_STAC
> >-3: mov -3(%_ASM_AX),%edx
> >- xor %eax,%eax
> >+3: mov -3(%_ASM_CX),%eax
> >+ xor %ecx,%ecx
> > ASM_CLAC
> > ret
> > CFI_ENDPROC
> >@@ -82,14 +81,30 @@ ENDPROC(__get_user_4)
> > #ifdef CONFIG_X86_64
> > ENTRY(__get_user_8)
> > CFI_STARTPROC
> >- add $7,%_ASM_AX
> >+ add $7,%_ASM_CX
> > jc bad_get_user
> >- GET_THREAD_INFO(%_ASM_DX)
> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> >+ GET_THREAD_INFO(%_ASM_AX)
> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> > jae bad_get_user
> > ASM_STAC
> >-4: movq -7(%_ASM_AX),%_ASM_DX
> >- xor %eax,%eax
> >+4: movq -7(%_ASM_CX),%_ASM_AX
> >+ xor %ecx,%ecx
> >+ ASM_CLAC
> >+ ret
> >+ CFI_ENDPROC
> >+ENDPROC(__get_user_8)
> >+#else
> >+ENTRY(__get_user_8)
> >+ CFI_STARTPROC
> >+ add $7,%_ASM_CX
> >+ jc bad_get_user_8
> >+ GET_THREAD_INFO(%_ASM_AX)
> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> >+ jae bad_get_user_8
> >+ ASM_STAC
> >+4: mov -7(%_ASM_CX),%eax
> >+5: mov -3(%_ASM_CX),%edx
> >+ xor %ecx,%ecx
> > ASM_CLAC
> > ret
> > CFI_ENDPROC
> >@@ -98,16 +113,31 @@ ENDPROC(__get_user_8)
> >
> > bad_get_user:
> > CFI_STARTPROC
> >- xor %edx,%edx
> >- mov $(-EFAULT),%_ASM_AX
> >+ xor %eax,%eax
> >+ mov $(-EFAULT),%_ASM_CX
> > ASM_CLAC
> > ret
> > CFI_ENDPROC
> > END(bad_get_user)
> >
> >+#ifdef CONFIG_X86_32
> >+bad_get_user_8:
> >+ CFI_STARTPROC
> >+ xor %eax,%eax
> >+ xor %edx,%edx
> >+ mov $(-EFAULT),%_ASM_CX
> >+ ASM_CLAC
> >+ ret
> >+ CFI_ENDPROC
> >+END(bad_get_user_8)
> >+#endif
> >+
> > _ASM_EXTABLE(1b,bad_get_user)
> > _ASM_EXTABLE(2b,bad_get_user)
> > _ASM_EXTABLE(3b,bad_get_user)
> > #ifdef CONFIG_X86_64
> > _ASM_EXTABLE(4b,bad_get_user)
> >+#else
> >+ _ASM_EXTABLE(4b,bad_get_user_8)
> >+ _ASM_EXTABLE(5b,bad_get_user_8)
> > #endif
>
> --
> Sent from my mobile phone. Please excuse brevity and lack of formatting.
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2012-12-12 16:32 ` Ville Syrjälä
@ 2012-12-12 16:45 ` H. Peter Anvin
0 siblings, 0 replies; 39+ messages in thread
From: H. Peter Anvin @ 2012-12-12 16:45 UTC (permalink / raw)
To: Ville Syrjälä
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier
It's a good change -- and one which opens up even more unification -- but right now we're worried about 3.8.
"Ville Syrjälä" <ville.syrjala@linux.intel.com> wrote:
>On Wed, Dec 12, 2012 at 08:15:12AM -0800, H. Peter Anvin wrote:
>> Can we worry about this after the merge window?
>
>Sure. The only use I have for this is in my drm/kms atomic
>modeset/pageflip patch set, and that's not 3.8 material.
>
>>
>> ville.syrjala@linux.intel.com wrote:
>>
>> >From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >
>> >Implement __get_user_8() for x86-32. It will return the
>> >64bit result in edx:eax register pair, and ecx is used
>> >to pass in the address and return the error value.
>> >
>> >For consistency, change the register assignment for all
>> >other __get_user_x() variants, so that address is passed in
>> >ecx/rcx, the error value is returned in ecx/rcx, and eax/rax
>> >contains the actual value.
>> >
>> >This is a partial refresh of a patch [1] by Jamie Lokier from
>> >2004. Only the minimal changes to implement 64bit get_user()
>> >were picked from the original patch.
>> >
>> >[1] http://article.gmane.org/gmane.linux.kernel/198823
>> >
>> >Cc: Jamie Lokier <jamie@shareable.org>
>> >Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>> >---
>> > arch/x86/include/asm/uaccess.h | 17 ++++++--
>> > arch/x86/kernel/i386_ksyms_32.c | 1 +
>> >arch/x86/lib/getuser.S | 82
>> >++++++++++++++++++++++++++------------
>> > 3 files changed, 69 insertions(+), 31 deletions(-)
>> >
>> >diff --git a/arch/x86/include/asm/uaccess.h
>> >b/arch/x86/include/asm/uaccess.h
>> >index 7ccf8d1..3f4387e 100644
>> >--- a/arch/x86/include/asm/uaccess.h
>> >+++ b/arch/x86/include/asm/uaccess.h
>> >@@ -127,7 +127,7 @@ extern int __get_user_bad(void);
>> >
>> > #define __get_user_x(size, ret, x, ptr) \
>> > asm volatile("call __get_user_" #size \
>> >- : "=a" (ret), "=d" (x) \
>> >+ : "=c" (ret), "=a" (x) \
>> > : "0" (ptr)) \
>> >
>> > /* Careful: we have to cast the result to the type of the pointer
>> >@@ -151,8 +151,11 @@ extern int __get_user_bad(void);
>> > * On error, the variable @x is set to zero.
>> > */
>> > #ifdef CONFIG_X86_32
>> >-#define __get_user_8(__ret_gu, __val_gu, ptr) \
>> >- __get_user_x(X, __ret_gu, __val_gu, ptr)
>> >+#define __get_user_8(ret, x, ptr) \
>> >+ asm volatile("call __get_user_8" \
>> >+ : "=c" (ret), "=A" (x) \
>> >+ : "0" (ptr)) \
>> >+
>> > #else
>> > #define __get_user_8(__ret_gu, __val_gu, ptr) \
>> > __get_user_x(8, __ret_gu, __val_gu, ptr)
>> >@@ -162,6 +165,7 @@ extern int __get_user_bad(void);
>> > ({ \
>> > int __ret_gu; \
>> > unsigned long __val_gu; \
>> >+ unsigned long long __val_gu8; \
>> > __chk_user_ptr(ptr); \
>> > might_fault(); \
>> > switch (sizeof(*(ptr))) { \
>> >@@ -175,13 +179,16 @@ extern int __get_user_bad(void);
>> > __get_user_x(4, __ret_gu, __val_gu, ptr); \
>> > break; \
>> > case 8: \
>> >- __get_user_8(__ret_gu, __val_gu, ptr); \
>> >+ __get_user_8(__ret_gu, __val_gu8, ptr); \
>> > break; \
>> > default: \
>> > __get_user_x(X, __ret_gu, __val_gu, ptr); \
>> > break; \
>> > } \
>> >- (x) = (__typeof__(*(ptr)))__val_gu; \
>> >+ if (sizeof(*(ptr)) == 8) \
>> >+ (x) = (__typeof__(*(ptr)))__val_gu8; \
>> >+ else \
>> >+ (x) = (__typeof__(*(ptr)))__val_gu; \
>> > __ret_gu; \
>> > })
>> >
>> >diff --git a/arch/x86/kernel/i386_ksyms_32.c
>> >b/arch/x86/kernel/i386_ksyms_32.c
>> >index 9c3bd4a..0fa6912 100644
>> >--- a/arch/x86/kernel/i386_ksyms_32.c
>> >+++ b/arch/x86/kernel/i386_ksyms_32.c
>> >@@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
>> > EXPORT_SYMBOL(__get_user_1);
>> > EXPORT_SYMBOL(__get_user_2);
>> > EXPORT_SYMBOL(__get_user_4);
>> >+EXPORT_SYMBOL(__get_user_8);
>> >
>> > EXPORT_SYMBOL(__put_user_1);
>> > EXPORT_SYMBOL(__put_user_2);
>> >diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
>> >index 156b9c8..38afef0 100644
>> >--- a/arch/x86/lib/getuser.S
>> >+++ b/arch/x86/lib/getuser.S
>> >@@ -14,12 +14,11 @@
>> > /*
>> > * __get_user_X
>> > *
>> >- * Inputs: %[r|e]ax contains the address.
>> >- * The register is modified, but all changes are undone
>> >- * before returning because the C code doesn't know about it.
>> >+ * Inputs: %[r|e]cx contains the address.
>> > *
>> >- * Outputs: %[r|e]ax is error code (0 or -EFAULT)
>> >- * %[r|e]dx contains zero-extended value
>> >+ * Outputs: %[r|e]cx is error code (0 or -EFAULT)
>> >+ * %[r|e]ax contains zero-extended value
>> >+ * %edx contains the high bits of the value for __get_user_8 on
>> >x86-32
>> > *
>> > *
>> > * These functions should not modify any other registers,
>> >@@ -38,12 +37,12 @@
>> > .text
>> > ENTRY(__get_user_1)
>> > CFI_STARTPROC
>> >- GET_THREAD_INFO(%_ASM_DX)
>> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>> >+ GET_THREAD_INFO(%_ASM_AX)
>> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
>> > jae bad_get_user
>> > ASM_STAC
>> >-1: movzb (%_ASM_AX),%edx
>> >- xor %eax,%eax
>> >+1: movzb (%_ASM_CX),%eax
>> >+ xor %ecx,%ecx
>> > ASM_CLAC
>> > ret
>> > CFI_ENDPROC
>> >@@ -51,14 +50,14 @@ ENDPROC(__get_user_1)
>> >
>> > ENTRY(__get_user_2)
>> > CFI_STARTPROC
>> >- add $1,%_ASM_AX
>> >+ add $1,%_ASM_CX
>> > jc bad_get_user
>> >- GET_THREAD_INFO(%_ASM_DX)
>> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>> >+ GET_THREAD_INFO(%_ASM_AX)
>> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
>> > jae bad_get_user
>> > ASM_STAC
>> >-2: movzwl -1(%_ASM_AX),%edx
>> >- xor %eax,%eax
>> >+2: movzwl -1(%_ASM_CX),%eax
>> >+ xor %ecx,%ecx
>> > ASM_CLAC
>> > ret
>> > CFI_ENDPROC
>> >@@ -66,14 +65,14 @@ ENDPROC(__get_user_2)
>> >
>> > ENTRY(__get_user_4)
>> > CFI_STARTPROC
>> >- add $3,%_ASM_AX
>> >+ add $3,%_ASM_CX
>> > jc bad_get_user
>> >- GET_THREAD_INFO(%_ASM_DX)
>> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>> >+ GET_THREAD_INFO(%_ASM_AX)
>> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
>> > jae bad_get_user
>> > ASM_STAC
>> >-3: mov -3(%_ASM_AX),%edx
>> >- xor %eax,%eax
>> >+3: mov -3(%_ASM_CX),%eax
>> >+ xor %ecx,%ecx
>> > ASM_CLAC
>> > ret
>> > CFI_ENDPROC
>> >@@ -82,14 +81,30 @@ ENDPROC(__get_user_4)
>> > #ifdef CONFIG_X86_64
>> > ENTRY(__get_user_8)
>> > CFI_STARTPROC
>> >- add $7,%_ASM_AX
>> >+ add $7,%_ASM_CX
>> > jc bad_get_user
>> >- GET_THREAD_INFO(%_ASM_DX)
>> >- cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
>> >+ GET_THREAD_INFO(%_ASM_AX)
>> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
>> > jae bad_get_user
>> > ASM_STAC
>> >-4: movq -7(%_ASM_AX),%_ASM_DX
>> >- xor %eax,%eax
>> >+4: movq -7(%_ASM_CX),%_ASM_AX
>> >+ xor %ecx,%ecx
>> >+ ASM_CLAC
>> >+ ret
>> >+ CFI_ENDPROC
>> >+ENDPROC(__get_user_8)
>> >+#else
>> >+ENTRY(__get_user_8)
>> >+ CFI_STARTPROC
>> >+ add $7,%_ASM_CX
>> >+ jc bad_get_user_8
>> >+ GET_THREAD_INFO(%_ASM_AX)
>> >+ cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
>> >+ jae bad_get_user_8
>> >+ ASM_STAC
>> >+4: mov -7(%_ASM_CX),%eax
>> >+5: mov -3(%_ASM_CX),%edx
>> >+ xor %ecx,%ecx
>> > ASM_CLAC
>> > ret
>> > CFI_ENDPROC
>> >@@ -98,16 +113,31 @@ ENDPROC(__get_user_8)
>> >
>> > bad_get_user:
>> > CFI_STARTPROC
>> >- xor %edx,%edx
>> >- mov $(-EFAULT),%_ASM_AX
>> >+ xor %eax,%eax
>> >+ mov $(-EFAULT),%_ASM_CX
>> > ASM_CLAC
>> > ret
>> > CFI_ENDPROC
>> > END(bad_get_user)
>> >
>> >+#ifdef CONFIG_X86_32
>> >+bad_get_user_8:
>> >+ CFI_STARTPROC
>> >+ xor %eax,%eax
>> >+ xor %edx,%edx
>> >+ mov $(-EFAULT),%_ASM_CX
>> >+ ASM_CLAC
>> >+ ret
>> >+ CFI_ENDPROC
>> >+END(bad_get_user_8)
>> >+#endif
>> >+
>> > _ASM_EXTABLE(1b,bad_get_user)
>> > _ASM_EXTABLE(2b,bad_get_user)
>> > _ASM_EXTABLE(3b,bad_get_user)
>> > #ifdef CONFIG_X86_64
>> > _ASM_EXTABLE(4b,bad_get_user)
>> >+#else
>> >+ _ASM_EXTABLE(4b,bad_get_user_8)
>> >+ _ASM_EXTABLE(5b,bad_get_user_8)
>> > #endif
>>
>> --
>> Sent from my mobile phone. Please excuse brevity and lack of
>formatting.
--
Sent from my mobile phone. Please excuse brevity and lack of formatting.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2012-12-12 11:34 [PATCH] x86: Add support for 64bit get_user() on x86-32 ville.syrjala
2012-12-12 16:15 ` H. Peter Anvin
@ 2013-02-07 16:53 ` Ville Syrjälä
2013-02-07 17:59 ` H. Peter Anvin
1 sibling, 1 reply; 39+ messages in thread
From: Ville Syrjälä @ 2013-02-07 16:53 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
Linus Torvalds, Jamie Lokier
On Wed, Dec 12, 2012 at 01:34:03PM +0200, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> Implement __get_user_8() for x86-32. It will return the
> 64bit result in edx:eax register pair, and ecx is used
> to pass in the address and return the error value.
>
> For consistency, change the register assignment for all
> other __get_user_x() variants, so that address is passed in
> ecx/rcx, the error value is returned in ecx/rcx, and eax/rax
> contains the actual value.
>
> This is a partial refresh of a patch [1] by Jamie Lokier from
> 2004. Only the minimal changes to implement 64bit get_user()
> were picked from the original patch.
>
> [1] http://article.gmane.org/gmane.linux.kernel/198823
Ping. I pretty much forgot about this patch since I posted it.
Based on the initial response there seems to be some interest towards
it at least. So I'm wondering what's the next step. Is it OK as is,
or does it need more work, or would people want to extend it to include
more of the original work?
I have quite a lot of other stuff on my plate currently, so it'd
actually be nice if I could find someone to adopt this patch,
especially if there's interest in increasing the scope.
> Cc: Jamie Lokier <jamie@shareable.org>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
> arch/x86/include/asm/uaccess.h | 17 ++++++--
> arch/x86/kernel/i386_ksyms_32.c | 1 +
> arch/x86/lib/getuser.S | 82 ++++++++++++++++++++++++++------------
> 3 files changed, 69 insertions(+), 31 deletions(-)
>
> diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
> index 7ccf8d1..3f4387e 100644
> --- a/arch/x86/include/asm/uaccess.h
> +++ b/arch/x86/include/asm/uaccess.h
> @@ -127,7 +127,7 @@ extern int __get_user_bad(void);
>
> #define __get_user_x(size, ret, x, ptr) \
> asm volatile("call __get_user_" #size \
> - : "=a" (ret), "=d" (x) \
> + : "=c" (ret), "=a" (x) \
> : "0" (ptr)) \
>
> /* Careful: we have to cast the result to the type of the pointer
> @@ -151,8 +151,11 @@ extern int __get_user_bad(void);
> * On error, the variable @x is set to zero.
> */
> #ifdef CONFIG_X86_32
> -#define __get_user_8(__ret_gu, __val_gu, ptr) \
> - __get_user_x(X, __ret_gu, __val_gu, ptr)
> +#define __get_user_8(ret, x, ptr) \
> + asm volatile("call __get_user_8" \
> + : "=c" (ret), "=A" (x) \
> + : "0" (ptr)) \
> +
> #else
> #define __get_user_8(__ret_gu, __val_gu, ptr) \
> __get_user_x(8, __ret_gu, __val_gu, ptr)
> @@ -162,6 +165,7 @@ extern int __get_user_bad(void);
> ({ \
> int __ret_gu; \
> unsigned long __val_gu; \
> + unsigned long long __val_gu8; \
> __chk_user_ptr(ptr); \
> might_fault(); \
> switch (sizeof(*(ptr))) { \
> @@ -175,13 +179,16 @@ extern int __get_user_bad(void);
> __get_user_x(4, __ret_gu, __val_gu, ptr); \
> break; \
> case 8: \
> - __get_user_8(__ret_gu, __val_gu, ptr); \
> + __get_user_8(__ret_gu, __val_gu8, ptr); \
> break; \
> default: \
> __get_user_x(X, __ret_gu, __val_gu, ptr); \
> break; \
> } \
> - (x) = (__typeof__(*(ptr)))__val_gu; \
> + if (sizeof(*(ptr)) == 8) \
> + (x) = (__typeof__(*(ptr)))__val_gu8; \
> + else \
> + (x) = (__typeof__(*(ptr)))__val_gu; \
> __ret_gu; \
> })
>
> diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c
> index 9c3bd4a..0fa6912 100644
> --- a/arch/x86/kernel/i386_ksyms_32.c
> +++ b/arch/x86/kernel/i386_ksyms_32.c
> @@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
> EXPORT_SYMBOL(__get_user_1);
> EXPORT_SYMBOL(__get_user_2);
> EXPORT_SYMBOL(__get_user_4);
> +EXPORT_SYMBOL(__get_user_8);
>
> EXPORT_SYMBOL(__put_user_1);
> EXPORT_SYMBOL(__put_user_2);
> diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
> index 156b9c8..38afef0 100644
> --- a/arch/x86/lib/getuser.S
> +++ b/arch/x86/lib/getuser.S
> @@ -14,12 +14,11 @@
> /*
> * __get_user_X
> *
> - * Inputs: %[r|e]ax contains the address.
> - * The register is modified, but all changes are undone
> - * before returning because the C code doesn't know about it.
> + * Inputs: %[r|e]cx contains the address.
> *
> - * Outputs: %[r|e]ax is error code (0 or -EFAULT)
> - * %[r|e]dx contains zero-extended value
> + * Outputs: %[r|e]cx is error code (0 or -EFAULT)
> + * %[r|e]ax contains zero-extended value
> + * %edx contains the high bits of the value for __get_user_8 on x86-32
> *
> *
> * These functions should not modify any other registers,
> @@ -38,12 +37,12 @@
> .text
> ENTRY(__get_user_1)
> CFI_STARTPROC
> - GET_THREAD_INFO(%_ASM_DX)
> - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> + GET_THREAD_INFO(%_ASM_AX)
> + cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
> -1: movzb (%_ASM_AX),%edx
> - xor %eax,%eax
> +1: movzb (%_ASM_CX),%eax
> + xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
> @@ -51,14 +50,14 @@ ENDPROC(__get_user_1)
>
> ENTRY(__get_user_2)
> CFI_STARTPROC
> - add $1,%_ASM_AX
> + add $1,%_ASM_CX
> jc bad_get_user
> - GET_THREAD_INFO(%_ASM_DX)
> - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> + GET_THREAD_INFO(%_ASM_AX)
> + cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
> -2: movzwl -1(%_ASM_AX),%edx
> - xor %eax,%eax
> +2: movzwl -1(%_ASM_CX),%eax
> + xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
> @@ -66,14 +65,14 @@ ENDPROC(__get_user_2)
>
> ENTRY(__get_user_4)
> CFI_STARTPROC
> - add $3,%_ASM_AX
> + add $3,%_ASM_CX
> jc bad_get_user
> - GET_THREAD_INFO(%_ASM_DX)
> - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> + GET_THREAD_INFO(%_ASM_AX)
> + cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
> -3: mov -3(%_ASM_AX),%edx
> - xor %eax,%eax
> +3: mov -3(%_ASM_CX),%eax
> + xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
> @@ -82,14 +81,30 @@ ENDPROC(__get_user_4)
> #ifdef CONFIG_X86_64
> ENTRY(__get_user_8)
> CFI_STARTPROC
> - add $7,%_ASM_AX
> + add $7,%_ASM_CX
> jc bad_get_user
> - GET_THREAD_INFO(%_ASM_DX)
> - cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
> + GET_THREAD_INFO(%_ASM_AX)
> + cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> jae bad_get_user
> ASM_STAC
> -4: movq -7(%_ASM_AX),%_ASM_DX
> - xor %eax,%eax
> +4: movq -7(%_ASM_CX),%_ASM_AX
> + xor %ecx,%ecx
> + ASM_CLAC
> + ret
> + CFI_ENDPROC
> +ENDPROC(__get_user_8)
> +#else
> +ENTRY(__get_user_8)
> + CFI_STARTPROC
> + add $7,%_ASM_CX
> + jc bad_get_user_8
> + GET_THREAD_INFO(%_ASM_AX)
> + cmp TI_addr_limit(%_ASM_AX),%_ASM_CX
> + jae bad_get_user_8
> + ASM_STAC
> +4: mov -7(%_ASM_CX),%eax
> +5: mov -3(%_ASM_CX),%edx
> + xor %ecx,%ecx
> ASM_CLAC
> ret
> CFI_ENDPROC
> @@ -98,16 +113,31 @@ ENDPROC(__get_user_8)
>
> bad_get_user:
> CFI_STARTPROC
> - xor %edx,%edx
> - mov $(-EFAULT),%_ASM_AX
> + xor %eax,%eax
> + mov $(-EFAULT),%_ASM_CX
> ASM_CLAC
> ret
> CFI_ENDPROC
> END(bad_get_user)
>
> +#ifdef CONFIG_X86_32
> +bad_get_user_8:
> + CFI_STARTPROC
> + xor %eax,%eax
> + xor %edx,%edx
> + mov $(-EFAULT),%_ASM_CX
> + ASM_CLAC
> + ret
> + CFI_ENDPROC
> +END(bad_get_user_8)
> +#endif
> +
> _ASM_EXTABLE(1b,bad_get_user)
> _ASM_EXTABLE(2b,bad_get_user)
> _ASM_EXTABLE(3b,bad_get_user)
> #ifdef CONFIG_X86_64
> _ASM_EXTABLE(4b,bad_get_user)
> +#else
> + _ASM_EXTABLE(4b,bad_get_user_8)
> + _ASM_EXTABLE(5b,bad_get_user_8)
> #endif
> --
> 1.7.8.6
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-07 16:53 ` Ville Syrjälä
@ 2013-02-07 17:59 ` H. Peter Anvin
2013-02-08 16:24 ` Ville Syrjälä
0 siblings, 1 reply; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-07 17:59 UTC (permalink / raw)
To: Ville Syrjälä
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier
On 02/07/2013 08:53 AM, Ville Syrjälä wrote:
>
> Based on the initial response there seems to be some interest towards
> it at least. So I'm wondering what's the next step. Is it OK as is,
> or does it need more work, or would people want to extend it to include
> more of the original work?
>
> I have quite a lot of other stuff on my plate currently, so it'd
> actually be nice if I could find someone to adopt this patch,
> especially if there's interest in increasing the scope.
>
Well, we can put it in and see what happens. It looks good from what I
can see.
How have you tested it?
-hpa
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-07 17:59 ` H. Peter Anvin
@ 2013-02-08 16:24 ` Ville Syrjälä
2013-02-08 17:30 ` H. Peter Anvin
0 siblings, 1 reply; 39+ messages in thread
From: Ville Syrjälä @ 2013-02-08 16:24 UTC (permalink / raw)
To: H. Peter Anvin
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier
On Thu, Feb 07, 2013 at 09:59:00AM -0800, H. Peter Anvin wrote:
> On 02/07/2013 08:53 AM, Ville Syrjälä wrote:
> >
> > Based on the initial response there seems to be some interest towards
> > it at least. So I'm wondering what's the next step. Is it OK as is,
> > or does it need more work, or would people want to extend it to include
> > more of the original work?
> >
> > I have quite a lot of other stuff on my plate currently, so it'd
> > actually be nice if I could find someone to adopt this patch,
> > especially if there's interest in increasing the scope.
> >
>
> Well, we can put it in and see what happens. It looks good from what I
> can see.
>
> How have you tested it?
I've tried it with my drm/kms atomic pageflip/modeset code. I also had
a small test module that did a couple of different sized get_user()
calls, but I'll be damned if I can find it again.
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-08 16:24 ` Ville Syrjälä
@ 2013-02-08 17:30 ` H. Peter Anvin
2013-02-08 18:23 ` Ville Syrjälä
0 siblings, 1 reply; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-08 17:30 UTC (permalink / raw)
To: Ville Syrjälä
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier, Russell King
On 02/08/2013 08:24 AM, Ville Syrjälä wrote:
>>
>> How have you tested it?
>
> I've tried it with my drm/kms atomic pageflip/modeset code. I also had
> a small test module that did a couple of different sized get_user()
> calls, but I'll be damned if I can find it again.
>
Did you see the warning spewage for pointers when you built it?
-hpa
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-08 17:30 ` H. Peter Anvin
@ 2013-02-08 18:23 ` Ville Syrjälä
2013-02-08 19:08 ` H. Peter Anvin
0 siblings, 1 reply; 39+ messages in thread
From: Ville Syrjälä @ 2013-02-08 18:23 UTC (permalink / raw)
To: H. Peter Anvin
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier, Russell King
On Fri, Feb 08, 2013 at 09:30:05AM -0800, H. Peter Anvin wrote:
> On 02/08/2013 08:24 AM, Ville Syrjälä wrote:
> >>
> >> How have you tested it?
> >
> > I've tried it with my drm/kms atomic pageflip/modeset code. I also had
> > a small test module that did a couple of different sized get_user()
> > calls, but I'll be damned if I can find it again.
> >
>
> Did you see the warning spewage for pointers when you built it?
Apparently my config was too small to genenerate enough of those to catch
my eye. Most of those seem to come from drivers that have pointers in their
ioctl structs, no?
--
Ville Syrjälä
Intel OTC
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-08 18:23 ` Ville Syrjälä
@ 2013-02-08 19:08 ` H. Peter Anvin
2013-02-09 10:41 ` Borislav Petkov
0 siblings, 1 reply; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-08 19:08 UTC (permalink / raw)
To: Ville Syrjälä
Cc: linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier, Russell King
Yes, or anything else getting a pointer in memory from user space.
"Ville Syrjälä" <ville.syrjala@linux.intel.com> wrote:
>On Fri, Feb 08, 2013 at 09:30:05AM -0800, H. Peter Anvin wrote:
>> On 02/08/2013 08:24 AM, Ville Syrjälä wrote:
>> >>
>> >> How have you tested it?
>> >
>> > I've tried it with my drm/kms atomic pageflip/modeset code. I also
>had
>> > a small test module that did a couple of different sized get_user()
>> > calls, but I'll be damned if I can find it again.
>> >
>>
>> Did you see the warning spewage for pointers when you built it?
>
>Apparently my config was too small to genenerate enough of those to
>catch
>my eye. Most of those seem to come from drivers that have pointers in
>their
>ioctl structs, no?
--
Sent from my mobile phone. Please excuse brevity and lack of formatting.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-08 19:08 ` H. Peter Anvin
@ 2013-02-09 10:41 ` Borislav Petkov
2013-02-09 11:00 ` Russell King - ARM Linux
0 siblings, 1 reply; 39+ messages in thread
From: Borislav Petkov @ 2013-02-09 10:41 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Ville Syrjälä,
linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier, Russell King
On Fri, Feb 08, 2013 at 11:08:52AM -0800, H. Peter Anvin wrote:
> Yes, or anything else getting a pointer in memory from user space.
Here are some more from a 32-bit build here:
fs/exec.c: In function ‘get_user_arg_ptr’:
fs/exec.c:414:6: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
fs/splice.c: In function ‘vmsplice_to_user’:
fs/splice.c:1556:11: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
ipc/syscall.c: In function ‘sys_ipc’:
ipc/syscall.c:39:7: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Thanks.
--
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH] x86: Add support for 64bit get_user() on x86-32
2013-02-09 10:41 ` Borislav Petkov
@ 2013-02-09 11:00 ` Russell King - ARM Linux
2013-02-12 1:37 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings tip-bot for H. Peter Anvin
0 siblings, 1 reply; 39+ messages in thread
From: Russell King - ARM Linux @ 2013-02-09 11:00 UTC (permalink / raw)
To: Borislav Petkov
Cc: H. Peter Anvin, Ville Syrjälä,
linux-kernel, x86, Thomas Gleixner, Ingo Molnar, Linus Torvalds,
Jamie Lokier
On Sat, Feb 09, 2013 at 11:41:42AM +0100, Borislav Petkov wrote:
> On Fri, Feb 08, 2013 at 11:08:52AM -0800, H. Peter Anvin wrote:
> > Yes, or anything else getting a pointer in memory from user space.
>
> Here are some more from a 32-bit build here:
>
> fs/exec.c: In function ‘get_user_arg_ptr’:
> fs/exec.c:414:6: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> fs/splice.c: In function ‘vmsplice_to_user’:
> fs/splice.c:1556:11: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
> ipc/syscall.c: In function ‘sys_ipc’:
> ipc/syscall.c:39:7: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Note that there's no need to build the entire tree to check for these -
you just need to have enough test cases which cover those found in the
kernel.
The set of test functions I replied with on the previous thread covers
all the cases I'm aware of in the kernel that matter, and should be
warning free except for the final test function (which is there to check
that the typechecking in get_user() does work.)
^ permalink raw reply [flat|nested] 39+ messages in thread
* [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-09 11:00 ` Russell King - ARM Linux
@ 2013-02-12 1:37 ` tip-bot for H. Peter Anvin
2013-02-12 3:33 ` Linus Torvalds
0 siblings, 1 reply; 39+ messages in thread
From: tip-bot for H. Peter Anvin @ 2013-02-12 1:37 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, torvalds, jamie, ville.syrjala, bp,
linux, tglx
Commit-ID: b390784dc1649f6e6c5e66e5f53c21e715ccf39b
Gitweb: http://git.kernel.org/tip/b390784dc1649f6e6c5e66e5f53c21e715ccf39b
Author: H. Peter Anvin <hpa@zytor.com>
AuthorDate: Mon, 11 Feb 2013 16:27:28 -0800
Committer: H. Peter Anvin <hpa@zytor.com>
CommitDate: Mon, 11 Feb 2013 17:26:51 -0800
x86, mm: Use a bitfield to mask nuisance get_user() warnings
Even though it is never executed, gcc wants to warn for casting from
a large integer to a pointer. Furthermore, using a variable with
__typeof__() doesn't work because __typeof__ retains storage
specifiers (const, restrict, volatile).
However, we can declare a bitfield using sizeof(), which is legal
because sizeof() is a constant expression. This quiets the warning,
although the code generated isn't 100% identical from the baseline
before 96477b4 x86-32: Add support for 64bit get_user():
[x86-mb is baseline, x86-mm is this commit]
text data bss filename
113716147 15858380 35037184 tip.x86-mb/o.i386-allconfig/vmlinux
113716145 15858380 35037184 tip.x86-mm/o.i386-allconfig/vmlinux
12989837 3597944 12255232 tip.x86-mb/o.i386-modconfig/vmlinux
12989831 3597944 12255232 tip.x86-mm/o.i386-modconfig/vmlinux
1462784 237608 1401988 tip.x86-mb/o.i386-noconfig/vmlinux
1462837 237608 1401964 tip.x86-mm/o.i386-noconfig/vmlinux
7938994 553688 7639040 tip.x86-mb/o.i386-pae/vmlinux
7943136 557784 7639040 tip.x86-mm/o.i386-pae/vmlinux
7186126 510572 6574080 tip.x86-mb/o.i386/vmlinux
7186124 510572 6574080 tip.x86-mm/o.i386/vmlinux
103747269 33578856 65888256 tip.x86-mb/o.x86_64-allconfig/vmlinux
103746949 33578856 65888256 tip.x86-mm/o.x86_64-allconfig/vmlinux
12116695 11035832 20160512 tip.x86-mb/o.x86_64-modconfig/vmlinux
12116567 11035832 20160512 tip.x86-mm/o.x86_64-modconfig/vmlinux
1700790 380524 511808 tip.x86-mb/o.x86_64-noconfig/vmlinux
1700790 380524 511808 tip.x86-mm/o.x86_64-noconfig/vmlinux
12413612 1133376 1101824 tip.x86-mb/o.x86_64/vmlinux
12413484 1133376 1101824 tip.x86-mm/o.x86_64/vmlinux
Cc: Jamie Lokier <jamie@shareable.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20130209110031.GA17833@n2100.arm.linux.org.uk
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
---
arch/x86/include/asm/uaccess.h | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 1e96326..a8d1265 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -168,31 +168,29 @@ do { \
#define get_user(x, ptr) \
({ \
int __ret_gu; \
- unsigned long __val_gu; \
- unsigned long long __val_gu8; \
+ struct { \
+ unsigned long long __val_n : 8*sizeof(*(ptr)); \
+ } __val_gu; \
__chk_user_ptr(ptr); \
might_fault(); \
switch (sizeof(*(ptr))) { \
case 1: \
- __get_user_x(1, __ret_gu, __val_gu, ptr); \
+ __get_user_x(1, __ret_gu, __val_gu.__val_n, ptr); \
break; \
case 2: \
- __get_user_x(2, __ret_gu, __val_gu, ptr); \
+ __get_user_x(2, __ret_gu, __val_gu.__val_n, ptr); \
break; \
case 4: \
- __get_user_x(4, __ret_gu, __val_gu, ptr); \
+ __get_user_x(4, __ret_gu, __val_gu.__val_n, ptr); \
break; \
case 8: \
- __get_user_8(__ret_gu, __val_gu8, ptr); \
+ __get_user_8(__ret_gu, __val_gu.__val_n, ptr); \
break; \
default: \
- __get_user_x(X, __ret_gu, __val_gu, ptr); \
+ __get_user_x(X, __ret_gu, __val_gu.__val_n, ptr); \
break; \
} \
- if (sizeof(*(ptr)) == 8) \
- (x) = (__typeof__(*(ptr)))__val_gu8; \
- else \
- (x) = (__typeof__(*(ptr)))__val_gu; \
+ (x) = (__typeof__(*(ptr)))__val_gu.__val_n; \
__ret_gu; \
})
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 1:37 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings tip-bot for H. Peter Anvin
@ 2013-02-12 3:33 ` Linus Torvalds
2013-02-12 4:21 ` H. Peter Anvin
0 siblings, 1 reply; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 3:33 UTC (permalink / raw)
To: Ingo Molnar, H. Peter Anvin, Linux Kernel Mailing List,
Jamie Lokier, Linus Torvalds, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner
Cc: linux-tip-commits
On Mon, Feb 11, 2013 at 5:37 PM, tip-bot for H. Peter Anvin
<hpa@zytor.com> wrote:
>
> However, we can declare a bitfield using sizeof(), which is legal
> because sizeof() is a constant expression. This quiets the warning,
> although the code generated isn't 100% identical from the baseline
> before 96477b4 x86-32: Add support for 64bit get_user():
Christ. This is so ugly that it's almost a work of art.
Has anybody run this past any gcc developers? And if so, did they run
away screaming?
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 3:33 ` Linus Torvalds
@ 2013-02-12 4:21 ` H. Peter Anvin
2013-02-12 4:42 ` Linus Torvalds
` (2 more replies)
0 siblings, 3 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 4:21 UTC (permalink / raw)
To: Linus Torvalds
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits, H.J. Lu
[-- Attachment #1: Type: text/plain, Size: 623 bytes --]
On 02/11/2013 07:33 PM, Linus Torvalds wrote:
> On Mon, Feb 11, 2013 at 5:37 PM, tip-bot for H. Peter Anvin
> <hpa@zytor.com> wrote:
>>
>> However, we can declare a bitfield using sizeof(), which is legal
>> because sizeof() is a constant expression. This quiets the warning,
>> although the code generated isn't 100% identical from the baseline
>> before 96477b4 x86-32: Add support for 64bit get_user():
>
> Christ. This is so ugly that it's almost a work of art.
:)
> Has anybody run this past any gcc developers? And if so, did they run
> away screaming?
I haven't no... H.J., any comments on this patch?
-hpa
[-- Attachment #2: Attached Message --]
[-- Type: message/rfc822, Size: 6168 bytes --]
From: "tip-bot for H. Peter Anvin" <hpa@zytor.com>
To: linux-tip-commits@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, hpa@zytor.com, mingo@kernel.org, torvalds@linux-foundation.org, jamie@shareable.org, ville.syrjala@linux.intel.com, bp@alien8.de, linux@arm.linux.org.uk, tglx@linutronix.de
Subject: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
Date: Mon, 11 Feb 2013 17:37:52 -0800
Message-ID: <tip-b390784dc1649f6e6c5e66e5f53c21e715ccf39b@git.kernel.org>
Commit-ID: b390784dc1649f6e6c5e66e5f53c21e715ccf39b
Gitweb: http://git.kernel.org/tip/b390784dc1649f6e6c5e66e5f53c21e715ccf39b
Author: H. Peter Anvin <hpa@zytor.com>
AuthorDate: Mon, 11 Feb 2013 16:27:28 -0800
Committer: H. Peter Anvin <hpa@zytor.com>
CommitDate: Mon, 11 Feb 2013 17:26:51 -0800
x86, mm: Use a bitfield to mask nuisance get_user() warnings
Even though it is never executed, gcc wants to warn for casting from
a large integer to a pointer. Furthermore, using a variable with
__typeof__() doesn't work because __typeof__ retains storage
specifiers (const, restrict, volatile).
However, we can declare a bitfield using sizeof(), which is legal
because sizeof() is a constant expression. This quiets the warning,
although the code generated isn't 100% identical from the baseline
before 96477b4 x86-32: Add support for 64bit get_user():
[x86-mb is baseline, x86-mm is this commit]
text data bss filename
113716147 15858380 35037184 tip.x86-mb/o.i386-allconfig/vmlinux
113716145 15858380 35037184 tip.x86-mm/o.i386-allconfig/vmlinux
12989837 3597944 12255232 tip.x86-mb/o.i386-modconfig/vmlinux
12989831 3597944 12255232 tip.x86-mm/o.i386-modconfig/vmlinux
1462784 237608 1401988 tip.x86-mb/o.i386-noconfig/vmlinux
1462837 237608 1401964 tip.x86-mm/o.i386-noconfig/vmlinux
7938994 553688 7639040 tip.x86-mb/o.i386-pae/vmlinux
7943136 557784 7639040 tip.x86-mm/o.i386-pae/vmlinux
7186126 510572 6574080 tip.x86-mb/o.i386/vmlinux
7186124 510572 6574080 tip.x86-mm/o.i386/vmlinux
103747269 33578856 65888256 tip.x86-mb/o.x86_64-allconfig/vmlinux
103746949 33578856 65888256 tip.x86-mm/o.x86_64-allconfig/vmlinux
12116695 11035832 20160512 tip.x86-mb/o.x86_64-modconfig/vmlinux
12116567 11035832 20160512 tip.x86-mm/o.x86_64-modconfig/vmlinux
1700790 380524 511808 tip.x86-mb/o.x86_64-noconfig/vmlinux
1700790 380524 511808 tip.x86-mm/o.x86_64-noconfig/vmlinux
12413612 1133376 1101824 tip.x86-mb/o.x86_64/vmlinux
12413484 1133376 1101824 tip.x86-mm/o.x86_64/vmlinux
Cc: Jamie Lokier <jamie@shareable.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: http://lkml.kernel.org/r/20130209110031.GA17833@n2100.arm.linux.org.uk
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
---
arch/x86/include/asm/uaccess.h | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 1e96326..a8d1265 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -168,31 +168,29 @@ do { \
#define get_user(x, ptr) \
({ \
int __ret_gu; \
- unsigned long __val_gu; \
- unsigned long long __val_gu8; \
+ struct { \
+ unsigned long long __val_n : 8*sizeof(*(ptr)); \
+ } __val_gu; \
__chk_user_ptr(ptr); \
might_fault(); \
switch (sizeof(*(ptr))) { \
case 1: \
- __get_user_x(1, __ret_gu, __val_gu, ptr); \
+ __get_user_x(1, __ret_gu, __val_gu.__val_n, ptr); \
break; \
case 2: \
- __get_user_x(2, __ret_gu, __val_gu, ptr); \
+ __get_user_x(2, __ret_gu, __val_gu.__val_n, ptr); \
break; \
case 4: \
- __get_user_x(4, __ret_gu, __val_gu, ptr); \
+ __get_user_x(4, __ret_gu, __val_gu.__val_n, ptr); \
break; \
case 8: \
- __get_user_8(__ret_gu, __val_gu8, ptr); \
+ __get_user_8(__ret_gu, __val_gu.__val_n, ptr); \
break; \
default: \
- __get_user_x(X, __ret_gu, __val_gu, ptr); \
+ __get_user_x(X, __ret_gu, __val_gu.__val_n, ptr); \
break; \
} \
- if (sizeof(*(ptr)) == 8) \
- (x) = (__typeof__(*(ptr)))__val_gu8; \
- else \
- (x) = (__typeof__(*(ptr)))__val_gu; \
+ (x) = (__typeof__(*(ptr)))__val_gu.__val_n; \
__ret_gu; \
})
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 4:21 ` H. Peter Anvin
@ 2013-02-12 4:42 ` Linus Torvalds
2013-02-12 4:47 ` Linus Torvalds
2013-02-12 8:10 ` Ingo Molnar
2013-02-12 16:38 ` H.J. Lu
2 siblings, 1 reply; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 4:42 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits, H.J. Lu
On Mon, Feb 11, 2013 at 8:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 02/11/2013 07:33 PM, Linus Torvalds wrote:
>
>> Has anybody run this past any gcc developers? And if so, did they run
>> away screaming?
>
> I haven't no... H.J., any comments on this patch?
I'd be most worried about any known pitfalls about bitfield code
generation. Looking at your code size numbers, it actually seems to
*improve* code generation except for the odd i386.pae case (bigger
code but also a different data size - odd) and i386 noconfig
(different bss, bigger code).
The code/data changes makes me wonder if the variable sometimes gets
flushed to memory as a 8-byte entry, and maybe there are things gcc
people can suggest..
But I don't see anything fundamentally wrong with it. Certainly it
looks much better than the disgusting and warning-prone
unsigned long long __val_gu8
thing.
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 4:42 ` Linus Torvalds
@ 2013-02-12 4:47 ` Linus Torvalds
2013-02-12 4:51 ` H. Peter Anvin
2013-02-12 7:12 ` H. Peter Anvin
0 siblings, 2 replies; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 4:47 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits, H.J. Lu
On Mon, Feb 11, 2013 at 8:42 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> But I don't see anything fundamentally wrong with it. Certainly it
> looks much better than the disgusting and warning-prone
>
> unsigned long long __val_gu8
>
> thing.
Oh. I just realized. That was your _baseline_ in the comparisons, wasn't it?
Can you please make the baseline be the current mainline git version
of <asm/uaccess.h>, not the first "unsigned long long __val_gu8"
version of the 64-bit get_user()?
Because we should compare against the straightforward code, not the
one that could have messed things up already..
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 4:47 ` Linus Torvalds
@ 2013-02-12 4:51 ` H. Peter Anvin
2013-02-12 7:12 ` H. Peter Anvin
1 sibling, 0 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 4:51 UTC (permalink / raw)
To: Linus Torvalds
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits, H.J. Lu
On 02/11/2013 08:47 PM, Linus Torvalds wrote:
> On Mon, Feb 11, 2013 at 8:42 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
>>
>> But I don't see anything fundamentally wrong with it. Certainly it
>> looks much better than the disgusting and warning-prone
>>
>> unsigned long long __val_gu8
>>
>> thing.
>
> Oh. I just realized. That was your _baseline_ in the comparisons, wasn't it?
>
> Can you please make the baseline be the current mainline git version
> of <asm/uaccess.h>, not the first "unsigned long long __val_gu8"
> version of the 64-bit get_user()?
>
> Because we should compare against the straightforward code, not the
> one that could have messed things up already..
>
No, the baseline was x86/mm before *any* of the 64-bit get_user() stuff
were applied.
Very small differences can often be slight differences in strings (which
end up in .rodata and thus count as text as far as size is concerned ...
things like pathnames and dates.) I am unclear about why the i386-pae
build case stood out like that.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 4:47 ` Linus Torvalds
2013-02-12 4:51 ` H. Peter Anvin
@ 2013-02-12 7:12 ` H. Peter Anvin
1 sibling, 0 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 7:12 UTC (permalink / raw)
To: Linus Torvalds
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits, H.J. Lu
Just to be sure, I re-ran the comparison using gcc 4.6.3 instead of gcc
4.7.2. With gcc 4.6.3 I consistently get a few hundred bytes longer
with the bitfield variant than with the pre-get_user() baseline.
I looked at some of the diffed disassembly, and the differences seem to
be in the code generated downstream of __get_user_1 and __get_user_2,
which I guess is to be expected, mostly in the form of padding.
Annoyingly enough in *both* cases I found unnecessary instructions like:
+c12f6fbb: 0f b7 d2 movzwl %dx,%edx
-hpa
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 4:21 ` H. Peter Anvin
2013-02-12 4:42 ` Linus Torvalds
@ 2013-02-12 8:10 ` Ingo Molnar
2013-02-12 16:38 ` H.J. Lu
2 siblings, 0 replies; 39+ messages in thread
From: Ingo Molnar @ 2013-02-12 8:10 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Linus Torvalds, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits, H.J. Lu
* H. Peter Anvin <hpa@zytor.com> wrote:
> On 02/11/2013 07:33 PM, Linus Torvalds wrote:
> > On Mon, Feb 11, 2013 at 5:37 PM, tip-bot for H. Peter Anvin
> > <hpa@zytor.com> wrote:
> >>
> >> However, we can declare a bitfield using sizeof(), which is legal
> >> because sizeof() is a constant expression. This quiets the warning,
> >> although the code generated isn't 100% identical from the baseline
> >> before 96477b4 x86-32: Add support for 64bit get_user():
> >
> > Christ. This is so ugly that it's almost a work of art.
>
> :)
A real possibility would be that if this ever breaks in a GCC
version, or generates some really crappy code, we might get a
"you got what you asked for" shrug from GCC developers?
It's not like we could start a revolution over that.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 4:21 ` H. Peter Anvin
2013-02-12 4:42 ` Linus Torvalds
2013-02-12 8:10 ` Ingo Molnar
@ 2013-02-12 16:38 ` H.J. Lu
2013-02-12 17:00 ` Linus Torvalds
2 siblings, 1 reply; 39+ messages in thread
From: H.J. Lu @ 2013-02-12 16:38 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Linus Torvalds, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, linux-tip-commits
On Mon, Feb 11, 2013 at 8:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 02/11/2013 07:33 PM, Linus Torvalds wrote:
>> On Mon, Feb 11, 2013 at 5:37 PM, tip-bot for H. Peter Anvin
>> <hpa@zytor.com> wrote:
>>>
>>> However, we can declare a bitfield using sizeof(), which is legal
>>> because sizeof() is a constant expression. This quiets the warning,
>>> although the code generated isn't 100% identical from the baseline
>>> before 96477b4 x86-32: Add support for 64bit get_user():
>>
>> Christ. This is so ugly that it's almost a work of art.
>
> :)
>
>> Has anybody run this past any gcc developers? And if so, did they run
>> away screaming?
>
> I haven't no... H.J., any comments on this patch?
>
Can you do something similar to what we did in glibc:
http://sourceware.org/git/?p=glibc.git;a=patch;h=c515fb5148f1d81d5f7736825e14c7502c15432a
--
H.J.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 16:38 ` H.J. Lu
@ 2013-02-12 17:00 ` Linus Torvalds
2013-02-12 17:14 ` H. Peter Anvin
0 siblings, 1 reply; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 17:00 UTC (permalink / raw)
To: H.J. Lu
Cc: H. Peter Anvin, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, linux-tip-commits
On Tue, Feb 12, 2013 at 8:38 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>
> Can you do something similar to what we did in glibc:
No. Because we use macros to be type-independent (i e"get_user()"
works *regardless* of type), so casting to "uintptr_t" doesn't work.
It throws away the type information, and truncates 64-bit values on
32-bit architectures.
The whole point of the bitmask thing is that it doesn't have that
issue, and gets the size correct automatically. It's not pretty, but
it allows the rest of the sources to be readable.
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:00 ` Linus Torvalds
@ 2013-02-12 17:14 ` H. Peter Anvin
2013-02-12 17:30 ` H.J. Lu
2013-02-12 17:32 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings Linus Torvalds
0 siblings, 2 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 17:14 UTC (permalink / raw)
To: Linus Torvalds
Cc: H.J. Lu, Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits
On 02/12/2013 09:00 AM, Linus Torvalds wrote:
> On Tue, Feb 12, 2013 at 8:38 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>
>> Can you do something similar to what we did in glibc:
>
> No. Because we use macros to be type-independent (i e"get_user()"
> works *regardless* of type), so casting to "uintptr_t" doesn't work.
> It throws away the type information, and truncates 64-bit values on
> 32-bit architectures.
>
> The whole point of the bitmask thing is that it doesn't have that
> issue, and gets the size correct automatically. It's not pretty, but
> it allows the rest of the sources to be readable.
>
No, I think what he is talking about it this bit:
/* 1 if 'type' is a pointer type, 0 otherwise. */
# define __pointer_type(type) (__builtin_classify_type ((type) 0) == 5)
/* __intptr_t if P is true, or T if P is false. */
# define __integer_if_pointer_type_sub(T, P) \
__typeof__ (*(0 ? (__typeof__ (0 ? (T *) 0 : (void *) (P))) 0 \
: (__typeof__ (0 ? (__intptr_t *) 0 : (void *)(!(P)))) 0))
/* __intptr_t if EXPR has a pointer type, or the type of EXPR otherwise. */
# define __integer_if_pointer_type(expr) \
__integer_if_pointer_type_sub(__typeof__ ((__typeof__ (expr)) 0), \
__pointer_type (__typeof__ (expr)))
/* Cast an integer or a pointer VAL to integer with proper type. */
# define cast_to_integer(val) ((__integer_if_pointer_type (val)) (val))
Good grief, this makes the bitfield look like Mona Lisa. On the other
hand, it relies on the *entirely* undocumented __builtin_classify_type()
-- there appears to be absolutely no reference to it in gcc documentation.
H.J., do you know what the bounds on the __builtin_classify_type() are
(gcc versions available and so on)? Sadly I don't think one can use
__builtin_types_compatible_p() instead.
-hpa
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:14 ` H. Peter Anvin
@ 2013-02-12 17:30 ` H.J. Lu
2013-02-12 18:25 ` H. Peter Anvin
2013-02-12 17:32 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings Linus Torvalds
1 sibling, 1 reply; 39+ messages in thread
From: H.J. Lu @ 2013-02-12 17:30 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Linus Torvalds, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, linux-tip-commits
On Tue, Feb 12, 2013 at 9:14 AM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 02/12/2013 09:00 AM, Linus Torvalds wrote:
>> On Tue, Feb 12, 2013 at 8:38 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>
>>> Can you do something similar to what we did in glibc:
>>
>> No. Because we use macros to be type-independent (i e"get_user()"
>> works *regardless* of type), so casting to "uintptr_t" doesn't work.
>> It throws away the type information, and truncates 64-bit values on
>> 32-bit architectures.
>>
>> The whole point of the bitmask thing is that it doesn't have that
>> issue, and gets the size correct automatically. It's not pretty, but
>> it allows the rest of the sources to be readable.
>>
>
> No, I think what he is talking about it this bit:
>
> /* 1 if 'type' is a pointer type, 0 otherwise. */
> # define __pointer_type(type) (__builtin_classify_type ((type) 0) == 5)
>
> /* __intptr_t if P is true, or T if P is false. */
> # define __integer_if_pointer_type_sub(T, P) \
> __typeof__ (*(0 ? (__typeof__ (0 ? (T *) 0 : (void *) (P))) 0 \
> : (__typeof__ (0 ? (__intptr_t *) 0 : (void *)(!(P)))) 0))
>
> /* __intptr_t if EXPR has a pointer type, or the type of EXPR otherwise. */
> # define __integer_if_pointer_type(expr) \
> __integer_if_pointer_type_sub(__typeof__ ((__typeof__ (expr)) 0), \
> __pointer_type (__typeof__ (expr)))
>
> /* Cast an integer or a pointer VAL to integer with proper type. */
> # define cast_to_integer(val) ((__integer_if_pointer_type (val)) (val))
>
> Good grief, this makes the bitfield look like Mona Lisa. On the other
> hand, it relies on the *entirely* undocumented __builtin_classify_type()
> -- there appears to be absolutely no reference to it in gcc documentation.
>
> H.J., do you know what the bounds on the __builtin_classify_type() are
> (gcc versions available and so on)? Sadly I don't think one can use
> __builtin_types_compatible_p() instead.
>
> -hpa
>
__builtin_classify_type is documented in "info gccint". typeclass.h has
/* Values returned by __builtin_classify_type. */
enum type_class
{
no_type_class = -1,
void_type_class, integer_type_class, char_type_class,
enumeral_type_class, boolean_type_class,
pointer_type_class, reference_type_class, offset_type_class,
real_type_class, complex_type_class,
function_type_class, method_type_class,
record_type_class, union_type_class,
array_type_class, string_type_class,
lang_type_class
};
__builtin_classify_type ((type) 0) == 5 is compatible with all GCCs,
dating back as far as the first checkin when GCC was switched
to CVS from RCS in 1989, which predates the current Linux kernel:
commit 17cf341d65a3766f6451fe3bc20b9c010d38ba3b
Author: mycroft <mycroft@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Sun Aug 13 19:24:27 1989 +0000
entered into RCS
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@3
138bc75d-0d04-0410-961f-82ee72b054a4
diff --git a/gcc/typeclass.h b/gcc/typeclass.h
new file mode 100644
index 0000000..b166042
--- /dev/null
+++ b/gcc/typeclass.h
@@ -0,0 +1,14 @@
+/* Values returned by __builtin_classify_type. */
+
+enum type_class
+{
+ no_type_class = -1,
+ void_type_class, integer_type_class, char_type_class,
+ enumeral_type_class, boolean_type_class,
+ pointer_type_class, reference_type_class, offset_type_class,
+ real_type_class, complex_type_class,
+ function_type_class, method_type_class,
+ record_type_class, union_type_class,
+ array_type_class, string_type_class, set_type_class, file_type_class,
+ lang_type_class
+};
--
H.J.
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:14 ` H. Peter Anvin
2013-02-12 17:30 ` H.J. Lu
@ 2013-02-12 17:32 ` Linus Torvalds
2013-02-12 17:35 ` H. Peter Anvin
2013-02-12 17:57 ` Russell King - ARM Linux
1 sibling, 2 replies; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 17:32 UTC (permalink / raw)
To: H. Peter Anvin
Cc: H.J. Lu, Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits
On Tue, Feb 12, 2013 at 9:14 AM, H. Peter Anvin <hpa@zytor.com> wrote:
>
> No, I think what he is talking about it this bit:
Ok, I agree that the bitfield code actually looks cleaner.
That said, maybe gcc has an easier time using a few odd builtins and
magic typeof's. But at least the bitfield trick looks half-way
portable..
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:32 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings Linus Torvalds
@ 2013-02-12 17:35 ` H. Peter Anvin
2013-02-12 17:49 ` Linus Torvalds
2013-02-12 17:57 ` Russell King - ARM Linux
1 sibling, 1 reply; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 17:35 UTC (permalink / raw)
To: Linus Torvalds
Cc: H.J. Lu, Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits
On 02/12/2013 09:32 AM, Linus Torvalds wrote:
> On Tue, Feb 12, 2013 at 9:14 AM, H. Peter Anvin <hpa@zytor.com> wrote:
>>
>> No, I think what he is talking about it this bit:
>
> Ok, I agree that the bitfield code actually looks cleaner.
>
> That said, maybe gcc has an easier time using a few odd builtins and
> magic typeof's. But at least the bitfield trick looks half-way
> portable..
>
On the other hand, it still uses two gcc extensions: long long bitfields
and typeof.
I'll see what kind of code we get with the macro.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:35 ` H. Peter Anvin
@ 2013-02-12 17:49 ` Linus Torvalds
0 siblings, 0 replies; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 17:49 UTC (permalink / raw)
To: H. Peter Anvin
Cc: H.J. Lu, Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits
On Tue, Feb 12, 2013 at 9:35 AM, H. Peter Anvin <hpa@zytor.com> wrote:
>
> On the other hand, it still uses two gcc extensions: long long bitfields and
> typeof.
>
> I'll see what kind of code we get with the macro.
At least one thing to look out for is the poor LLVM people who are
trying to make the kernel compile with that compiler.. We shouldn't
make it arbitrarily harder for them, so *some* level of portability is
a good idea.
Then there is icc, but I don't know how relevant that would ever be.
At least LLVM has the potential to be widely available.
Of course, they may both already support even the odd gcc builtins -
we already use a lot of the more straightforward ones...
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:32 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings Linus Torvalds
2013-02-12 17:35 ` H. Peter Anvin
@ 2013-02-12 17:57 ` Russell King - ARM Linux
1 sibling, 0 replies; 39+ messages in thread
From: Russell King - ARM Linux @ 2013-02-12 17:57 UTC (permalink / raw)
To: Linus Torvalds
Cc: H. Peter Anvin, H.J. Lu, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov, Thomas Gleixner,
linux-tip-commits
On Tue, Feb 12, 2013 at 09:32:54AM -0800, Linus Torvalds wrote:
> On Tue, Feb 12, 2013 at 9:14 AM, H. Peter Anvin <hpa@zytor.com> wrote:
> >
> > No, I think what he is talking about it this bit:
>
> Ok, I agree that the bitfield code actually looks cleaner.
>
> That said, maybe gcc has an easier time using a few odd builtins and
> magic typeof's. But at least the bitfield trick looks half-way
> portable..
I've just been trying hpa's solution on ARM, and I can't get it to work,
because the compiler refuses to put the struct { unsigned long long ... }
into the register(s) we need for the out of line assembly:
#define get_user(x,p) \
({ \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
register int __e asm("r0"); \
register struct { \
unsigned long long __r2:8 * sizeof(*(__p)); \
} __v asm("r2"); \
switch (sizeof(*(__p))) { \
case 1: \
__get_user_x(__v.__r2, __p, __e, 1, "lr"); \
break; \
case 2: \
__get_user_x(__v.__r2, __p, __e, 2, "r3", "lr");\
break; \
case 4: \
__get_user_x(__v.__r2, __p, __e, 4, "lr"); \
break; \
case 8: \
__get_user_x(__v.__r2, __p, __e, 8, "lr"); \
break; \
default: __e = __get_user_bad(); break; \
} \
x = (typeof(*(__p))) __v.__r2; \
__e; \
})
This ends up with __v.__r2 ending up in r1/(r2) not r2/(r3).
However, I do have a working solution for 32-bit ARM which seems to work
fine with my test cases here, though as I mentioned to hpa, it may not
be portable to other 32-bit architectures:
#ifdef BIG_ENDIAN
#define __get_user_xb(__r2,__p,__e,__s,__i...) \
__get_user_x(__r2,(unsigned)__p+4,__e,__s,__i)
#else
#define __get_user_xb __get_user_x
#endif
#define get_user(x,p) \
({ \
register const typeof(*(p)) __user *__p asm("r0") = (p);\
register int __e asm("r0"); \
register typeof(x) __r2 asm("r2"); \
switch (sizeof(*(__p))) { \
case 1: \
__get_user_x(__r2, __p, __e, 1, "lr"); \
break; \
case 2: \
__get_user_x(__r2, __p, __e, 2, "r3", "lr"); \
break; \
case 4: \
__get_user_x(__r2, __p, __e, 4, "lr"); \
break; \
case 8: \
{ \
if (sizeof((x)) < 8) \
__get_user_xb(__r2, __p, __e, 4, "lr"); \
else \
__get_user_x(__r2, __p, __e, 8, "lr"); \
} \
break; \
default: __e = __get_user_bad(); break; \
} \
x = (typeof(*(__p))) __r2; \
__e; \
})
It's risky because it relies upon a "register" being allocated as 32-bits
even if typeof(x) is 8-bit or 16-bit.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 17:30 ` H.J. Lu
@ 2013-02-12 18:25 ` H. Peter Anvin
2013-02-12 18:29 ` H.J. Lu
` (2 more replies)
0 siblings, 3 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 18:25 UTC (permalink / raw)
To: H.J. Lu
Cc: Linus Torvalds, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, linux-tip-commits
[-- Attachment #1: Type: text/plain, Size: 310 bytes --]
I just thought up this variant, I'm about to test it, but H.J., do you
see any problems with it?
#define itype(x) \
__typeof__(__builtin_choose_expr(sizeof(*(x)) > sizeof(0UL), 0ULL, 0UL))
I tried it out with a small test program (attached), and it seems to
work. Next for using it in the kernel...
-hpa
[-- Attachment #2: testgcc.c --]
[-- Type: text/x-csrc, Size: 634 bytes --]
#include <stdio.h>
#include <stdlib.h>
#define itype(x) __typeof__(__builtin_choose_expr(sizeof(*(x)) > sizeof(0UL), 0ULL, 0UL))
int main(void)
{
const char *a;
const short *b;
const int *c;
const long *d;
const long long *e;
const void **p;
itype(a) aa;
itype(b) bb;
itype(c) cc;
itype(d) dd;
itype(e) ee;
itype(p) pp;
aa = 1;
bb = 2;
cc = 3;
dd = 4;
ee = 5;
pp = 6;
printf("a = %zu\n", sizeof(aa));
printf("b = %zu\n", sizeof(bb));
printf("c = %zu\n", sizeof(cc));
printf("d = %zu\n", sizeof(dd));
printf("e = %zu\n", sizeof(ee));
printf("p = %zu\n", sizeof(pp));
return 0;
}
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 18:25 ` H. Peter Anvin
@ 2013-02-12 18:29 ` H.J. Lu
2013-02-12 18:46 ` Linus Torvalds
2013-02-12 20:55 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack tip-bot for H. Peter Anvin
2 siblings, 0 replies; 39+ messages in thread
From: H.J. Lu @ 2013-02-12 18:29 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Linus Torvalds, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, linux-tip-commits
On Tue, Feb 12, 2013 at 10:25 AM, H. Peter Anvin <hpa@zytor.com> wrote:
> I just thought up this variant, I'm about to test it, but H.J., do you
> see any problems with it?
>
> #define itype(x) \
> __typeof__(__builtin_choose_expr(sizeof(*(x)) > sizeof(0UL), 0ULL, 0UL))
>
> I tried it out with a small test program (attached), and it seems to
> work. Next for using it in the kernel...
>
> -hpa
>
It looks OK to me.
--
H.J.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 18:25 ` H. Peter Anvin
2013-02-12 18:29 ` H.J. Lu
@ 2013-02-12 18:46 ` Linus Torvalds
2013-02-12 18:58 ` H. Peter Anvin
2013-02-12 20:55 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack tip-bot for H. Peter Anvin
2 siblings, 1 reply; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 18:46 UTC (permalink / raw)
To: H. Peter Anvin
Cc: H.J. Lu, Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits
On Tue, Feb 12, 2013 at 10:25 AM, H. Peter Anvin <hpa@zytor.com> wrote:
> I just thought up this variant, I'm about to test it, but H.J., do you
> see any problems with it?
Looks good to me. And we already use __builtin_choose_expr(), so it's
"portable". And it should avoid all the potential issues with
bitfields (rmk already pointed out how bitfields don't work well with
the ARM model, who knows what other pitfalls bitfield code generation
could have)
I wonder if we could/should eventually do some of the sizeof() in
generic code - not have these magic things duplicated in all the
architectures, just have the architectures specify the raw typed
details (__copy_to_user_4() etc). So cross-platform portability could
be a good thing. That's a separate discussion, though, and possibly
not worth it.
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings
2013-02-12 18:46 ` Linus Torvalds
@ 2013-02-12 18:58 ` H. Peter Anvin
0 siblings, 0 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 18:58 UTC (permalink / raw)
To: Linus Torvalds
Cc: H.J. Lu, Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, linux-tip-commits
On 02/12/2013 10:46 AM, Linus Torvalds wrote:
> On Tue, Feb 12, 2013 at 10:25 AM, H. Peter Anvin <hpa@zytor.com> wrote:
>> I just thought up this variant, I'm about to test it, but H.J., do you
>> see any problems with it?
>
> Looks good to me. And we already use __builtin_choose_expr(), so it's
> "portable". And it should avoid all the potential issues with
> bitfields (rmk already pointed out how bitfields don't work well with
> the ARM model, who knows what other pitfalls bitfield code generation
> could have)
>
> I wonder if we could/should eventually do some of the sizeof() in
> generic code - not have these magic things duplicated in all the
> architectures, just have the architectures specify the raw typed
> details (__copy_to_user_4() etc). So cross-platform portability could
> be a good thing. That's a separate discussion, though, and possibly
> not worth it.
>
I'm getting rid of the switch statement in the variant that I'm
currently testing, so that would probably be undesirable.
-hpa
--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.
^ permalink raw reply [flat|nested] 39+ messages in thread
* [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack
2013-02-12 18:25 ` H. Peter Anvin
2013-02-12 18:29 ` H.J. Lu
2013-02-12 18:46 ` Linus Torvalds
@ 2013-02-12 20:55 ` tip-bot for H. Peter Anvin
2013-02-12 23:06 ` Linus Torvalds
2 siblings, 1 reply; 39+ messages in thread
From: tip-bot for H. Peter Anvin @ 2013-02-12 20:55 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, torvalds, jamie, ville.syrjala, bp,
linux, tglx, hpa, hjl.tools
Commit-ID: 3578baaed4613a9fc09bab9f79f6ce2ac682e8a3
Gitweb: http://git.kernel.org/tip/3578baaed4613a9fc09bab9f79f6ce2ac682e8a3
Author: H. Peter Anvin <hpa@linux.intel.com>
AuthorDate: Tue, 12 Feb 2013 11:47:31 -0800
Committer: H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 12 Feb 2013 12:46:40 -0800
x86, mm: Redesign get_user with a __builtin_choose_expr hack
Instead of using a bitfield, use an odd little trick using typeof,
__builtin_choose_expr, and sizeof. __builtin_choose_expr is
explicitly defined to not convert its type (its argument is required
to be a constant expression) so this should be well-defined.
The code is still not 100% preturbation-free versus the baseline
before 64-bit get_user(), but the differences seem to be very small,
mostly related to padding and to gcc deciding when to spill registers.
Cc: Jamie Lokier <jamie@shareable.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: H. J. Lu <hjl.tools@gmail.com>
Link: http://lkml.kernel.org/r/511A8922.6050908@zytor.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
arch/x86/include/asm/uaccess.h | 57 +++++++++++-------------------------------
1 file changed, 14 insertions(+), 43 deletions(-)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a8d1265..d710a25 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -125,13 +125,12 @@ extern int __get_user_4(void);
extern int __get_user_8(void);
extern int __get_user_bad(void);
-#define __get_user_x(size, ret, x, ptr) \
- asm volatile("call __get_user_" #size \
- : "=a" (ret), "=d" (x) \
- : "0" (ptr)) \
-
-/* Careful: we have to cast the result to the type of the pointer
- * for sign reasons */
+/*
+ * This is a type: either unsigned long, if the argument fits into
+ * that type, or otherwise unsigned long long.
+ */
+#define __inttype(x) \
+__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
/**
* get_user: - Get a simple variable from user space.
@@ -149,48 +148,20 @@ extern int __get_user_bad(void);
*
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
+ *
+ * Careful: we have to cast the result to the type of the pointer
+ * for sign reasons.
*/
-#ifdef CONFIG_X86_32
-#define __get_user_8(ret, x, ptr) \
-do { \
- register unsigned long long __xx asm("%edx"); \
- asm volatile("call __get_user_8" \
- : "=a" (ret), "=r" (__xx) \
- : "0" (ptr)); \
- (x) = __xx; \
-} while (0)
-
-#else
-#define __get_user_8(__ret_gu, __val_gu, ptr) \
- __get_user_x(8, __ret_gu, __val_gu, ptr)
-#endif
-
#define get_user(x, ptr) \
({ \
int __ret_gu; \
- struct { \
- unsigned long long __val_n : 8*sizeof(*(ptr)); \
- } __val_gu; \
+ register __inttype(*(ptr)) __val_gu asm("%edx"); \
__chk_user_ptr(ptr); \
might_fault(); \
- switch (sizeof(*(ptr))) { \
- case 1: \
- __get_user_x(1, __ret_gu, __val_gu.__val_n, ptr); \
- break; \
- case 2: \
- __get_user_x(2, __ret_gu, __val_gu.__val_n, ptr); \
- break; \
- case 4: \
- __get_user_x(4, __ret_gu, __val_gu.__val_n, ptr); \
- break; \
- case 8: \
- __get_user_8(__ret_gu, __val_gu.__val_n, ptr); \
- break; \
- default: \
- __get_user_x(X, __ret_gu, __val_gu.__val_n, ptr); \
- break; \
- } \
- (x) = (__typeof__(*(ptr)))__val_gu.__val_n; \
+ asm volatile("call __get_user_%P3" \
+ : "=a" (__ret_gu), "=r" (__val_gu) \
+ : "0" (ptr), "i" (sizeof(*(ptr)))); \
+ (x) = (__typeof__(*(ptr))) __val_gu; \
__ret_gu; \
})
^ permalink raw reply related [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack
2013-02-12 20:55 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack tip-bot for H. Peter Anvin
@ 2013-02-12 23:06 ` Linus Torvalds
2013-02-12 23:19 ` H. Peter Anvin
2013-02-12 23:21 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack Russell King - ARM Linux
0 siblings, 2 replies; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 23:06 UTC (permalink / raw)
To: Ingo Molnar, H. Peter Anvin, Linux Kernel Mailing List,
Jamie Lokier, Linus Torvalds, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, H. Peter Anvin,
H.J. Lu
Cc: linux-tip-commits
So this looks clean, but I noticed something (that was true even of
the old 64-bit accesses)
On Tue, Feb 12, 2013 at 12:55 PM, tip-bot for H. Peter Anvin
<hpa@linux.intel.com> wrote:
> + register __inttype(*(ptr)) __val_gu asm("%edx"); \
How does gcc even alllow this?
On x86-32, you cannot put a 64-bit value in %edx.
Where do the upper bits go? It clearly cannot be %edx:%eax, since we
put the error value in %eax.
So is the rule for x86-32 that naming "long long" register values
names the first register, and the high bits go into the next one (I
forget the crazy register numbering, I assume it's %ecx). Or what?
This should have a comment.
Also, come to think of it, we have tried the "named register
variables" thing before, and it has resulted in problems with scope.
In particular, two variables within the same scope and the same
register have been problematic. And it *does* happen, when you have
things like
/* copy_user */
put_user(get_user(.., addr), addr2);
and then things go downhill.
Maybe we do not have these issues, but there are good reasons why
we've tried very hard on x86 to avoid named register variables.
(I realize that they happen, and some other architectures don't even
have good support for naming registers any other way so they are way
more common there, so I probably worry needlessly, but it does worry
me).
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack
2013-02-12 23:06 ` Linus Torvalds
@ 2013-02-12 23:19 ` H. Peter Anvin
2013-02-12 23:49 ` Linus Torvalds
2013-02-13 0:01 ` [tip:x86/mm] x86, doc: Clarify the use of asm("%edx") in uaccess.h tip-bot for H. Peter Anvin
2013-02-12 23:21 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack Russell King - ARM Linux
1 sibling, 2 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 23:19 UTC (permalink / raw)
To: Linus Torvalds
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, H. Peter Anvin, H.J. Lu, linux-tip-commits
On 02/12/2013 03:06 PM, Linus Torvalds wrote:
> So this looks clean, but I noticed something (that was true even of
> the old 64-bit accesses)
>
> On Tue, Feb 12, 2013 at 12:55 PM, tip-bot for H. Peter Anvin
> <hpa@linux.intel.com> wrote:
>> + register __inttype(*(ptr)) __val_gu asm("%edx"); \
>
> How does gcc even alllow this?
>
> On x86-32, you cannot put a 64-bit value in %edx.
>
> Where do the upper bits go? It clearly cannot be %edx:%eax, since we
> put the error value in %eax.
>
> So is the rule for x86-32 that naming "long long" register values
> names the first register, and the high bits go into the next one (I
> forget the crazy register numbering, I assume it's %ecx). Or what?
> This should have a comment.
>
Yes, it goes into the next register in gcc's register numbering, which
is %ecx. This works with the register variable because the named
register is treated as a starting point, whereas using "=d" is treated
as a singleton register set.
I'll add a comment.
gcc's register numbering isn't all that crazy, incidentally: the only
difference from the standard x86 register numbering is that %ecx and
%edx is swapped, so that the standard %edx:%eax and %ebx:%ecx register
pairs end up consecutive. It isn't really gcc's fault that the x86
register numbering doesn't match its (hard-coded!) register conventions...
> Also, come to think of it, we have tried the "named register
> variables" thing before, and it has resulted in problems with scope.
> In particular, two variables within the same scope and the same
> register have been problematic. And it *does* happen, when you have
> things like
>
> /* copy_user */
> put_user(get_user(.., addr), addr2);
>
> and then things go downhill.
>
> Maybe we do not have these issues, but there are good reasons why
> we've tried very hard on x86 to avoid named register variables.
Yes, but there doesn't seem to be any other way to do this. gcc won't
even allow "=cd" even if we know the variable is 64 bits, even though
"=A" is documented to be equivalent to "=da".
I don't think we have any additional problem here,though. If we are
inside a scope with "%edx" as a named register variable *and* that
variable is live at the point get_user() happens, then yes, we can and
will have a problem, regardless if we use "=d" or a named register
variable. The only solution to that is to keep the named register
variable live for as short time as possible.
If we do run into trouble, we could introduce a second copy, thus
reducing the lifespan of the named variable to the absolute minimum:
register __inttype(*(ptr)) __val_gu asm("%edx");
__inttype(*(ptr)) __val_gv;
asm volatile(...);
__val_gv = __val_gu;
(x) = (__typeof__(*(ptr))) __val_gv;
That way if the evaluation of (x) as an lvalue somehow requires specific
registers they don't collide.
I would prefer if we could worry about that when we actually need to,
though. It will trigger a compile error if relevant, so it shouldn't
cause any risk of silent corruption.
> (I realize that they happen, and some other architectures don't even
> have good support for naming registers any other way so they are way
> more common there, so I probably worry needlessly, but it does worry
> me).
Let me know what you think.
-hpa
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack
2013-02-12 23:06 ` Linus Torvalds
2013-02-12 23:19 ` H. Peter Anvin
@ 2013-02-12 23:21 ` Russell King - ARM Linux
1 sibling, 0 replies; 39+ messages in thread
From: Russell King - ARM Linux @ 2013-02-12 23:21 UTC (permalink / raw)
To: Linus Torvalds
Cc: Ingo Molnar, H. Peter Anvin, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov, Thomas Gleixner,
H. Peter Anvin, H.J. Lu, linux-tip-commits
On Tue, Feb 12, 2013 at 03:06:51PM -0800, Linus Torvalds wrote:
> So this looks clean, but I noticed something (that was true even of
> the old 64-bit accesses)
>
> On Tue, Feb 12, 2013 at 12:55 PM, tip-bot for H. Peter Anvin
> <hpa@linux.intel.com> wrote:
> > + register __inttype(*(ptr)) __val_gu asm("%edx"); \
>
> How does gcc even alllow this?
>
> On x86-32, you cannot put a 64-bit value in %edx.
>
> Where do the upper bits go? It clearly cannot be %edx:%eax, since we
> put the error value in %eax.
I can't talk for x86, but the ARM version is this:
register __inttype(*p) __r2 asm("r2");
r2 is only 32-bit, so you can ask the same question there. The answer
is, it ends up in r3, the next register, as required by the compiler
ABI. (64-bit values are always contained in a consecutive even, odd
register pair.)
> Also, come to think of it, we have tried the "named register
> variables" thing before, and it has resulted in problems with scope.
> In particular, two variables within the same scope and the same
> register have been problematic. And it *does* happen, when you have
> things like
>
> /* copy_user */
> put_user(get_user(.., addr), addr2);
>
> and then things go downhill.
Umm. Why would you want to put_user() the error code from get_user() ?
That's just weird, don't we normally want to return the error code?
But yes, I can see that kind of thing causing problems - I'll check
what the behaviour is on ARM. What we _do_ have is a bit of assembly
level checking which verifies that the arguments are passed in the
correct registers, so at least we get build errors should things go
wrong. We haven't seen that though.
> Maybe we do not have these issues, but there are good reasons why
> we've tried very hard on x86 to avoid named register variables.
Unfortunately on ARM there's no other way to get close to specifying
registers for asm code. :(
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack
2013-02-12 23:19 ` H. Peter Anvin
@ 2013-02-12 23:49 ` Linus Torvalds
2013-02-12 23:52 ` H. Peter Anvin
2013-02-13 0:01 ` [tip:x86/mm] x86, doc: Clarify the use of asm("%edx") in uaccess.h tip-bot for H. Peter Anvin
1 sibling, 1 reply; 39+ messages in thread
From: Linus Torvalds @ 2013-02-12 23:49 UTC (permalink / raw)
To: H. Peter Anvin
Cc: Ingo Molnar, Linux Kernel Mailing List, Jamie Lokier,
ville.syrjala, Borislav Petkov, Russell King - ARM Linux,
Thomas Gleixner, H. Peter Anvin, H.J. Lu, linux-tip-commits
On Tue, Feb 12, 2013 at 3:19 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>
> Yes, but there doesn't seem to be any other way to do this. gcc won't
> even allow "=cd" even if we know the variable is 64 bits, even though
> "=A" is documented to be equivalent to "=da".
No, "=da" means value "in edx _or_ %eax". Not the same as "A".
But you're right, there's nothing similar for %ebx:%ecx. I thought
there was. I was really sure we did something special for 64-bit adc
etc.
> Let me know what you think.
I guess we don't have any choice. And the other cleanups certainly look good.
Linus
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack
2013-02-12 23:49 ` Linus Torvalds
@ 2013-02-12 23:52 ` H. Peter Anvin
0 siblings, 0 replies; 39+ messages in thread
From: H. Peter Anvin @ 2013-02-12 23:52 UTC (permalink / raw)
To: Linus Torvalds
Cc: H. Peter Anvin, Ingo Molnar, Linux Kernel Mailing List,
Jamie Lokier, ville.syrjala, Borislav Petkov,
Russell King - ARM Linux, Thomas Gleixner, H.J. Lu,
linux-tip-commits
On 02/12/2013 03:49 PM, Linus Torvalds wrote:
> On Tue, Feb 12, 2013 at 3:19 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>>
>> Yes, but there doesn't seem to be any other way to do this. gcc won't
>> even allow "=cd" even if we know the variable is 64 bits, even though
>> "=A" is documented to be equivalent to "=da".
>
> No, "=da" means value "in edx _or_ %eax". Not the same as "A".
>
Actually, if you look at how gcc implements them, they are the same, and
if you are luckless enough to try to use a 32-bit value with an "A"
constraint you have it end up in either %eax or %edx.
However, they seem to have added some additional linting which prohibits
the compound form. I'm not sure it would have worked anyway since we
need the two-register bit to be conditional.
> But you're right, there's nothing similar for %ebx:%ecx. I thought
> there was. I was really sure we did something special for 64-bit adc
> etc.
>
>> Let me know what you think.
>
> I guess we don't have any choice. And the other cleanups certainly look good.
OK, will commit the comment. We can add the additional copy if we need it.
-hpa
^ permalink raw reply [flat|nested] 39+ messages in thread
* [tip:x86/mm] x86, doc: Clarify the use of asm("%edx") in uaccess.h
2013-02-12 23:19 ` H. Peter Anvin
2013-02-12 23:49 ` Linus Torvalds
@ 2013-02-13 0:01 ` tip-bot for H. Peter Anvin
1 sibling, 0 replies; 39+ messages in thread
From: tip-bot for H. Peter Anvin @ 2013-02-13 0:01 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, torvalds, jamie, ville.syrjala, bp,
linux, tglx, hpa, hjl.tools
Commit-ID: ff52c3b02b3f73178bfe0c219cd22abdcb0e46c3
Gitweb: http://git.kernel.org/tip/ff52c3b02b3f73178bfe0c219cd22abdcb0e46c3
Author: H. Peter Anvin <hpa@linux.intel.com>
AuthorDate: Tue, 12 Feb 2013 15:37:02 -0800
Committer: H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 12 Feb 2013 15:37:02 -0800
x86, doc: Clarify the use of asm("%edx") in uaccess.h
Put in a comment that explains that the use of asm("%edx") in
uaccess.h doesn't actually necessarily mean %edx alone.
Cc: Jamie Lokier <jamie@shareable.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: H. J. Lu <hjl.tools@gmail.com>
Link: http://lkml.kernel.org/r/511ACDFB.1050707@zytor.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
arch/x86/include/asm/uaccess.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index d710a25..5ee2687 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -148,9 +148,16 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
*
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
- *
+ */
+/*
* Careful: we have to cast the result to the type of the pointer
* for sign reasons.
+ *
+ * The use of %edx as the register specifier is a bit of a
+ * simplification, as gcc only cares about it as the starting point
+ * and not size: for a 64-bit value it will use %ecx:%edx on 32 bits
+ * (%ecx being the next register in gcc's x86 register sequence), and
+ * %rdx on 64 bits.
*/
#define get_user(x, ptr) \
({ \
^ permalink raw reply related [flat|nested] 39+ messages in thread
end of thread, other threads:[~2013-02-13 0:03 UTC | newest]
Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-12-12 11:34 [PATCH] x86: Add support for 64bit get_user() on x86-32 ville.syrjala
2012-12-12 16:15 ` H. Peter Anvin
2012-12-12 16:32 ` Ville Syrjälä
2012-12-12 16:45 ` H. Peter Anvin
2013-02-07 16:53 ` Ville Syrjälä
2013-02-07 17:59 ` H. Peter Anvin
2013-02-08 16:24 ` Ville Syrjälä
2013-02-08 17:30 ` H. Peter Anvin
2013-02-08 18:23 ` Ville Syrjälä
2013-02-08 19:08 ` H. Peter Anvin
2013-02-09 10:41 ` Borislav Petkov
2013-02-09 11:00 ` Russell King - ARM Linux
2013-02-12 1:37 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings tip-bot for H. Peter Anvin
2013-02-12 3:33 ` Linus Torvalds
2013-02-12 4:21 ` H. Peter Anvin
2013-02-12 4:42 ` Linus Torvalds
2013-02-12 4:47 ` Linus Torvalds
2013-02-12 4:51 ` H. Peter Anvin
2013-02-12 7:12 ` H. Peter Anvin
2013-02-12 8:10 ` Ingo Molnar
2013-02-12 16:38 ` H.J. Lu
2013-02-12 17:00 ` Linus Torvalds
2013-02-12 17:14 ` H. Peter Anvin
2013-02-12 17:30 ` H.J. Lu
2013-02-12 18:25 ` H. Peter Anvin
2013-02-12 18:29 ` H.J. Lu
2013-02-12 18:46 ` Linus Torvalds
2013-02-12 18:58 ` H. Peter Anvin
2013-02-12 20:55 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack tip-bot for H. Peter Anvin
2013-02-12 23:06 ` Linus Torvalds
2013-02-12 23:19 ` H. Peter Anvin
2013-02-12 23:49 ` Linus Torvalds
2013-02-12 23:52 ` H. Peter Anvin
2013-02-13 0:01 ` [tip:x86/mm] x86, doc: Clarify the use of asm("%edx") in uaccess.h tip-bot for H. Peter Anvin
2013-02-12 23:21 ` [tip:x86/mm] x86, mm: Redesign get_user with a __builtin_choose_expr hack Russell King - ARM Linux
2013-02-12 17:32 ` [tip:x86/mm] x86, mm: Use a bitfield to mask nuisance get_user() warnings Linus Torvalds
2013-02-12 17:35 ` H. Peter Anvin
2013-02-12 17:49 ` Linus Torvalds
2013-02-12 17:57 ` Russell King - ARM Linux
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).