]>
Commit | Line | Data |
---|---|---|
1965aae3 PA |
1 | #ifndef _ASM_X86_UACCESS_64_H |
2 | #define _ASM_X86_UACCESS_64_H | |
1da177e4 LT |
3 | |
4 | /* | |
5 | * User space memory access functions | |
6 | */ | |
1da177e4 LT |
7 | #include <linux/compiler.h> |
8 | #include <linux/errno.h> | |
1da177e4 | 9 | #include <linux/prefetch.h> |
16dbc6c9 | 10 | #include <linux/lockdep.h> |
1da177e4 LT |
11 | #include <asm/page.h> |
12 | ||
1da177e4 LT |
13 | /* |
14 | * Copy To/From Userspace | |
15 | */ | |
16 | ||
17 | /* Handles exceptions in both to and from, but doesn't do access_ok */ | |
95912008 AK |
18 | __must_check unsigned long |
19 | copy_user_generic(void *to, const void *from, unsigned len); | |
20 | ||
21 | __must_check unsigned long | |
22 | copy_to_user(void __user *to, const void *from, unsigned len); | |
23 | __must_check unsigned long | |
9f0cf4ad | 24 | _copy_from_user(void *to, const void __user *from, unsigned len); |
95912008 AK |
25 | __must_check unsigned long |
26 | copy_in_user(void __user *to, const void __user *from, unsigned len); | |
27 | ||
9f0cf4ad AV |
28 | static inline unsigned long __must_check copy_from_user(void *to, |
29 | const void __user *from, | |
30 | unsigned long n) | |
31 | { | |
32 | int sz = __compiletime_object_size(to); | |
33 | int ret = -EFAULT; | |
34 | ||
35 | if (likely(sz == -1 || sz >= n)) | |
36 | ret = _copy_from_user(to, from, n); | |
37 | #ifdef CONFIG_DEBUG_VM | |
38 | else | |
39 | WARN(1, "Buffer overflow detected!\n"); | |
40 | #endif | |
41 | return ret; | |
42 | } | |
43 | ||
44 | ||
95912008 AK |
45 | static __always_inline __must_check |
46 | int __copy_from_user(void *dst, const void __user *src, unsigned size) | |
b896313e | 47 | { |
383d079b | 48 | int ret = 0; |
c10d38dd | 49 | |
3ee1afa3 | 50 | might_fault(); |
1da177e4 | 51 | if (!__builtin_constant_p(size)) |
b896313e JP |
52 | return copy_user_generic(dst, (__force void *)src, size); |
53 | switch (size) { | |
54 | case 1:__get_user_asm(*(u8 *)dst, (u8 __user *)src, | |
55 | ret, "b", "b", "=q", 1); | |
1da177e4 | 56 | return ret; |
b896313e JP |
57 | case 2:__get_user_asm(*(u16 *)dst, (u16 __user *)src, |
58 | ret, "w", "w", "=r", 2); | |
1da177e4 | 59 | return ret; |
b896313e JP |
60 | case 4:__get_user_asm(*(u32 *)dst, (u32 __user *)src, |
61 | ret, "l", "k", "=r", 4); | |
62 | return ret; | |
63 | case 8:__get_user_asm(*(u64 *)dst, (u64 __user *)src, | |
64 | ret, "q", "", "=r", 8); | |
1da177e4 | 65 | return ret; |
1da177e4 | 66 | case 10: |
b896313e | 67 | __get_user_asm(*(u64 *)dst, (u64 __user *)src, |
20a4a236 | 68 | ret, "q", "", "=r", 10); |
b896313e JP |
69 | if (unlikely(ret)) |
70 | return ret; | |
71 | __get_user_asm(*(u16 *)(8 + (char *)dst), | |
72 | (u16 __user *)(8 + (char __user *)src), | |
73 | ret, "w", "w", "=r", 2); | |
74 | return ret; | |
1da177e4 | 75 | case 16: |
b896313e JP |
76 | __get_user_asm(*(u64 *)dst, (u64 __user *)src, |
77 | ret, "q", "", "=r", 16); | |
78 | if (unlikely(ret)) | |
79 | return ret; | |
80 | __get_user_asm(*(u64 *)(8 + (char *)dst), | |
81 | (u64 __user *)(8 + (char __user *)src), | |
82 | ret, "q", "", "=r", 8); | |
83 | return ret; | |
1da177e4 | 84 | default: |
b896313e | 85 | return copy_user_generic(dst, (__force void *)src, size); |
1da177e4 | 86 | } |
b896313e | 87 | } |
1da177e4 | 88 | |
95912008 AK |
89 | static __always_inline __must_check |
90 | int __copy_to_user(void __user *dst, const void *src, unsigned size) | |
b896313e | 91 | { |
383d079b | 92 | int ret = 0; |
c10d38dd | 93 | |
3ee1afa3 | 94 | might_fault(); |
1da177e4 | 95 | if (!__builtin_constant_p(size)) |
b896313e JP |
96 | return copy_user_generic((__force void *)dst, src, size); |
97 | switch (size) { | |
98 | case 1:__put_user_asm(*(u8 *)src, (u8 __user *)dst, | |
99 | ret, "b", "b", "iq", 1); | |
1da177e4 | 100 | return ret; |
b896313e JP |
101 | case 2:__put_user_asm(*(u16 *)src, (u16 __user *)dst, |
102 | ret, "w", "w", "ir", 2); | |
1da177e4 | 103 | return ret; |
b896313e JP |
104 | case 4:__put_user_asm(*(u32 *)src, (u32 __user *)dst, |
105 | ret, "l", "k", "ir", 4); | |
106 | return ret; | |
107 | case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst, | |
155b7352 | 108 | ret, "q", "", "er", 8); |
1da177e4 | 109 | return ret; |
1da177e4 | 110 | case 10: |
b896313e | 111 | __put_user_asm(*(u64 *)src, (u64 __user *)dst, |
155b7352 | 112 | ret, "q", "", "er", 10); |
b896313e JP |
113 | if (unlikely(ret)) |
114 | return ret; | |
1da177e4 | 115 | asm("":::"memory"); |
b896313e JP |
116 | __put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst, |
117 | ret, "w", "w", "ir", 2); | |
118 | return ret; | |
1da177e4 | 119 | case 16: |
b896313e | 120 | __put_user_asm(*(u64 *)src, (u64 __user *)dst, |
155b7352 | 121 | ret, "q", "", "er", 16); |
b896313e JP |
122 | if (unlikely(ret)) |
123 | return ret; | |
1da177e4 | 124 | asm("":::"memory"); |
b896313e | 125 | __put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst, |
155b7352 | 126 | ret, "q", "", "er", 8); |
b896313e | 127 | return ret; |
1da177e4 | 128 | default: |
b896313e | 129 | return copy_user_generic((__force void *)dst, src, size); |
1da177e4 | 130 | } |
b896313e | 131 | } |
1da177e4 | 132 | |
95912008 AK |
133 | static __always_inline __must_check |
134 | int __copy_in_user(void __user *dst, const void __user *src, unsigned size) | |
b896313e | 135 | { |
383d079b | 136 | int ret = 0; |
c10d38dd | 137 | |
3ee1afa3 | 138 | might_fault(); |
1da177e4 | 139 | if (!__builtin_constant_p(size)) |
b896313e JP |
140 | return copy_user_generic((__force void *)dst, |
141 | (__force void *)src, size); | |
142 | switch (size) { | |
143 | case 1: { | |
1da177e4 | 144 | u8 tmp; |
b896313e JP |
145 | __get_user_asm(tmp, (u8 __user *)src, |
146 | ret, "b", "b", "=q", 1); | |
1da177e4 | 147 | if (likely(!ret)) |
b896313e JP |
148 | __put_user_asm(tmp, (u8 __user *)dst, |
149 | ret, "b", "b", "iq", 1); | |
1da177e4 LT |
150 | return ret; |
151 | } | |
b896313e | 152 | case 2: { |
1da177e4 | 153 | u16 tmp; |
b896313e JP |
154 | __get_user_asm(tmp, (u16 __user *)src, |
155 | ret, "w", "w", "=r", 2); | |
1da177e4 | 156 | if (likely(!ret)) |
b896313e JP |
157 | __put_user_asm(tmp, (u16 __user *)dst, |
158 | ret, "w", "w", "ir", 2); | |
1da177e4 LT |
159 | return ret; |
160 | } | |
161 | ||
b896313e | 162 | case 4: { |
1da177e4 | 163 | u32 tmp; |
b896313e JP |
164 | __get_user_asm(tmp, (u32 __user *)src, |
165 | ret, "l", "k", "=r", 4); | |
1da177e4 | 166 | if (likely(!ret)) |
b896313e JP |
167 | __put_user_asm(tmp, (u32 __user *)dst, |
168 | ret, "l", "k", "ir", 4); | |
1da177e4 LT |
169 | return ret; |
170 | } | |
b896313e | 171 | case 8: { |
1da177e4 | 172 | u64 tmp; |
b896313e JP |
173 | __get_user_asm(tmp, (u64 __user *)src, |
174 | ret, "q", "", "=r", 8); | |
1da177e4 | 175 | if (likely(!ret)) |
b896313e | 176 | __put_user_asm(tmp, (u64 __user *)dst, |
155b7352 | 177 | ret, "q", "", "er", 8); |
1da177e4 LT |
178 | return ret; |
179 | } | |
180 | default: | |
b896313e JP |
181 | return copy_user_generic((__force void *)dst, |
182 | (__force void *)src, size); | |
1da177e4 | 183 | } |
b896313e | 184 | } |
1da177e4 | 185 | |
b896313e | 186 | __must_check long |
95912008 | 187 | strncpy_from_user(char *dst, const char __user *src, long count); |
b896313e | 188 | __must_check long |
95912008 AK |
189 | __strncpy_from_user(char *dst, const char __user *src, long count); |
190 | __must_check long strnlen_user(const char __user *str, long n); | |
191 | __must_check long __strnlen_user(const char __user *str, long n); | |
192 | __must_check long strlen_user(const char __user *str); | |
193 | __must_check unsigned long clear_user(void __user *mem, unsigned long len); | |
194 | __must_check unsigned long __clear_user(void __user *mem, unsigned long len); | |
195 | ||
14722485 JB |
196 | static __must_check __always_inline int |
197 | __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size) | |
198 | { | |
199 | return copy_user_generic(dst, (__force const void *)src, size); | |
200 | } | |
b885808e AK |
201 | |
202 | static __must_check __always_inline int | |
203 | __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size) | |
204 | { | |
205 | return copy_user_generic((__force void *)dst, src, size); | |
206 | } | |
1da177e4 | 207 | |
b896313e JP |
208 | extern long __copy_user_nocache(void *dst, const void __user *src, |
209 | unsigned size, int zerorest); | |
0812a579 | 210 | |
f1800536 IM |
211 | static inline int |
212 | __copy_from_user_nocache(void *dst, const void __user *src, unsigned size) | |
0812a579 AK |
213 | { |
214 | might_sleep(); | |
f1800536 | 215 | return __copy_user_nocache(dst, src, size, 1); |
0812a579 AK |
216 | } |
217 | ||
f1800536 IM |
218 | static inline int |
219 | __copy_from_user_inatomic_nocache(void *dst, const void __user *src, | |
220 | unsigned size) | |
0812a579 | 221 | { |
f1800536 | 222 | return __copy_user_nocache(dst, src, size, 0); |
0812a579 AK |
223 | } |
224 | ||
1129585a VM |
225 | unsigned long |
226 | copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest); | |
227 | ||
1965aae3 | 228 | #endif /* _ASM_X86_UACCESS_64_H */ |