relayd: move the interface fixup to the right place
[openwrt/openwrt.git] / target / linux / coldfire / files-2.6.31 / arch / m68k / include / asm / cf_uaccess.h
1 /*
2 * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
3 */
4 #ifndef __M68K_CF_UACCESS_H
5 #define __M68K_CF_UACCESS_H
6
7 /*
8 * User space memory access functions
9 */
10
11 /* The "moves" command is not available in the CF instruction set. */
12 #include <linux/compiler.h>
13 #include <linux/errno.h>
14 #include <linux/types.h>
15 #include <linux/sched.h>
16 #include <asm/segment.h>
17
18 #define VERIFY_READ 0
19 #define VERIFY_WRITE 1
20
21 /* We let the MMU do all checking */
22 #define access_ok(type, addr, size) 1
23
24 /*
25 * The exception table consists of pairs of addresses: the first is the
26 * address of an instruction that is allowed to fault, and the second is
27 * the address at which the program should continue. No registers are
28 * modified, so it is entirely up to the continuation code to figure out
29 * what to do.
30 *
31 * All the routines below use bits of fixup code that are out of line
32 * with the main instruction path. This means when everything is well,
33 * we don't even have to jump over them. Further, they do not intrude
34 * on our cache or tlb entries.
35 */
36
37 struct exception_table_entry
38 {
39 unsigned long insn, fixup;
40 };
41
42 extern int __put_user_bad(void);
43 extern int __get_user_bad(void);
44
45 #define __put_user_asm(res, x, ptr, bwl, reg, err) \
46 asm volatile ("\n" \
47 "1: move."#bwl" %2,%1\n" \
48 "2:\n" \
49 " .section .fixup,\"ax\"\n" \
50 " .even\n" \
51 "10: moveq.l %3,%0\n" \
52 " jra 2b\n" \
53 " .previous\n" \
54 "\n" \
55 " .section __ex_table,\"a\"\n" \
56 " .align 4\n" \
57 " .long 1b,10b\n" \
58 " .long 2b,10b\n" \
59 " .previous" \
60 : "+d" (res), "=m" (*(ptr)) \
61 : #reg (x), "i" (err))
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
68 #define __put_user(x, ptr) \
69 ({ \
70 typeof(*(ptr)) __pu_val = (x); \
71 int __pu_err = 0; \
72 __chk_user_ptr(ptr); \
73 switch (sizeof (*(ptr))) { \
74 case 1: \
75 __put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
76 break; \
77 case 2: \
78 __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \
79 break; \
80 case 4: \
81 __put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
82 break; \
83 case 8: \
84 { \
85 const void __user *__pu_ptr = (ptr); \
86 asm volatile ("\n" \
87 "1: move.l %2,(%1)+\n" \
88 "2: move.l %R2,(%1)\n" \
89 "3:\n" \
90 " .section .fixup,\"ax\"\n" \
91 " .even\n" \
92 "10: movel %3,%0\n" \
93 " jra 3b\n" \
94 " .previous\n" \
95 "\n" \
96 " .section __ex_table,\"a\"\n" \
97 " .align 4\n" \
98 " .long 1b,10b\n" \
99 " .long 2b,10b\n" \
100 " .long 3b,10b\n" \
101 " .previous" \
102 : "+d" (__pu_err), "+a" (__pu_ptr) \
103 : "r" (__pu_val), "i" (-EFAULT) \
104 : "memory"); \
105 break; \
106 } \
107 default: \
108 __pu_err = __put_user_bad(); \
109 break; \
110 } \
111 __pu_err; \
112 })
113 #define put_user(x, ptr) __put_user(x, ptr)
114
115
116 #define __get_user_asm(res, x, ptr, type, bwl, reg, err) ({ \
117 type __gu_val; \
118 asm volatile ("\n" \
119 "1: move."#bwl" %2,%1\n" \
120 "2:\n" \
121 " .section .fixup,\"ax\"\n" \
122 " .even\n" \
123 "10: move.l %3,%0\n" \
124 " subl %1,%1\n" \
125 " jra 2b\n" \
126 " .previous\n" \
127 "\n" \
128 " .section __ex_table,\"a\"\n" \
129 " .align 4\n" \
130 " .long 1b,10b\n" \
131 " .previous" \
132 : "+d" (res), "=&" #reg (__gu_val) \
133 : "m" (*(ptr)), "i" (err)); \
134 (x) = (typeof(*(ptr)))(unsigned long)__gu_val; \
135 })
136
137 #define __get_user(x, ptr) \
138 ({ \
139 int __gu_err = 0; \
140 __chk_user_ptr(ptr); \
141 switch (sizeof(*(ptr))) { \
142 case 1: \
143 __get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \
144 break; \
145 case 2: \
146 __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \
147 break; \
148 case 4: \
149 __get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
150 break; \
151 /* case 8: disabled because gcc-4.1 has a broken typeof \
152 { \
153 const void *__gu_ptr = (ptr); \
154 u64 __gu_val; \
155 asm volatile ("\n" \
156 "1: move.l (%2)+,%1\n" \
157 "2: move.l (%2),%R1\n" \
158 "3:\n" \
159 " .section .fixup,\"ax\"\n" \
160 " .even\n" \
161 "10: move.l %3,%0\n" \
162 " subl %1,%1\n" \
163 " subl %R1,%R1\n" \
164 " jra 3b\n" \
165 " .previous\n" \
166 "\n" \
167 " .section __ex_table,\"a\"\n" \
168 " .align 4\n" \
169 " .long 1b,10b\n" \
170 " .long 2b,10b\n" \
171 " .previous" \
172 : "+d" (__gu_err), "=&r" (__gu_val), \
173 "+a" (__gu_ptr) \
174 : "i" (-EFAULT) \
175 : "memory"); \
176 (x) = (typeof(*(ptr)))__gu_val; \
177 break; \
178 } */ \
179 default: \
180 __gu_err = __get_user_bad(); \
181 break; \
182 } \
183 __gu_err; \
184 })
185 #define get_user(x, ptr) __get_user(x, ptr)
186
187 unsigned long __generic_copy_from_user(void *to, const void __user *from,
188 unsigned long n);
189 unsigned long __generic_copy_to_user(void __user *to, const void *from,
190 unsigned long n);
191
192 #define __constant_copy_from_user_asm(res, to, from, tmp, n, s1, s2, s3)\
193 asm volatile ("\n" \
194 "1: move."#s1" (%2)+,%3\n" \
195 " move."#s1" %3,(%1)+\n" \
196 "2: move."#s2" (%2)+,%3\n" \
197 " move."#s2" %3,(%1)+\n" \
198 " .ifnc \""#s3"\",\"\"\n" \
199 "3: move."#s3" (%2)+,%3\n" \
200 " move."#s3" %3,(%1)+\n" \
201 " .endif\n" \
202 "4:\n" \
203 " .section __ex_table,\"a\"\n" \
204 " .align 4\n" \
205 " .long 1b,10f\n" \
206 " .long 2b,20f\n" \
207 " .ifnc \""#s3"\",\"\"\n" \
208 " .long 3b,30f\n" \
209 " .endif\n" \
210 " .previous\n" \
211 "\n" \
212 " .section .fixup,\"ax\"\n" \
213 " .even\n" \
214 "10: clr."#s1" (%1)+\n" \
215 "20: clr."#s2" (%1)+\n" \
216 " .ifnc \""#s3"\",\"\"\n" \
217 "30: clr."#s3" (%1)+\n" \
218 " .endif\n" \
219 " moveq.l #"#n",%0\n" \
220 " jra 4b\n" \
221 " .previous\n" \
222 : "+d" (res), "+&a" (to), "+a" (from), "=&d" (tmp) \
223 : : "memory")
224
225 static __always_inline unsigned long
226 __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
227 {
228 unsigned long res = 0, tmp;
229
230 switch (n) {
231 case 1:
232 __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1);
233 break;
234 case 2:
235 __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w,
236 d, 2);
237 break;
238 case 3:
239 __constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
240 break;
241 case 4:
242 __get_user_asm(res, *(u32 *)to, (u32 __user *)from, u32, l,
243 r, 4);
244 break;
245 case 5:
246 __constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
247 break;
248 case 6:
249 __constant_copy_from_user_asm(res, to, from, tmp, 6, l, w,);
250 break;
251 case 7:
252 __constant_copy_from_user_asm(res, to, from, tmp, 7, l, w, b);
253 break;
254 case 8:
255 __constant_copy_from_user_asm(res, to, from, tmp, 8, l, l,);
256 break;
257 case 9:
258 __constant_copy_from_user_asm(res, to, from, tmp, 9, l, l, b);
259 break;
260 case 10:
261 __constant_copy_from_user_asm(res, to, from, tmp, 10, l, l, w);
262 break;
263 case 12:
264 __constant_copy_from_user_asm(res, to, from, tmp, 12, l, l, l);
265 break;
266 default:
267 /* we limit the inlined version to 3 moves */
268 return __generic_copy_from_user(to, from, n);
269 }
270
271 return res;
272 }
273
274 #define __constant_copy_to_user_asm(res, to, from, tmp, n, s1, s2, s3) \
275 asm volatile ("\n" \
276 " move."#s1" (%2)+,%3\n" \
277 "11: move."#s1" %3,(%1)+\n" \
278 "12: move."#s2" (%2)+,%3\n" \
279 "21: move."#s2" %3,(%1)+\n" \
280 "22:\n" \
281 " .ifnc \""#s3"\",\"\"\n" \
282 " move."#s3" (%2)+,%3\n" \
283 "31: move."#s3" %3,(%1)+\n" \
284 "32:\n" \
285 " .endif\n" \
286 "4:\n" \
287 "\n" \
288 " .section __ex_table,\"a\"\n" \
289 " .align 4\n" \
290 " .long 11b,5f\n" \
291 " .long 12b,5f\n" \
292 " .long 21b,5f\n" \
293 " .long 22b,5f\n" \
294 " .ifnc \""#s3"\",\"\"\n" \
295 " .long 31b,5f\n" \
296 " .long 32b,5f\n" \
297 " .endif\n" \
298 " .previous\n" \
299 "\n" \
300 " .section .fixup,\"ax\"\n" \
301 " .even\n" \
302 "5: moveq.l #"#n",%0\n" \
303 " jra 4b\n" \
304 " .previous\n" \
305 : "+d" (res), "+a" (to), "+a" (from), "=&d" (tmp) \
306 : : "memory")
307
308 static __always_inline unsigned long
309 __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
310 {
311 unsigned long res = 0, tmp;
312
313 switch (n) {
314 case 1:
315 __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
316 break;
317 case 2:
318 __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2);
319 break;
320 case 3:
321 __constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
322 break;
323 case 4:
324 __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
325 break;
326 case 5:
327 __constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
328 break;
329 case 6:
330 __constant_copy_to_user_asm(res, to, from, tmp, 6, l, w,);
331 break;
332 case 7:
333 __constant_copy_to_user_asm(res, to, from, tmp, 7, l, w, b);
334 break;
335 case 8:
336 __constant_copy_to_user_asm(res, to, from, tmp, 8, l, l,);
337 break;
338 case 9:
339 __constant_copy_to_user_asm(res, to, from, tmp, 9, l, l, b);
340 break;
341 case 10:
342 __constant_copy_to_user_asm(res, to, from, tmp, 10, l, l, w);
343 break;
344 case 12:
345 __constant_copy_to_user_asm(res, to, from, tmp, 12, l, l, l);
346 break;
347 default:
348 /* limit the inlined version to 3 moves */
349 return __generic_copy_to_user(to, from, n);
350 }
351
352 return res;
353 }
354
355 #define __copy_from_user(to, from, n) \
356 (__builtin_constant_p(n) ? \
357 __constant_copy_from_user(to, from, n) : \
358 __generic_copy_from_user(to, from, n))
359
360 #define __copy_to_user(to, from, n) \
361 (__builtin_constant_p(n) ? \
362 __constant_copy_to_user(to, from, n) : \
363 __generic_copy_to_user(to, from, n))
364
365 #define __copy_to_user_inatomic __copy_to_user
366 #define __copy_from_user_inatomic __copy_from_user
367
368 #define copy_from_user(to, from, n) __copy_from_user(to, from, n)
369 #define copy_to_user(to, from, n) __copy_to_user(to, from, n)
370
371 long strncpy_from_user(char *dst, const char __user *src, long count);
372 long strnlen_user(const char __user *src, long n);
373 unsigned long __clear_user(void __user *to, unsigned long n);
374
375 #define clear_user __clear_user
376
377 #define strlen_user(str) strnlen_user(str, 32767)
378
379 #endif /* _M68K_CF_UACCESS_H */