cleanup
[linux-2.4.git] / include / asm-s390x / uaccess.h
1 /*
2  *  include/asm-s390/uaccess.h
3  *
4  *  S390 version
5  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6  *    Author(s): Hartmut Penner (hpenner@de.ibm.com),
7  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
8  *
9  *  Derived from "include/asm-i386/uaccess.h"
10  */
11 #ifndef __S390_UACCESS_H
12 #define __S390_UACCESS_H
13
14 /*
15  * User space memory access functions
16  */
17 #include <linux/sched.h>
18
19 #define VERIFY_READ     0
20 #define VERIFY_WRITE    1
21
22
23 /*
24  * The fs value determines whether argument validity checking should be
25  * performed or not.  If get_fs() == USER_DS, checking is performed, with
26  * get_fs() == KERNEL_DS, checking is bypassed.
27  *
28  * For historical reasons, these macros are grossly misnamed.
29  */
30
31 #define MAKE_MM_SEG(s)  ((mm_segment_t) { (s) })
32
33
34 #define KERNEL_DS       MAKE_MM_SEG(0)
35 #define USER_DS         MAKE_MM_SEG(1)
36
37 #define get_ds()        (KERNEL_DS)
38 #define get_fs()        (current->addr_limit)
39 #define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4));\
40                           current->addr_limit = (x);})
41
42 #define segment_eq(a,b) ((a).ar4 == (b).ar4)
43
44
45 #define __access_ok(addr,size) (1)
46
47 #define access_ok(type,addr,size) __access_ok(addr,size)
48
49 extern inline int verify_area(int type, const void * addr, unsigned long size)
50 {
51         return access_ok(type,addr,size)?0:-EFAULT;
52 }
53
54 /*
55  * The exception table consists of pairs of addresses: the first is the
56  * address of an instruction that is allowed to fault, and the second is
57  * the address at which the program should continue.  No registers are
58  * modified, so it is entirely up to the continuation code to figure out
59  * what to do.
60  *
61  * All the routines below use bits of fixup code that are out of line
62  * with the main instruction path.  This means when everything is well,
63  * we don't even have to jump over them.  Further, they do not intrude
64  * on our cache or tlb entries.
65  */
66
67 struct exception_table_entry
68 {
69         unsigned long insn, fixup;
70 };
71
72 /* Returns 0 if exception not found and fixup otherwise.  */
73 extern unsigned long search_exception_table(unsigned long);
74
75
76 /*
77  * These are the main single-value transfer routines.  They automatically
78  * use the right size if we just have the right pointer type.
79  */
80
81 extern inline int __put_user_asm_8(__u64 x, void *ptr)
82 {
83         int err;
84
85         __asm__ __volatile__ (  "   sr    %1,%1\n"
86                                 "   la    4,%0\n"
87                                 "   sacf  512\n"
88                                 "0: stg   %2,0(4)\n"
89                                 "1: sacf  0\n"
90                                 ".section .fixup,\"ax\"\n"
91                                 "2: lhi   %1,%h3\n"
92                                 "   jg    1b\n"
93                                 ".previous\n"
94                                 ".section __ex_table,\"a\"\n"
95                                 "   .align 8\n"
96                                 "   .quad  0b,2b\n"
97                                 ".previous"
98                                 : "=m" (*((__u64*) ptr)) , "=&d" (err)
99                                 : "d" (x), "K" (-EFAULT)
100                                 : "cc", "4" );
101         return err;
102 }
103 extern inline int __put_user_asm_4(__u32 x, void *ptr)
104 {
105         int err;
106
107         __asm__ __volatile__ (  "   sr    %1,%1\n"
108                                 "   la    4,%0\n"
109                                 "   sacf  512\n"
110                                 "0: st    %2,0(4)\n"
111                                 "1: sacf  0\n"
112                                 ".section .fixup,\"ax\"\n"
113                                 "2: lhi   %1,%h3\n"
114                                 "   jg    1b\n"
115                                 ".previous\n"
116                                 ".section __ex_table,\"a\"\n"
117                                 "   .align 8\n"
118                                 "   .quad  0b,2b\n"
119                                 ".previous"
120                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
121                                 : "d" (x), "K" (-EFAULT)
122                                 : "cc", "4" );
123         return err;
124 }
125
126 extern inline int __put_user_asm_2(__u16 x, void *ptr)
127 {
128         int err;
129
130         __asm__ __volatile__ (  "   sr    %1,%1\n"
131                                 "   la    4,%0\n"
132                                 "   sacf  512\n"
133                                 "0: sth   %2,0(4)\n"
134                                 "1: sacf  0\n"
135                                 ".section .fixup,\"ax\"\n"
136                                 "2: lhi   %1,%h3\n"
137                                 "   jg    1b\n"
138                                 ".previous\n"
139                                 ".section __ex_table,\"a\"\n"
140                                 "   .align 8\n"
141                                 "   .quad  0b,2b\n"
142                                 ".previous"
143                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
144                                 : "d" (x), "K" (-EFAULT)
145                                 : "cc", "4" );
146         return err;
147 }
148
149 extern inline int __put_user_asm_1(__u8 x, void *ptr)
150 {
151         int err;
152
153         __asm__ __volatile__ (  "   sr    %1,%1\n"
154                                 "   la    4,%0\n"
155                                 "   sacf  512\n"
156                                 "0: stc   %2,0(4)\n"
157                                 "1: sacf  0\n"
158                                 ".section .fixup,\"ax\"\n"
159                                 "2: lhi   %1,%h3\n"
160                                 "   jg    1b\n"
161                                 ".previous\n"
162                                 ".section __ex_table,\"a\"\n"
163                                 "   .align 8\n"
164                                 "   .quad  0b,2b\n"
165                                 ".previous"
166                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
167                                 : "d" (x), "K" (-EFAULT)
168                                 : "cc", "1", "4" );
169         return err;
170 }
171
172 /*
173  * (u?)(u64) ... autsch, but that the only way we can suppress the
174  * warnings when compiling binfmt_elf.c
175  */
176 #define __put_user(x, ptr)                                      \
177 ({                                                              \
178         __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
179         __typeof__(*(ptr)) __x = (x);                           \
180         int __pu_err;                                           \
181         switch (sizeof (*(__pu_addr))) {                        \
182         case 1:                                                 \
183                 __pu_err = __put_user_asm_1((__u8)(__u64)(__x), \
184                                             __pu_addr);         \
185                 break;                                          \
186         case 2:                                                 \
187                 __pu_err = __put_user_asm_2((__u16)(__u64)(__x),\
188                                             __pu_addr);         \
189                 break;                                          \
190         case 4:                                                 \
191                 __pu_err = __put_user_asm_4((__u32)(__u64)(__x),\
192                                             __pu_addr);         \
193                 break;                                          \
194         case 8:                                                 \
195                 __pu_err = __put_user_asm_8((__u64)(__x),       \
196                                             __pu_addr);         \
197                 break;                                          \
198         default:                                                \
199                 __pu_err = __put_user_bad();                    \
200                 break;                                          \
201          }                                                      \
202         __pu_err;                                               \
203 })
204
205 #define put_user(x, ptr) __put_user(x, ptr)
206
207 extern int __put_user_bad(void);
208
209 #define __get_user_asm_8(x, ptr, err)                                      \
210 ({                                                                         \
211         __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
212                                 "   la    4,%2\n"                          \
213                                 "   sacf  512\n"                           \
214                                 "0: lg    %0,0(4)\n"                       \
215                                 "1: sacf  0\n"                             \
216                                 ".section .fixup,\"ax\"\n"                 \
217                                 "2: lhi   %1,%h3\n"                        \
218                                 "   jg    1b\n"                            \
219                                 ".previous\n"                              \
220                                 ".section __ex_table,\"a\"\n"              \
221                                 "   .align 8\n"                            \
222                                 "   .quad 0b,2b\n"                         \
223                                 ".previous"                                \
224                                 : "=d" (x) , "=&d" (err)                   \
225                                 : "m" (*(const __u64*)(ptr)),"K" (-EFAULT) \
226                                 : "cc", "4" );                             \
227 })
228 #define __get_user_asm_4(x, ptr, err)                                      \
229 ({                                                                         \
230         __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
231                                 "   la    4,%2\n"                          \
232                                 "   sacf  512\n"                           \
233                                 "0: l     %0,0(4)\n"                       \
234                                 "1: sacf  0\n"                             \
235                                 ".section .fixup,\"ax\"\n"                 \
236                                 "2: lhi   %1,%h3\n"                        \
237                                 "   jg    1b\n"                            \
238                                 ".previous\n"                              \
239                                 ".section __ex_table,\"a\"\n"              \
240                                 "   .align 8\n"                            \
241                                 "   .quad 0b,2b\n"                         \
242                                 ".previous"                                \
243                                 : "=d" (x) , "=&d" (err)                   \
244                                 : "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
245                                 : "cc", "4" );                             \
246 })
247
248 #define __get_user_asm_2(x, ptr, err)                                      \
249 ({                                                                         \
250         __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
251                                 "   la    4,%2\n"                          \
252                                 "   sacf  512\n"                           \
253                                 "0: lh    %0,0(4)\n"                       \
254                                 "1: sacf  0\n"                             \
255                                 ".section .fixup,\"ax\"\n"                 \
256                                 "2: lhi   %1,%h3\n"                        \
257                                 "   jg    1b\n"                            \
258                                 ".previous\n"                              \
259                                 ".section __ex_table,\"a\"\n"              \
260                                 "   .align 8\n"                            \
261                                 "   .quad 0b,2b\n"                         \
262                                 ".previous"                                \
263                                 : "=d" (x) , "=&d" (err)                   \
264                                 : "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
265                                 : "cc", "4" );                             \
266 })
267
268 #define __get_user_asm_1(x, ptr, err)                                     \
269 ({                                                                        \
270         __asm__ __volatile__ (  "   sr    %1,%1\n"                        \
271                                 "   la    4,%2\n"                         \
272                                 "   sr    %0,%0\n"                        \
273                                 "   sacf  512\n"                          \
274                                 "0: ic    %0,0(4)\n"                      \
275                                 "1: sacf  0\n"                            \
276                                 ".section .fixup,\"ax\"\n"                \
277                                 "2: lhi   %1,%h3\n"                       \
278                                 "   jg    1b\n"                           \
279                                 ".previous\n"                             \
280                                 ".section __ex_table,\"a\"\n"             \
281                                 "   .align 8\n"                           \
282                                 "   .quad 0b,2b\n"                        \
283                                 ".previous"                               \
284                                 : "=d" (x) , "=&d" (err)                  \
285                                 : "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
286                                 : "cc", "4" );                            \
287 })
288
289 #define __get_user(x, ptr)                                      \
290 ({                                                              \
291         __typeof__(ptr) __gu_addr = (ptr);                      \
292         __typeof__(*(ptr)) __x;                                 \
293         int __gu_err;                                           \
294         switch (sizeof(*(ptr))) {                               \
295         case 1:                                                 \
296                 __get_user_asm_1(__x,__gu_addr,__gu_err);       \
297                 break;                                          \
298         case 2:                                                 \
299                 __get_user_asm_2(__x,__gu_addr,__gu_err);       \
300                 break;                                          \
301         case 4:                                                 \
302                 __get_user_asm_4(__x,__gu_addr,__gu_err);       \
303                 break;                                          \
304         case 8:                                                 \
305                 __get_user_asm_8(__x,__gu_addr,__gu_err);       \
306                 break;                                          \
307         default:                                                \
308                 __x = 0;                                        \
309                 __gu_err = __get_user_bad();                    \
310                 break;                                          \
311         }                                                       \
312         (x) = __x;                                              \
313         __gu_err;                                               \
314 })
315
316 #define get_user(x, ptr) __get_user(x, ptr)
317
318 extern int __get_user_bad(void);
319
320 /*
321  * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel)
322  */
323
324 extern long __copy_to_user_asm(const void *from, long n, void *to);
325
326 #define __copy_to_user(to, from, n)                             \
327 ({                                                              \
328         __copy_to_user_asm(from, n, to);                        \
329 })
330
331 #define copy_to_user(to, from, n)                               \
332 ({                                                              \
333         long err = 0;                                           \
334         __typeof__(n) __n = (n);                                \
335         if (__access_ok(to,__n)) {                              \
336                 err = __copy_to_user_asm(from, __n, to);        \
337         }                                                       \
338         else                                                    \
339                 err = __n;                                      \
340         err;                                                    \
341 })
342
343 extern long __copy_from_user_asm(void *to, long n, const void *from);
344
345 #define __copy_from_user(to, from, n)                           \
346 ({                                                              \
347         __copy_from_user_asm(to, n, from);                      \
348 })
349
350 #define copy_from_user(to, from, n)                             \
351 ({                                                              \
352         long err = 0;                                           \
353         __typeof__(n) __n = (n);                                \
354         if (__access_ok(from,__n)) {                            \
355                 err = __copy_from_user_asm(to, __n, from);      \
356         }                                                       \
357         else                                                    \
358                 err = __n;                                      \
359         err;                                                    \
360 })
361
362 /*
363  * Copy a null terminated string from userspace.
364  */
365
366 static inline long
367 __strncpy_from_user(char *dst, const char *src, long count)
368 {
369         long len;
370         __asm__ __volatile__ (  "   slgr  %0,%0\n"
371                                 "   lgr   2,%1\n"
372                                 "   lgr   4,%2\n"
373                                 "   slr   3,3\n"
374                                 "   sacf  512\n"
375                                 "0: ic    3,0(%0,4)\n"
376                                 "1: stc   3,0(%0,2)\n"
377                                 "   ltr   3,3\n"
378                                 "   jz    2f\n"
379                                 "   aghi  %0,1\n"
380                                 "   cgr   %0,%3\n"
381                                 "   jl    0b\n"
382                                 "2: sacf  0\n"
383                                 ".section .fixup,\"ax\"\n"
384                                 "3: lghi  %0,%h4\n"
385                                 "   jg    2b\n"  
386                                 ".previous\n"
387                                 ".section __ex_table,\"a\"\n"
388                                 "   .align 8\n"
389                                 "   .quad  0b,3b\n"
390                                 "   .quad  1b,3b\n"
391                                 ".previous"
392                                 : "=&a" (len)
393                                 : "a"  (dst), "d" (src), "d" (count),
394                                   "K" (-EFAULT)
395                                 : "cc", "2" ,"3", "4" );
396         return len;
397 }
398
399 static inline long
400 strncpy_from_user(char *dst, const char *src, long count)
401 {
402         long res = -EFAULT;
403         if (access_ok(VERIFY_READ, src, 1))
404                 res = __strncpy_from_user(dst, src, count);
405         return res;
406 }
407
408 /*
409  * Return the size of a string (including the ending 0)
410  *
411  * Return 0 for error
412  */
413 static inline unsigned long
414 strnlen_user(const char * src, unsigned long n)
415 {
416 #if 0
417         __asm__ __volatile__ ("   algr  %0,%1\n"
418                               "   slgr  0,0\n"
419                               "   lgr   4,%1\n"
420                               "   sacf  512\n"
421                               "0: srst  %0,4\n"
422                               "   jo    0b\n"
423                               "   slgr  %0,%1\n"
424                               "   aghi  %0,1\n"
425                               "1: sacf  0\n"
426                               ".section .fixup,\"ax\"\n"
427                               "2: slgr  %0,%0\n"
428                               "   jg    1b\n"
429                               ".previous\n"
430                               ".section __ex_table,\"a\"\n"
431                               "   .align 8\n"
432                               "   .quad  0b,2b\n"
433                               ".previous"
434                               : "+&a" (n) : "d" (src)
435                               : "cc", "0", "4" );
436 #else
437         __asm__ __volatile__ ("   lgr   4,%1\n"
438                               "   sacf  512\n"
439                               "0: cli   0(4),0x00\n"
440                               "   la    4,1(4)\n"
441                               "   je    1f\n"
442                               "   brctg %0,0b\n"
443                               "1: lgr   %0,4\n"
444                               "   slgr  %0,%1\n"
445                               "2: sacf  0\n"
446                               ".section .fixup,\"ax\"\n"
447                               "3: slgr  %0,%0\n"
448                               "   jg    2b\n"  
449                               ".previous\n"
450                               ".section __ex_table,\"a\"\n"
451                               "   .align 8\n"
452                               "   .quad  0b,3b\n"
453                               ".previous"
454                               : "+&a" (n) : "d" (src)
455                               : "cc", "4" );
456 #endif
457         return n;
458 }
459 #define strlen_user(str) strnlen_user(str, ~0UL)
460
461 /*
462  * Zero Userspace
463  */
464
465 extern long __clear_user_asm(void *to, long n);
466
467 #define __clear_user(to, n)                                     \
468 ({                                                              \
469         __clear_user_asm(to, n);                                \
470 })
471
472 static inline unsigned long
473 clear_user(void *to, unsigned long n)
474 {
475         if (access_ok(VERIFY_WRITE, to, n))
476                 n = __clear_user(to, n);
477         return n;
478 }
479
480 #endif                                 /* _S390_UACCESS_H                  */
481
482
483
484
485