提交 3578baae 编写于 作者: H H. Peter Anvin

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.comSigned-off-by: NH. Peter Anvin <hpa@linux.intel.com>
上级 16640165
...@@ -125,13 +125,12 @@ extern int __get_user_4(void); ...@@ -125,13 +125,12 @@ extern int __get_user_4(void);
extern int __get_user_8(void); extern int __get_user_8(void);
extern int __get_user_bad(void); extern int __get_user_bad(void);
#define __get_user_x(size, ret, x, ptr) \ /*
asm volatile("call __get_user_" #size \ * This is a type: either unsigned long, if the argument fits into
: "=a" (ret), "=d" (x) \ * that type, or otherwise unsigned long long.
: "0" (ptr)) \ */
#define __inttype(x) \
/* Careful: we have to cast the result to the type of the pointer __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
* for sign reasons */
/** /**
* get_user: - Get a simple variable from user space. * get_user: - Get a simple variable from user space.
...@@ -149,48 +148,20 @@ extern int __get_user_bad(void); ...@@ -149,48 +148,20 @@ extern int __get_user_bad(void);
* *
* Returns zero on success, or -EFAULT on error. * Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero. * 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) \ #define get_user(x, ptr) \
({ \ ({ \
int __ret_gu; \ int __ret_gu; \
struct { \ register __inttype(*(ptr)) __val_gu asm("%edx"); \
unsigned long long __val_n : 8*sizeof(*(ptr)); \
} __val_gu; \
__chk_user_ptr(ptr); \ __chk_user_ptr(ptr); \
might_fault(); \ might_fault(); \
switch (sizeof(*(ptr))) { \ asm volatile("call __get_user_%P3" \
case 1: \ : "=a" (__ret_gu), "=r" (__val_gu) \
__get_user_x(1, __ret_gu, __val_gu.__val_n, ptr); \ : "0" (ptr), "i" (sizeof(*(ptr)))); \
break; \ (x) = (__typeof__(*(ptr))) __val_gu; \
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; \
__ret_gu; \ __ret_gu; \
}) })
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册