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

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

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

  1 #ifdef __KERNEL__
  2 #ifndef _PPC_UACCESS_H
  3 #define _PPC_UACCESS_H
  4 
  5 #ifndef __ASSEMBLY__
  6 #include <linux/sched.h>
  7 #include <linux/errno.h>
  8 #include <asm/processor.h>
  9 
 10 #define VERIFY_READ     0
 11 #define VERIFY_WRITE    1
 12 
 13 /*
 14  * The fs value determines whether argument validity checking should be
 15  * performed or not.  If get_fs() == USER_DS, checking is performed, with
 16  * get_fs() == KERNEL_DS, checking is bypassed.
 17  *
 18  * For historical reasons, these macros are grossly misnamed.
 19  */
 20 
 21 #define KERNEL_DS       ((mm_segment_t) { 0 })
 22 #define USER_DS         ((mm_segment_t) { 1 })
 23 
 24 #define get_ds()        (KERNEL_DS)
 25 #define get_fs()        (current->thread.fs)
 26 #define set_fs(val)     (current->thread.fs = (val))
 27 
 28 #define segment_eq(a,b) ((a).seg == (b).seg)
 29 
 30 #define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
 31 #define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
 32 #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
 33 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 34 
 35 extern inline int verify_area(int type, const void * addr, unsigned long size)
 36 {
 37         return access_ok(type,addr,size) ? 0 : -EFAULT;
 38 }
 39 
 40 
 41 /*
 42  * The exception table consists of pairs of addresses: the first is the
 43  * address of an instruction that is allowed to fault, and the second is
 44  * the address at which the program should continue.  No registers are
 45  * modified, so it is entirely up to the continuation code to figure out
 46  * what to do.
 47  *
 48  * All the routines below use bits of fixup code that are out of line
 49  * with the main instruction path.  This means when everything is well,
 50  * we don't even have to jump over them.  Further, they do not intrude
 51  * on our cache or tlb entries.
 52  */
 53 
 54 struct exception_table_entry
 55 {
 56         unsigned long insn, fixup;
 57 };
 58 
 59 /* Returns 0 if exception not found and fixup otherwise.  */
 60 extern unsigned long search_exception_table(unsigned long);
 61 extern void sort_exception_table(void);
 62 
 63 /*
 64  * These are the main single-value transfer routines.  They automatically
 65  * use the right size if we just have the right pointer type.
 66  *
 67  * This gets kind of ugly. We want to return _two_ values in "get_user()"
 68  * and yet we don't want to do any pointers, because that is too much
 69  * of a performance impact. Thus we have a few rather ugly macros here,
 70  * and hide all the uglyness from the user.
 71  *
 72  * The "__xxx" versions of the user access functions are versions that
 73  * do not verify the address space, that must have been done previously
 74  * with a separate "access_ok()" call (this is used when we do multiple
 75  * accesses to the same area of user memory).
 76  *
 77  * As we use the same address space for kernel and user data on the
 78  * PowerPC, we can just do these as direct assignments.  (Of course, the
 79  * exception handling means that it's no longer "just"...)
 80  */
 81 #define get_user(x,ptr) \
 82   __get_user_check((x),(ptr),sizeof(*(ptr)))
 83 #define put_user(x,ptr) \
 84   __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 85 
 86 #define __get_user(x,ptr) \
 87   __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
 88 #define __put_user(x,ptr) \
 89   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 90 
 91 extern long __put_user_bad(void);
 92 
 93 #define __put_user_nocheck(x,ptr,size)                  \
 94 ({                                                      \
 95         long __pu_err;                                  \
 96         __put_user_size((x),(ptr),(size),__pu_err);     \
 97         __pu_err;                                       \
 98 })
 99 
