1 #ifndef __M68K_UACCESS_H
2 #define __M68K_UACCESS_H
5 * User space memory access functions
7 #include <linux/compiler.h>
8 #include <linux/errno.h>
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <asm/segment.h>
14 #define VERIFY_WRITE 1
16 /* We let the MMU do all checking */
17 static inline int access_ok(int type
, const void __user
*addr
,
24 * The exception table consists of pairs of addresses: the first is the
25 * address of an instruction that is allowed to fault, and the second is
26 * the address at which the program should continue. No registers are
27 * modified, so it is entirely up to the continuation code to figure out
30 * All the routines below use bits of fixup code that are out of line
31 * with the main instruction path. This means when everything is well,
32 * we don't even have to jump over them. Further, they do not intrude
33 * on our cache or tlb entries.
36 struct exception_table_entry
38 unsigned long insn
, fixup
;
41 extern int __put_user_bad(void);
42 extern int __get_user_bad(void);
44 #define __put_user_asm(res, x, ptr, bwl, reg, err) \
46 "1: moves."#bwl" %2,%1\n" \
48 " .section .fixup,\"ax\"\n" \
50 "10: moveq.l %3,%0\n" \
54 " .section __ex_table,\"a\"\n" \
59 : "+d" (res), "=m" (*(ptr)) \
60 : #reg (x), "i" (err))
63 * These are the main single-value transfer routines. They automatically
64 * use the right size if we just have the right pointer type.
67 #define __put_user(x, ptr) \
69 typeof(*(ptr)) __pu_val = (x); \
71 __chk_user_ptr(ptr); \
72 switch (sizeof (*(ptr))) { \
74 __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
77 __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \
80 __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
84 const void __user *__pu_ptr = (ptr); \
86 "1: moves.l %2,(%1)+\n" \
87 "2: moves.l %R2,(%1)\n" \
89 " .section .fixup,\"ax\"\n" \
95 " .section __ex_table,\"a\"\n" \
101 : "+d" (__pu_err), "+a" (__pu_ptr) \
102 : "r" (__pu_val), "i" (-EFAULT) \
107 __pu_err = __put_user_bad(); \
112 #define put_user(x, ptr) __put_user(x, ptr)
115 #define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \
118 "1: moves."#bwl" %2,%1\n" \
120 " .section .fixup,\"ax\"\n" \
122 "10: move.l %3,%0\n" \
123 " sub."#bwl" %1,%1\n" \
127 " .section __ex_table,\"a\"\n" \
131 : "+d" (res), "=&" #reg (__gu_val) \
132 : "m" (*(ptr)), "i" (err)); \
133 (x) = (typeof(*(ptr)))(unsigned long)__gu_val; \
136 #define __get_user(x, ptr) \
139 __chk_user_ptr(ptr); \
140 switch (sizeof(*(ptr))) { \
142 __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \
145 __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \
148 __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
150 /* case 8: disabled because gcc-4.1 has a broken typeof \
152 const void *__gu_ptr = (ptr); \
155 "1: moves.l (%2)+,%1\n" \
156 "2: moves.l (%2),%R1\n" \
158 " .section .fixup,\"ax\"\n" \
160 "10: move.l %3,%0\n" \
166 " .section __ex_table,\"a\"\n" \
171 : "+d" (__gu_err), "=&r" (__gu_val), \
175 (x) = (typeof(*(ptr)))__gu_val; \
179 __gu_err = __get_user_bad(); \
184 #define get_user(x, ptr) __get_user(x, ptr)
186 unsigned long __generic_copy_from_user(void *to
, const void __user
*from
, unsigned long n
);
187 unsigned long __generic_copy_to_user(void __user
*to
, const void *from
, unsigned long n
);
189 #define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
191 "1: moves."#s1" (%2)+,%3\n" \
192 " move."#s1" %3,(%1)+\n" \
193 "2: moves."#s2" (%2)+,%3\n" \
194 " move."#s2" %3,(%1)+\n" \
195 " .ifnc \""#s3"\",\"\"\n" \
196 "3: moves."#s3" (%2)+,%3\n" \
197 " move."#s3" %3,(%1)+\n" \
200 " .section __ex_table,\"a\"\n" \
204 " .ifnc \""#s3"\",\"\"\n" \
209 " .section .fixup,\"ax\"\n" \
211 "10: clr."#s1" (%1)+\n" \
212 "20: clr."#s2" (%1)+\n" \
213 " .ifnc \""#s3"\",\"\"\n" \
214 "30: clr."#s3" (%1)+\n" \
216 " moveq.l #"#n",%0\n" \
219 : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
222 static __always_inline
unsigned long
223 __constant_copy_from_user(void *to
, const void __user
*from
, unsigned long n
)
225 unsigned long res
= 0, tmp
;
229 __get_user_asm(res
, *(u8
*)to
, (u8 __user
*)from
, u8
, b
, d
, 1);
232 __get_user_asm(res
, *(u16
*)to
, (u16 __user
*)from
, u16
, w
, d
, 2);
235 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 3, w
, b
,);
238 __get_user_asm(res
, *(u32
*)to
, (u32 __user
*)from
, u32
, l
, r
, 4);
241 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 5, l
, b
,);
244 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 6, l
, w
,);
247 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 7, l
, w
, b
);
250 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 8, l
, l
,);
253 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 9, l
, l
, b
);
256 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 10, l
, l
, w
);
259 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 12, l
, l
, l
);
262 /* we limit the inlined version to 3 moves */
263 return __generic_copy_from_user(to
, from
, n
);
269 #define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
271 " move."#s1" (%2)+,%3\n" \
272 "11: moves."#s1" %3,(%1)+\n" \
273 "12: move."#s2" (%2)+,%3\n" \
274 "21: moves."#s2" %3,(%1)+\n" \
276 " .ifnc \""#s3"\",\"\"\n" \
277 " move."#s3" (%2)+,%3\n" \
278 "31: moves."#s3" %3,(%1)+\n" \
283 " .section __ex_table,\"a\"\n" \
289 " .ifnc \""#s3"\",\"\"\n" \
295 " .section .fixup,\"ax\"\n" \
297 "5: moveq.l #"#n",%0\n" \
300 : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
303 static __always_inline
unsigned long
304 __constant_copy_to_user(void __user
*to
, const void *from
, unsigned long n
)
306 unsigned long res
= 0, tmp
;
310 __put_user_asm(res
, *(u8
*)from
, (u8 __user
*)to
, b
, d
, 1);
313 __put_user_asm(res
, *(u16
*)from
, (u16 __user
*)to
, w
, d
, 2);
316 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 3, w
, b
,);
319 __put_user_asm(res
, *(u32
*)from
, (u32 __user
*)to
, l
, r
, 4);
322 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 5, l
, b
,);
325 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 6, l
, w
,);
328 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 7, l
, w
, b
);
331 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 8, l
, l
,);
334 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 9, l
, l
, b
);
337 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 10, l
, l
, w
);
340 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 12, l
, l
, l
);
343 /* limit the inlined version to 3 moves */
344 return __generic_copy_to_user(to
, from
, n
);
350 #define __copy_from_user(to, from, n) \
351 (__builtin_constant_p(n) ? \
352 __constant_copy_from_user(to, from, n) : \
353 __generic_copy_from_user(to, from, n))
355 #define __copy_to_user(to, from, n) \
356 (__builtin_constant_p(n) ? \
357 __constant_copy_to_user(to, from, n) : \
358 __generic_copy_to_user(to, from, n))
360 #define __copy_to_user_inatomic __copy_to_user
361 #define __copy_from_user_inatomic __copy_from_user
363 #define copy_from_user(to, from, n) __copy_from_user(to, from, n)
364 #define copy_to_user(to, from, n) __copy_to_user(to, from, n)
366 long strncpy_from_user(char *dst
, const char __user
*src
, long count
);
367 long strnlen_user(const char __user
*src
, long n
);
368 unsigned long __clear_user(void __user
*to
, unsigned long n
);
370 #define clear_user __clear_user
372 #define strlen_user(str) strnlen_user(str, 32767)
374 #endif /* _M68K_UACCESS_H */