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