diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-03-25 19:33:21 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-03-29 12:06:28 -0400 |
commit | beba3a20bf90ce1b93e24592c3ebf0d0bb581bbe (patch) | |
tree | 065a869987df6450138fd091c9d215e2d2fca498 | |
parent | a41e0d754240fe8ca9c4f2070bf67e3b0228aa22 (diff) |
x86: switch to RAW_COPY_USER
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 53 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess_32.h | 95 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess_64.h | 45 | ||||
-rw-r--r-- | arch/x86/lib/usercopy.c | 55 | ||||
-rw-r--r-- | arch/x86/lib/usercopy_32.c | 170 |
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 | ||
179 | config INSTRUCTION_DECODER | 180 | config 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 | ||
685 | unsigned long __must_check _copy_from_user(void *to, const void __user *from, | ||
686 | unsigned n); | ||
687 | unsigned long __must_check _copy_to_user(void __user *to, const void *from, | ||
688 | unsigned n); | ||
689 | |||
690 | extern void __compiletime_error("usercopy buffer size is too small") | ||
691 | __bad_copy_user(void); | ||
692 | |||
693 | static inline void copy_user_overflow(int size, unsigned long count) | ||
694 | { | ||
695 | WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); | ||
696 | } | ||
697 | |||
698 | static __always_inline unsigned long __must_check | ||
699 | copy_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 | |||
718 | static __always_inline unsigned long __must_check | ||
719 | copy_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 | ||
11 | unsigned long __must_check __copy_to_user_ll | 11 | unsigned 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); |
13 | unsigned long __must_check __copy_from_user_ll | ||
14 | (void *to, const void __user *from, unsigned long n); | ||
15 | unsigned long __must_check __copy_from_user_ll_nozero | ||
16 | (void *to, const void __user *from, unsigned long n); | ||
17 | unsigned long __must_check __copy_from_user_ll_nocache_nozero | 13 | unsigned 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 | */ | ||
33 | static __always_inline unsigned long __must_check | 16 | static __always_inline unsigned long __must_check |
34 | __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n) | 17 | raw_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 | */ | ||
55 | static __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 | |||
62 | static __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 | */ | ||
91 | static __always_inline unsigned long | 22 | static __always_inline unsigned long |
92 | __copy_from_user(void *to, const void __user *from, unsigned long n) | 23 | raw_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 | ||
120 | static __always_inline unsigned long | 55 | static __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 | 48 | static __always_inline __must_check unsigned long |
49 | copy_in_user(void __user *to, const void __user *from, unsigned len); | 49 | raw_copy_from_user(void *dst, const void __user *src, unsigned long size) |
50 | |||
51 | static __always_inline __must_check | ||
52 | int __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 | ||
109 | static __always_inline __must_check | 105 | static __always_inline __must_check unsigned long |
110 | int __copy_from_user(void *dst, const void __user *src, unsigned size) | 106 | raw_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 | |||
117 | static __always_inline __must_check | ||
118 | int __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 | ||
177 | static __always_inline __must_check | 164 | static __always_inline __must_check |
178 | int __copy_to_user(void __user *dst, const void *src, unsigned size) | 165 | unsigned 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 | |||
185 | static __always_inline __must_check | ||
186 | int __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 | ||
192 | static __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 | |||
199 | static __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 | |||
206 | extern long __copy_user_nocache(void *dst, const void __user *src, | 171 | extern 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 | } |
36 | EXPORT_SYMBOL_GPL(copy_from_user_nmi); | 33 | EXPORT_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 | */ | ||
52 | unsigned 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 | } | ||
58 | EXPORT_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 | */ | ||
77 | unsigned 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 | } | ||
86 | EXPORT_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 | ||
204 | static 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 | |||
296 | static unsigned long __copy_user_intel_nocache(void *to, | 199 | static 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 | */ |
390 | unsigned long __copy_user_zeroing_intel(void *to, const void __user *from, | ||
391 | unsigned long size); | ||
392 | unsigned long __copy_user_intel(void __user *to, const void *from, | 293 | unsigned 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) \ | 331 | unsigned long __copy_user_ll(void *to, const void *from, unsigned long n) |
431 | do { \ | ||
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 | |||
469 | unsigned 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 | } |
480 | EXPORT_SYMBOL(__copy_to_user_ll); | 341 | EXPORT_SYMBOL(__copy_user_ll); |
481 | |||
482 | unsigned 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 | } | ||
493 | EXPORT_SYMBOL(__copy_from_user_ll); | ||
494 | |||
495 | unsigned 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 | } | ||
507 | EXPORT_SYMBOL(__copy_from_user_ll_nozero); | ||
508 | 342 | ||
509 | unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, | 343 | unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from, |
510 | unsigned long n) | 344 | unsigned long n) |