make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / include / asm-mips64 / uaccess.h
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
7  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8  */
9 #ifndef _ASM_UACCESS_H
10 #define _ASM_UACCESS_H
11
12 #include <linux/errno.h>
13 #include <linux/sched.h>
14
15 #define STR(x)  __STR(x)
16 #define __STR(x)  #x
17
18 /*
19  * The fs value determines whether argument validity checking should be
20  * performed or not.  If get_fs() == USER_DS, checking is performed, with
21  * get_fs() == KERNEL_DS, checking is bypassed.
22  *
23  * For historical reasons, these macros are grossly misnamed.
24  */
25 #define KERNEL_DS       ((mm_segment_t) { (unsigned long) 0L })
26 #define USER_DS         ((mm_segment_t) { (unsigned long) -1L })
27
28 #define VERIFY_READ    0
29 #define VERIFY_WRITE   1
30
31 #define get_fs()        (current->thread.current_ds)
32 #define get_ds()        (KERNEL_DS)
33 #define set_fs(x)       (current->thread.current_ds=(x))
34
35 #define segment_eq(a,b) ((a).seg == (b).seg)
36
37
38 /*
39  * Is a address valid? This does a straighforward calculation rather
40  * than tests.
41  *
42  * Address valid if:
43  *  - "addr" doesn't have any high-bits set
44  *  - AND "size" doesn't have any high-bits set
45  *  - AND "addr+size" doesn't have any high-bits set
46  *  - OR we are in kernel mode.
47  */
48 #define __ua_size(size)                                                 \
49         (__builtin_constant_p(size) && (signed long) (size) > 0 ? 0 : (size))
50
51 #define __access_ok(addr,size,mask)                                     \
52         (((signed long)((mask)&(addr | (addr + size) | __ua_size(size)))) >= 0)
53
54 #define __access_mask ((long)(get_fs().seg))
55
56 #define access_ok(type,addr,size) \
57         __access_ok(((unsigned long)(addr)),(size),__access_mask)
58
59 static inline int verify_area(int type, const void * addr, unsigned long size)
60 {
61         return access_ok(type,addr,size) ? 0 : -EFAULT;
62 }
63
64 /*
65  * Uh, these should become the main single-value transfer routines ...
66  * They automatically use the right size if we just have the right
67  * pointer type ...
68  *
69  * As MIPS uses the same address space for kernel and user data, we
70  * can just do these as direct assignments.
71  *
72  * Careful to not
73  * (a) re-use the arguments for side effects (sizeof is ok)
74  * (b) require any knowledge of processes at this stage
75  */
76 #define put_user(x,ptr) \
77         __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
78 #define get_user(x,ptr) \
79         __get_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
80
81 /*
82  * The "__xxx" versions do not do address space checking, useful when
83  * doing multiple accesses to the same area (the user has to do the
84  * checks by hand with "access_ok()")
85  */
86 #define __put_user(x,ptr) \
87         __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
88 #define __get_user(x,ptr) \
89         __get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
90
91 struct __large_struct { unsigned long buf[100]; };
92 #define __m(x) (*(struct __large_struct *)(x))
93
94 #define __get_user_nocheck(x,ptr,size)                          \
95 ({                                                              \
96         long __gu_err;                                          \
97         __typeof(*(ptr)) __gu_val;                              \
98         long __gu_addr;                                         \
99         __asm__("":"=r" (__gu_val));                            \
100         __gu_addr = (long) (ptr);                               \
101         __asm__("":"=r" (__gu_err));                            \
102         switch (size) {                                         \
103         case 1: __get_user_asm("lb"); break;                    \
104         case 2: __get_user_asm("lh"); break;                    \
105         case 4: __get_user_asm("lw"); break;                    \
106         case 8: __get_user_asm("ld"); break;                    \
107         default: __get_user_unknown(); break;                   \
108         } x = (__typeof__(*(ptr))) __gu_val; __gu_err;          \
109 })
110
111 #define __get_user_check(x,ptr,size)                            \
112 ({                                                              \
113         long __gu_err;                                          \
114         __typeof__(*(ptr)) __gu_val;                            \
115         long __gu_addr;                                         \
116         __asm__("":"=r" (__gu_val));                            \
117         __gu_addr = (long) (ptr);                               \
118         __asm__("":"=r" (__gu_err));                            \
119         if (__access_ok(__gu_addr,size,__access_mask)) {        \
120                 switch (size) {                                 \
121                 case 1: __get_user_asm("lb"); break;            \
122                 case 2: __get_user_asm("lh"); break;            \
123                 case 4: __get_user_asm("lw"); break;            \
124                 case 8: __get_user_asm("ld"); break;            \
125                 default: __get_user_unknown(); break;           \
126                 }                                               \
127         } x = (__typeof__(*(ptr))) __gu_val; __gu_err;          \
128 })
129
130 #define __get_user_asm(insn)                                    \
131 ({                                                              \
132         __asm__ __volatile__(                                   \
133         "1:\t" insn "\t%1,%2\n\t"                               \
134         "move\t%0,$0\n"                                         \
135         "2:\n\t"                                                \
136         ".section\t.fixup,\"ax\"\n"                             \
137         "3:\tli\t%0,%3\n\t"                                     \
138         "move\t%1,$0\n\t"                                       \
139         "j\t2b\n\t"                                             \
140         ".previous\n\t"                                         \
141         ".section\t__ex_table,\"a\"\n\t"                        \
142         ".dword\t1b,3b\n\t"                                     \
143         ".previous"                                             \
144         :"=r" (__gu_err), "=r" (__gu_val)                       \
145         :"o" (__m(__gu_addr)), "i" (-EFAULT));                  \
146 })
147
148 extern void __get_user_unknown(void);
149
150 #define __put_user_nocheck(x,ptr,size)                          \
151 ({                                                              \
152         long __pu_err;                                          \
153         __typeof__(*(ptr)) __pu_val;                            \
154         long __pu_addr;                                         \
155         __pu_val = (x);                                         \
156         __pu_addr = (long) (ptr);                               \
157         __asm__("":"=r" (__pu_err));                            \
158         switch (size) {                                         \
159         case 1: __put_user_asm("sb"); break;                    \
160         case 2: __put_user_asm("sh"); break;                    \
161         case 4: __put_user_asm("sw"); break;                    \
162         case 8: __put_user_asm("sd"); break;                    \
163         default: __put_user_unknown(); break;                   \
164         } __pu_err;                                             \
165 })
166
167 #define __put_user_check(x,ptr,size)                            \
168 ({                                                              \
169         long __pu_err;                                          \
170         __typeof__(*(ptr)) __pu_val;                            \
171         long __pu_addr;                                         \
172         __pu_val = (x);                                         \
173         __pu_addr = (long) (ptr);                               \
174         __asm__("":"=r" (__pu_err));                            \
175         if (__access_ok(__pu_addr,size,__access_mask)) {        \
176                 switch (size) {                                 \
177                 case 1: __put_user_asm("sb"); break;            \
178                 case 2: __put_user_asm("sh"); break;            \
179                 case 4: __put_user_asm("sw"); break;            \
180                 case 8: __put_user_asm("sd"); break;            \
181                 default: __put_user_unknown(); break;           \
182                 }                                               \
183         } __pu_err;                                             \
184 })
185
186 #define __put_user_asm(insn)                                    \
187 ({                                                              \
188         __asm__ __volatile__(                                   \
189         "1:\t" insn "\t%z1, %2\t\t\t# __put_user_asm\n\t"       \
190         "move\t%0,$0\n"                                         \
191         "2:\n\t"                                                \
192         ".section\t.fixup,\"ax\"\n"                             \
193         "3:\tli\t%0,%3\n\t"                                     \
194         "j\t2b\n\t"                                             \
195         ".previous\n\t"                                         \
196         ".section\t__ex_table,\"a\"\n\t"                        \
197         ".dword\t1b,3b\n\t"                                     \
198         ".previous"                                             \
199         :"=r" (__pu_err)                                        \
200         :"Jr" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); \
201 })
202
203 extern void __put_user_unknown(void);
204
205 /*
206  * We're generating jump to subroutines which will be outside the range of
207  * jump instructions
208  */
209 #ifdef MODULE
210 #define __MODULE_JAL(destination)       \
211         ".set\tnoat\n\t"                \
212         "dla\t$1, " #destination "\n\t" \
213         "jalr\t$1\n\t"                  \
214         ".set\tat\n\t"
215 #else
216 #define __MODULE_JAL(destination)       \
217         "jal\t" #destination "\n\t"
218 #endif
219
220 extern size_t __copy_user(void *__to, const void *__from, size_t __n);
221
222 #define __invoke_copy_to_user(to,from,n)                                \
223 ({                                                                      \
224         register void *__cu_to_r __asm__ ("$4");                        \
225         register const void *__cu_from_r __asm__ ("$5");                \
226         register long __cu_len_r __asm__ ("$6");                        \
227                                                                         \
228         __cu_to_r = (to);                                               \
229         __cu_from_r = (from);                                           \
230         __cu_len_r = (n);                                               \
231         __asm__ __volatile__(                                           \
232         __MODULE_JAL(__copy_user)                                       \
233         : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)       \
234         :                                                               \
235         : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",         \
236           "memory");                                                    \
237         __cu_len_r;                                                     \
238 })
239
240 #define __copy_to_user(to,from,n)                                       \
241 ({                                                                      \
242         void *__cu_to;                                                  \
243         const void *__cu_from;                                          \
244         long __cu_len;                                                  \
245                                                                         \
246         __cu_to = (to);                                                 \
247         __cu_from = (from);                                             \
248         __cu_len = (n);                                                 \
249         __cu_len = __invoke_copy_to_user(__cu_to, __cu_from, __cu_len); \
250         __cu_len;                                                       \
251 })
252
253 #define copy_to_user(to,from,n)                                         \
254 ({                                                                      \
255         void *__cu_to;                                                  \
256         const void *__cu_from;                                          \
257         long __cu_len;                                                  \
258                                                                         \
259         __cu_to = (to);                                                 \
260         __cu_from = (from);                                             \
261         __cu_len = (n);                                                 \
262         if (access_ok(VERIFY_WRITE, __cu_to, __cu_len))                 \
263                 __cu_len = __invoke_copy_to_user(__cu_to, __cu_from,    \
264                                                 __cu_len);              \
265         __cu_len;                                                       \
266 })
267
268 #define __invoke_copy_from_user(to,from,n)                              \
269 ({                                                                      \
270         register void *__cu_to_r __asm__ ("$4");                        \
271         register const void *__cu_from_r __asm__ ("$5");                \
272         register long __cu_len_r __asm__ ("$6");                        \
273                                                                         \
274         __cu_to_r = (to);                                               \
275         __cu_from_r = (from);                                           \
276         __cu_len_r = (n);                                               \
277         __asm__ __volatile__(                                           \
278         ".set\tnoreorder\n\t"                                           \
279         __MODULE_JAL(__copy_user)                                       \
280         ".set\tnoat\n\t"                                                \
281         "daddu\t$1, %1, %2\n\t"                                         \
282         ".set\tat\n\t"                                                  \
283         ".set\treorder\n\t"                                             \
284         "move\t%0, $6"                                                  \
285         : "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)       \
286         :                                                               \
287         : "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",         \
288           "memory");                                                    \
289         __cu_len_r;                                                     \
290 })
291
292 #define __copy_from_user(to,from,n)                                     \
293 ({                                                                      \
294         void *__cu_to;                                                  \
295         const void *__cu_from;                                          \
296         long __cu_len;                                                  \
297                                                                         \
298         __cu_to = (to);                                                 \
299         __cu_from = (from);                                             \
300         __cu_len = (n);                                                 \
301         __cu_len = __invoke_copy_from_user(__cu_to, __cu_from,          \
302                                            __cu_len);                   \
303         __cu_len;                                                       \
304 })
305
306 #define copy_from_user(to,from,n)                                       \
307 ({                                                                      \
308         void *__cu_to;                                                  \
309         const void *__cu_from;                                          \
310         long __cu_len;                                                  \
311                                                                         \
312         __cu_to = (to);                                                 \
313         __cu_from = (from);                                             \
314         __cu_len = (n);                                                 \
315         if (access_ok(VERIFY_READ, __cu_from, __cu_len))                \
316                 __cu_len = __invoke_copy_from_user(__cu_to, __cu_from,  \
317                                                    __cu_len);           \
318         __cu_len;                                                       \
319 })
320
321 static inline __kernel_size_t
322 __clear_user(void *addr, __kernel_size_t size)
323 {
324         __kernel_size_t res;
325
326         __asm__ __volatile__(
327                 "move\t$4, %1\n\t"
328                 "move\t$5, $0\n\t"
329                 "move\t$6, %2\n\t"
330                 __MODULE_JAL(__bzero)
331                 "move\t%0, $6"
332                 : "=r" (res)
333                 : "r" (addr), "r" (size)
334                 : "$4", "$5", "$6", "$8", "$9", "$31");
335
336         return res;
337 }
338
339 #define clear_user(addr,n)                                      \
340 ({                                                              \
341         void * __cl_addr = (addr);                              \
342         unsigned long __cl_size = (n);                          \
343         if (__cl_size && __access_ok(VERIFY_WRITE,              \
344                ((unsigned long)(__cl_addr)), __cl_size))        \
345                 __cl_size = __clear_user(__cl_addr, __cl_size); \
346         __cl_size;                                              \
347 })
348
349 /*
350  * Returns: -EFAULT if exception before terminator, N if the entire
351  * buffer filled, else strlen.
352  */
353 static inline long
354 __strncpy_from_user(char *__to, const char *__from, long __len)
355 {
356         long res;
357
358         __asm__ __volatile__(
359                 "move\t$4, %1\n\t"
360                 "move\t$5, %2\n\t"
361                 "move\t$6, %3\n\t"
362                 __MODULE_JAL(__strncpy_from_user_nocheck_asm)
363                 "move\t%0, $2"
364                 : "=r" (res)
365                 : "r" (__to), "r" (__from), "r" (__len)
366                 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
367
368         return res;
369 }
370
371 static inline long
372 strncpy_from_user(char *__to, const char *__from, long __len)
373 {
374         long res;
375
376         __asm__ __volatile__(
377                 "move\t$4, %1\n\t"
378                 "move\t$5, %2\n\t"
379                 "move\t$6, %3\n\t"
380                 __MODULE_JAL(__strncpy_from_user_asm)
381                 "move\t%0, $2"
382                 : "=r" (res)
383                 : "r" (__to), "r" (__from), "r" (__len)
384                 : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
385
386         return res;
387 }
388
389 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
390 static inline long __strlen_user(const char *s)
391 {
392         long res;
393
394         __asm__ __volatile__(
395                 "move\t$4, %1\n\t"
396                 __MODULE_JAL(__strlen_user_nocheck_asm)
397                 "move\t%0, $2"
398                 : "=r" (res)
399                 : "r" (s)
400                 : "$2", "$4", "$8", "$31");
401
402         return res;
403 }
404
405 static inline long strlen_user(const char *s)
406 {
407         long res;
408
409         __asm__ __volatile__(
410                 "move\t$4, %1\n\t"
411                 __MODULE_JAL(__strlen_user_asm)
412                 "move\t%0, $2"
413                 : "=r" (res)
414                 : "r" (s)
415                 : "$2", "$4", "$8", "$31");
416
417         return res;
418 }
419
420 /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
421 static inline long __strnlen_user(const char *s, long n)
422 {
423         long res;
424
425         __asm__ __volatile__(
426                 "move\t$4, %1\n\t"
427                 "move\t$5, %2\n\t"
428                 __MODULE_JAL(__strnlen_user_nocheck_asm)
429                 "move\t%0, $2"
430                 : "=r" (res)
431                 : "r" (s), "r" (n)
432                 : "$2", "$4", "$5", "$8", "$31");
433
434         return res;
435 }
436
437 static inline long strnlen_user(const char *s, long n)
438 {
439         long res;
440
441         __asm__ __volatile__(
442                 "move\t$4, %1\n\t"
443                 "move\t$5, %2\n\t"
444                 __MODULE_JAL(__strnlen_user_asm)
445                 "move\t%0, $2"
446                 : "=r" (res)
447                 : "r" (s), "r" (n)
448                 : "$2", "$4", "$5", "$8", "$31");
449
450         return res;
451 }
452
453 struct exception_table_entry
454 {
455         unsigned long insn;
456         unsigned long nextinsn;
457 };
458
459 /* Returns 0 if exception not found and fixup.unit otherwise.  */
460 extern unsigned long search_exception_table(unsigned long addr);
461
462 /* Returns the new pc */
463 #define fixup_exception(map_reg, fixup_unit, pc)                \
464 ({                                                              \
465         fixup_unit;                                             \
466 })
467
468 #endif /* _ASM_UACCESS_H */