aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-s390/uaccess.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-s390/uaccess.h')
-rw-r--r--include/asm-s390/uaccess.h172
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__ 88struct 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" 101extern struct uaccess_ops uaccess;
102#else /* __s390x__ */ 102extern struct uaccess_ops uaccess_std;
103#define __uaccess_fixup \ 103extern struct uaccess_ops uaccess_mvcos;
104 ".section .fixup,\"ax\"\n" \ 104
105 "2: lghi %0,%4\n" \ 105static 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" 111static 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
173extern int __put_user_bad(void) __attribute__((noreturn)); 148extern 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
250extern 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);
266static inline unsigned long 215static 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
297extern 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);
316static inline unsigned long 266static 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
349extern unsigned long __copy_in_user_asm(const void __user *from, long n,
350 void __user *to);
351
352static inline unsigned long 302static 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
358static inline unsigned long 308static 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 */
370extern long __strncpy_from_user_asm(long count, char *dst,
371 const char __user *src);
372
373static inline long 320static inline long
374strncpy_from_user(char *dst, const char __user *src, long count) 321strncpy_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
384extern long __strnlen_user_asm(long count, const char __user *src);
385
386static inline unsigned long 330static inline unsigned long
387strnlen_user(const char __user * src, unsigned long n) 331strnlen_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
413extern long __clear_user_asm(void __user *to, long n);
414
415static inline unsigned long 357static 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
421static inline unsigned long 363static 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