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
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.