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 * Not all varients of the 68k family support the notion of address spaces.
25 * The traditional 680x0 parts do, and they use the sfc/dfc registers and
26 * the "moves" instruction to access user space from kernel space. Other
27 * family members like ColdFire don't support this, and only have a single
28 * address space, and use the usual "move" instruction for user space access.
30 * Outside of this difference the user space access functions are the same.
31 * So lets keep the code simple and just define in what we need to use.
33 #ifdef CONFIG_CPU_HAS_ADDRESS_SPACES
40 * The exception table consists of pairs of addresses: the first is the
41 * address of an instruction that is allowed to fault, and the second is
42 * the address at which the program should continue. No registers are
43 * modified, so it is entirely up to the continuation code to figure out
46 * All the routines below use bits of fixup code that are out of line
47 * with the main instruction path. This means when everything is well,
48 * we don't even have to jump over them. Further, they do not intrude
49 * on our cache or tlb entries.
52 struct exception_table_entry
54 unsigned long insn
, fixup
;
57 extern int __put_user_bad(void);
58 extern int __get_user_bad(void);
60 #define __put_user_asm(res, x, ptr, bwl, reg, err) \
62 "1: "MOVES"."#bwl" %2,%1\n" \
64 " .section .fixup,\"ax\"\n" \
66 "10: moveq.l %3,%0\n" \
70 " .section __ex_table,\"a\"\n" \
75 : "+d" (res), "=m" (*(ptr)) \
76 : #reg (x), "i" (err))
79 * These are the main single-value transfer routines. They automatically
80 * use the right size if we just have the right pointer type.
83 #define __put_user(x, ptr) \
85 typeof(*(ptr)) __pu_val = (x); \
87 __chk_user_ptr(ptr); \
88 switch (sizeof (*(ptr))) { \
90 __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
93 __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \
96 __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
100 const void __user *__pu_ptr = (ptr); \
102 "1: "MOVES".l %2,(%1)+\n" \
103 "2: "MOVES".l %R2,(%1)\n" \
105 " .section .fixup,\"ax\"\n" \
107 "10: movel %3,%0\n" \
111 " .section __ex_table,\"a\"\n" \
117 : "+d" (__pu_err), "+a" (__pu_ptr) \
118 : "r" (__pu_val), "i" (-EFAULT) \
123 __pu_err = __put_user_bad(); \
128 #define put_user(x, ptr) __put_user(x, ptr)
131 #define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \
134 "1: "MOVES"."#bwl" %2,%1\n" \
136 " .section .fixup,\"ax\"\n" \
138 "10: move.l %3,%0\n" \
143 " .section __ex_table,\"a\"\n" \
147 : "+d" (res), "=&" #reg (__gu_val) \
148 : "m" (*(ptr)), "i" (err)); \
149 (x) = (__force typeof(*(ptr)))(__force unsigned long)__gu_val; \
152 #define __get_user(x, ptr) \
155 __chk_user_ptr(ptr); \
156 switch (sizeof(*(ptr))) { \
158 __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \
161 __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT); \
164 __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
166 /* case 8: disabled because gcc-4.1 has a broken typeof \
168 const void *__gu_ptr = (ptr); \
171 "1: "MOVES".l (%2)+,%1\n" \
172 "2: "MOVES".l (%2),%R1\n" \
174 " .section .fixup,\"ax\"\n" \
176 "10: move.l %3,%0\n" \
182 " .section __ex_table,\"a\"\n" \
187 : "+d" (__gu_err), "=&r" (__gu_val), \
191 (x) = (__force typeof(*(ptr)))__gu_val; \
195 __gu_err = __get_user_bad(); \
200 #define get_user(x, ptr) __get_user(x, ptr)
202 unsigned long __generic_copy_from_user(void *to
, const void __user
*from
, unsigned long n
);
203 unsigned long __generic_copy_to_user(void __user
*to
, const void *from
, unsigned long n
);
205 #define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
207 "1: "MOVES"."#s1" (%2)+,%3\n" \
208 " move."#s1" %3,(%1)+\n" \
209 "2: "MOVES"."#s2" (%2)+,%3\n" \
210 " move."#s2" %3,(%1)+\n" \
211 " .ifnc \""#s3"\",\"\"\n" \
212 "3: "MOVES"."#s3" (%2)+,%3\n" \
213 " move."#s3" %3,(%1)+\n" \
216 " .section __ex_table,\"a\"\n" \
220 " .ifnc \""#s3"\",\"\"\n" \
225 " .section .fixup,\"ax\"\n" \
227 "10: clr."#s1" (%1)+\n" \
228 "20: clr."#s2" (%1)+\n" \
229 " .ifnc \""#s3"\",\"\"\n" \
230 "30: clr."#s3" (%1)+\n" \
232 " moveq.l #"#n",%0\n" \
235 : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
238 static __always_inline
unsigned long
239 __constant_copy_from_user(void *to
, const void __user
*from
, unsigned long n
)
241 unsigned long res
= 0, tmp
;
245 __get_user_asm(res
, *(u8
*)to
, (u8 __user
*)from
, u8
, b
, d
, 1);
248 __get_user_asm(res
, *(u16
*)to
, (u16 __user
*)from
, u16
, w
, r
, 2);
251 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 3, w
, b
,);
254 __get_user_asm(res
, *(u32
*)to
, (u32 __user
*)from
, u32
, l
, r
, 4);
257 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 5, l
, b
,);
260 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 6, l
, w
,);
263 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 7, l
, w
, b
);
266 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 8, l
, l
,);
269 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 9, l
, l
, b
);
272 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 10, l
, l
, w
);
275 __constant_copy_from_user_asm(res
, to
, from
, tmp
, 12, l
, l
, l
);
278 /* we limit the inlined version to 3 moves */
279 return __generic_copy_from_user(to
, from
, n
);
285 #define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
287 " move."#s1" (%2)+,%3\n" \
288 "11: "MOVES"."#s1" %3,(%1)+\n" \
289 "12: move."#s2" (%2)+,%3\n" \
290 "21: "MOVES"."#s2" %3,(%1)+\n" \
292 " .ifnc \""#s3"\",\"\"\n" \
293 " move."#s3" (%2)+,%3\n" \
294 "31: "MOVES"."#s3" %3,(%1)+\n" \
299 " .section __ex_table,\"a\"\n" \
305 " .ifnc \""#s3"\",\"\"\n" \
311 " .section .fixup,\"ax\"\n" \
313 "5: moveq.l #"#n",%0\n" \
316 : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
319 static __always_inline
unsigned long
320 __constant_copy_to_user(void __user
*to
, const void *from
, unsigned long n
)
322 unsigned long res
= 0, tmp
;
326 __put_user_asm(res
, *(u8
*)from
, (u8 __user
*)to
, b
, d
, 1);
329 __put_user_asm(res
, *(u16
*)from
, (u16 __user
*)to
, w
, r
, 2);
332 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 3, w
, b
,);
335 __put_user_asm(res
, *(u32
*)from
, (u32 __user
*)to
, l
, r
, 4);
338 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 5, l
, b
,);
341 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 6, l
, w
,);
344 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 7, l
, w
, b
);
347 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 8, l
, l
,);
350 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 9, l
, l
, b
);
353 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 10, l
, l
, w
);
356 __constant_copy_to_user_asm(res
, to
, from
, tmp
, 12, l
, l
, l
);
359 /* limit the inlined version to 3 moves */
360 return __generic_copy_to_user(to
, from
, n
);
366 #define __copy_from_user(to, from, n) \
367 (__builtin_constant_p(n) ? \
368 __constant_copy_from_user(to, from, n) : \
369 __generic_copy_from_user(to, from, n))
371 #define __copy_to_user(to, from, n) \
372 (__builtin_constant_p(n) ? \
373 __constant_copy_to_user(to, from, n) : \
374 __generic_copy_to_user(to, from, n))
376 #define __copy_to_user_inatomic __copy_to_user
377 #define __copy_from_user_inatomic __copy_from_user
379 #define copy_from_user(to, from, n) __copy_from_user(to, from, n)
380 #define copy_to_user(to, from, n) __copy_to_user(to, from, n)
382 #define user_addr_max() \
383 (segment_eq(get_fs(), USER_DS) ? TASK_SIZE : ~0UL)
385 extern long strncpy_from_user(char *dst
, const char __user
*src
, long count
);
386 extern __must_check
long strlen_user(const char __user
*str
);
387 extern __must_check
long strnlen_user(const char __user
*str
, long n
);
389 unsigned long __clear_user(void __user
*to
, unsigned long n
);
391 #define clear_user __clear_user
393 #endif /* _M68K_UACCESS_H */