aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2017-03-25 19:33:21 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2017-03-29 12:06:28 -0400
commitbeba3a20bf90ce1b93e24592c3ebf0d0bb581bbe (patch)
tree065a869987df6450138fd091c9d215e2d2fca498
parenta41e0d754240fe8ca9c4f2070bf67e3b0228aa22 (diff)
x86: switch to RAW_COPY_USER
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/uaccess.h53
-rw-r--r--arch/x86/include/asm/uaccess_32.h95
-rw-r--r--arch/x86/include/asm/uaccess_64.h45
-rw-r--r--arch/x86/lib/usercopy.c55
-rw-r--r--arch/x86/lib/usercopy_32.c170
6 files changed, 24 insertions, 395 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index cc98d5a294ee..5f59fc388063 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -175,6 +175,7 @@ config X86
175 select USER_STACKTRACE_SUPPORT 175 select USER_STACKTRACE_SUPPORT
176 select VIRT_TO_BUS 176 select VIRT_TO_BUS
177 select X86_FEATURE_NAMES if PROC_FS 177 select X86_FEATURE_NAMES if PROC_FS
178 select ARCH_HAS_RAW_COPY_USER
178 179
179config INSTRUCTION_DECODER 180config INSTRUCTION_DECODER
180 def_bool y 181 def_bool y
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 26410afcb8b0..68766b276d9e 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -682,59 +682,6 @@ extern struct movsl_mask {
682# include <asm/uaccess_64.h> 682# include <asm/uaccess_64.h>
683#endif 683#endif
684 684
685unsigned long __must_check _copy_from_user(void *to, const void __user *from,
686 unsigned n);
687unsigned long __must_check _copy_to_user(void __user *to, const void *from,
688 unsigned n);
689
690extern void __compiletime_error("usercopy buffer size is too small")
691__bad_copy_user(void);
692
693static inline void copy_user_overflow(int size, unsigned long count)
694{
695 WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count);
696}
697
698static __always_inline unsigned long __must_check
699copy_from_user(void *to, const void __user *from, unsigned long n)
700{
701 int sz = __compiletime_object_size(to);
702
703 might_fault();
704
705 kasan_check_write(to, n);
706
707 if (likely(sz < 0 || sz >= n)) {
708 check_object_size(to, n, false);
709 n = _copy_from_user(to, from, n);
710 } else if (!__builtin_constant_p(n))
711 copy_user_overflow(sz, n);
712 else
713 __bad_copy_user();
714
715 return n;
716}
717
718static __always_inline unsigned long __must_check
719copy_to_user(void __user *to, const void *from, unsigned long n)
720{
721 int sz = __compiletime_object_size(from);
722
723 kasan_check_read(from, n);
724
725 might_fault();
726
727 if (likely(sz < 0 || sz >= n)) {
728 check_object_size(from, n, true);
729 n = _copy_to_user(to, from, n);
730 } else if (!__builtin_constant_p(n))
731 copy_user_overflow(sz, n);
732 else
733 __bad_copy_user();
734
735 return n;
736}
737
738/* 685/*
739 * We rely on the nested NMI work to allow atomic faults from the NMI path; the 686 * We rely on the nested NMI work to allow atomic faults from the NMI path; the
740 * nested NMI paths are careful to preserve CR2. 687 * nested NMI paths are careful to preserve CR2.
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 19e6c050c438..aeda9bb8af50 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -8,113 +8,48 @@
8#include <asm/asm.h> 8#include <asm/asm.h>
9#include <asm/page.h> 9#include <asm/page.h>
10 10
11unsigned long __must_check __copy_to_user_ll 11unsigned long __must_check __copy_user_ll
12 (void __user *to, const void *from, unsigned long n); 12 (void *to, const void *from, unsigned long n);
13unsigned long __must_check __copy_from_user_ll
14 (void *to, const void __user *from, unsigned long n);
15unsigned long __must_check __copy_from_user_ll_nozero
16 (void *to, const void __user *from, unsigned long n);
17unsigned long __must_check __copy_from_user_ll_nocache_nozero 13unsigned long __must_check __copy_from_user_ll_nocache_nozero
18 (void *to, const void __user *from, unsigned long n); 14 (void *to, const void __user *from, unsigned long n);
19 15
20/**
21 * __copy_to_user_inatomic: - Copy a block of data into user space, with less checking.
22 * @to: Destination address, in user space.
23 * @from: Source address, in kernel space.
24 * @n: Number of bytes to copy.
25 *
26 * Context: User context only.
27 *
28 * Copy data from kernel space to user space. Caller must check
29 * the specified block with access_ok() before calling this function.
30 * The caller should also make sure he pins the user space address
31 * so that we don't result in page fault and sleep.
32 */
33static __always_inline unsigned long __must_check 16static __always_inline unsigned long __must_check
34__copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) 17raw_copy_to_user(void __user *to, const void *from, unsigned long n)
35{ 18{
36 check_object_size(from, n, true); 19 return __copy_user_ll((__force void *)to, from, n);
37 return __copy_to_user_ll(to, from, n);
38} 20}
39 21
40/**
41 * __copy_to_user: - Copy a block of data into user space, with less checking.
42 * @to: Destination address, in user space.
43 * @from: Source address, in kernel space.
44 * @n: Number of bytes to copy.
45 *
46 * Context: User context only. This function may sleep if pagefaults are
47 * enabled.
48 *
49 * Copy data from kernel space to user space. Caller must check
50 * the specified block with access_ok() before calling this function.
51 *
52 * Returns number of bytes that could not be copied.
53 * On success, this will be zero.
54 */
55static __always_inline unsigned long __must_check
56__copy_to_user(void __user *to, const void *from, unsigned long n)
57{
58 might_fault();
59 return __copy_to_user_inatomic(to, from, n);
60}
61
62static __always_inline unsigned long
63__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
64{
65 return __copy_from_user_ll_nozero(to, from, n);
66}
67
68/**
69 * __copy_from_user: - Copy a block of data from user space, with less checking.
70 * @to: Destination address, in kernel space.
71 * @from: Source address, in user space.
72 * @n: Number of bytes to copy.
73 *
74 * Context: User context only. This function may sleep if pagefaults are
75 * enabled.
76 *
77 * Copy data from user space to kernel space. Caller must check
78 * the specified block with access_ok() before calling this function.
79 *
80 * Returns number of bytes that could not be copied.
81 * On success, this will be zero.
82 *
83 * If some data could not be copied, this function will pad the copied
84 * data to the requested size using zero bytes.
85 *
86 * An alternate version - __copy_from_user_inatomic() - may be called from
87 * atomic context and will fail rather than sleep. In this case the
88 * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h
89 * for explanation of why this is needed.
90 */
91static __always_inline unsigned long 22static __always_inline unsigned long
92__copy_from_user(void *to, const void __user *from, unsigned long n) 23raw_copy_from_user(void *to, const void __user *from, unsigned long n)
93{ 24{
94 might_fault();
95 check_object_size(to, n, false);
96 if (__builtin_constant_p(n)) { 25 if (__builtin_constant_p(n)) {
97 unsigned long ret; 26 unsigned long ret;
98 27
99 switch (n) { 28 switch (n) {
100 case 1: 29 case 1:
30 ret = 0;
101 __uaccess_begin(); 31 __uaccess_begin();
102 __get_user_size(*(u8 *)to, from, 1, ret, 1); 32 __get_user_asm_nozero(*(u8 *)to, from, ret,
33 "b", "b", "=q", 1);
103 __uaccess_end(); 34 __uaccess_end();
104 return ret; 35 return ret;
105 case 2: 36 case 2:
37 ret = 0;
106 __uaccess_begin(); 38 __uaccess_begin();
107 __get_user_size(*(u16 *)to, from, 2, ret, 2); 39 __get_user_asm_nozero(*(u16 *)to, from, ret,
40 "w", "w", "=r", 2);
108 __uaccess_end(); 41 __uaccess_end();
109 return ret; 42 return ret;
110 case 4: 43 case 4:
44 ret = 0;
111 __uaccess_begin(); 45 __uaccess_begin();
112 __get_user_size(*(u32 *)to, from, 4, ret, 4); 46 __get_user_asm_nozero(*(u32 *)to, from, ret,
47 "l", "k", "=r", 4);
113 __uaccess_end(); 48 __uaccess_end();
114 return ret; 49 return ret;
115 } 50 }
116 } 51 }
117 return __copy_from_user_ll(to, from, n); 52 return __copy_user_ll(to, (__force const void *)from, n);
118} 53}
119 54
120static __always_inline unsigned long 55static __always_inline unsigned long
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 497ca1bb0440..c5504b9a472e 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -45,15 +45,11 @@ copy_user_generic(void *to, const void *from, unsigned len)
45 return ret; 45 return ret;
46} 46}
47 47
48__must_check unsigned long 48static __always_inline __must_check unsigned long
49copy_in_user(void __user *to, const void __user *from, unsigned len); 49raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
50
51static __always_inline __must_check
52int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
53{ 50{
54 int ret = 0; 51 int ret = 0;
55 52
56 check_object_size(dst, size, false);
57 if (!__builtin_constant_p(size)) 53 if (!__builtin_constant_p(size))
58 return copy_user_generic(dst, (__force void *)src, size); 54 return copy_user_generic(dst, (__force void *)src, size);
59 switch (size) { 55 switch (size) {
@@ -106,20 +102,11 @@ int __copy_from_user_nocheck(void *dst, const void __user *src, unsigned size)
106 } 102 }
107} 103}
108 104
109static __always_inline __must_check 105static __always_inline __must_check unsigned long
110int __copy_from_user(void *dst, const void __user *src, unsigned size) 106raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
111{
112 might_fault();
113 kasan_check_write(dst, size);
114 return __copy_from_user_nocheck(dst, src, size);
115}
116
117static __always_inline __must_check
118int __copy_to_user_nocheck(void __user *dst, const void *src, unsigned size)
119{ 107{
120 int ret = 0; 108 int ret = 0;
121 109
122 check_object_size(src, size, true);
123 if (!__builtin_constant_p(size)) 110 if (!__builtin_constant_p(size))
124 return copy_user_generic((__force void *)dst, src, size); 111 return copy_user_generic((__force void *)dst, src, size);
125 switch (size) { 112 switch (size) {
@@ -175,34 +162,12 @@ int __copy_to_user_nocheck(void __user *dst, const void *src, unsigned size)
175} 162}
176 163
177static __always_inline __must_check 164static __always_inline __must_check
178int __copy_to_user(void __user *dst, const void *src, unsigned size) 165unsigned long raw_copy_in_user(void __user *dst, const void __user *src, unsigned long size)
179{
180 might_fault();
181 kasan_check_read(src, size);
182 return __copy_to_user_nocheck(dst, src, size);
183}
184
185static __always_inline __must_check
186int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
187{ 166{
188 return copy_user_generic((__force void *)dst, 167 return copy_user_generic((__force void *)dst,
189 (__force void *)src, size); 168 (__force void *)src, size);
190} 169}
191 170
192static __must_check __always_inline int
193__copy_from_user_inatomic(void *dst, const void __user *src, unsigned size)
194{
195 kasan_check_write(dst, size);
196 return __copy_from_user_nocheck(dst, src, size);
197}
198
199static __must_check __always_inline int
200__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
201{
202 kasan_check_read(src, size);
203 return __copy_to_user_nocheck(dst, src, size);
204}
205
206extern long __copy_user_nocache(void *dst, const void __user *src, 171extern long __copy_user_nocache(void *dst, const void __user *src,
207 unsigned size, int zerorest); 172 unsigned size, int zerorest);
208 173
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
index a851f3d199c2..c8c6ad0d58b8 100644
--- a/arch/x86/lib/usercopy.c
+++ b/arch/x86/lib/usercopy.c
@@ -4,12 +4,9 @@
4 * For licencing details see kernel-base/COPYING 4 * For licencing details see kernel-base/COPYING
5 */ 5 */
6 6
7#include <linux/highmem.h> 7#include <linux/uaccess.h>
8#include <linux/export.h> 8#include <linux/export.h>
9 9
10#include <asm/word-at-a-time.h>
11#include <linux/sched.h>
12
13/* 10/*
14 * We rely on the nested NMI work to allow atomic faults from the NMI path; the 11 * We rely on the nested NMI work to allow atomic faults from the NMI path; the
15 * nested NMI paths are careful to preserve CR2. 12 * nested NMI paths are careful to preserve CR2.
@@ -34,53 +31,3 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
34 return ret; 31 return ret;
35} 32}
36EXPORT_SYMBOL_GPL(copy_from_user_nmi); 33EXPORT_SYMBOL_GPL(copy_from_user_nmi);
37
38/**
39 * copy_to_user: - Copy a block of data into user space.
40 * @to: Destination address, in user space.
41 * @from: Source address, in kernel space.
42 * @n: Number of bytes to copy.
43 *
44 * Context: User context only. This function may sleep if pagefaults are
45 * enabled.
46 *
47 * Copy data from kernel space to user space.
48 *
49 * Returns number of bytes that could not be copied.
50 * On success, this will be zero.
51 */
52unsigned long _copy_to_user(void __user *to, const void *from, unsigned n)
53{
54 if (access_ok(VERIFY_WRITE, to, n))
55 n = __copy_to_user(to, from, n);
56 return n;
57}
58EXPORT_SYMBOL(_copy_to_user);
59
60/**
61 * copy_from_user: - Copy a block of data from user space.
62 * @to: Destination address, in kernel space.
63 * @from: Source address, in user space.
64 * @n: Number of bytes to copy.
65 *
66 * Context: User context only. This function may sleep if pagefaults are
67 * enabled.
68 *
69 * Copy data from user space to kernel space.
70 *
71 * Returns number of bytes that could not be copied.
72 * On success, this will be zero.
73 *
74 * If some data could not be copied, this function will pad the copied
75 * data to the requested size using zero bytes.
76 */
77unsigned long _copy_from_user(void *to, const void __user *from, unsigned n)
78{
79 unsigned long res = n;
80 if (access_ok(VERIFY_READ, from, n))
81 res = __copy_from_user_inatomic(to, from, n);
82 if (unlikely(res))
83 memset(to + n - res, 0, res);
84 return res;
85}
86EXPORT_SYMBOL(_copy_from_user);
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 02aa7aa8b9f3..bd057a4ffe6e 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -5,12 +5,7 @@
5 * Copyright 1997 Andi Kleen <ak@muc.de> 5 * Copyright 1997 Andi Kleen <ak@muc.de>
6 * Copyright 1997 Linus Torvalds 6 * Copyright 1997 Linus Torvalds
7 */ 7 */
8#include <linux/mm.h>
9#include <linux/highmem.h>
10#include <linux/blkdev.h>
11#include <linux/export.h> 8#include <linux/export.h>
12#include <linux/backing-dev.h>
13#include <linux/interrupt.h>
14#include <linux/uaccess.h> 9#include <linux/uaccess.h>
15#include <asm/mmx.h> 10#include <asm/mmx.h>
16#include <asm/asm.h> 11#include <asm/asm.h>
@@ -201,98 +196,6 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size)
201 return size; 196 return size;
202} 197}
203 198
204static unsigned long
205__copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
206{
207 int d0, d1;
208 __asm__ __volatile__(
209 " .align 2,0x90\n"
210 "0: movl 32(%4), %%eax\n"
211 " cmpl $67, %0\n"
212 " jbe 2f\n"
213 "1: movl 64(%4), %%eax\n"
214 " .align 2,0x90\n"
215 "2: movl 0(%4), %%eax\n"
216 "21: movl 4(%4), %%edx\n"
217 " movl %%eax, 0(%3)\n"
218 " movl %%edx, 4(%3)\n"
219 "3: movl 8(%4), %%eax\n"
220 "31: movl 12(%4),%%edx\n"
221 " movl %%eax, 8(%3)\n"
222 " movl %%edx, 12(%3)\n"
223 "4: movl 16(%4), %%eax\n"
224 "41: movl 20(%4), %%edx\n"
225 " movl %%eax, 16(%3)\n"
226 " movl %%edx, 20(%3)\n"
227 "10: movl 24(%4), %%eax\n"
228 "51: movl 28(%4), %%edx\n"
229 " movl %%eax, 24(%3)\n"
230 " movl %%edx, 28(%3)\n"
231 "11: movl 32(%4), %%eax\n"
232 "61: movl 36(%4), %%edx\n"
233 " movl %%eax, 32(%3)\n"
234 " movl %%edx, 36(%3)\n"
235 "12: movl 40(%4), %%eax\n"
236 "71: movl 44(%4), %%edx\n"
237 " movl %%eax, 40(%3)\n"
238 " movl %%edx, 44(%3)\n"
239 "13: movl 48(%4), %%eax\n"
240 "81: movl 52(%4), %%edx\n"
241 " movl %%eax, 48(%3)\n"
242 " movl %%edx, 52(%3)\n"
243 "14: movl 56(%4), %%eax\n"
244 "91: movl 60(%4), %%edx\n"
245 " movl %%eax, 56(%3)\n"
246 " movl %%edx, 60(%3)\n"
247 " addl $-64, %0\n"
248 " addl $64, %4\n"
249 " addl $64, %3\n"
250 " cmpl $63, %0\n"
251 " ja 0b\n"
252 "5: movl %0, %%eax\n"
253 " shrl $2, %0\n"
254 " andl $3, %%eax\n"
255 " cld\n"
256 "6: rep; movsl\n"
257 " movl %%eax,%0\n"
258 "7: rep; movsb\n"
259 "8:\n"
260 ".section .fixup,\"ax\"\n"
261 "9: lea 0(%%eax,%0,4),%0\n"
262 "16: pushl %0\n"
263 " pushl %%eax\n"
264 " xorl %%eax,%%eax\n"
265 " rep; stosb\n"
266 " popl %%eax\n"
267 " popl %0\n"
268 " jmp 8b\n"
269 ".previous\n"
270 _ASM_EXTABLE(0b,16b)
271 _ASM_EXTABLE(1b,16b)
272 _ASM_EXTABLE(2b,16b)
273 _ASM_EXTABLE(21b,16b)
274 _ASM_EXTABLE(3b,16b)
275 _ASM_EXTABLE(31b,16b)
276 _ASM_EXTABLE(4b,16b)
277 _ASM_EXTABLE(41b,16b)
278 _ASM_EXTABLE(10b,16b)
279 _ASM_EXTABLE(51b,16b)
280 _ASM_EXTABLE(11b,16b)
281 _ASM_EXTABLE(61b,16b)
282 _ASM_EXTABLE(12b,16b)
283 _ASM_EXTABLE(71b,16b)
284 _ASM_EXTABLE(13b,16b)
285 _ASM_EXTABLE(81b,16b)
286 _ASM_EXTABLE(14b,16b)
287 _ASM_EXTABLE(91b,16b)
288 _ASM_EXTABLE(6b,9b)
289 _ASM_EXTABLE(7b,16b)
290 : "=&c"(size), "=&D" (d0), "=&S" (d1)
291 : "1"(to), "2"(from), "0"(size)
292 : "eax", "edx", "memory");
293 return size;
294}
295
296static unsigned long __copy_user_intel_nocache(void *to, 199static unsigned long __copy_user_intel_nocache(void *to,
297 const void __user *from, unsigned long size) 200 const void __user *from, unsigned long size)
298{ 201{
@@ -387,8 +290,6 @@ static unsigned long __copy_user_intel_nocache(void *to,
387 * Leave these declared but undefined. They should not be any references to 290 * Leave these declared but undefined. They should not be any references to
388 * them 291 * them
389 */ 292 */
390unsigned long __copy_user_zeroing_intel(void *to, const void __user *from,
391 unsigned long size);
392unsigned long __copy_user_intel(void __user *to, const void *from, 293unsigned long __copy_user_intel(void __user *to, const void *from,
393 unsigned long size); 294 unsigned long size);
394#endif /* CONFIG_X86_INTEL_USERCOPY */ 295#endif /* CONFIG_X86_INTEL_USERCOPY */
@@ -427,47 +328,7 @@ do { \
427 : "memory"); \ 328 : "memory"); \
428} while (0) 329} while (0)
429 330
430#define __copy_user_zeroing(to, from, size) \ 331unsigned long __copy_user_ll(void *to, const void *from, unsigned long n)
431do { \
432 int __d0, __d1, __d2; \
433 __asm__ __volatile__( \
434 " cmp $7,%0\n" \
435 " jbe 1f\n" \
436 " movl %1,%0\n" \
437 " negl %0\n" \
438 " andl $7,%0\n" \
439 " subl %0,%3\n" \
440 "4: rep; movsb\n" \
441 " movl %3,%0\n" \
442 " shrl $2,%0\n" \
443 " andl $3,%3\n" \
444 " .align 2,0x90\n" \
445 "0: rep; movsl\n" \
446 " movl %3,%0\n" \
447 "1: rep; movsb\n" \
448 "2:\n" \
449 ".section .fixup,\"ax\"\n" \
450 "5: addl %3,%0\n" \
451 " jmp 6f\n" \
452 "3: lea 0(%3,%0,4),%0\n" \
453 "6: pushl %0\n" \
454 " pushl %%eax\n" \
455 " xorl %%eax,%%eax\n" \
456 " rep; stosb\n" \
457 " popl %%eax\n" \
458 " popl %0\n" \
459 " jmp 2b\n" \
460 ".previous\n" \
461 _ASM_EXTABLE(4b,5b) \
462 _ASM_EXTABLE(0b,3b) \
463 _ASM_EXTABLE(1b,6b) \
464 : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
465 : "3"(size), "0"(size), "1"(to), "2"(from) \
466 : "memory"); \
467} while (0)
468
469unsigned long __copy_to_user_ll(void __user *to, const void *from,
470 unsigned long n)
471{ 332{
472 stac(); 333 stac();
473 if (movsl_is_ok(to, from, n)) 334 if (movsl_is_ok(to, from, n))
@@ -477,34 +338,7 @@ unsigned long __copy_to_user_ll(void __user *to, const void *from,
477 clac(); 338 clac();
478 return n; 339 return n;
479} 340}
480EXPORT_SYMBOL(__copy_to_user_ll); 341EXPORT_SYMBOL(__copy_user_ll);
481
482unsigned long __copy_from_user_ll(void *to, const void __user *from,
483 unsigned long n)
484{
485 stac();
486 if (movsl_is_ok(to, from, n))
487 __copy_user_zeroing(to, from, n);
488 else
489 n = __copy_user_zeroing_intel(to, from, n);
490 clac();
491 return n;
492}
493EXPORT_SYMBOL(__copy_from_user_ll);
494
495unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
496 unsigned long n)
497{
498 stac();
499 if (movsl_is_ok(to, from, n))
500 __copy_user(to, from, n);
501 else
502 n = __copy_user_intel((void __user *)to,
503 (const void *)from, n);
504 clac();
505 return n;
506}
507EXPORT_SYMBOL(__copy_from_user_ll_nozero);
508 342
509unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, 343unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
510 unsigned long n) 344 unsigned long n)