aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2013-02-12 14:47:31 -0500
committerH. Peter Anvin <hpa@linux.intel.com>2013-02-12 15:46:40 -0500
commit3578baaed4613a9fc09bab9f79f6ce2ac682e8a3 (patch)
tree2f58dbf5dcc6325fd87f17ccafd00f08bed741d8
parent16640165c9079e2cf36fdcfca093f29663a716f7 (diff)
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>
-rw-r--r--arch/x86/include/asm/uaccess.h57
1 files changed, 14 insertions, 43 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index a8d12653f304..d710a2555fd6 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);
125extern int __get_user_8(void); 125extern int __get_user_8(void);
126extern int __get_user_bad(void); 126extern int __get_user_bad(void);
127 127
128#define __get_user_x(size, ret, x, ptr) \ 128/*
129 asm volatile("call __get_user_" #size \ 129 * This is a type: either unsigned long, if the argument fits into
130 : "=a" (ret), "=d" (x) \ 130 * that type, or otherwise unsigned long long.
131 : "0" (ptr)) \ 131 */
132 132#define __inttype(x) \
133/* Careful: we have to cast the result to the type of the pointer 133__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
134 * for sign reasons */
135 134
136/** 135/**
137 * get_user: - Get a simple variable from user space. 136 * get_user: - Get a simple variable from user space.
@@ -149,48 +148,20 @@ extern int __get_user_bad(void);
149 * 148 *
150 * Returns zero on success, or -EFAULT on error. 149 * Returns zero on success, or -EFAULT on error.
151 * On error, the variable @x is set to zero. 150 * On error, the variable @x is set to zero.
151 *
152 * Careful: we have to cast the result to the type of the pointer
153 * for sign reasons.
152 */ 154 */
153#ifdef CONFIG_X86_32
154#define __get_user_8(ret, x, ptr) \
155do { \
156 register unsigned long long __xx asm("%edx"); \
157 asm volatile("call __get_user_8" \
158 : "=a" (ret), "=r" (__xx) \
159 : "0" (ptr)); \
160 (x) = __xx; \
161} while (0)
162
163#else
164#define __get_user_8(__ret_gu, __val_gu, ptr) \
165 __get_user_x(8, __ret_gu, __val_gu, ptr)
166#endif
167
168#define get_user(x, ptr) \ 155#define get_user(x, ptr) \
169({ \ 156({ \
170 int __ret_gu; \ 157 int __ret_gu; \
171 struct { \ 158 register __inttype(*(ptr)) __val_gu asm("%edx"); \
172 unsigned long long __val_n : 8*sizeof(*(ptr)); \
173 } __val_gu; \
174 __chk_user_ptr(ptr); \ 159 __chk_user_ptr(ptr); \
175 might_fault(); \ 160 might_fault(); \
176 switch (sizeof(*(ptr))) { \ 161 asm volatile("call __get_user_%P3" \
177 case 1: \ 162 : "=a" (__ret_gu), "=r" (__val_gu) \
178 __get_user_x(1, __ret_gu, __val_gu.__val_n, ptr); \ 163 : "0" (ptr), "i" (sizeof(*(ptr)))); \
179 break; \ 164 (x) = (__typeof__(*(ptr))) __val_gu; \
180 case 2: \
181 __get_user_x(2, __ret_gu, __val_gu.__val_n, ptr); \
182 break; \
183 case 4: \
184 __get_user_x(4, __ret_gu, __val_gu.__val_n, ptr); \
185 break; \
186 case 8: \
187 __get_user_8(__ret_gu, __val_gu.__val_n, ptr); \
188 break; \
189 default: \
190 __get_user_x(X, __ret_gu, __val_gu.__val_n, ptr); \
191 break; \
192 } \
193 (x) = (__typeof__(*(ptr)))__val_gu.__val_n; \
194 __ret_gu; \ 165 __ret_gu; \
195}) 166})
196 167