File: /usr/src/linux/include/asm-sh/uaccess.h

1     /* $Id: uaccess.h,v 1.12 2001/07/27 06:09:47 gniibe Exp $
2      *
3      * User space memory access functions
4      *
5      * Copyright (C) 1999  Niibe Yutaka
6      *
7      *  Based on:
8      *     MIPS implementation version 1.15 by
9      *              Copyright (C) 1996, 1997, 1998 by Ralf Baechle
10      *     and i386 version.
11      */
12     #ifndef __ASM_SH_UACCESS_H
13     #define __ASM_SH_UACCESS_H
14     
15     #include <linux/errno.h>
16     #include <linux/sched.h>
17     
18     #define VERIFY_READ    0
19     #define VERIFY_WRITE   1
20     
21     /*
22      * The fs value determines whether argument validity checking should be
23      * performed or not.  If get_fs() == USER_DS, checking is performed, with
24      * get_fs() == KERNEL_DS, checking is bypassed.
25      *
26      * For historical reasons (Data Segment Register?), these macros are misnamed.
27      */
28     
29     #define MAKE_MM_SEG(s)	((mm_segment_t) { (s) })
30     
31     #define KERNEL_DS	MAKE_MM_SEG(0xFFFFFFFF)
32     #define USER_DS		MAKE_MM_SEG(0x80000000)
33     
34     #define get_ds()	(KERNEL_DS)
35     #define get_fs()        (current->addr_limit)
36     #define set_fs(x)       (current->addr_limit=(x))
37     
38     #define segment_eq(a,b)	((a).seg == (b).seg)
39     
40     #define __addr_ok(addr) ((unsigned long)(addr) < (current->addr_limit.seg))
41     
42     /*
43      * Uhhuh, this needs 33-bit arithmetic. We have a carry..
44      *
45      * sum := addr + size;  carry? --> flag = true;
46      * if (sum >= addr_limit) flag = true;
47      */
48     #define __range_ok(addr,size) ({					      \
49     	unsigned long flag,sum; 					      \
50     	__asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0"	      \
51     		:"=&r" (flag), "=r" (sum) 				      \
52     		:"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg) \
53     		:"t"); 							      \
54     	flag; })
55     
56     #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
57     #define __access_ok(addr,size) (__range_ok(addr,size) == 0)
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 SuperH 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)	__put_user_check((x),(ptr),sizeof(*(ptr)))
77     #define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
78     
79     /*
80      * The "__xxx" versions do not do address space checking, useful when
81      * doing multiple accesses to the same area (the user has to do the
82      * checks by hand with "access_ok()")
83      */
84     #define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
85     #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
86     
87     struct __large_struct { unsigned long buf[100]; };
88     #define __m(x) (*(struct __large_struct *)(x))
89     
90     #define __get_user_nocheck(x,ptr,size) ({ \
91     long __gu_err; \
92     __typeof(*(ptr)) __gu_val; \
93     long __gu_addr; \
94     __asm__("":"=r" (__gu_val)); \
95     __gu_addr = (long) (ptr); \
96     __asm__("":"=r" (__gu_err)); \
97     switch (size) { \
98     case 1: __get_user_asm("b"); break; \
99     case 2: __get_user_asm("w"); break; \
100     case 4: __get_user_asm("l"); break; \
101     default: __get_user_unknown(); break; \
102     } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
103     
104     #define __get_user_check(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     if (__access_ok(__gu_addr,size)) { \
112     switch (size) { \
113     case 1: __get_user_asm("b"); break; \
114     case 2: __get_user_asm("w"); break; \
115     case 4: __get_user_asm("l"); break; \
116     default: __get_user_unknown(); break; \
117     } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
118     
119     #define __get_user_asm(insn) \
120     ({ \
121     __asm__ __volatile__( \
122     	"1:\n\t" \
123     	"mov." insn "	%2, %1\n\t" \
124     	"mov	#0, %0\n" \
125     	"2:\n" \
126     	".section	.fixup,\"ax\"\n" \
127     	"3:\n\t" \
128     	"mov	#0, %1\n\t" \
129     	"mov.l	4f, %0\n\t" \
130     	"jmp	@%0\n\t" \
131     	" mov	%3, %0\n" \
132     	"4:	.long	2b\n\t" \
133     	".previous\n" \
134     	".section	__ex_table,\"a\"\n\t" \
135     	".long	1b, 3b\n\t" \
136     	".previous" \
137     	:"=&r" (__gu_err), "=&r" (__gu_val) \
138     	:"m" (__m(__gu_addr)), "i" (-EFAULT)); })
139     
140     extern void __get_user_unknown(void);
141     
142     #define __put_user_nocheck(x,ptr,size) ({ \
143     long __pu_err; \
144     __typeof__(*(ptr)) __pu_val; \
145     long __pu_addr; \
146     __pu_val = (x); \
147     __pu_addr = (long) (ptr); \
148     __asm__("":"=r" (__pu_err)); \
149     switch (size) { \
150     case 1: __put_user_asm("b"); break; \
151     case 2: __put_user_asm("w"); break; \
152     case 4: __put_user_asm("l"); break; \
153     default: __put_user_unknown(); break; \
154     } __pu_err; })
155     
156     #define __put_user_check(x,ptr,size) ({ \
157     long __pu_err; \
158     __typeof__(*(ptr)) __pu_val; \
159     long __pu_addr; \
160     __pu_val = (x); \
161     __pu_addr = (long) (ptr); \
162     __asm__("":"=r" (__pu_err)); \
163     if (__access_ok(__pu_addr,size)) { \
164     switch (size) { \
165     case 1: __put_user_asm("b"); break; \
166     case 2: __put_user_asm("w"); break; \
167     case 4: __put_user_asm("l"); break; \
168     default: __put_user_unknown(); break; \
169     } } __pu_err; })
170     
171     #define __put_user_asm(insn) \
172     ({ \
173     __asm__ __volatile__( \
174     	"1:\n\t" \
175     	"mov." insn "	%1, %2\n\t" \
176     	"mov	#0, %0\n" \
177     	"2:\n" \
178     	".section	.fixup,\"ax\"\n" \
179     	"3:\n\t" \
180     	"nop\n\t" \
181     	"mov.l	4f, %0\n\t" \
182     	"jmp	@%0\n\t" \
183     	"mov	%3, %0\n" \
184     	"4:	.long	2b\n\t" \
185     	".previous\n" \
186     	".section	__ex_table,\"a\"\n\t" \
187     	".long	1b, 3b\n\t" \
188     	".previous" \
189     	:"=&r" (__pu_err) \
190     	:"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT) \
191             :"memory"); })
192     
193     extern void __put_user_unknown(void);
194     
195     /* Generic arbitrary sized copy.  */
196     /* Return the number of bytes NOT copied */
197     /* XXX: should be such that: 4byte and the rest. */
198     static __inline__ __kernel_size_t
199     __copy_user(void *__to, const void *__from, __kernel_size_t __n)
200     {
201     	unsigned long __dummy, _f, _t;
202     	__kernel_size_t res;
203     
204     	if ((res = __n))
205     	__asm__ __volatile__(
206     		"9:\n\t"
207     		"mov.b	@%2+, %1\n\t"
208     		"dt	%0\n"
209     		"1:\n\t"
210     		"mov.b	%1, @%3\n\t"
211     		"bf/s	9b\n\t"
212     		" add	#1, %3\n"
213     		"2:\n"
214     		".section .fixup,\"ax\"\n"
215     		"3:\n\t"
216     		"mov.l	5f, %1\n\t"
217     		"jmp	@%1\n\t"
218     		" add	#1, %0\n\t"
219     		".balign 4\n"
220     		"5:	.long 2b\n"
221     		".previous\n"
222     		".section __ex_table,\"a\"\n"
223     		"	.balign 4\n"
224     		"	.long 9b,2b\n"
225     		"	.long 1b,3b\n"
226     		".previous"
227     		: "=r" (res), "=&z" (__dummy), "=r" (_f), "=r" (_t)
228     		: "2" (__from), "3" (__to), "0" (res)
229     		: "memory", "t");
230     
231     	return res;
232     }
233     
234     #define copy_to_user(to,from,n) ({ \
235     void *__copy_to = (void *) (to); \
236     __kernel_size_t __copy_size = (__kernel_size_t) (n); \
237     __kernel_size_t __copy_res; \
238     if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \
239     __copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
240     } else __copy_res = __copy_size; \
241     __copy_res; })
242     
243     #define __copy_to_user(to,from,n)		\
244     	__copy_user((void *)(to),		\
245     		    (void *)(from), n)
246     
247     #define copy_from_user(to,from,n) ({ \
248     void *__copy_to = (void *) (to); \
249     void *__copy_from = (void *) (from); \
250     __kernel_size_t __copy_size = (__kernel_size_t) (n); \
251     __kernel_size_t __copy_res; \
252     if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
253     __copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
254     } else __copy_res = __copy_size; \
255     __copy_res; })
256     
257     #define __copy_from_user(to,from,n)		\
258     	__copy_user((void *)(to),		\
259     		    (void *)(from), n)
260     
261     /* XXX: Not sure it works well..
262        should be such that: 4byte clear and the rest. */
263     static __inline__ __kernel_size_t
264     __clear_user(void *addr, __kernel_size_t size)
265     {
266     	unsigned long __a;
267     
268     	__asm__ __volatile__(
269     		"9:\n\t"
270     		"dt	%0\n"
271     		"1:\n\t"
272     		"mov.b	%4, @%1\n\t"
273     		"bf/s	9b\n\t"
274     		" add	#1, %1\n"
275     		"2:\n"
276     		".section .fixup,\"ax\"\n"
277     		"3:\n\t"
278     		"mov.l	4f, %1\n\t"
279     		"jmp	@%1\n\t"
280     		" nop\n"
281     		".balign 4\n"
282     		"4:	.long 2b\n"
283     		".previous\n"
284     		".section __ex_table,\"a\"\n"
285     		"	.balign 4\n"
286     		"	.long 1b,3b\n"
287     		".previous"
288     		: "=r" (size), "=r" (__a)
289     		: "0" (size), "1" (addr), "r" (0)
290     		: "memory", "t");
291     
292     	return size;
293     }
294     
295     #define clear_user(addr,n) ({ \
296     void * __cl_addr = (addr); \
297     unsigned long __cl_size = (n); \
298     if (__cl_size && __access_ok(((unsigned long)(__cl_addr)), __cl_size)) \
299     __cl_size = __clear_user(__cl_addr, __cl_size); \
300     __cl_size; })
301     
302     static __inline__ int
303     __strncpy_from_user(unsigned long __dest, unsigned long __src, int __count)
304     {
305     	__kernel_size_t res;
306     	unsigned long __dummy, _d, _s;
307     
308     	__asm__ __volatile__(
309     		"9:\n"
310     		"mov.b	@%2+, %1\n\t"
311     		"cmp/eq	#0, %1\n\t"
312     		"bt/s	2f\n"
313     		"1:\n"
314     		"mov.b	%1, @%3\n\t"
315     		"dt	%7\n\t"
316     		"bf/s	9b\n\t"
317     		" add	#1, %3\n\t"
318     		"2:\n\t"
319     		"sub	%7, %0\n"
320     		"3:\n"
321     		".section .fixup,\"ax\"\n"
322     		"4:\n\t"
323     		"mov.l	5f, %1\n\t"
324     		"jmp	@%1\n\t"
325     		" mov	%8, %0\n\t"
326     		".balign 4\n"
327     		"5:	.long 3b\n"
328     		".previous\n"
329     		".section __ex_table,\"a\"\n"
330     		"	.balign 4\n"
331     		"	.long 9b,4b\n"
332     		".previous"
333     		: "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d)
334     		: "0" (__count), "2" (__src), "3" (__dest), "r" (__count),
335     		  "i" (-EFAULT)
336     		: "memory", "t");
337     
338     	return res;
339     }
340     
341     #define strncpy_from_user(dest,src,count) ({ \
342     unsigned long __sfu_src = (unsigned long) (src); \
343     int __sfu_count = (int) (count); \
344     long __sfu_res = -EFAULT; \
345     if(__access_ok(__sfu_src, __sfu_count)) { \
346     __sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
347     } __sfu_res; })
348     
349     #define strlen_user(str) strnlen_user(str, ~0UL >> 1)
350     
351     /*
352      * Return the size of a string (including the ending 0!)
353      */
354     static __inline__ long __strnlen_user(const char *__s, long __n)
355     {
356     	unsigned long res;
357     	unsigned long __dummy;
358     
359     	__asm__ __volatile__(
360     		"9:\n"
361     		"cmp/eq	%4, %0\n\t"
362     		"bt	2f\n"
363     		"1:\t"
364     		"mov.b	@(%0,%3), %1\n\t"
365     		"tst	%1, %1\n\t"
366     		"bf/s	9b\n\t"
367     		" add	#1, %0\n"
368     		"2:\n"
369     		".section .fixup,\"ax\"\n"
370     		"3:\n\t"
371     		"mov.l	4f, %1\n\t"
372     		"jmp	@%1\n\t"
373     		" mov	%5, %0\n"
374     		".balign 4\n"
375     		"4:	.long 2b\n"
376     		".previous\n"
377     		".section __ex_table,\"a\"\n"
378     		"	.balign 4\n"
379     		"	.long 1b,3b\n"
380     		".previous"
381     		: "=z" (res), "=&r" (__dummy)
382     		: "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)
383     		: "t");
384     	return res;
385     }
386     
387     static __inline__ long strnlen_user(const char *s, long n)
388     {
389     	if (!__addr_ok(s))
390     		return 0;
391     	else
392     		return __strnlen_user(s, n);
393     }
394     
395     struct exception_table_entry
396     {
397     	unsigned long insn, fixup;
398     };
399     
400     /* Returns 0 if exception not found and fixup.unit otherwise.  */
401     extern unsigned long search_exception_table(unsigned long addr);
402     
403     /* Returns the new pc */
404     #define fixup_exception(map_reg, fixup_unit, pc)                \
405     ({                                                              \
406     	fixup_unit;                                             \
407     })
408     
409     #endif /* __ASM_SH_UACCESS_H */
410