diff options
Diffstat (limited to 'include/asm-s390/uaccess.h')
-rw-r--r-- | include/asm-s390/uaccess.h | 172 |
1 files changed, 57 insertions, 115 deletions
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index 0b7c0ca4c3d7..e2047b0c9092 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h | |||
@@ -47,7 +47,7 @@ | |||
47 | S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ | 47 | S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ |
48 | asm volatile ("lctlg 7,7,%0" : : "m" (__pto) ); \ | 48 | asm volatile ("lctlg 7,7,%0" : : "m" (__pto) ); \ |
49 | }) | 49 | }) |
50 | #else | 50 | #else /* __s390x__ */ |
51 | #define set_fs(x) \ | 51 | #define set_fs(x) \ |
52 | ({ \ | 52 | ({ \ |
53 | unsigned long __pto; \ | 53 | unsigned long __pto; \ |
@@ -56,7 +56,7 @@ | |||
56 | S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ | 56 | S390_lowcore.user_asce : S390_lowcore.kernel_asce; \ |
57 | asm volatile ("lctl 7,7,%0" : : "m" (__pto) ); \ | 57 | asm volatile ("lctl 7,7,%0" : : "m" (__pto) ); \ |
58 | }) | 58 | }) |
59 | #endif | 59 | #endif /* __s390x__ */ |
60 | 60 | ||
61 | #define segment_eq(a,b) ((a).ar4 == (b).ar4) | 61 | #define segment_eq(a,b) ((a).ar4 == (b).ar4) |
62 | 62 | ||
@@ -85,76 +85,51 @@ struct exception_table_entry | |||
85 | unsigned long insn, fixup; | 85 | unsigned long insn, fixup; |
86 | }; | 86 | }; |
87 | 87 | ||
88 | #ifndef __s390x__ | 88 | struct uaccess_ops { |
89 | #define __uaccess_fixup \ | 89 | size_t (*copy_from_user)(size_t, const void __user *, void *); |
90 | ".section .fixup,\"ax\"\n" \ | 90 | size_t (*copy_from_user_small)(size_t, const void __user *, void *); |
91 | "2: lhi %0,%4\n" \ | 91 | size_t (*copy_to_user)(size_t, void __user *, const void *); |
92 | " bras 1,3f\n" \ | 92 | size_t (*copy_to_user_small)(size_t, void __user *, const void *); |
93 | " .long 1b\n" \ | 93 | size_t (*copy_in_user)(size_t, void __user *, const void __user *); |
94 | "3: l 1,0(1)\n" \ | 94 | size_t (*clear_user)(size_t, void __user *); |
95 | " br 1\n" \ | 95 | size_t (*strnlen_user)(size_t, const char __user *); |
96 | ".previous\n" \ | 96 | size_t (*strncpy_from_user)(size_t, const char __user *, char *); |
97 | ".section __ex_table,\"a\"\n" \ | 97 | int (*futex_atomic_op)(int op, int __user *, int oparg, int *old); |
98 | " .align 4\n" \ | 98 | int (*futex_atomic_cmpxchg)(int __user *, int old, int new); |
99 | " .long 0b,2b\n" \ | 99 | }; |
100 | ".previous" | 100 | |
101 | #define __uaccess_clobber "cc", "1" | 101 | extern struct uaccess_ops uaccess; |
102 | #else /* __s390x__ */ | 102 | extern struct uaccess_ops uaccess_std; |
103 | #define __uaccess_fixup \ | 103 | extern struct uaccess_ops uaccess_mvcos; |
104 | ".section .fixup,\"ax\"\n" \ | 104 | |
105 | "2: lghi %0,%4\n" \ | 105 | static inline int __put_user_fn(size_t size, void __user *ptr, void *x) |
106 | " jg 1b\n" \ | 106 | { |
107 | ".previous\n" \ | 107 | size = uaccess.copy_to_user_small(size, ptr, x); |
108 | ".section __ex_table,\"a\"\n" \ | 108 | return size ? -EFAULT : size; |
109 | " .align 8\n" \ | 109 | } |
110 | " .quad 0b,2b\n" \ | 110 | |
111 | ".previous" | 111 | static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) |
112 | #define __uaccess_clobber "cc" | 112 | { |
113 | #endif /* __s390x__ */ | 113 | size = uaccess.copy_from_user_small(size, ptr, x); |
114 | return size ? -EFAULT : size; | ||
115 | } | ||
114 | 116 | ||
115 | /* | 117 | /* |
116 | * These are the main single-value transfer routines. They automatically | 118 | * These are the main single-value transfer routines. They automatically |
117 | * use the right size if we just have the right pointer type. | 119 | * use the right size if we just have the right pointer type. |
118 | */ | 120 | */ |
119 | #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) | ||
120 | #define __put_user_asm(x, ptr, err) \ | ||
121 | ({ \ | ||
122 | err = 0; \ | ||
123 | asm volatile( \ | ||
124 | "0: mvcs 0(%1,%2),%3,%0\n" \ | ||
125 | "1:\n" \ | ||
126 | __uaccess_fixup \ | ||
127 | : "+&d" (err) \ | ||
128 | : "d" (sizeof(*(ptr))), "a" (ptr), "Q" (x), \ | ||
129 | "K" (-EFAULT) \ | ||
130 | : __uaccess_clobber ); \ | ||
131 | }) | ||
132 | #else | ||
133 | #define __put_user_asm(x, ptr, err) \ | ||
134 | ({ \ | ||
135 | err = 0; \ | ||
136 | asm volatile( \ | ||
137 | "0: mvcs 0(%1,%2),0(%3),%0\n" \ | ||
138 | "1:\n" \ | ||
139 | __uaccess_fixup \ | ||
140 | : "+&d" (err) \ | ||
141 | : "d" (sizeof(*(ptr))), "a" (ptr), "a" (&(x)), \ | ||
142 | "K" (-EFAULT), "m" (x) \ | ||
143 | : __uaccess_clobber ); \ | ||
144 | }) | ||
145 | #endif | ||
146 | |||
147 | #define __put_user(x, ptr) \ | 121 | #define __put_user(x, ptr) \ |
148 | ({ \ | 122 | ({ \ |
149 | __typeof__(*(ptr)) __x = (x); \ | 123 | __typeof__(*(ptr)) __x = (x); \ |
150 | int __pu_err; \ | 124 | int __pu_err = -EFAULT; \ |
151 | __chk_user_ptr(ptr); \ | 125 | __chk_user_ptr(ptr); \ |
152 | switch (sizeof (*(ptr))) { \ | 126 | switch (sizeof (*(ptr))) { \ |
153 | case 1: \ | 127 | case 1: \ |
154 | case 2: \ | 128 | case 2: \ |
155 | case 4: \ | 129 | case 4: \ |
156 | case 8: \ | 130 | case 8: \ |
157 | __put_user_asm(__x, ptr, __pu_err); \ | 131 | __pu_err = __put_user_fn(sizeof (*(ptr)), \ |
132 | ptr, &__x); \ | ||
158 | break; \ | 133 | break; \ |
159 | default: \ | 134 | default: \ |
160 | __put_user_bad(); \ | 135 | __put_user_bad(); \ |
@@ -172,60 +147,36 @@ struct exception_table_entry | |||
172 | 147 | ||
173 | extern int __put_user_bad(void) __attribute__((noreturn)); | 148 | extern int __put_user_bad(void) __attribute__((noreturn)); |
174 | 149 | ||
175 | #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) | ||
176 | #define __get_user_asm(x, ptr, err) \ | ||
177 | ({ \ | ||
178 | err = 0; \ | ||
179 | asm volatile ( \ | ||
180 | "0: mvcp %O1(%2,%R1),0(%3),%0\n" \ | ||
181 | "1:\n" \ | ||
182 | __uaccess_fixup \ | ||
183 | : "+&d" (err), "=Q" (x) \ | ||
184 | : "d" (sizeof(*(ptr))), "a" (ptr), \ | ||
185 | "K" (-EFAULT) \ | ||
186 | : __uaccess_clobber ); \ | ||
187 | }) | ||
188 | #else | ||
189 | #define __get_user_asm(x, ptr, err) \ | ||
190 | ({ \ | ||
191 | err = 0; \ | ||
192 | asm volatile ( \ | ||
193 | "0: mvcp 0(%2,%5),0(%3),%0\n" \ | ||
194 | "1:\n" \ | ||
195 | __uaccess_fixup \ | ||
196 | : "+&d" (err), "=m" (x) \ | ||
197 | : "d" (sizeof(*(ptr))), "a" (ptr), \ | ||
198 | "K" (-EFAULT), "a" (&(x)) \ | ||
199 | : __uaccess_clobber ); \ | ||
200 | }) | ||
201 | #endif | ||
202 | |||
203 | #define __get_user(x, ptr) \ | 150 | #define __get_user(x, ptr) \ |
204 | ({ \ | 151 | ({ \ |
205 | int __gu_err; \ | 152 | int __gu_err = -EFAULT; \ |
206 | __chk_user_ptr(ptr); \ | 153 | __chk_user_ptr(ptr); \ |
207 | switch (sizeof(*(ptr))) { \ | 154 | switch (sizeof(*(ptr))) { \ |
208 | case 1: { \ | 155 | case 1: { \ |
209 | unsigned char __x; \ | 156 | unsigned char __x; \ |
210 | __get_user_asm(__x, ptr, __gu_err); \ | 157 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
158 | ptr, &__x); \ | ||
211 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | 159 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
212 | break; \ | 160 | break; \ |
213 | }; \ | 161 | }; \ |
214 | case 2: { \ | 162 | case 2: { \ |
215 | unsigned short __x; \ | 163 | unsigned short __x; \ |
216 | __get_user_asm(__x, ptr, __gu_err); \ | 164 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
165 | ptr, &__x); \ | ||
217 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | 166 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
218 | break; \ | 167 | break; \ |
219 | }; \ | 168 | }; \ |
220 | case 4: { \ | 169 | case 4: { \ |
221 | unsigned int __x; \ | 170 | unsigned int __x; \ |
222 | __get_user_asm(__x, ptr, __gu_err); \ | 171 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
172 | ptr, &__x); \ | ||
223 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | 173 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
224 | break; \ | 174 | break; \ |
225 | }; \ | 175 | }; \ |
226 | case 8: { \ | 176 | case 8: { \ |
227 | unsigned long long __x; \ | 177 | unsigned long long __x; \ |
228 | __get_user_asm(__x, ptr, __gu_err); \ | 178 | __gu_err = __get_user_fn(sizeof (*(ptr)), \ |
179 | ptr, &__x); \ | ||
229 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ | 180 | (x) = *(__force __typeof__(*(ptr)) *) &__x; \ |
230 | break; \ | 181 | break; \ |
231 | }; \ | 182 | }; \ |
@@ -247,8 +198,6 @@ extern int __get_user_bad(void) __attribute__((noreturn)); | |||
247 | #define __put_user_unaligned __put_user | 198 | #define __put_user_unaligned __put_user |
248 | #define __get_user_unaligned __get_user | 199 | #define __get_user_unaligned __get_user |
249 | 200 | ||
250 | extern long __copy_to_user_asm(const void *from, long n, void __user *to); | ||
251 | |||
252 | /** | 201 | /** |
253 | * __copy_to_user: - Copy a block of data into user space, with less checking. | 202 | * __copy_to_user: - Copy a block of data into user space, with less checking. |
254 | * @to: Destination address, in user space. | 203 | * @to: Destination address, in user space. |
@@ -266,7 +215,10 @@ extern long __copy_to_user_asm(const void *from, long n, void __user *to); | |||
266 | static inline unsigned long | 215 | static inline unsigned long |
267 | __copy_to_user(void __user *to, const void *from, unsigned long n) | 216 | __copy_to_user(void __user *to, const void *from, unsigned long n) |
268 | { | 217 | { |
269 | return __copy_to_user_asm(from, n, to); | 218 | if (__builtin_constant_p(n) && (n <= 256)) |
219 | return uaccess.copy_to_user_small(n, to, from); | ||
220 | else | ||
221 | return uaccess.copy_to_user(n, to, from); | ||
270 | } | 222 | } |
271 | 223 | ||
272 | #define __copy_to_user_inatomic __copy_to_user | 224 | #define __copy_to_user_inatomic __copy_to_user |
@@ -294,8 +246,6 @@ copy_to_user(void __user *to, const void *from, unsigned long n) | |||
294 | return n; | 246 | return n; |
295 | } | 247 | } |
296 | 248 | ||
297 | extern long __copy_from_user_asm(void *to, long n, const void __user *from); | ||
298 | |||
299 | /** | 249 | /** |
300 | * __copy_from_user: - Copy a block of data from user space, with less checking. | 250 | * __copy_from_user: - Copy a block of data from user space, with less checking. |
301 | * @to: Destination address, in kernel space. | 251 | * @to: Destination address, in kernel space. |
@@ -316,7 +266,10 @@ extern long __copy_from_user_asm(void *to, long n, const void __user *from); | |||
316 | static inline unsigned long | 266 | static inline unsigned long |
317 | __copy_from_user(void *to, const void __user *from, unsigned long n) | 267 | __copy_from_user(void *to, const void __user *from, unsigned long n) |
318 | { | 268 | { |
319 | return __copy_from_user_asm(to, n, from); | 269 | if (__builtin_constant_p(n) && (n <= 256)) |
270 | return uaccess.copy_from_user_small(n, from, to); | ||
271 | else | ||
272 | return uaccess.copy_from_user(n, from, to); | ||
320 | } | 273 | } |
321 | 274 | ||
322 | /** | 275 | /** |
@@ -346,13 +299,10 @@ copy_from_user(void *to, const void __user *from, unsigned long n) | |||
346 | return n; | 299 | return n; |
347 | } | 300 | } |
348 | 301 | ||
349 | extern unsigned long __copy_in_user_asm(const void __user *from, long n, | ||
350 | void __user *to); | ||
351 | |||
352 | static inline unsigned long | 302 | static inline unsigned long |
353 | __copy_in_user(void __user *to, const void __user *from, unsigned long n) | 303 | __copy_in_user(void __user *to, const void __user *from, unsigned long n) |
354 | { | 304 | { |
355 | return __copy_in_user_asm(from, n, to); | 305 | return uaccess.copy_in_user(n, to, from); |
356 | } | 306 | } |
357 | 307 | ||
358 | static inline unsigned long | 308 | static inline unsigned long |
@@ -360,34 +310,28 @@ copy_in_user(void __user *to, const void __user *from, unsigned long n) | |||
360 | { | 310 | { |
361 | might_sleep(); | 311 | might_sleep(); |
362 | if (__access_ok(from,n) && __access_ok(to,n)) | 312 | if (__access_ok(from,n) && __access_ok(to,n)) |
363 | n = __copy_in_user_asm(from, n, to); | 313 | n = __copy_in_user(to, from, n); |
364 | return n; | 314 | return n; |
365 | } | 315 | } |
366 | 316 | ||
367 | /* | 317 | /* |
368 | * Copy a null terminated string from userspace. | 318 | * Copy a null terminated string from userspace. |
369 | */ | 319 | */ |
370 | extern long __strncpy_from_user_asm(long count, char *dst, | ||
371 | const char __user *src); | ||
372 | |||
373 | static inline long | 320 | static inline long |
374 | strncpy_from_user(char *dst, const char __user *src, long count) | 321 | strncpy_from_user(char *dst, const char __user *src, long count) |
375 | { | 322 | { |
376 | long res = -EFAULT; | 323 | long res = -EFAULT; |
377 | might_sleep(); | 324 | might_sleep(); |
378 | if (access_ok(VERIFY_READ, src, 1)) | 325 | if (access_ok(VERIFY_READ, src, 1)) |
379 | res = __strncpy_from_user_asm(count, dst, src); | 326 | res = uaccess.strncpy_from_user(count, src, dst); |
380 | return res; | 327 | return res; |
381 | } | 328 | } |
382 | 329 | ||
383 | |||
384 | extern long __strnlen_user_asm(long count, const char __user *src); | ||
385 | |||
386 | static inline unsigned long | 330 | static inline unsigned long |
387 | strnlen_user(const char __user * src, unsigned long n) | 331 | strnlen_user(const char __user * src, unsigned long n) |
388 | { | 332 | { |
389 | might_sleep(); | 333 | might_sleep(); |
390 | return __strnlen_user_asm(n, src); | 334 | return uaccess.strnlen_user(n, src); |
391 | } | 335 | } |
392 | 336 | ||
393 | /** | 337 | /** |
@@ -410,12 +354,10 @@ strnlen_user(const char __user * src, unsigned long n) | |||
410 | * Zero Userspace | 354 | * Zero Userspace |
411 | */ | 355 | */ |
412 | 356 | ||
413 | extern long __clear_user_asm(void __user *to, long n); | ||
414 | |||
415 | static inline unsigned long | 357 | static inline unsigned long |
416 | __clear_user(void __user *to, unsigned long n) | 358 | __clear_user(void __user *to, unsigned long n) |
417 | { | 359 | { |
418 | return __clear_user_asm(to, n); | 360 | return uaccess.clear_user(n, to); |
419 | } | 361 | } |
420 | 362 | ||
421 | static inline unsigned long | 363 | static inline unsigned long |
@@ -423,7 +365,7 @@ clear_user(void __user *to, unsigned long n) | |||
423 | { | 365 | { |
424 | might_sleep(); | 366 | might_sleep(); |
425 | if (access_ok(VERIFY_WRITE, to, n)) | 367 | if (access_ok(VERIFY_WRITE, to, n)) |
426 | n = __clear_user_asm(to, n); | 368 | n = uaccess.clear_user(n, to); |
427 | return n; | 369 | return n; |
428 | } | 370 | } |
429 | 371 | ||