File: /usr/src/linux/include/asm-mips/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     extern 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     /*
95      * Yuck.  We need two variants, one for 64bit operation and one
96      * for 32 bit mode and old iron.
97      */
98     #ifdef __mips64
99     #define __GET_USER_DW __get_user_asm("ld")
100     #else
101     #define __GET_USER_DW __get_user_asm_ll32
102     #endif
103     
104     #define __get_user_nocheck(x,ptr,size) ({ \
105     long __gu_err; \
106     __typeof(*(ptr)) __gu_val; \
107     long __gu_addr; \
108     __asm__("":"=r" (__gu_val)); \
109     __gu_addr = (long) (ptr); \
110     __asm__("":"=r" (__gu_err)); \
111     switch (size) { \
112     case 1: __get_user_asm("lb"); break; \
113     case 2: __get_user_asm("lh"); break; \
114     case 4: __get_user_asm("lw"); break; \
115     case 8: __GET_USER_DW; break; \
116     default: __get_user_unknown(); break; \
117     } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
118     
119     #define __get_user_check(x,ptr,size) ({ \
120     long __gu_err; \
121     __typeof__(*(ptr)) __gu_val; \
122     long __gu_addr; \
123     __asm__("":"=r" (__gu_val)); \
124     __gu_addr = (long) (ptr); \
125     __asm__("":"=r" (__gu_err)); \
126     if (__access_ok(__gu_addr,size,__access_mask)) { \
127     switch (size) { \
128     case 1: __get_user_asm("lb"); break; \
129     case 2: __get_user_asm("lh"); break; \
130     case 4: __get_user_asm("lw"); break; \
131     case 8: __GET_USER_DW; break; \
132     default: __get_user_unknown(); break; \
133     } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
134     
135     #define __get_user_asm(insn) \
136     ({ \
137     __asm__ __volatile__( \
138     	"1:\t" insn "\t%1,%2\n\t" \
139     	"move\t%0,$0\n" \
140     	"2:\n\t" \
141     	".section\t.fixup,\"ax\"\n" \
142     	"3:\tli\t%0,%3\n\t" \
143     	"move\t%1,$0\n\t" \
144     	"j\t2b\n\t" \
145     	".previous\n\t" \
146     	".section\t__ex_table,\"a\"\n\t" \
147     	".word\t1b,3b\n\t" \
148     	".previous" \
149     	:"=r" (__gu_err), "=r" (__gu_val) \
150     	:"o" (__m(__gu_addr)), "i" (-EFAULT)); })
151     
152     /*
153      * Get a long long 64 using 32 bit registers.
154      */
155     #define __get_user_asm_ll32 \
156     ({ \
157     __asm__ __volatile__( \
158     	"1:\tlw\t%1,%2\n" \
159     	"2:\tlw\t%D1,%3\n\t" \
160     	"move\t%0,$0\n" \
161     	"3:\t.section\t.fixup,\"ax\"\n" \
162     	"4:\tli\t%0,%4\n\t" \
163     	"move\t%1,$0\n\t" \
164     	"move\t%D1,$0\n\t" \
165     	"j\t3b\n\t" \
166     	".previous\n\t" \
167     	".section\t__ex_table,\"a\"\n\t" \
168     	".word\t1b,4b\n\t" \
169     	".word\t2b,4b\n\t" \
170     	".previous" \
171     	:"=r" (__gu_err), "=&r" (__gu_val) \
172     	:"o" (__m(__gu_addr)), "o" (__m(__gu_addr + 4)), \
173     	 "i" (-EFAULT)); })
174     
175     extern void __get_user_unknown(void);
176     
177     /*
178      * Yuck.  We need two variants, one for 64bit operation and one
179      * for 32 bit mode and old iron.
180      */
181     #ifdef __mips64
182     #define __PUT_USER_DW __put_user_asm("sd")
183     #else
184     #define __PUT_USER_DW __put_user_asm_ll32
185     #endif
186     
187     #define __put_user_nocheck(x,ptr,size) ({ \
188     long __pu_err; \
189     __typeof__(*(ptr)) __pu_val; \
190     long __pu_addr; \
191     __pu_val = (x); \
192     __pu_addr = (long) (ptr); \
193     __asm__("":"=r" (__pu_err)); \
194     switch (size) { \
195     case 1: __put_user_asm("sb"); break; \
196     case 2: __put_user_asm("sh"); break; \
197     case 4: __put_user_asm("sw"); break; \
198     case 8: __PUT_USER_DW; break; \
199     default: __put_user_unknown(); break; \
200     } __pu_err; })
201     
202     #define __put_user_check(x,ptr,size) ({ \
203     long __pu_err; \
204     __typeof__(*(ptr)) __pu_val; \
205     long __pu_addr; \
206     __pu_val = (x); \
207     __pu_addr = (long) (ptr); \
208     __asm__("":"=r" (__pu_err)); \
209     if (__access_ok(__pu_addr,size,__access_mask)) { \
210     switch (size) { \
211     case 1: __put_user_asm("sb"); break; \
212     case 2: __put_user_asm("sh"); break; \
213     case 4: __put_user_asm("sw"); break; \
214     case 8: __PUT_USER_DW; break; \
215     default: __put_user_unknown(); break; \
216     } } __pu_err; })
217     
218     #define __put_user_asm(insn) \
219     ({ \
220     __asm__ __volatile__( \
221     	"1:\t" insn "\t%z1, %2\t\t\t# __put_user_asm\n\t" \
222     	"move\t%0, $0\n" \
223     	"2:\n\t" \
224     	".section\t.fixup,\"ax\"\n" \
225     	"3:\tli\t%0,%3\n\t" \
226     	"j\t2b\n\t" \
227     	".previous\n\t" \
228     	".section\t__ex_table,\"a\"\n\t" \
229     	".word\t1b,3b\n\t" \
230     	".previous" \
231     	:"=r" (__pu_err) \
232     	:"Jr" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); })
233     
234     #define __put_user_asm_ll32 \
235     ({ \
236     __asm__ __volatile__( \
237     	"1:\tsw\t%1, %2\t\t\t# __put_user_asm_ll32\n\t" \
238     	"2:\tsw\t%D1, %3\n" \
239     	"move\t%0, $0\n" \
240     	"3:\n\t" \
241     	".section\t.fixup,\"ax\"\n" \
242     	"4:\tli\t%0,%4\n\t" \
243     	"j\t3b\n\t" \
244     	".previous\n\t" \
245     	".section\t__ex_table,\"a\"\n\t" \
246     	".word\t1b,4b\n\t" \
247     	".word\t2b,4b\n\t" \
248     	".previous" \
249     	:"=r" (__pu_err) \
250     	:"r" (__pu_val), "o" (__m(__pu_addr)), "o" (__m(__pu_addr + 4)), \
251     	 "i" (-EFAULT)); })
252     
253     extern void __put_user_unknown(void);
254     
255     /*
256      * We're generating jump to subroutines which will be outside the range of
257      * jump instructions
258      */
259     #ifdef MODULE
260     #define __MODULE_JAL(destination) \
261     	".set\tnoat\n\t" \
262     	"la\t$1, " #destination "\n\t" \
263     	"jalr\t$1\n\t" \
264     	".set\tat\n\t"
265     #else
266     #define __MODULE_JAL(destination) \
267     	"jal\t" #destination "\n\t"
268     #endif
269     
270     extern size_t __copy_user(void *__to, const void *__from, size_t __n);
271     
272     #define __copy_to_user(to,from,n) ({ \
273     	void *__cu_to; \
274     	const void *__cu_from; \
275     	long __cu_len; \
276     	\
277     	__cu_to = (to); \
278     	__cu_from = (from); \
279     	__cu_len = (n); \
280     	__asm__ __volatile__( \
281     		"move\t$4, %1\n\t" \
282     		"move\t$5, %2\n\t" \
283     		"move\t$6, %3\n\t" \
284     		__MODULE_JAL(__copy_user) \
285     		"move\t%0, $6" \
286     		: "=r" (__cu_len) \
287     		: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
288     		: "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
289     		  "$24", "$31","memory"); \
290     	__cu_len; \
291     })
292     
293     #define __copy_from_user(to,from,n) ({ \
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     	__asm__ __volatile__( \
302     		"move\t$4, %1\n\t" \
303     		"move\t$5, %2\n\t" \
304     		"move\t$6, %3\n\t" \
305     		".set\tnoreorder\n\t" \
306     		__MODULE_JAL(__copy_user) \
307     		".set\tnoat\n\t" \
308     		"addu\t$1, %2, %3\n\t" \
309     		".set\tat\n\t" \
310     		".set\treorder\n\t" \
311     		"move\t%0, $6" \
312     		: "=r" (__cu_len) \
313     		: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
314     		: "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
315     		  "$24", "$31","memory"); \
316     	__cu_len; \
317     })
318     
319     #define copy_to_user(to,from,n) ({ \
320     	void *__cu_to; \
321     	const void *__cu_from; \
322     	long __cu_len; \
323     	\
324     	__cu_to = (to); \
325     	__cu_from = (from); \
326     	__cu_len = (n); \
327     	if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) \
328     		__asm__ __volatile__( \
329     			"move\t$4, %1\n\t" \
330     			"move\t$5, %2\n\t" \
331     			"move\t$6, %3\n\t" \
332     			__MODULE_JAL(__copy_user) \
333     			"move\t%0, $6" \
334     			: "=r" (__cu_len) \
335     			: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
336     			: "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
337     			  "$15", "$24", "$31","memory"); \
338     	__cu_len; \
339     })
340     
341     #define copy_from_user(to,from,n) ({ \
342     	void *__cu_to; \
343     	const void *__cu_from; \
344     	long __cu_len; \
345     	\
346     	__cu_to = (to); \
347     	__cu_from = (from); \
348     	__cu_len = (n); \
349     	if (access_ok(VERIFY_READ, __cu_from, __cu_len)) \
350     		__asm__ __volatile__( \
351     			"move\t$4, %1\n\t" \
352     			"move\t$5, %2\n\t" \
353     			"move\t$6, %3\n\t" \
354     			".set\tnoreorder\n\t" \
355     			__MODULE_JAL(__copy_user) \
356     			".set\tnoat\n\t" \
357     			"addu\t$1, %2, %3\n\t" \
358     			".set\tat\n\t" \
359     			".set\treorder\n\t" \
360     			"move\t%0, $6" \
361     			: "=r" (__cu_len) \
362     			: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
363     			: "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
364     			  "$15", "$24", "$31","memory"); \
365     	__cu_len; \
366     })
367     
368     extern inline __kernel_size_t
369     __clear_user(void *addr, __kernel_size_t size)
370     {
371     	__kernel_size_t res;
372     
373     	__asm__ __volatile__(
374     		"move\t$4, %1\n\t"
375     		"move\t$5, $0\n\t"
376     		"move\t$6, %2\n\t"
377     		__MODULE_JAL(__bzero)
378     		"move\t%0, $6"
379     		: "=r" (res)
380     		: "r" (addr), "r" (size)
381     		: "$4", "$5", "$6", "$8", "$9", "$31");
382     
383     	return res;
384     }
385     
386     #define clear_user(addr,n) ({ \
387     void * __cl_addr = (addr); \
388     unsigned long __cl_size = (n); \
389     if (__cl_size && access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
390     __cl_size = __clear_user(__cl_addr, __cl_size); \
391     __cl_size; })
392     
393     /*
394      * Returns: -EFAULT if exception before terminator, N if the entire
395      * buffer filled, else strlen.
396      */
397     extern inline long
398     __strncpy_from_user(char *__to, const char *__from, long __len)
399     {
400     	long res;
401     
402     	__asm__ __volatile__(
403     		"move\t$4, %1\n\t"
404     		"move\t$5, %2\n\t"
405     		"move\t$6, %3\n\t"
406     		__MODULE_JAL(__strncpy_from_user_nocheck_asm)
407     		"move\t%0, $2"
408     		: "=r" (res)
409     		: "r" (__to), "r" (__from), "r" (__len)
410     		: "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
411     
412     	return res;
413     }
414     
415     extern inline long
416     strncpy_from_user(char *__to, const char *__from, long __len)
417     {
418     	long res;
419     
420     	__asm__ __volatile__(
421     		"move\t$4, %1\n\t"
422     		"move\t$5, %2\n\t"
423     		"move\t$6, %3\n\t"
424     		__MODULE_JAL(__strncpy_from_user_asm)
425     		"move\t%0, $2"
426     		: "=r" (res)
427     		: "r" (__to), "r" (__from), "r" (__len)
428     		: "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
429     
430     	return res;
431     }
432     
433     /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
434     extern inline long __strlen_user(const char *s)
435     {
436     	long res;
437     
438     	__asm__ __volatile__(
439     		"move\t$4, %1\n\t"
440     		__MODULE_JAL(__strlen_user_nocheck_asm)
441     		"move\t%0, $2"
442     		: "=r" (res)
443     		: "r" (s)
444     		: "$2", "$4", "$8", "$31");
445     
446     	return res;
447     }
448     
449     extern inline long strlen_user(const char *s)
450     {
451     	long res;
452     
453     	__asm__ __volatile__(
454     		"move\t$4, %1\n\t"
455     		__MODULE_JAL(__strlen_user_asm)
456     		"move\t%0, $2"
457     		: "=r" (res)
458     		: "r" (s)
459     		: "$2", "$4", "$8", "$31");
460     
461     	return res;
462     }
463     
464     /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
465     extern inline long __strnlen_user(const char *s, long n)
466     {
467     	long res;
468     
469     	__asm__ __volatile__(
470     		"move\t$4, %1\n\t"
471     		"move\t$5, %2\n\t"
472     		__MODULE_JAL(__strnlen_user_nocheck_asm)
473     		"move\t%0, $2"
474     		: "=r" (res)
475     		: "r" (s), "r" (n)
476     		: "$2", "$4", "$5", "$8", "$31");
477     
478     	return res;
479     }
480     
481     extern inline long strnlen_user(const char *s, long n)
482     {
483     	long res;
484     
485     	__asm__ __volatile__(
486     		"move\t$4, %1\n\t"
487     		"move\t$5, %2\n\t"
488     		__MODULE_JAL(__strnlen_user_asm)
489     		"move\t%0, $2"
490     		: "=r" (res)
491     		: "r" (s), "r" (n)
492     		: "$2", "$4", "$5", "$8", "$31");
493     
494     	return res;
495     }
496     
497     struct exception_table_entry
498     {
499     	unsigned long insn;
500     	unsigned long nextinsn;
501     };
502     
503     /* Returns 0 if exception not found and fixup.unit otherwise.  */
504     extern unsigned long search_exception_table(unsigned long addr);
505     
506     /* Returns the new pc */
507     #define fixup_exception(map_reg, fixup_unit, pc)                \
508     ({                                                              \
509     	fixup_unit;                                             \
510     })
511     
512     #endif /* _ASM_UACCESS_H */
513