File: /usr/src/linux/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     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     #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 __copy_to_user(to,from,n)				\
223     ({								\
224     	void *__cu_to;						\
225     	const void *__cu_from;					\
226     	long __cu_len;						\
227     								\
228     	__cu_to = (to);						\
229     	__cu_from = (from);					\
230     	__cu_len = (n);						\
231     	__asm__ __volatile__(					\
232     	"move\t$4, %1\n\t"					\
233     	"move\t$5, %2\n\t"					\
234     	"move\t$6, %3\n\t"					\
235     	__MODULE_JAL(__copy_user)				\
236     	"move\t%0, $6"						\
237     	: "=r" (__cu_len)					\
238     	: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len)	\
239     	: "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12",	\
240     	  "$15", "$24", "$31","memory");			\
241     	__cu_len;						\
242     })
243     
244     #define __copy_from_user(to,from,n)				\
245     ({								\
246     	void *__cu_to;						\
247     	const void *__cu_from;					\
248     	long __cu_len;						\
249     								\
250     	__cu_to = (to);						\
251     	__cu_from = (from);					\
252     	__cu_len = (n);						\
253     	__asm__ __volatile__(					\
254     	"move\t$4, %1\n\t"					\
255     	"move\t$5, %2\n\t"					\
256     	"move\t$6, %3\n\t"					\
257     	".set\tnoreorder\n\t"					\
258     	__MODULE_JAL(__copy_user)				\
259     	".set\tnoat\n\t"					\
260     	"daddu\t$1, %2, %3\n\t"					\
261     	".set\tat\n\t"						\
262     	".set\treorder\n\t"					\
263     	"move\t%0, $6"						\
264     	: "=r" (__cu_len)					\
265     	: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len)	\
266     	: "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12",	\
267     	  "$15", "$24", "$31","memory");			\
268     	__cu_len;						\
269     })
270     
271     #define copy_to_user(to,from,n)					\
272     ({								\
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     	if (access_ok(VERIFY_WRITE, __cu_to, __cu_len))		\
281     		__asm__ __volatile__(				\
282     		"move\t$4, %1\n\t"				\
283     		"move\t$5, %2\n\t"				\
284     		"move\t$6, %3\n\t"				\
285     		__MODULE_JAL(__copy_user)			\
286     		"move\t%0, $6"					\
287     		: "=r" (__cu_len)				\
288     		: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
289     		: "$4", "$5", "$6", "$8", "$9", "$10", "$11",	\
290     		  "$12", "$15", "$24", "$31","memory");		\
291     	__cu_len;						\
292     })
293     
294     #define copy_from_user(to,from,n)				\
295     ({								\
296     	void *__cu_to;						\
297     	const void *__cu_from;					\
298     	long __cu_len;						\
299     								\
300     	__cu_to = (to);						\
301     	__cu_from = (from);					\
302     	__cu_len = (n);						\
303     	if (access_ok(VERIFY_READ, __cu_from, __cu_len))	\
304     		__asm__ __volatile__(				\
305     		"move\t$4, %1\n\t"				\
306     		"move\t$5, %2\n\t"				\
307     		"move\t$6, %3\n\t"				\
308     		".set\tnoreorder\n\t"				\
309     		__MODULE_JAL(__copy_user)			\
310     		".set\tnoat\n\t"				\
311     		"daddu\t$1, %2, %3\n\t"				\
312     		".set\tat\n\t"					\
313     		".set\treorder\n\t"				\
314     		"move\t%0, $6"					\
315     		: "=r" (__cu_len)				\
316     		: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
317     		: "$4", "$5", "$6", "$8", "$9", "$10", "$11",	\
318     		  "$12", "$15", "$24", "$31","memory");		\
319     	__cu_len;						\
320     })
321     
322     extern inline __kernel_size_t
323     __clear_user(void *addr, __kernel_size_t size)
324     {
325     	__kernel_size_t res;
326     
327     	__asm__ __volatile__(
328     		"move\t$4, %1\n\t"
329     		"move\t$5, $0\n\t"
330     		"move\t$6, %2\n\t"
331     		__MODULE_JAL(__bzero)
332     		"move\t%0, $6"
333     		: "=r" (res)
334     		: "r" (addr), "r" (size)
335     		: "$4", "$5", "$6", "$8", "$9", "$31");
336     
337     	return res;
338     }
339     
340     #define clear_user(addr,n)					\
341     ({								\
342     	void * __cl_addr = (addr);				\
343     	unsigned long __cl_size = (n);				\
344     	if (__cl_size && __access_ok(VERIFY_WRITE,		\
345     	       ((unsigned long)(__cl_addr)), __cl_size))	\
346     		__cl_size = __clear_user(__cl_addr, __cl_size);	\
347     	__cl_size;						\
348     })
349     
350     /*
351      * Returns: -EFAULT if exception before terminator, N if the entire
352      * buffer filled, else strlen.
353      */
354     extern inline long
355     __strncpy_from_user(char *__to, const char *__from, long __len)
356     {
357     	long res;
358     
359     	__asm__ __volatile__(
360     		"move\t$4, %1\n\t"
361     		"move\t$5, %2\n\t"
362     		"move\t$6, %3\n\t"
363     		__MODULE_JAL(__strncpy_from_user_nocheck_asm)
364     		"move\t%0, $2"
365     		: "=r" (res)
366     		: "r" (__to), "r" (__from), "r" (__len)
367     		: "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
368     
369     	return res;
370     }
371     
372     extern inline long
373     strncpy_from_user(char *__to, const char *__from, long __len)
374     {
375     	long res;
376     
377     	__asm__ __volatile__(
378     		"move\t$4, %1\n\t"
379     		"move\t$5, %2\n\t"
380     		"move\t$6, %3\n\t"
381     		__MODULE_JAL(__strncpy_from_user_asm)
382     		"move\t%0, $2"
383     		: "=r" (res)
384     		: "r" (__to), "r" (__from), "r" (__len)
385     		: "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
386     
387     	return res;
388     }
389     
390     /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
391     extern inline long __strlen_user(const char *s)
392     {
393     	long res;
394     
395     	__asm__ __volatile__(
396     		"move\t$4, %1\n\t"
397     		__MODULE_JAL(__strlen_user_nocheck_asm)
398     		"move\t%0, $2"
399     		: "=r" (res)
400     		: "r" (s)
401     		: "$2", "$4", "$8", "$31");
402     
403     	return res;
404     }
405     
406     extern inline long strlen_user(const char *s)
407     {
408     	long res;
409     
410     	__asm__ __volatile__(
411     		"move\t$4, %1\n\t"
412     		__MODULE_JAL(__strlen_user_asm)
413     		"move\t%0, $2"
414     		: "=r" (res)
415     		: "r" (s)
416     		: "$2", "$4", "$8", "$31");
417     
418     	return res;
419     }
420     
421     /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
422     extern inline long __strnlen_user(const char *s, long n)
423     {
424     	long res;
425     
426     	__asm__ __volatile__(
427     		"move\t$4, %1\n\t"
428     		"move\t$5, %2\n\t"
429     		__MODULE_JAL(__strlen_user_nocheck_asm)
430     		"move\t%0, $2"
431     		: "=r" (res)
432     		: "r" (s), "r" (n)
433     		: "$2", "$4", "$5", "$8", "$31");
434     
435     	return res;
436     }
437     
438     extern inline long strnlen_user(const char *s, long n)
439     {
440     	long res;
441     
442     	__asm__ __volatile__(
443     		"move\t$4, %1\n\t"
444     		"move\t$5, %2\n\t"
445     		__MODULE_JAL(__strlen_user_asm)
446     		"move\t%0, $2"
447     		: "=r" (res)
448     		: "r" (s), "r" (n)
449     		: "$2", "$4", "$5", "$8", "$31");
450     
451     	return res;
452     }
453     
454     struct exception_table_entry
455     {
456     	unsigned long insn;
457     	unsigned long nextinsn;
458     };
459     
460     /* Returns 0 if exception not found and fixup.unit otherwise.  */
461     extern unsigned long search_exception_table(unsigned long addr);
462     
463     /* Returns the new pc */
464     #define fixup_exception(map_reg, fixup_unit, pc)                \
465     ({                                                              \
466     	fixup_unit;                                             \
467     })
468     
469     #endif /* _ASM_UACCESS_H */
470