100 #define __put_user_check(x,ptr,size)                            \
101 ({                                                              \
102         long __pu_err = -EFAULT;                                \
103         __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
104         if (access_ok(VERIFY_WRITE,__pu_addr,size))             \
105                 __put_user_size((x),__pu_addr,(size),__pu_err); \
106         __pu_err;                                               \
107 })
108 
109 #define __put_user_size(x,ptr,size,retval)                      \
110 do {                                                            \
111         retval = 0;                                             \
112         switch (size) {                                         \
113           case 1: __put_user_asm(x,ptr,retval,"stb"); break;    \
114           case 2: __put_user_asm(x,ptr,retval,"sth"); break;    \
115           case 4: __put_user_asm(x,ptr,retval,"stw"); break;    \
116           default: __put_user_bad();                            \
117         }                                                       \
118 } while (0)
119 
120 struct __large_struct { unsigned long buf[100]; };
121 #define __m(x) (*(struct __large_struct *)(x))
122 
123 /*
124  * We don't tell gcc that we are accessing memory, but this is OK
125  * because we do not write to any memory gcc knows about, so there
126  * are no aliasing issues.
127  */
128 #define __put_user_asm(x, addr, err, op)                        \
129         __asm__ __volatile__(                                   \
130                 "1:     "op" %1,0(%2)\n"                        \
131                 "2:\n"                                          \
132                 ".section .fixup,\"ax\"\n"                      \
133                 "3:     li %0,%3\n"                             \
134                 "       b 2b\n"                                 \
135                 ".previous\n"                                   \
136                 ".section __ex_table,\"a\"\n"                   \
137                 "       .align 2\n"                             \
138                 "       .long 1b,3b\n"                          \
139                 ".previous"                                     \
140                 : "=r"(err)                                     \
141                 : "r"(x), "b"(addr), "i"(-EFAULT), ""(err))
142 
143 
144 #define __get_user_nocheck(x,ptr,size)                          \
145 ({                                                              \
146         long __gu_err, __gu_val;                                \
147         __get_user_size(__gu_val,(ptr),(size),__gu_err);        \
148         (x) = (__typeof__(*(ptr)))__gu_val;                     \
149         __gu_err;                                               \
150 })
151 
152 #define __get_user_check(x,ptr,size)                                    \
153 ({                                                                      \
154         long __gu_err = -EFAULT, __gu_val = 0;                          \
155         const __typeof__(*(ptr)) *__gu_addr = (ptr);                    \
156         if (access_ok(VERIFY_READ,__gu_addr,size))                      \
157                 __get_user_size(__gu_val,__gu_addr,(size),__gu_err);    \
158         (x) = (__typeof__(*(ptr)))__gu_val;                             \
159         __gu_err;                                                       \
160 })
161 
162 extern long __get_user_bad(void);
163 
164 #define __get_user_size(x,ptr,size,retval)                      \
165 do {                                                            \
166         retval = 0;                                             \
167         switch (size) {                                         \
168           case 1: __get_user_asm(x,ptr,retval,"lbz"); break;    \
169           case 2: __get_user_asm(x,ptr,retval,"lhz"); break;    \
170           case 4: __get_user_asm(x,ptr,retval,"lwz"); break;    \
171           default: (x) = __get_user_bad();                      \
172         }                                                       \
173 } while (0)
174 
175 #define __get_user_asm(x, addr, err, op)                \
176         __asm__ __volatile__(                           \
177                 "1:     "op" %1,0(%2)\n"                \
178                 "2:\n"                                  \
179                 ".section .fixup,\"ax\"\n"              \
180                 "3:     li %0,%3\n"                     \
181                 "       li %1,0\n"                      \
182                 "       b 2b\n"                         \
183                 ".previous\n"                           \
184                 ".section __ex_table,\"a\"\n"           \
185                 "       .align 2\n"                     \
186                 "       .long 1b,3b\n"                  \
187                 ".previous"                             \
188                 : "=r"(err), "=r"(x)                    \
189                 : "b"(addr), "i"(-EFAULT), ""(err))
190 
191 /* more complex routines */
192 
193 extern int __copy_tofrom_user(void *to, const void *from, unsigned long size);
194 
195 extern inline unsigned long
196 copy_from_user(void *to, const void *from, unsigned long n)
197 {
198         unsigned long over;
199 
200         if (access_ok(VERIFY_READ, from, n))
201                 return __copy_tofrom_user(to, from, n);
202         if ((unsigned long)from < TASK_SIZE) {
203                 over = (unsigned long)from + n - TASK_SIZE;
204                 return __copy_tofrom_user(to, from, n - over) + over;
205         }
206         return n;
207 }
208 
209 extern inline unsigned long
210 copy_to_user(void *to, const void *from, unsigned long n)
211 {
212         unsigned long over;
213 
214         if (access_ok(VERIFY_WRITE, to, n))
215                 return __copy_tofrom_user(to, from, n);
216         if ((unsigned long)to < TASK_SIZE) {
217                 over = (unsigned long)to + n - TASK_SIZE;
218                 return __copy_tofrom_user(to, from, n - over) + over;
219         }
220         return n;
221 }
222 
223 #define __copy_from_user(to, from, size) \
224         __copy_tofrom_user((to), (from), (size))
225 #define __copy_to_user(to, from, size) \
226         __copy_tofrom_user((to), (from), (size))
227 
228 extern unsigned long __clear_user(void *addr, unsigned long size);
229 
230 extern inline unsigned long
231 clear_user(void *addr, unsigned long size)
232 {
233         if (access_ok(VERIFY_WRITE, addr, size))
234                 return __clear_user(addr, size);
235         return size? -EFAULT: 0;
236 }
237 
238 extern int __strncpy_from_user(char *dst, const char *src, long count);
239 
240 extern inline long
241 strncpy_from_user(char *dst, const char *src, long count)
242 {
243         if (access_ok(VERIFY_READ, src, 1))
244                 return __strncpy_from_user(dst, src, count);
245         return -EFAULT;
246 }
247 
248 /*
249  * Return the size of a string (including the ending 0)
250  *
251  * Return 0 for error
252  */
253 
254 extern int __strnlen_user(const char *str, long len, unsigned long top);
255 
256 /*
257  * Returns the length of the string at str (including the null byte),
258  * or 0 if we hit a page we can't access,
259  * or something > len if we didn't find a null byte.
260  *
261  * The `top' parameter to __strnlen_user is to make sure that
262  * we can never overflow from the user area into kernel space.
263  */
264 extern __inline__ int strnlen_user(const char *str, long len)
265 {
266         unsigned long top = __kernel_ok? ~0UL: TASK_SIZE - 1;
267 
268         if ((unsigned long)str > top)
269                 return 0;
270         return __strnlen_user(str, len, top);
271 }
272 
273 #define strlen_user(str)        strnlen_user((str), 0x7ffffffe)
274 
275 #endif  /* __ASSEMBLY__ */
276 
277 #endif  /* _PPC_UACCESS_H */
278 #endif /* __KERNEL__ */
279 

~ [ 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.