diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-20 14:51:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-20 14:51:00 -0500 |
commit | 4cd4156994d1e66759a86446feb82d932f63f5c8 (patch) | |
tree | 3c4c9d8af8e10b9511373c4e23ac5df6218f4649 | |
parent | 1a7dbbcc8cc6b34f3a4ae92026759fc057ffcba2 (diff) | |
parent | a740576a4abf933de8f50787f24f24456cebd761 (diff) |
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86/asm changes from Ingo Molnar:
"Misc optimizations"
* 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86: Slightly tweak the access_ok() C variant for better code
x86: Replace assembly access_ok() with a C variant
x86-64, copy_user: Use leal to produce 32-bit results
x86-64, copy_user: Remove zero byte check before copy user buffer.
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 32 | ||||
-rw-r--r-- | arch/x86/lib/copy_user_64.S | 12 |
2 files changed, 24 insertions, 20 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 8ec57c07b125..6f1bb74d547b 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -40,22 +40,30 @@ | |||
40 | /* | 40 | /* |
41 | * Test whether a block of memory is a valid user space address. | 41 | * Test whether a block of memory is a valid user space address. |
42 | * Returns 0 if the range is valid, nonzero otherwise. | 42 | * Returns 0 if the range is valid, nonzero otherwise. |
43 | * | ||
44 | * This is equivalent to the following test: | ||
45 | * (u33)addr + (u33)size > (u33)current->addr_limit.seg (u65 for x86_64) | ||
46 | * | ||
47 | * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... | ||
48 | */ | 43 | */ |
44 | static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, unsigned long limit) | ||
45 | { | ||
46 | /* | ||
47 | * If we have used "sizeof()" for the size, | ||
48 | * we know it won't overflow the limit (but | ||
49 | * it might overflow the 'addr', so it's | ||
50 | * important to subtract the size from the | ||
51 | * limit, not add it to the address). | ||
52 | */ | ||
53 | if (__builtin_constant_p(size)) | ||
54 | return addr > limit - size; | ||
55 | |||
56 | /* Arbitrary sizes? Be careful about overflow */ | ||
57 | addr += size; | ||
58 | if (addr < size) | ||
59 | return true; | ||
60 | return addr > limit; | ||
61 | } | ||
49 | 62 | ||
50 | #define __range_not_ok(addr, size, limit) \ | 63 | #define __range_not_ok(addr, size, limit) \ |
51 | ({ \ | 64 | ({ \ |
52 | unsigned long flag, roksum; \ | ||
53 | __chk_user_ptr(addr); \ | 65 | __chk_user_ptr(addr); \ |
54 | asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ | 66 | __chk_range_not_ok((unsigned long __force)(addr), size, limit); \ |
55 | : "=&r" (flag), "=r" (roksum) \ | ||
56 | : "1" (addr), "g" ((long)(size)), \ | ||
57 | "rm" (limit)); \ | ||
58 | flag; \ | ||
59 | }) | 67 | }) |
60 | 68 | ||
61 | /** | 69 | /** |
@@ -78,7 +86,7 @@ | |||
78 | * this function, memory access functions may still return -EFAULT. | 86 | * this function, memory access functions may still return -EFAULT. |
79 | */ | 87 | */ |
80 | #define access_ok(type, addr, size) \ | 88 | #define access_ok(type, addr, size) \ |
81 | (likely(__range_not_ok(addr, size, user_addr_max()) == 0)) | 89 | likely(!__range_not_ok(addr, size, user_addr_max())) |
82 | 90 | ||
83 | /* | 91 | /* |
84 | * The exception table consists of pairs of addresses relative to the | 92 | * The exception table consists of pairs of addresses relative to the |
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index a30ca15be21c..dee945d55594 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S | |||
@@ -186,7 +186,7 @@ ENTRY(copy_user_generic_unrolled) | |||
186 | 30: shll $6,%ecx | 186 | 30: shll $6,%ecx |
187 | addl %ecx,%edx | 187 | addl %ecx,%edx |
188 | jmp 60f | 188 | jmp 60f |
189 | 40: lea (%rdx,%rcx,8),%rdx | 189 | 40: leal (%rdx,%rcx,8),%edx |
190 | jmp 60f | 190 | jmp 60f |
191 | 50: movl %ecx,%edx | 191 | 50: movl %ecx,%edx |
192 | 60: jmp copy_user_handle_tail /* ecx is zerorest also */ | 192 | 60: jmp copy_user_handle_tail /* ecx is zerorest also */ |
@@ -236,8 +236,6 @@ ENDPROC(copy_user_generic_unrolled) | |||
236 | ENTRY(copy_user_generic_string) | 236 | ENTRY(copy_user_generic_string) |
237 | CFI_STARTPROC | 237 | CFI_STARTPROC |
238 | ASM_STAC | 238 | ASM_STAC |
239 | andl %edx,%edx | ||
240 | jz 4f | ||
241 | cmpl $8,%edx | 239 | cmpl $8,%edx |
242 | jb 2f /* less than 8 bytes, go to byte copy loop */ | 240 | jb 2f /* less than 8 bytes, go to byte copy loop */ |
243 | ALIGN_DESTINATION | 241 | ALIGN_DESTINATION |
@@ -249,12 +247,12 @@ ENTRY(copy_user_generic_string) | |||
249 | 2: movl %edx,%ecx | 247 | 2: movl %edx,%ecx |
250 | 3: rep | 248 | 3: rep |
251 | movsb | 249 | movsb |
252 | 4: xorl %eax,%eax | 250 | xorl %eax,%eax |
253 | ASM_CLAC | 251 | ASM_CLAC |
254 | ret | 252 | ret |
255 | 253 | ||
256 | .section .fixup,"ax" | 254 | .section .fixup,"ax" |
257 | 11: lea (%rdx,%rcx,8),%rcx | 255 | 11: leal (%rdx,%rcx,8),%ecx |
258 | 12: movl %ecx,%edx /* ecx is zerorest also */ | 256 | 12: movl %ecx,%edx /* ecx is zerorest also */ |
259 | jmp copy_user_handle_tail | 257 | jmp copy_user_handle_tail |
260 | .previous | 258 | .previous |
@@ -279,12 +277,10 @@ ENDPROC(copy_user_generic_string) | |||
279 | ENTRY(copy_user_enhanced_fast_string) | 277 | ENTRY(copy_user_enhanced_fast_string) |
280 | CFI_STARTPROC | 278 | CFI_STARTPROC |
281 | ASM_STAC | 279 | ASM_STAC |
282 | andl %edx,%edx | ||
283 | jz 2f | ||
284 | movl %edx,%ecx | 280 | movl %edx,%ecx |
285 | 1: rep | 281 | 1: rep |
286 | movsb | 282 | movsb |
287 | 2: xorl %eax,%eax | 283 | xorl %eax,%eax |
288 | ASM_CLAC | 284 | ASM_CLAC |
289 | ret | 285 | ret |
290 | 286 | ||