diff options
Diffstat (limited to 'include/asm-cris/arch-v10/uaccess.h')
-rw-r--r-- | include/asm-cris/arch-v10/uaccess.h | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/include/asm-cris/arch-v10/uaccess.h b/include/asm-cris/arch-v10/uaccess.h new file mode 100644 index 000000000000..787d2e60c83c --- /dev/null +++ b/include/asm-cris/arch-v10/uaccess.h | |||
@@ -0,0 +1,660 @@ | |||
1 | /* | ||
2 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
3 | * Hans-Peter Nilsson (hp@axis.com) | ||
4 | * | ||
5 | */ | ||
6 | #ifndef _CRIS_ARCH_UACCESS_H | ||
7 | #define _CRIS_ARCH_UACCESS_H | ||
8 | |||
9 | /* | ||
10 | * We don't tell gcc that we are accessing memory, but this is OK | ||
11 | * because we do not write to any memory gcc knows about, so there | ||
12 | * are no aliasing issues. | ||
13 | * | ||
14 | * Note that PC at a fault is the address *after* the faulting | ||
15 | * instruction. | ||
16 | */ | ||
17 | #define __put_user_asm(x, addr, err, op) \ | ||
18 | __asm__ __volatile__( \ | ||
19 | " "op" %1,[%2]\n" \ | ||
20 | "2:\n" \ | ||
21 | " .section .fixup,\"ax\"\n" \ | ||
22 | "3: move.d %3,%0\n" \ | ||
23 | " jump 2b\n" \ | ||
24 | " .previous\n" \ | ||
25 | " .section __ex_table,\"a\"\n" \ | ||
26 | " .dword 2b,3b\n" \ | ||
27 | " .previous\n" \ | ||
28 | : "=r" (err) \ | ||
29 | : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) | ||
30 | |||
31 | #define __put_user_asm_64(x, addr, err) \ | ||
32 | __asm__ __volatile__( \ | ||
33 | " move.d %M1,[%2]\n" \ | ||
34 | "2: move.d %H1,[%2+4]\n" \ | ||
35 | "4:\n" \ | ||
36 | " .section .fixup,\"ax\"\n" \ | ||
37 | "3: move.d %3,%0\n" \ | ||
38 | " jump 4b\n" \ | ||
39 | " .previous\n" \ | ||
40 | " .section __ex_table,\"a\"\n" \ | ||
41 | " .dword 2b,3b\n" \ | ||
42 | " .dword 4b,3b\n" \ | ||
43 | " .previous\n" \ | ||
44 | : "=r" (err) \ | ||
45 | : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) | ||
46 | |||
47 | /* See comment before __put_user_asm. */ | ||
48 | |||
49 | #define __get_user_asm(x, addr, err, op) \ | ||
50 | __asm__ __volatile__( \ | ||
51 | " "op" [%2],%1\n" \ | ||
52 | "2:\n" \ | ||
53 | " .section .fixup,\"ax\"\n" \ | ||
54 | "3: move.d %3,%0\n" \ | ||
55 | " moveq 0,%1\n" \ | ||
56 | " jump 2b\n" \ | ||
57 | " .previous\n" \ | ||
58 | " .section __ex_table,\"a\"\n" \ | ||
59 | " .dword 2b,3b\n" \ | ||
60 | " .previous\n" \ | ||
61 | : "=r" (err), "=r" (x) \ | ||
62 | : "r" (addr), "g" (-EFAULT), "0" (err)) | ||
63 | |||
64 | #define __get_user_asm_64(x, addr, err) \ | ||
65 | __asm__ __volatile__( \ | ||
66 | " move.d [%2],%M1\n" \ | ||
67 | "2: move.d [%2+4],%H1\n" \ | ||
68 | "4:\n" \ | ||
69 | " .section .fixup,\"ax\"\n" \ | ||
70 | "3: move.d %3,%0\n" \ | ||
71 | " moveq 0,%1\n" \ | ||
72 | " jump 4b\n" \ | ||
73 | " .previous\n" \ | ||
74 | " .section __ex_table,\"a\"\n" \ | ||
75 | " .dword 2b,3b\n" \ | ||
76 | " .dword 4b,3b\n" \ | ||
77 | " .previous\n" \ | ||
78 | : "=r" (err), "=r" (x) \ | ||
79 | : "r" (addr), "g" (-EFAULT), "0" (err)) | ||
80 | |||
81 | /* | ||
82 | * Copy a null terminated string from userspace. | ||
83 | * | ||
84 | * Must return: | ||
85 | * -EFAULT for an exception | ||
86 | * count if we hit the buffer limit | ||
87 | * bytes copied if we hit a null byte | ||
88 | * (without the null byte) | ||
89 | */ | ||
90 | extern inline long | ||
91 | __do_strncpy_from_user(char *dst, const char *src, long count) | ||
92 | { | ||
93 | long res; | ||
94 | |||
95 | if (count == 0) | ||
96 | return 0; | ||
97 | |||
98 | /* | ||
99 | * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop. | ||
100 | * So do we. | ||
101 | * | ||
102 | * This code is deduced from: | ||
103 | * | ||
104 | * char tmp2; | ||
105 | * long tmp1, tmp3 | ||
106 | * tmp1 = count; | ||
107 | * while ((*dst++ = (tmp2 = *src++)) != 0 | ||
108 | * && --tmp1) | ||
109 | * ; | ||
110 | * | ||
111 | * res = count - tmp1; | ||
112 | * | ||
113 | * with tweaks. | ||
114 | */ | ||
115 | |||
116 | __asm__ __volatile__ ( | ||
117 | " move.d %3,%0\n" | ||
118 | " move.b [%2+],$r9\n" | ||
119 | "1: beq 2f\n" | ||
120 | " move.b $r9,[%1+]\n" | ||
121 | |||
122 | " subq 1,%0\n" | ||
123 | " bne 1b\n" | ||
124 | " move.b [%2+],$r9\n" | ||
125 | |||
126 | "2: sub.d %3,%0\n" | ||
127 | " neg.d %0,%0\n" | ||
128 | "3:\n" | ||
129 | " .section .fixup,\"ax\"\n" | ||
130 | "4: move.d %7,%0\n" | ||
131 | " jump 3b\n" | ||
132 | |||
133 | /* There's one address for a fault at the first move, and | ||
134 | two possible PC values for a fault at the second move, | ||
135 | being a delay-slot filler. However, the branch-target | ||
136 | for the second move is the same as the first address. | ||
137 | Just so you don't get confused... */ | ||
138 | " .previous\n" | ||
139 | " .section __ex_table,\"a\"\n" | ||
140 | " .dword 1b,4b\n" | ||
141 | " .dword 2b,4b\n" | ||
142 | " .previous" | ||
143 | : "=r" (res), "=r" (dst), "=r" (src), "=r" (count) | ||
144 | : "3" (count), "1" (dst), "2" (src), "g" (-EFAULT) | ||
145 | : "r9"); | ||
146 | |||
147 | return res; | ||
148 | } | ||
149 | |||
150 | /* A few copy asms to build up the more complex ones from. | ||
151 | |||
152 | Note again, a post-increment is performed regardless of whether a bus | ||
153 | fault occurred in that instruction, and PC for a faulted insn is the | ||
154 | address *after* the insn. */ | ||
155 | |||
156 | #define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
157 | __asm__ __volatile__ ( \ | ||
158 | COPY \ | ||
159 | "1:\n" \ | ||
160 | " .section .fixup,\"ax\"\n" \ | ||
161 | FIXUP \ | ||
162 | " jump 1b\n" \ | ||
163 | " .previous\n" \ | ||
164 | " .section __ex_table,\"a\"\n" \ | ||
165 | TENTRY \ | ||
166 | " .previous\n" \ | ||
167 | : "=r" (to), "=r" (from), "=r" (ret) \ | ||
168 | : "0" (to), "1" (from), "2" (ret) \ | ||
169 | : "r9", "memory") | ||
170 | |||
171 | #define __asm_copy_from_user_1(to, from, ret) \ | ||
172 | __asm_copy_user_cont(to, from, ret, \ | ||
173 | " move.b [%1+],$r9\n" \ | ||
174 | "2: move.b $r9,[%0+]\n", \ | ||
175 | "3: addq 1,%2\n" \ | ||
176 | " clear.b [%0+]\n", \ | ||
177 | " .dword 2b,3b\n") | ||
178 | |||
179 | #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
180 | __asm_copy_user_cont(to, from, ret, \ | ||
181 | " move.w [%1+],$r9\n" \ | ||
182 | "2: move.w $r9,[%0+]\n" COPY, \ | ||
183 | "3: addq 2,%2\n" \ | ||
184 | " clear.w [%0+]\n" FIXUP, \ | ||
185 | " .dword 2b,3b\n" TENTRY) | ||
186 | |||
187 | #define __asm_copy_from_user_2(to, from, ret) \ | ||
188 | __asm_copy_from_user_2x_cont(to, from, ret, "", "", "") | ||
189 | |||
190 | #define __asm_copy_from_user_3(to, from, ret) \ | ||
191 | __asm_copy_from_user_2x_cont(to, from, ret, \ | ||
192 | " move.b [%1+],$r9\n" \ | ||
193 | "4: move.b $r9,[%0+]\n", \ | ||
194 | "5: addq 1,%2\n" \ | ||
195 | " clear.b [%0+]\n", \ | ||
196 | " .dword 4b,5b\n") | ||
197 | |||
198 | #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
199 | __asm_copy_user_cont(to, from, ret, \ | ||
200 | " move.d [%1+],$r9\n" \ | ||
201 | "2: move.d $r9,[%0+]\n" COPY, \ | ||
202 | "3: addq 4,%2\n" \ | ||
203 | " clear.d [%0+]\n" FIXUP, \ | ||
204 | " .dword 2b,3b\n" TENTRY) | ||
205 | |||
206 | #define __asm_copy_from_user_4(to, from, ret) \ | ||
207 | __asm_copy_from_user_4x_cont(to, from, ret, "", "", "") | ||
208 | |||
209 | #define __asm_copy_from_user_5(to, from, ret) \ | ||
210 | __asm_copy_from_user_4x_cont(to, from, ret, \ | ||
211 | " move.b [%1+],$r9\n" \ | ||
212 | "4: move.b $r9,[%0+]\n", \ | ||
213 | "5: addq 1,%2\n" \ | ||
214 | " clear.b [%0+]\n", \ | ||
215 | " .dword 4b,5b\n") | ||
216 | |||
217 | #define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
218 | __asm_copy_from_user_4x_cont(to, from, ret, \ | ||
219 | " move.w [%1+],$r9\n" \ | ||
220 | "4: move.w $r9,[%0+]\n" COPY, \ | ||
221 | "5: addq 2,%2\n" \ | ||
222 | " clear.w [%0+]\n" FIXUP, \ | ||
223 | " .dword 4b,5b\n" TENTRY) | ||
224 | |||
225 | #define __asm_copy_from_user_6(to, from, ret) \ | ||
226 | __asm_copy_from_user_6x_cont(to, from, ret, "", "", "") | ||
227 | |||
228 | #define __asm_copy_from_user_7(to, from, ret) \ | ||
229 | __asm_copy_from_user_6x_cont(to, from, ret, \ | ||
230 | " move.b [%1+],$r9\n" \ | ||
231 | "6: move.b $r9,[%0+]\n", \ | ||
232 | "7: addq 1,%2\n" \ | ||
233 | " clear.b [%0+]\n", \ | ||
234 | " .dword 6b,7b\n") | ||
235 | |||
236 | #define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
237 | __asm_copy_from_user_4x_cont(to, from, ret, \ | ||
238 | " move.d [%1+],$r9\n" \ | ||
239 | "4: move.d $r9,[%0+]\n" COPY, \ | ||
240 | "5: addq 4,%2\n" \ | ||
241 | " clear.d [%0+]\n" FIXUP, \ | ||
242 | " .dword 4b,5b\n" TENTRY) | ||
243 | |||
244 | #define __asm_copy_from_user_8(to, from, ret) \ | ||
245 | __asm_copy_from_user_8x_cont(to, from, ret, "", "", "") | ||
246 | |||
247 | #define __asm_copy_from_user_9(to, from, ret) \ | ||
248 | __asm_copy_from_user_8x_cont(to, from, ret, \ | ||
249 | " move.b [%1+],$r9\n" \ | ||
250 | "6: move.b $r9,[%0+]\n", \ | ||
251 | "7: addq 1,%2\n" \ | ||
252 | " clear.b [%0+]\n", \ | ||
253 | " .dword 6b,7b\n") | ||
254 | |||
255 | #define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
256 | __asm_copy_from_user_8x_cont(to, from, ret, \ | ||
257 | " move.w [%1+],$r9\n" \ | ||
258 | "6: move.w $r9,[%0+]\n" COPY, \ | ||
259 | "7: addq 2,%2\n" \ | ||
260 | " clear.w [%0+]\n" FIXUP, \ | ||
261 | " .dword 6b,7b\n" TENTRY) | ||
262 | |||
263 | #define __asm_copy_from_user_10(to, from, ret) \ | ||
264 | __asm_copy_from_user_10x_cont(to, from, ret, "", "", "") | ||
265 | |||
266 | #define __asm_copy_from_user_11(to, from, ret) \ | ||
267 | __asm_copy_from_user_10x_cont(to, from, ret, \ | ||
268 | " move.b [%1+],$r9\n" \ | ||
269 | "8: move.b $r9,[%0+]\n", \ | ||
270 | "9: addq 1,%2\n" \ | ||
271 | " clear.b [%0+]\n", \ | ||
272 | " .dword 8b,9b\n") | ||
273 | |||
274 | #define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
275 | __asm_copy_from_user_8x_cont(to, from, ret, \ | ||
276 | " move.d [%1+],$r9\n" \ | ||
277 | "6: move.d $r9,[%0+]\n" COPY, \ | ||
278 | "7: addq 4,%2\n" \ | ||
279 | " clear.d [%0+]\n" FIXUP, \ | ||
280 | " .dword 6b,7b\n" TENTRY) | ||
281 | |||
282 | #define __asm_copy_from_user_12(to, from, ret) \ | ||
283 | __asm_copy_from_user_12x_cont(to, from, ret, "", "", "") | ||
284 | |||
285 | #define __asm_copy_from_user_13(to, from, ret) \ | ||
286 | __asm_copy_from_user_12x_cont(to, from, ret, \ | ||
287 | " move.b [%1+],$r9\n" \ | ||
288 | "8: move.b $r9,[%0+]\n", \ | ||
289 | "9: addq 1,%2\n" \ | ||
290 | " clear.b [%0+]\n", \ | ||
291 | " .dword 8b,9b\n") | ||
292 | |||
293 | #define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
294 | __asm_copy_from_user_12x_cont(to, from, ret, \ | ||
295 | " move.w [%1+],$r9\n" \ | ||
296 | "8: move.w $r9,[%0+]\n" COPY, \ | ||
297 | "9: addq 2,%2\n" \ | ||
298 | " clear.w [%0+]\n" FIXUP, \ | ||
299 | " .dword 8b,9b\n" TENTRY) | ||
300 | |||
301 | #define __asm_copy_from_user_14(to, from, ret) \ | ||
302 | __asm_copy_from_user_14x_cont(to, from, ret, "", "", "") | ||
303 | |||
304 | #define __asm_copy_from_user_15(to, from, ret) \ | ||
305 | __asm_copy_from_user_14x_cont(to, from, ret, \ | ||
306 | " move.b [%1+],$r9\n" \ | ||
307 | "10: move.b $r9,[%0+]\n", \ | ||
308 | "11: addq 1,%2\n" \ | ||
309 | " clear.b [%0+]\n", \ | ||
310 | " .dword 10b,11b\n") | ||
311 | |||
312 | #define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
313 | __asm_copy_from_user_12x_cont(to, from, ret, \ | ||
314 | " move.d [%1+],$r9\n" \ | ||
315 | "8: move.d $r9,[%0+]\n" COPY, \ | ||
316 | "9: addq 4,%2\n" \ | ||
317 | " clear.d [%0+]\n" FIXUP, \ | ||
318 | " .dword 8b,9b\n" TENTRY) | ||
319 | |||
320 | #define __asm_copy_from_user_16(to, from, ret) \ | ||
321 | __asm_copy_from_user_16x_cont(to, from, ret, "", "", "") | ||
322 | |||
323 | #define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
324 | __asm_copy_from_user_16x_cont(to, from, ret, \ | ||
325 | " move.d [%1+],$r9\n" \ | ||
326 | "10: move.d $r9,[%0+]\n" COPY, \ | ||
327 | "11: addq 4,%2\n" \ | ||
328 | " clear.d [%0+]\n" FIXUP, \ | ||
329 | " .dword 10b,11b\n" TENTRY) | ||
330 | |||
331 | #define __asm_copy_from_user_20(to, from, ret) \ | ||
332 | __asm_copy_from_user_20x_cont(to, from, ret, "", "", "") | ||
333 | |||
334 | #define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
335 | __asm_copy_from_user_20x_cont(to, from, ret, \ | ||
336 | " move.d [%1+],$r9\n" \ | ||
337 | "12: move.d $r9,[%0+]\n" COPY, \ | ||
338 | "13: addq 4,%2\n" \ | ||
339 | " clear.d [%0+]\n" FIXUP, \ | ||
340 | " .dword 12b,13b\n" TENTRY) | ||
341 | |||
342 | #define __asm_copy_from_user_24(to, from, ret) \ | ||
343 | __asm_copy_from_user_24x_cont(to, from, ret, "", "", "") | ||
344 | |||
345 | /* And now, the to-user ones. */ | ||
346 | |||
347 | #define __asm_copy_to_user_1(to, from, ret) \ | ||
348 | __asm_copy_user_cont(to, from, ret, \ | ||
349 | " move.b [%1+],$r9\n" \ | ||
350 | " move.b $r9,[%0+]\n2:\n", \ | ||
351 | "3: addq 1,%2\n", \ | ||
352 | " .dword 2b,3b\n") | ||
353 | |||
354 | #define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
355 | __asm_copy_user_cont(to, from, ret, \ | ||
356 | " move.w [%1+],$r9\n" \ | ||
357 | " move.w $r9,[%0+]\n2:\n" COPY, \ | ||
358 | "3: addq 2,%2\n" FIXUP, \ | ||
359 | " .dword 2b,3b\n" TENTRY) | ||
360 | |||
361 | #define __asm_copy_to_user_2(to, from, ret) \ | ||
362 | __asm_copy_to_user_2x_cont(to, from, ret, "", "", "") | ||
363 | |||
364 | #define __asm_copy_to_user_3(to, from, ret) \ | ||
365 | __asm_copy_to_user_2x_cont(to, from, ret, \ | ||
366 | " move.b [%1+],$r9\n" \ | ||
367 | " move.b $r9,[%0+]\n4:\n", \ | ||
368 | "5: addq 1,%2\n", \ | ||
369 | " .dword 4b,5b\n") | ||
370 | |||
371 | #define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
372 | __asm_copy_user_cont(to, from, ret, \ | ||
373 | " move.d [%1+],$r9\n" \ | ||
374 | " move.d $r9,[%0+]\n2:\n" COPY, \ | ||
375 | "3: addq 4,%2\n" FIXUP, \ | ||
376 | " .dword 2b,3b\n" TENTRY) | ||
377 | |||
378 | #define __asm_copy_to_user_4(to, from, ret) \ | ||
379 | __asm_copy_to_user_4x_cont(to, from, ret, "", "", "") | ||
380 | |||
381 | #define __asm_copy_to_user_5(to, from, ret) \ | ||
382 | __asm_copy_to_user_4x_cont(to, from, ret, \ | ||
383 | " move.b [%1+],$r9\n" \ | ||
384 | " move.b $r9,[%0+]\n4:\n", \ | ||
385 | "5: addq 1,%2\n", \ | ||
386 | " .dword 4b,5b\n") | ||
387 | |||
388 | #define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
389 | __asm_copy_to_user_4x_cont(to, from, ret, \ | ||
390 | " move.w [%1+],$r9\n" \ | ||
391 | " move.w $r9,[%0+]\n4:\n" COPY, \ | ||
392 | "5: addq 2,%2\n" FIXUP, \ | ||
393 | " .dword 4b,5b\n" TENTRY) | ||
394 | |||
395 | #define __asm_copy_to_user_6(to, from, ret) \ | ||
396 | __asm_copy_to_user_6x_cont(to, from, ret, "", "", "") | ||
397 | |||
398 | #define __asm_copy_to_user_7(to, from, ret) \ | ||
399 | __asm_copy_to_user_6x_cont(to, from, ret, \ | ||
400 | " move.b [%1+],$r9\n" \ | ||
401 | " move.b $r9,[%0+]\n6:\n", \ | ||
402 | "7: addq 1,%2\n", \ | ||
403 | " .dword 6b,7b\n") | ||
404 | |||
405 | #define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
406 | __asm_copy_to_user_4x_cont(to, from, ret, \ | ||
407 | " move.d [%1+],$r9\n" \ | ||
408 | " move.d $r9,[%0+]\n4:\n" COPY, \ | ||
409 | "5: addq 4,%2\n" FIXUP, \ | ||
410 | " .dword 4b,5b\n" TENTRY) | ||
411 | |||
412 | #define __asm_copy_to_user_8(to, from, ret) \ | ||
413 | __asm_copy_to_user_8x_cont(to, from, ret, "", "", "") | ||
414 | |||
415 | #define __asm_copy_to_user_9(to, from, ret) \ | ||
416 | __asm_copy_to_user_8x_cont(to, from, ret, \ | ||
417 | " move.b [%1+],$r9\n" \ | ||
418 | " move.b $r9,[%0+]\n6:\n", \ | ||
419 | "7: addq 1,%2\n", \ | ||
420 | " .dword 6b,7b\n") | ||
421 | |||
422 | #define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
423 | __asm_copy_to_user_8x_cont(to, from, ret, \ | ||
424 | " move.w [%1+],$r9\n" \ | ||
425 | " move.w $r9,[%0+]\n6:\n" COPY, \ | ||
426 | "7: addq 2,%2\n" FIXUP, \ | ||
427 | " .dword 6b,7b\n" TENTRY) | ||
428 | |||
429 | #define __asm_copy_to_user_10(to, from, ret) \ | ||
430 | __asm_copy_to_user_10x_cont(to, from, ret, "", "", "") | ||
431 | |||
432 | #define __asm_copy_to_user_11(to, from, ret) \ | ||
433 | __asm_copy_to_user_10x_cont(to, from, ret, \ | ||
434 | " move.b [%1+],$r9\n" \ | ||
435 | " move.b $r9,[%0+]\n8:\n", \ | ||
436 | "9: addq 1,%2\n", \ | ||
437 | " .dword 8b,9b\n") | ||
438 | |||
439 | #define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
440 | __asm_copy_to_user_8x_cont(to, from, ret, \ | ||
441 | " move.d [%1+],$r9\n" \ | ||
442 | " move.d $r9,[%0+]\n6:\n" COPY, \ | ||
443 | "7: addq 4,%2\n" FIXUP, \ | ||
444 | " .dword 6b,7b\n" TENTRY) | ||
445 | |||
446 | #define __asm_copy_to_user_12(to, from, ret) \ | ||
447 | __asm_copy_to_user_12x_cont(to, from, ret, "", "", "") | ||
448 | |||
449 | #define __asm_copy_to_user_13(to, from, ret) \ | ||
450 | __asm_copy_to_user_12x_cont(to, from, ret, \ | ||
451 | " move.b [%1+],$r9\n" \ | ||
452 | " move.b $r9,[%0+]\n8:\n", \ | ||
453 | "9: addq 1,%2\n", \ | ||
454 | " .dword 8b,9b\n") | ||
455 | |||
456 | #define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
457 | __asm_copy_to_user_12x_cont(to, from, ret, \ | ||
458 | " move.w [%1+],$r9\n" \ | ||
459 | " move.w $r9,[%0+]\n8:\n" COPY, \ | ||
460 | "9: addq 2,%2\n" FIXUP, \ | ||
461 | " .dword 8b,9b\n" TENTRY) | ||
462 | |||
463 | #define __asm_copy_to_user_14(to, from, ret) \ | ||
464 | __asm_copy_to_user_14x_cont(to, from, ret, "", "", "") | ||
465 | |||
466 | #define __asm_copy_to_user_15(to, from, ret) \ | ||
467 | __asm_copy_to_user_14x_cont(to, from, ret, \ | ||
468 | " move.b [%1+],$r9\n" \ | ||
469 | " move.b $r9,[%0+]\n10:\n", \ | ||
470 | "11: addq 1,%2\n", \ | ||
471 | " .dword 10b,11b\n") | ||
472 | |||
473 | #define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
474 | __asm_copy_to_user_12x_cont(to, from, ret, \ | ||
475 | " move.d [%1+],$r9\n" \ | ||
476 | " move.d $r9,[%0+]\n8:\n" COPY, \ | ||
477 | "9: addq 4,%2\n" FIXUP, \ | ||
478 | " .dword 8b,9b\n" TENTRY) | ||
479 | |||
480 | #define __asm_copy_to_user_16(to, from, ret) \ | ||
481 | __asm_copy_to_user_16x_cont(to, from, ret, "", "", "") | ||
482 | |||
483 | #define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
484 | __asm_copy_to_user_16x_cont(to, from, ret, \ | ||
485 | " move.d [%1+],$r9\n" \ | ||
486 | " move.d $r9,[%0+]\n10:\n" COPY, \ | ||
487 | "11: addq 4,%2\n" FIXUP, \ | ||
488 | " .dword 10b,11b\n" TENTRY) | ||
489 | |||
490 | #define __asm_copy_to_user_20(to, from, ret) \ | ||
491 | __asm_copy_to_user_20x_cont(to, from, ret, "", "", "") | ||
492 | |||
493 | #define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ | ||
494 | __asm_copy_to_user_20x_cont(to, from, ret, \ | ||
495 | " move.d [%1+],$r9\n" \ | ||
496 | " move.d $r9,[%0+]\n12:\n" COPY, \ | ||
497 | "13: addq 4,%2\n" FIXUP, \ | ||
498 | " .dword 12b,13b\n" TENTRY) | ||
499 | |||
500 | #define __asm_copy_to_user_24(to, from, ret) \ | ||
501 | __asm_copy_to_user_24x_cont(to, from, ret, "", "", "") | ||
502 | |||
503 | /* Define a few clearing asms with exception handlers. */ | ||
504 | |||
505 | /* This frame-asm is like the __asm_copy_user_cont one, but has one less | ||
506 | input. */ | ||
507 | |||
508 | #define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
509 | __asm__ __volatile__ ( \ | ||
510 | CLEAR \ | ||
511 | "1:\n" \ | ||
512 | " .section .fixup,\"ax\"\n" \ | ||
513 | FIXUP \ | ||
514 | " jump 1b\n" \ | ||
515 | " .previous\n" \ | ||
516 | " .section __ex_table,\"a\"\n" \ | ||
517 | TENTRY \ | ||
518 | " .previous" \ | ||
519 | : "=r" (to), "=r" (ret) \ | ||
520 | : "0" (to), "1" (ret) \ | ||
521 | : "memory") | ||
522 | |||
523 | #define __asm_clear_1(to, ret) \ | ||
524 | __asm_clear(to, ret, \ | ||
525 | " clear.b [%0+]\n2:\n", \ | ||
526 | "3: addq 1,%1\n", \ | ||
527 | " .dword 2b,3b\n") | ||
528 | |||
529 | #define __asm_clear_2(to, ret) \ | ||
530 | __asm_clear(to, ret, \ | ||
531 | " clear.w [%0+]\n2:\n", \ | ||
532 | "3: addq 2,%1\n", \ | ||
533 | " .dword 2b,3b\n") | ||
534 | |||
535 | #define __asm_clear_3(to, ret) \ | ||
536 | __asm_clear(to, ret, \ | ||
537 | " clear.w [%0+]\n" \ | ||
538 | "2: clear.b [%0+]\n3:\n", \ | ||
539 | "4: addq 2,%1\n" \ | ||
540 | "5: addq 1,%1\n", \ | ||
541 | " .dword 2b,4b\n" \ | ||
542 | " .dword 3b,5b\n") | ||
543 | |||
544 | #define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
545 | __asm_clear(to, ret, \ | ||
546 | " clear.d [%0+]\n2:\n" CLEAR, \ | ||
547 | "3: addq 4,%1\n" FIXUP, \ | ||
548 | " .dword 2b,3b\n" TENTRY) | ||
549 | |||
550 | #define __asm_clear_4(to, ret) \ | ||
551 | __asm_clear_4x_cont(to, ret, "", "", "") | ||
552 | |||
553 | #define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
554 | __asm_clear_4x_cont(to, ret, \ | ||
555 | " clear.d [%0+]\n4:\n" CLEAR, \ | ||
556 | "5: addq 4,%1\n" FIXUP, \ | ||
557 | " .dword 4b,5b\n" TENTRY) | ||
558 | |||
559 | #define __asm_clear_8(to, ret) \ | ||
560 | __asm_clear_8x_cont(to, ret, "", "", "") | ||
561 | |||
562 | #define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
563 | __asm_clear_8x_cont(to, ret, \ | ||
564 | " clear.d [%0+]\n6:\n" CLEAR, \ | ||
565 | "7: addq 4,%1\n" FIXUP, \ | ||
566 | " .dword 6b,7b\n" TENTRY) | ||
567 | |||
568 | #define __asm_clear_12(to, ret) \ | ||
569 | __asm_clear_12x_cont(to, ret, "", "", "") | ||
570 | |||
571 | #define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
572 | __asm_clear_12x_cont(to, ret, \ | ||
573 | " clear.d [%0+]\n8:\n" CLEAR, \ | ||
574 | "9: addq 4,%1\n" FIXUP, \ | ||
575 | " .dword 8b,9b\n" TENTRY) | ||
576 | |||
577 | #define __asm_clear_16(to, ret) \ | ||
578 | __asm_clear_16x_cont(to, ret, "", "", "") | ||
579 | |||
580 | #define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
581 | __asm_clear_16x_cont(to, ret, \ | ||
582 | " clear.d [%0+]\n10:\n" CLEAR, \ | ||
583 | "11: addq 4,%1\n" FIXUP, \ | ||
584 | " .dword 10b,11b\n" TENTRY) | ||
585 | |||
586 | #define __asm_clear_20(to, ret) \ | ||
587 | __asm_clear_20x_cont(to, ret, "", "", "") | ||
588 | |||
589 | #define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ | ||
590 | __asm_clear_20x_cont(to, ret, \ | ||
591 | " clear.d [%0+]\n12:\n" CLEAR, \ | ||
592 | "13: addq 4,%1\n" FIXUP, \ | ||
593 | " .dword 12b,13b\n" TENTRY) | ||
594 | |||
595 | #define __asm_clear_24(to, ret) \ | ||
596 | __asm_clear_24x_cont(to, ret, "", "", "") | ||
597 | |||
598 | /* | ||
599 | * Return the size of a string (including the ending 0) | ||
600 | * | ||
601 | * Return length of string in userspace including terminating 0 | ||
602 | * or 0 for error. Return a value greater than N if too long. | ||
603 | */ | ||
604 | |||
605 | extern inline long | ||
606 | strnlen_user(const char *s, long n) | ||
607 | { | ||
608 | long res, tmp1; | ||
609 | |||
610 | if (!access_ok(VERIFY_READ, s, 0)) | ||
611 | return 0; | ||
612 | |||
613 | /* | ||
614 | * This code is deduced from: | ||
615 | * | ||
616 | * tmp1 = n; | ||
617 | * while (tmp1-- > 0 && *s++) | ||
618 | * ; | ||
619 | * | ||
620 | * res = n - tmp1; | ||
621 | * | ||
622 | * (with tweaks). | ||
623 | */ | ||
624 | |||
625 | __asm__ __volatile__ ( | ||
626 | " move.d %1,$r9\n" | ||
627 | "0:\n" | ||
628 | " ble 1f\n" | ||
629 | " subq 1,$r9\n" | ||
630 | |||
631 | " test.b [%0+]\n" | ||
632 | " bne 0b\n" | ||
633 | " test.d $r9\n" | ||
634 | "1:\n" | ||
635 | " move.d %1,%0\n" | ||
636 | " sub.d $r9,%0\n" | ||
637 | "2:\n" | ||
638 | " .section .fixup,\"ax\"\n" | ||
639 | |||
640 | "3: clear.d %0\n" | ||
641 | " jump 2b\n" | ||
642 | |||
643 | /* There's one address for a fault at the first move, and | ||
644 | two possible PC values for a fault at the second move, | ||
645 | being a delay-slot filler. However, the branch-target | ||
646 | for the second move is the same as the first address. | ||
647 | Just so you don't get confused... */ | ||
648 | " .previous\n" | ||
649 | " .section __ex_table,\"a\"\n" | ||
650 | " .dword 0b,3b\n" | ||
651 | " .dword 1b,3b\n" | ||
652 | " .previous\n" | ||
653 | : "=r" (res), "=r" (tmp1) | ||
654 | : "0" (s), "1" (n) | ||
655 | : "r9"); | ||
656 | |||
657 | return res; | ||
658 | } | ||
659 | |||
660 | #endif | ||