~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/include/asm-sh/uaccess.h

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* $Id: uaccess.h,v 1.10 2000/03/24 13:53:45 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 extern __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), "" (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 extern __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                 : "" (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 extern __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                 : "" (__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 extern __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), "r" (__s), "r" (__n), "i" (-EFAULT)
383                 : "t");
384         return res;
385 }
386 
387 extern __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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.