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