]>
Commit | Line | Data |
---|---|---|
eed417dd AB |
1 | #ifndef __ASM_GENERIC_UACCESS_H |
2 | #define __ASM_GENERIC_UACCESS_H | |
3 | ||
4 | /* | |
5 | * User space memory access functions, these should work | |
0a4a6647 | 6 | * on any machine that has kernel and user data in the same |
eed417dd AB |
7 | * address space, e.g. all NOMMU machines. |
8 | */ | |
eed417dd AB |
9 | #include <linux/string.h> |
10 | ||
11 | #include <asm/segment.h> | |
12 | ||
13 | #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) | |
14 | ||
15 | #ifndef KERNEL_DS | |
16 | #define KERNEL_DS MAKE_MM_SEG(~0UL) | |
17 | #endif | |
18 | ||
19 | #ifndef USER_DS | |
20 | #define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) | |
21 | #endif | |
22 | ||
23 | #ifndef get_fs | |
24 | #define get_ds() (KERNEL_DS) | |
25 | #define get_fs() (current_thread_info()->addr_limit) | |
26 | ||
27 | static inline void set_fs(mm_segment_t fs) | |
28 | { | |
29 | current_thread_info()->addr_limit = fs; | |
30 | } | |
31 | #endif | |
32 | ||
10a6007b | 33 | #ifndef segment_eq |
eed417dd | 34 | #define segment_eq(a, b) ((a).seg == (b).seg) |
10a6007b | 35 | #endif |
eed417dd | 36 | |
eed417dd AB |
37 | #define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size)) |
38 | ||
39 | /* | |
40 | * The architecture should really override this if possible, at least | |
41 | * doing a check on the get_fs() | |
42 | */ | |
43 | #ifndef __access_ok | |
44 | static inline int __access_ok(unsigned long addr, unsigned long size) | |
45 | { | |
46 | return 1; | |
47 | } | |
48 | #endif | |
49 | ||
eed417dd AB |
50 | /* |
51 | * These are the main single-value transfer routines. They automatically | |
52 | * use the right size if we just have the right pointer type. | |
53 | * This version just falls back to copy_{from,to}_user, which should | |
54 | * provide a fast-path for small values. | |
55 | */ | |
56 | #define __put_user(x, ptr) \ | |
57 | ({ \ | |
58 | __typeof__(*(ptr)) __x = (x); \ | |
59 | int __pu_err = -EFAULT; \ | |
60 | __chk_user_ptr(ptr); \ | |
61 | switch (sizeof (*(ptr))) { \ | |
62 | case 1: \ | |
63 | case 2: \ | |
64 | case 4: \ | |
65 | case 8: \ | |
66 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ | |
67 | ptr, &__x); \ | |
68 | break; \ | |
69 | default: \ | |
70 | __put_user_bad(); \ | |
71 | break; \ | |
72 | } \ | |
73 | __pu_err; \ | |
74 | }) | |
75 | ||
76 | #define put_user(x, ptr) \ | |
77 | ({ \ | |
a02613a4 | 78 | void *__p = (ptr); \ |
e0acd0bd | 79 | might_fault(); \ |
a02613a4 YS |
80 | access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ? \ |
81 | __put_user((x), ((__typeof__(*(ptr)) *)__p)) : \ | |
eed417dd AB |
82 | -EFAULT; \ |
83 | }) | |
84 | ||
05d88a49 VG |
85 | #ifndef __put_user_fn |
86 | ||
eed417dd AB |
87 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
88 | { | |
89 | size = __copy_to_user(ptr, x, size); | |
90 | return size ? -EFAULT : size; | |
91 | } | |
92 | ||
05d88a49 VG |
93 | #define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) |
94 | ||
95 | #endif | |
96 | ||
eed417dd AB |
97 | extern int __put_user_bad(void) __attribute__((noreturn)); |
98 | ||
99 | #define __get_user(x, ptr) \ | |
100 | ({ \ | |
101 | int __gu_err = -EFAULT; \ | |
102 | __chk_user_ptr(ptr); \ | |
103 | switch (sizeof(*(ptr))) { \ | |
104 | case 1: { \ | |
105 | unsigned char __x; \ | |
106 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ | |
107 | ptr, &__x); \ | |
108 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
109 | break; \ | |
110 | }; \ | |
111 | case 2: { \ | |
112 | unsigned short __x; \ | |
113 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ | |
114 | ptr, &__x); \ | |
115 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
116 | break; \ | |
117 | }; \ | |
118 | case 4: { \ | |
119 | unsigned int __x; \ | |
120 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ | |
121 | ptr, &__x); \ | |
122 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
123 | break; \ | |
124 | }; \ | |
125 | case 8: { \ | |
126 | unsigned long long __x; \ | |
127 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ | |
128 | ptr, &__x); \ | |
129 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | |
130 | break; \ | |
131 | }; \ | |
132 | default: \ | |
133 | __get_user_bad(); \ | |
134 | break; \ | |
135 | } \ | |
136 | __gu_err; \ | |
137 | }) | |
138 | ||
139 | #define get_user(x, ptr) \ | |
140 | ({ \ | |
a02613a4 | 141 | const void *__p = (ptr); \ |
e0acd0bd | 142 | might_fault(); \ |
a02613a4 YS |
143 | access_ok(VERIFY_READ, __p, sizeof(*ptr)) ? \ |
144 | __get_user((x), (__typeof__(*(ptr)) *)__p) : \ | |
9ad18b75 | 145 | ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ |
eed417dd AB |
146 | }) |
147 | ||
05d88a49 | 148 | #ifndef __get_user_fn |
eed417dd AB |
149 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
150 | { | |
9ad18b75 AV |
151 | size_t n = __copy_from_user(x, ptr, size); |
152 | if (unlikely(n)) { | |
153 | memset(x + (size - n), 0, n); | |
154 | return -EFAULT; | |
155 | } | |
156 | return 0; | |
eed417dd AB |
157 | } |
158 | ||
05d88a49 VG |
159 | #define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) |
160 | ||
161 | #endif | |
162 | ||
eed417dd AB |
163 | extern int __get_user_bad(void) __attribute__((noreturn)); |
164 | ||
165 | #ifndef __copy_from_user_inatomic | |
166 | #define __copy_from_user_inatomic __copy_from_user | |
167 | #endif | |
168 | ||
169 | #ifndef __copy_to_user_inatomic | |
170 | #define __copy_to_user_inatomic __copy_to_user | |
171 | #endif | |
172 | ||
173 | static inline long copy_from_user(void *to, | |
174 | const void __user * from, unsigned long n) | |
175 | { | |
2545e5da | 176 | unsigned long res = n; |
e0acd0bd | 177 | might_fault(); |
2545e5da AV |
178 | if (likely(access_ok(VERIFY_READ, from, n))) |
179 | res = __copy_from_user(to, from, n); | |
180 | if (unlikely(res)) | |
181 | memset(to + (n - res), 0, res); | |
182 | return res; | |
eed417dd AB |
183 | } |
184 | ||
185 | static inline long copy_to_user(void __user *to, | |
186 | const void *from, unsigned long n) | |
187 | { | |
e0acd0bd | 188 | might_fault(); |
a9ede5b3 | 189 | if (access_ok(VERIFY_WRITE, to, n)) |
eed417dd AB |
190 | return __copy_to_user(to, from, n); |
191 | else | |
192 | return n; | |
193 | } | |
194 | ||
195 | /* | |
196 | * Copy a null terminated string from userspace. | |
197 | */ | |
198 | #ifndef __strncpy_from_user | |
199 | static inline long | |
200 | __strncpy_from_user(char *dst, const char __user *src, long count) | |
201 | { | |
202 | char *tmp; | |
203 | strncpy(dst, (const char __force *)src, count); | |
204 | for (tmp = dst; *tmp && count > 0; tmp++, count--) | |
205 | ; | |
206 | return (tmp - dst); | |
207 | } | |
208 | #endif | |
209 | ||
210 | static inline long | |
211 | strncpy_from_user(char *dst, const char __user *src, long count) | |
212 | { | |
a9ede5b3 | 213 | if (!access_ok(VERIFY_READ, src, 1)) |
eed417dd AB |
214 | return -EFAULT; |
215 | return __strncpy_from_user(dst, src, count); | |
216 | } | |
217 | ||
218 | /* | |
219 | * Return the size of a string (including the ending 0) | |
220 | * | |
221 | * Return 0 on exception, a value greater than N if too long | |
222 | */ | |
7f509a9e | 223 | #ifndef __strnlen_user |
830f5800 | 224 | #define __strnlen_user(s, n) (strnlen((s), (n)) + 1) |
7f509a9e G |
225 | #endif |
226 | ||
830f5800 MS |
227 | /* |
228 | * Unlike strnlen, strnlen_user includes the nul terminator in | |
229 | * its returned count. Callers should check for a returned value | |
230 | * greater than N as an indication the string is too long. | |
231 | */ | |
eed417dd AB |
232 | static inline long strnlen_user(const char __user *src, long n) |
233 | { | |
9844813f MF |
234 | if (!access_ok(VERIFY_READ, src, 1)) |
235 | return 0; | |
7f509a9e | 236 | return __strnlen_user(src, n); |
eed417dd | 237 | } |
eed417dd AB |
238 | |
239 | static inline long strlen_user(const char __user *src) | |
240 | { | |
241 | return strnlen_user(src, 32767); | |
242 | } | |
243 | ||
244 | /* | |
245 | * Zero Userspace | |
246 | */ | |
247 | #ifndef __clear_user | |
248 | static inline __must_check unsigned long | |
249 | __clear_user(void __user *to, unsigned long n) | |
250 | { | |
251 | memset((void __force *)to, 0, n); | |
252 | return 0; | |
253 | } | |
254 | #endif | |
255 | ||
256 | static inline __must_check unsigned long | |
257 | clear_user(void __user *to, unsigned long n) | |
258 | { | |
e0acd0bd | 259 | might_fault(); |
a9ede5b3 | 260 | if (!access_ok(VERIFY_WRITE, to, n)) |
eed417dd AB |
261 | return n; |
262 | ||
263 | return __clear_user(to, n); | |
264 | } | |
265 | ||
aaa2e7ac AV |
266 | #include <asm/extable.h> |
267 | ||
eed417dd | 268 | #endif /* __ASM_GENERIC_UACCESS_H */ |