Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / metag / lib / usercopy.c
1 /*
2  * User address space access functions.
3  * The non-inlined parts of asm-metag/uaccess.h are here.
4  *
5  * Copyright (C) 2006, Imagination Technologies.
6  * Copyright (C) 2000, Axis Communications AB.
7  *
8  * Written by Hans-Peter Nilsson.
9  * Pieces used from memcpy, originally by Kenny Ranerup long time ago.
10  * Modified for Meta by Will Newton.
11  */
12
13 #include <linux/export.h>
14 #include <linux/uaccess.h>
15 #include <asm/cache.h>                  /* def of L1_CACHE_BYTES */
16
17 #define USE_RAPF
18 #define RAPF_MIN_BUF_SIZE       (3*L1_CACHE_BYTES)
19
20
21 /* The "double write" in this code is because the Meta will not fault
22  * immediately unless the memory pipe is forced to by e.g. a data stall or
23  * another memory op. The second write should be discarded by the write
24  * combiner so should have virtually no cost.
25  */
26
27 #define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \
28         asm volatile (                                           \
29                 COPY                                             \
30                 "1:\n"                                           \
31                 "       .section .fixup,\"ax\"\n"                \
32                 "       MOV D1Ar1,#0\n"                          \
33                 FIXUP                                            \
34                 "       MOVT    D1Ar1,#HI(1b)\n"                 \
35                 "       JUMP    D1Ar1,#LO(1b)\n"                 \
36                 "       .previous\n"                             \
37                 "       .section __ex_table,\"a\"\n"             \
38                 TENTRY                                           \
39                 "       .previous\n"                             \
40                 : "=r" (to), "=r" (from), "=r" (ret)             \
41                 : "0" (to), "1" (from), "2" (ret)                \
42                 : "D1Ar1", "memory")
43
44
45 #define __asm_copy_to_user_1(to, from, ret)     \
46         __asm_copy_user_cont(to, from, ret,     \
47                 "       GETB D1Ar1,[%1++]\n"    \
48                 "       SETB [%0],D1Ar1\n"      \
49                 "2:     SETB [%0++],D1Ar1\n",   \
50                 "3:     ADD  %2,%2,#1\n",       \
51                 "       .long 2b,3b\n")
52
53 #define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
54         __asm_copy_user_cont(to, from, ret,             \
55                 "       GETW D1Ar1,[%1++]\n"            \
56                 "       SETW [%0],D1Ar1\n"              \
57                 "2:     SETW [%0++],D1Ar1\n" COPY,      \
58                 "3:     ADD  %2,%2,#2\n" FIXUP,         \
59                 "       .long 2b,3b\n" TENTRY)
60
61 #define __asm_copy_to_user_2(to, from, ret) \
62         __asm_copy_to_user_2x_cont(to, from, ret, "", "", "")
63
64 #define __asm_copy_to_user_3(to, from, ret) \
65         __asm_copy_to_user_2x_cont(to, from, ret,       \
66                 "       GETB D1Ar1,[%1++]\n"            \
67                 "       SETB [%0],D1Ar1\n"              \
68                 "4:     SETB [%0++],D1Ar1\n",           \
69                 "5:     ADD  %2,%2,#1\n",               \
70                 "       .long 4b,5b\n")
71
72 #define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
73         __asm_copy_user_cont(to, from, ret,             \
74                 "       GETD D1Ar1,[%1++]\n"            \
75                 "       SETD [%0],D1Ar1\n"              \
76                 "2:     SETD [%0++],D1Ar1\n" COPY,      \
77                 "3:     ADD  %2,%2,#4\n" FIXUP,         \
78                 "       .long 2b,3b\n" TENTRY)
79
80 #define __asm_copy_to_user_4(to, from, ret) \
81         __asm_copy_to_user_4x_cont(to, from, ret, "", "", "")
82
83 #define __asm_copy_to_user_5(to, from, ret) \
84         __asm_copy_to_user_4x_cont(to, from, ret,       \
85                 "       GETB D1Ar1,[%1++]\n"            \
86                 "       SETB [%0],D1Ar1\n"              \
87                 "4:     SETB [%0++],D1Ar1\n",           \
88                 "5:     ADD  %2,%2,#1\n",               \
89                 "       .long 4b,5b\n")
90
91 #define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
92         __asm_copy_to_user_4x_cont(to, from, ret,       \
93                 "       GETW D1Ar1,[%1++]\n"            \
94                 "       SETW [%0],D1Ar1\n"              \
95                 "4:     SETW [%0++],D1Ar1\n" COPY,      \
96                 "5:     ADD  %2,%2,#2\n" FIXUP,         \
97                 "       .long 4b,5b\n" TENTRY)
98
99 #define __asm_copy_to_user_6(to, from, ret) \
100         __asm_copy_to_user_6x_cont(to, from, ret, "", "", "")
101
102 #define __asm_copy_to_user_7(to, from, ret) \
103         __asm_copy_to_user_6x_cont(to, from, ret,       \
104                 "       GETB D1Ar1,[%1++]\n"            \
105                 "       SETB [%0],D1Ar1\n"              \
106                 "6:     SETB [%0++],D1Ar1\n",           \
107                 "7:     ADD  %2,%2,#1\n",               \
108                 "       .long 6b,7b\n")
109
110 #define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
111         __asm_copy_to_user_4x_cont(to, from, ret,       \
112                 "       GETD D1Ar1,[%1++]\n"            \
113                 "       SETD [%0],D1Ar1\n"              \
114                 "4:     SETD [%0++],D1Ar1\n" COPY,      \
115                 "5:     ADD  %2,%2,#4\n"  FIXUP,        \
116                 "       .long 4b,5b\n" TENTRY)
117
118 #define __asm_copy_to_user_8(to, from, ret) \
119         __asm_copy_to_user_8x_cont(to, from, ret, "", "", "")
120
121 #define __asm_copy_to_user_9(to, from, ret) \
122         __asm_copy_to_user_8x_cont(to, from, ret,       \
123                 "       GETB D1Ar1,[%1++]\n"            \
124                 "       SETB [%0],D1Ar1\n"              \
125                 "6:     SETB [%0++],D1Ar1\n",           \
126                 "7:     ADD  %2,%2,#1\n",               \
127                 "       .long 6b,7b\n")
128
129 #define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
130         __asm_copy_to_user_8x_cont(to, from, ret,       \
131                 "       GETW D1Ar1,[%1++]\n"            \
132                 "       SETW [%0],D1Ar1\n"              \
133                 "6:     SETW [%0++],D1Ar1\n" COPY,      \
134                 "7:     ADD  %2,%2,#2\n" FIXUP,         \
135                 "       .long 6b,7b\n" TENTRY)
136
137 #define __asm_copy_to_user_10(to, from, ret) \
138         __asm_copy_to_user_10x_cont(to, from, ret, "", "", "")
139
140 #define __asm_copy_to_user_11(to, from, ret) \
141         __asm_copy_to_user_10x_cont(to, from, ret,      \
142                 "       GETB D1Ar1,[%1++]\n"            \
143                 "       SETB [%0],D1Ar1\n"              \
144                 "8:     SETB [%0++],D1Ar1\n",           \
145                 "9:     ADD  %2,%2,#1\n",               \
146                 "       .long 8b,9b\n")
147
148 #define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
149         __asm_copy_to_user_8x_cont(to, from, ret,       \
150                 "       GETD D1Ar1,[%1++]\n"            \
151                 "       SETD [%0],D1Ar1\n"              \
152                 "6:     SETD [%0++],D1Ar1\n" COPY,      \
153                 "7:     ADD  %2,%2,#4\n" FIXUP,         \
154                 "       .long 6b,7b\n" TENTRY)
155 #define __asm_copy_to_user_12(to, from, ret) \
156         __asm_copy_to_user_12x_cont(to, from, ret, "", "", "")
157
158 #define __asm_copy_to_user_13(to, from, ret) \
159         __asm_copy_to_user_12x_cont(to, from, ret,      \
160                 "       GETB D1Ar1,[%1++]\n"            \
161                 "       SETB [%0],D1Ar1\n"              \
162                 "8:     SETB [%0++],D1Ar1\n",           \
163                 "9:     ADD  %2,%2,#1\n",               \
164                 "       .long 8b,9b\n")
165
166 #define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
167         __asm_copy_to_user_12x_cont(to, from, ret,      \
168                 "       GETW D1Ar1,[%1++]\n"            \
169                 "       SETW [%0],D1Ar1\n"              \
170                 "8:     SETW [%0++],D1Ar1\n" COPY,      \
171                 "9:     ADD  %2,%2,#2\n" FIXUP,         \
172                 "       .long 8b,9b\n" TENTRY)
173
174 #define __asm_copy_to_user_14(to, from, ret) \
175         __asm_copy_to_user_14x_cont(to, from, ret, "", "", "")
176
177 #define __asm_copy_to_user_15(to, from, ret) \
178         __asm_copy_to_user_14x_cont(to, from, ret,      \
179                 "       GETB D1Ar1,[%1++]\n"            \
180                 "       SETB [%0],D1Ar1\n"              \
181                 "10:    SETB [%0++],D1Ar1\n",           \
182                 "11:    ADD  %2,%2,#1\n",               \
183                 "       .long 10b,11b\n")
184
185 #define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
186         __asm_copy_to_user_12x_cont(to, from, ret,      \
187                 "       GETD D1Ar1,[%1++]\n"            \
188                 "       SETD [%0],D1Ar1\n"              \
189                 "8:     SETD [%0++],D1Ar1\n" COPY,      \
190                 "9:     ADD  %2,%2,#4\n" FIXUP,         \
191                 "       .long 8b,9b\n" TENTRY)
192
193 #define __asm_copy_to_user_16(to, from, ret) \
194                 __asm_copy_to_user_16x_cont(to, from, ret, "", "", "")
195
196 #define __asm_copy_to_user_8x64(to, from, ret) \
197         asm volatile (                                  \
198                 "       GETL D0Ar2,D1Ar1,[%1++]\n"      \
199                 "       SETL [%0],D0Ar2,D1Ar1\n"        \
200                 "2:     SETL [%0++],D0Ar2,D1Ar1\n"      \
201                 "1:\n"                                  \
202                 "       .section .fixup,\"ax\"\n"       \
203                 "3:     ADD  %2,%2,#8\n"                \
204                 "       MOVT    D0Ar2,#HI(1b)\n"        \
205                 "       JUMP    D0Ar2,#LO(1b)\n"        \
206                 "       .previous\n"                    \
207                 "       .section __ex_table,\"a\"\n"    \
208                 "       .long 2b,3b\n"                  \
209                 "       .previous\n"                    \
210                 : "=r" (to), "=r" (from), "=r" (ret)    \
211                 : "0" (to), "1" (from), "2" (ret)       \
212                 : "D1Ar1", "D0Ar2", "memory")
213
214 /*
215  *      optimized copying loop using RAPF when 64 bit aligned
216  *
217  *      n               will be automatically decremented inside the loop
218  *      ret             will be left intact. if error occurs we will rewind
219  *                      so that the original non optimized code will fill up
220  *                      this value correctly.
221  *
222  *      on fault:
223  *              >       n will hold total number of uncopied bytes
224  *
225  *              >       {'to','from'} will be rewind back so that
226  *                      the non-optimized code will do the proper fix up
227  *
228  *      DCACHE drops the cacheline which helps in reducing cache
229  *      pollution.
230  *
231  *      We introduce an extra SETL at the end of the loop to
232  *      ensure we don't fall off the loop before we catch all
233  *      erros.
234  *
235  *      NOTICE:
236  *              LSM_STEP in TXSTATUS must be cleared in fix up code.
237  *              since we're using M{S,G}ETL, a fault might happen at
238  *              any address in the middle of M{S,G}ETL causing
239  *              the value of LSM_STEP to be incorrect which can
240  *              cause subsequent use of M{S,G}ET{L,D} to go wrong.
241  *              ie: if LSM_STEP was 1 when a fault occurs, the
242  *              next call to M{S,G}ET{L,D} will skip the first
243  *              copy/getting as it think that the first 1 has already
244  *              been done.
245  *
246  */
247 #define __asm_copy_user_64bit_rapf_loop(                                \
248                 to, from, ret, n, id, FIXUP)                            \
249         asm volatile (                                                  \
250                 ".balign 8\n"                                           \
251                 "MOV    RAPF, %1\n"                                     \
252                 "MSETL  [A0StP++], D0Ar6, D0FrT, D0.5, D0.6, D0.7\n"    \
253                 "MOV    D0Ar6, #0\n"                                    \
254                 "LSR    D1Ar5, %3, #6\n"                                \
255                 "SUB    TXRPT, D1Ar5, #2\n"                             \
256                 "MOV    RAPF, %1\n"                                     \
257                 "$Lloop"id":\n"                                         \
258                 "ADD    RAPF, %1, #64\n"                                \
259                 "21:\n"                                                 \
260                 "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
261                 "22:\n"                                                 \
262                 "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
263                 "SUB    %3, %3, #32\n"                                  \
264                 "23:\n"                                                 \
265                 "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
266                 "24:\n"                                                 \
267                 "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
268                 "SUB    %3, %3, #32\n"                                  \
269                 "DCACHE [%1+#-64], D0Ar6\n"                             \
270                 "BR     $Lloop"id"\n"                                   \
271                                                                         \
272                 "MOV    RAPF, %1\n"                                     \
273                 "25:\n"                                                 \
274                 "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
275                 "26:\n"                                                 \
276                 "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
277                 "SUB    %3, %3, #32\n"                                  \
278                 "27:\n"                                                 \
279                 "MGETL  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
280                 "28:\n"                                                 \
281                 "MSETL  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
282                 "SUB    %0, %0, #8\n"                                   \
283                 "29:\n"                                                 \
284                 "SETL   [%0++], D0.7, D1.7\n"                           \
285                 "SUB    %3, %3, #32\n"                                  \
286                 "1:"                                                    \
287                 "DCACHE [%1+#-64], D0Ar6\n"                             \
288                 "GETL    D0Ar6, D1Ar5, [A0StP+#-40]\n"                  \
289                 "GETL    D0FrT, D1RtP, [A0StP+#-32]\n"                  \
290                 "GETL    D0.5, D1.5, [A0StP+#-24]\n"                    \
291                 "GETL    D0.6, D1.6, [A0StP+#-16]\n"                    \
292                 "GETL    D0.7, D1.7, [A0StP+#-8]\n"                     \
293                 "SUB A0StP, A0StP, #40\n"                               \
294                 "       .section .fixup,\"ax\"\n"                       \
295                 "4:\n"                                                  \
296                 "       ADD     %0, %0, #8\n"                           \
297                 "3:\n"                                                  \
298                 "       MOV     D0Ar2, TXSTATUS\n"                      \
299                 "       MOV     D1Ar1, TXSTATUS\n"                      \
300                 "       AND     D1Ar1, D1Ar1, #0xFFFFF8FF\n"            \
301                 "       MOV     TXSTATUS, D1Ar1\n"                      \
302                         FIXUP                                           \
303                 "       MOVT    D0Ar2,#HI(1b)\n"                        \
304                 "       JUMP    D0Ar2,#LO(1b)\n"                        \
305                 "       .previous\n"                                    \
306                 "       .section __ex_table,\"a\"\n"                    \
307                 "       .long 21b,3b\n"                                 \
308                 "       .long 22b,3b\n"                                 \
309                 "       .long 23b,3b\n"                                 \
310                 "       .long 24b,3b\n"                                 \
311                 "       .long 25b,3b\n"                                 \
312                 "       .long 26b,3b\n"                                 \
313                 "       .long 27b,3b\n"                                 \
314                 "       .long 28b,3b\n"                                 \
315                 "       .long 29b,4b\n"                                 \
316                 "       .previous\n"                                    \
317                 : "=r" (to), "=r" (from), "=r" (ret), "=d" (n)          \
318                 : "0" (to), "1" (from), "2" (ret), "3" (n)              \
319                 : "D1Ar1", "D0Ar2", "memory")
320
321 /*      rewind 'to' and 'from'  pointers when a fault occurs
322  *
323  *      Rationale:
324  *              A fault always occurs on writing to user buffer. A fault
325  *              is at a single address, so we need to rewind by only 4
326  *              bytes.
327  *              Since we do a complete read from kernel buffer before
328  *              writing, we need to rewind it also. The amount to be
329  *              rewind equals the number of faulty writes in MSETD
330  *              which is: [4 - (LSM_STEP-1)]*8
331  *              LSM_STEP is bits 10:8 in TXSTATUS which is already read
332  *              and stored in D0Ar2
333  *
334  *              NOTE: If a fault occurs at the last operation in M{G,S}ETL
335  *                      LSM_STEP will be 0. ie: we do 4 writes in our case, if
336  *                      a fault happens at the 4th write, LSM_STEP will be 0
337  *                      instead of 4. The code copes with that.
338  *
339  *              n is updated by the number of successful writes, which is:
340  *              n = n - (LSM_STEP-1)*8
341  */
342 #define __asm_copy_to_user_64bit_rapf_loop(to,  from, ret, n, id)\
343         __asm_copy_user_64bit_rapf_loop(to, from, ret, n, id,           \
344                 "LSR    D0Ar2, D0Ar2, #8\n"                             \
345                 "AND    D0Ar2, D0Ar2, #0x7\n"                           \
346                 "ADDZ   D0Ar2, D0Ar2, #4\n"                             \
347                 "SUB    D0Ar2, D0Ar2, #1\n"                             \
348                 "MOV    D1Ar1, #4\n"                                    \
349                 "SUB    D0Ar2, D1Ar1, D0Ar2\n"                          \
350                 "LSL    D0Ar2, D0Ar2, #3\n"                             \
351                 "LSL    D1Ar1, D1Ar1, #3\n"                             \
352                 "SUB    D1Ar1, D1Ar1, D0Ar2\n"                          \
353                 "SUB    %0, %0, #8\n"                                   \
354                 "SUB    %1,     %1,D0Ar2\n"                             \
355                 "SUB    %3, %3, D1Ar1\n")
356
357 /*
358  *      optimized copying loop using RAPF when 32 bit aligned
359  *
360  *      n               will be automatically decremented inside the loop
361  *      ret             will be left intact. if error occurs we will rewind
362  *                      so that the original non optimized code will fill up
363  *                      this value correctly.
364  *
365  *      on fault:
366  *              >       n will hold total number of uncopied bytes
367  *
368  *              >       {'to','from'} will be rewind back so that
369  *                      the non-optimized code will do the proper fix up
370  *
371  *      DCACHE drops the cacheline which helps in reducing cache
372  *      pollution.
373  *
374  *      We introduce an extra SETD at the end of the loop to
375  *      ensure we don't fall off the loop before we catch all
376  *      erros.
377  *
378  *      NOTICE:
379  *              LSM_STEP in TXSTATUS must be cleared in fix up code.
380  *              since we're using M{S,G}ETL, a fault might happen at
381  *              any address in the middle of M{S,G}ETL causing
382  *              the value of LSM_STEP to be incorrect which can
383  *              cause subsequent use of M{S,G}ET{L,D} to go wrong.
384  *              ie: if LSM_STEP was 1 when a fault occurs, the
385  *              next call to M{S,G}ET{L,D} will skip the first
386  *              copy/getting as it think that the first 1 has already
387  *              been done.
388  *
389  */
390 #define __asm_copy_user_32bit_rapf_loop(                                \
391                         to,     from, ret, n, id, FIXUP)                \
392         asm volatile (                                                  \
393                 ".balign 8\n"                                           \
394                 "MOV    RAPF, %1\n"                                     \
395                 "MSETL  [A0StP++], D0Ar6, D0FrT, D0.5, D0.6, D0.7\n"    \
396                 "MOV    D0Ar6, #0\n"                                    \
397                 "LSR    D1Ar5, %3, #6\n"                                \
398                 "SUB    TXRPT, D1Ar5, #2\n"                             \
399                 "MOV    RAPF, %1\n"                                     \
400         "$Lloop"id":\n"                                                 \
401                 "ADD    RAPF, %1, #64\n"                                \
402                 "21:\n"                                                 \
403                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
404                 "22:\n"                                                 \
405                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
406                 "SUB    %3, %3, #16\n"                                  \
407                 "23:\n"                                                 \
408                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
409                 "24:\n"                                                 \
410                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
411                 "SUB    %3, %3, #16\n"                                  \
412                 "25:\n"                                                 \
413                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
414                 "26:\n"                                                 \
415                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
416                 "SUB    %3, %3, #16\n"                                  \
417                 "27:\n"                                                 \
418                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
419                 "28:\n"                                                 \
420                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
421                 "SUB    %3, %3, #16\n"                                  \
422                 "DCACHE [%1+#-64], D0Ar6\n"                             \
423                 "BR     $Lloop"id"\n"                                   \
424                                                                         \
425                 "MOV    RAPF, %1\n"                                     \
426                 "29:\n"                                                 \
427                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
428                 "30:\n"                                                 \
429                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
430                 "SUB    %3, %3, #16\n"                                  \
431                 "31:\n"                                                 \
432                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
433                 "32:\n"                                                 \
434                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
435                 "SUB    %3, %3, #16\n"                                  \
436                 "33:\n"                                                 \
437                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
438                 "34:\n"                                                 \
439                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
440                 "SUB    %3, %3, #16\n"                                  \
441                 "35:\n"                                                 \
442                 "MGETD  D0FrT, D0.5, D0.6, D0.7, [%1++]\n"              \
443                 "36:\n"                                                 \
444                 "MSETD  [%0++], D0FrT, D0.5, D0.6, D0.7\n"              \
445                 "SUB    %0, %0, #4\n"                                   \
446                 "37:\n"                                                 \
447                 "SETD   [%0++], D0.7\n"                                 \
448                 "SUB    %3, %3, #16\n"                                  \
449                 "1:"                                                    \
450                 "DCACHE [%1+#-64], D0Ar6\n"                             \
451                 "GETL    D0Ar6, D1Ar5, [A0StP+#-40]\n"                  \
452                 "GETL    D0FrT, D1RtP, [A0StP+#-32]\n"                  \
453                 "GETL    D0.5, D1.5, [A0StP+#-24]\n"                    \
454                 "GETL    D0.6, D1.6, [A0StP+#-16]\n"                    \
455                 "GETL    D0.7, D1.7, [A0StP+#-8]\n"                     \
456                 "SUB A0StP, A0StP, #40\n"                               \
457                 "       .section .fixup,\"ax\"\n"                       \
458                 "4:\n"                                                  \
459                 "       ADD             %0, %0, #4\n"                   \
460                 "3:\n"                                                  \
461                 "       MOV     D0Ar2, TXSTATUS\n"                      \
462                 "       MOV     D1Ar1, TXSTATUS\n"                      \
463                 "       AND     D1Ar1, D1Ar1, #0xFFFFF8FF\n"            \
464                 "       MOV     TXSTATUS, D1Ar1\n"                      \
465                         FIXUP                                           \
466                 "       MOVT    D0Ar2,#HI(1b)\n"                        \
467                 "       JUMP    D0Ar2,#LO(1b)\n"                        \
468                 "       .previous\n"                                    \
469                 "       .section __ex_table,\"a\"\n"                    \
470                 "       .long 21b,3b\n"                                 \
471                 "       .long 22b,3b\n"                                 \
472                 "       .long 23b,3b\n"                                 \
473                 "       .long 24b,3b\n"                                 \
474                 "       .long 25b,3b\n"                                 \
475                 "       .long 26b,3b\n"                                 \
476                 "       .long 27b,3b\n"                                 \
477                 "       .long 28b,3b\n"                                 \
478                 "       .long 29b,3b\n"                                 \
479                 "       .long 30b,3b\n"                                 \
480                 "       .long 31b,3b\n"                                 \
481                 "       .long 32b,3b\n"                                 \
482                 "       .long 33b,3b\n"                                 \
483                 "       .long 34b,3b\n"                                 \
484                 "       .long 35b,3b\n"                                 \
485                 "       .long 36b,3b\n"                                 \
486                 "       .long 37b,4b\n"                                 \
487                 "       .previous\n"                                    \
488                 : "=r" (to), "=r" (from), "=r" (ret), "=d" (n)          \
489                 : "0" (to), "1" (from), "2" (ret), "3" (n)              \
490                 : "D1Ar1", "D0Ar2", "memory")
491
492 /*      rewind 'to' and 'from'  pointers when a fault occurs
493  *
494  *      Rationale:
495  *              A fault always occurs on writing to user buffer. A fault
496  *              is at a single address, so we need to rewind by only 4
497  *              bytes.
498  *              Since we do a complete read from kernel buffer before
499  *              writing, we need to rewind it also. The amount to be
500  *              rewind equals the number of faulty writes in MSETD
501  *              which is: [4 - (LSM_STEP-1)]*4
502  *              LSM_STEP is bits 10:8 in TXSTATUS which is already read
503  *              and stored in D0Ar2
504  *
505  *              NOTE: If a fault occurs at the last operation in M{G,S}ETL
506  *                      LSM_STEP will be 0. ie: we do 4 writes in our case, if
507  *                      a fault happens at the 4th write, LSM_STEP will be 0
508  *                      instead of 4. The code copes with that.
509  *
510  *              n is updated by the number of successful writes, which is:
511  *              n = n - (LSM_STEP-1)*4
512  */
513 #define __asm_copy_to_user_32bit_rapf_loop(to, from, ret, n, id)\
514         __asm_copy_user_32bit_rapf_loop(to, from, ret, n, id,           \
515                 "LSR    D0Ar2, D0Ar2, #8\n"                             \
516                 "AND    D0Ar2, D0Ar2, #0x7\n"                           \
517                 "ADDZ   D0Ar2, D0Ar2, #4\n"                             \
518                 "SUB    D0Ar2, D0Ar2, #1\n"                             \
519                 "MOV    D1Ar1, #4\n"                                    \
520                 "SUB    D0Ar2, D1Ar1, D0Ar2\n"                          \
521                 "LSL    D0Ar2, D0Ar2, #2\n"                             \
522                 "LSL    D1Ar1, D1Ar1, #2\n"                             \
523                 "SUB    D1Ar1, D1Ar1, D0Ar2\n"                          \
524                 "SUB    %0, %0, #4\n"                                   \
525                 "SUB    %1,     %1,     D0Ar2\n"                        \
526                 "SUB    %3, %3, D1Ar1\n")
527
528 unsigned long __copy_user(void __user *pdst, const void *psrc,
529                           unsigned long n)
530 {
531         register char __user *dst asm ("A0.2") = pdst;
532         register const char *src asm ("A1.2") = psrc;
533         unsigned long retn = 0;
534
535         if (n == 0)
536                 return 0;
537
538         if ((unsigned long) src & 1) {
539                 __asm_copy_to_user_1(dst, src, retn);
540                 n--;
541         }
542         if ((unsigned long) dst & 1) {
543                 /* Worst case - byte copy */
544                 while (n > 0) {
545                         __asm_copy_to_user_1(dst, src, retn);
546                         n--;
547                 }
548         }
549         if (((unsigned long) src & 2) && n >= 2) {
550                 __asm_copy_to_user_2(dst, src, retn);
551                 n -= 2;
552         }
553         if ((unsigned long) dst & 2) {
554                 /* Second worst case - word copy */
555                 while (n >= 2) {
556                         __asm_copy_to_user_2(dst, src, retn);
557                         n -= 2;
558                 }
559         }
560
561 #ifdef USE_RAPF
562         /* 64 bit copy loop */
563         if (!(((unsigned long) src | (__force unsigned long) dst) & 7)) {
564                 if (n >= RAPF_MIN_BUF_SIZE) {
565                         /* copy user using 64 bit rapf copy */
566                         __asm_copy_to_user_64bit_rapf_loop(dst, src, retn,
567                                                         n, "64cu");
568                 }
569                 while (n >= 8) {
570                         __asm_copy_to_user_8x64(dst, src, retn);
571                         n -= 8;
572                 }
573         }
574         if (n >= RAPF_MIN_BUF_SIZE) {
575                 /* copy user using 32 bit rapf copy */
576                 __asm_copy_to_user_32bit_rapf_loop(dst, src, retn, n, "32cu");
577         }
578 #else
579         /* 64 bit copy loop */
580         if (!(((unsigned long) src | (__force unsigned long) dst) & 7)) {
581                 while (n >= 8) {
582                         __asm_copy_to_user_8x64(dst, src, retn);
583                         n -= 8;
584                 }
585         }
586 #endif
587
588         while (n >= 16) {
589                 __asm_copy_to_user_16(dst, src, retn);
590                 n -= 16;
591         }
592
593         while (n >= 4) {
594                 __asm_copy_to_user_4(dst, src, retn);
595                 n -= 4;
596         }
597
598         switch (n) {
599         case 0:
600                 break;
601         case 1:
602                 __asm_copy_to_user_1(dst, src, retn);
603                 break;
604         case 2:
605                 __asm_copy_to_user_2(dst, src, retn);
606                 break;
607         case 3:
608                 __asm_copy_to_user_3(dst, src, retn);
609                 break;
610         }
611
612         return retn;
613 }
614 EXPORT_SYMBOL(__copy_user);
615
616 #define __asm_copy_from_user_1(to, from, ret) \
617         __asm_copy_user_cont(to, from, ret,     \
618                 "       GETB D1Ar1,[%1++]\n"    \
619                 "2:     SETB [%0++],D1Ar1\n",   \
620                 "3:     ADD  %2,%2,#1\n"        \
621                 "       SETB [%0++],D1Ar1\n",   \
622                 "       .long 2b,3b\n")
623
624 #define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
625         __asm_copy_user_cont(to, from, ret,             \
626                 "       GETW D1Ar1,[%1++]\n"            \
627                 "2:     SETW [%0++],D1Ar1\n" COPY,      \
628                 "3:     ADD  %2,%2,#2\n"                \
629                 "       SETW [%0++],D1Ar1\n" FIXUP,     \
630                 "       .long 2b,3b\n" TENTRY)
631
632 #define __asm_copy_from_user_2(to, from, ret) \
633         __asm_copy_from_user_2x_cont(to, from, ret, "", "", "")
634
635 #define __asm_copy_from_user_3(to, from, ret)           \
636         __asm_copy_from_user_2x_cont(to, from, ret,     \
637                 "       GETB D1Ar1,[%1++]\n"            \
638                 "4:     SETB [%0++],D1Ar1\n",           \
639                 "5:     ADD  %2,%2,#1\n"                \
640                 "       SETB [%0++],D1Ar1\n",           \
641                 "       .long 4b,5b\n")
642
643 #define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
644         __asm_copy_user_cont(to, from, ret,             \
645                 "       GETD D1Ar1,[%1++]\n"            \
646                 "2:     SETD [%0++],D1Ar1\n" COPY,      \
647                 "3:     ADD  %2,%2,#4\n"                \
648                 "       SETD [%0++],D1Ar1\n" FIXUP,     \
649                 "       .long 2b,3b\n" TENTRY)
650
651 #define __asm_copy_from_user_4(to, from, ret) \
652         __asm_copy_from_user_4x_cont(to, from, ret, "", "", "")
653
654 #define __asm_copy_from_user_5(to, from, ret) \
655         __asm_copy_from_user_4x_cont(to, from, ret,     \
656                 "       GETB D1Ar1,[%1++]\n"            \
657                 "4:     SETB [%0++],D1Ar1\n",           \
658                 "5:     ADD  %2,%2,#1\n"                \
659                 "       SETB [%0++],D1Ar1\n",           \
660                 "       .long 4b,5b\n")
661
662 #define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
663         __asm_copy_from_user_4x_cont(to, from, ret,     \
664                 "       GETW D1Ar1,[%1++]\n"            \
665                 "4:     SETW [%0++],D1Ar1\n" COPY,      \
666                 "5:     ADD  %2,%2,#2\n"                \
667                 "       SETW [%0++],D1Ar1\n" FIXUP,     \
668                 "       .long 4b,5b\n" TENTRY)
669
670 #define __asm_copy_from_user_6(to, from, ret) \
671         __asm_copy_from_user_6x_cont(to, from, ret, "", "", "")
672
673 #define __asm_copy_from_user_7(to, from, ret) \
674         __asm_copy_from_user_6x_cont(to, from, ret,     \
675                 "       GETB D1Ar1,[%1++]\n"            \
676                 "6:     SETB [%0++],D1Ar1\n",           \
677                 "7:     ADD  %2,%2,#1\n"                \
678                 "       SETB [%0++],D1Ar1\n",           \
679                 "       .long 6b,7b\n")
680
681 #define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
682         __asm_copy_from_user_4x_cont(to, from, ret,     \
683                 "       GETD D1Ar1,[%1++]\n"            \
684                 "4:     SETD [%0++],D1Ar1\n" COPY,      \
685                 "5:     ADD  %2,%2,#4\n"                        \
686                 "       SETD [%0++],D1Ar1\n" FIXUP,             \
687                 "       .long 4b,5b\n" TENTRY)
688
689 #define __asm_copy_from_user_8(to, from, ret) \
690         __asm_copy_from_user_8x_cont(to, from, ret, "", "", "")
691
692 #define __asm_copy_from_user_9(to, from, ret) \
693         __asm_copy_from_user_8x_cont(to, from, ret,     \
694                 "       GETB D1Ar1,[%1++]\n"            \
695                 "6:     SETB [%0++],D1Ar1\n",           \
696                 "7:     ADD  %2,%2,#1\n"                \
697                 "       SETB [%0++],D1Ar1\n",           \
698                 "       .long 6b,7b\n")
699
700 #define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
701         __asm_copy_from_user_8x_cont(to, from, ret,     \
702                 "       GETW D1Ar1,[%1++]\n"            \
703                 "6:     SETW [%0++],D1Ar1\n" COPY,      \
704                 "7:     ADD  %2,%2,#2\n"                \
705                 "       SETW [%0++],D1Ar1\n" FIXUP,     \
706                 "       .long 6b,7b\n" TENTRY)
707
708 #define __asm_copy_from_user_10(to, from, ret) \
709         __asm_copy_from_user_10x_cont(to, from, ret, "", "", "")
710
711 #define __asm_copy_from_user_11(to, from, ret)          \
712         __asm_copy_from_user_10x_cont(to, from, ret,    \
713                 "       GETB D1Ar1,[%1++]\n"            \
714                 "8:     SETB [%0++],D1Ar1\n",           \
715                 "9:     ADD  %2,%2,#1\n"                \
716                 "       SETB [%0++],D1Ar1\n",           \
717                 "       .long 8b,9b\n")
718
719 #define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
720         __asm_copy_from_user_8x_cont(to, from, ret,     \
721                 "       GETD D1Ar1,[%1++]\n"            \
722                 "6:     SETD [%0++],D1Ar1\n" COPY,      \
723                 "7:     ADD  %2,%2,#4\n"                \
724                 "       SETD [%0++],D1Ar1\n" FIXUP,     \
725                 "       .long 6b,7b\n" TENTRY)
726
727 #define __asm_copy_from_user_12(to, from, ret) \
728         __asm_copy_from_user_12x_cont(to, from, ret, "", "", "")
729
730 #define __asm_copy_from_user_13(to, from, ret) \
731         __asm_copy_from_user_12x_cont(to, from, ret,    \
732                 "       GETB D1Ar1,[%1++]\n"            \
733                 "8:     SETB [%0++],D1Ar1\n",           \
734                 "9:     ADD  %2,%2,#1\n"                \
735                 "       SETB [%0++],D1Ar1\n",           \
736                 "       .long 8b,9b\n")
737
738 #define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
739         __asm_copy_from_user_12x_cont(to, from, ret,    \
740                 "       GETW D1Ar1,[%1++]\n"            \
741                 "8:     SETW [%0++],D1Ar1\n" COPY,      \
742                 "9:     ADD  %2,%2,#2\n"                \
743                 "       SETW [%0++],D1Ar1\n" FIXUP,     \
744                 "       .long 8b,9b\n" TENTRY)
745
746 #define __asm_copy_from_user_14(to, from, ret) \
747         __asm_copy_from_user_14x_cont(to, from, ret, "", "", "")
748
749 #define __asm_copy_from_user_15(to, from, ret) \
750         __asm_copy_from_user_14x_cont(to, from, ret,    \
751                 "       GETB D1Ar1,[%1++]\n"            \
752                 "10:    SETB [%0++],D1Ar1\n",           \
753                 "11:    ADD  %2,%2,#1\n"                \
754                 "       SETB [%0++],D1Ar1\n",           \
755                 "       .long 10b,11b\n")
756
757 #define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \
758         __asm_copy_from_user_12x_cont(to, from, ret,    \
759                 "       GETD D1Ar1,[%1++]\n"            \
760                 "8:     SETD [%0++],D1Ar1\n" COPY,      \
761                 "9:     ADD  %2,%2,#4\n"                \
762                 "       SETD [%0++],D1Ar1\n" FIXUP,     \
763                 "       .long 8b,9b\n" TENTRY)
764
765 #define __asm_copy_from_user_16(to, from, ret) \
766         __asm_copy_from_user_16x_cont(to, from, ret, "", "", "")
767
768 #define __asm_copy_from_user_8x64(to, from, ret) \
769         asm volatile (                          \
770                 "       GETL D0Ar2,D1Ar1,[%1++]\n"      \
771                 "2:     SETL [%0++],D0Ar2,D1Ar1\n"      \
772                 "1:\n"                                  \
773                 "       .section .fixup,\"ax\"\n"       \
774                 "       MOV D1Ar1,#0\n"                 \
775                 "       MOV D0Ar2,#0\n"                 \
776                 "3:     ADD  %2,%2,#8\n"                \
777                 "       SETL [%0++],D0Ar2,D1Ar1\n"      \
778                 "       MOVT    D0Ar2,#HI(1b)\n"        \
779                 "       JUMP    D0Ar2,#LO(1b)\n"        \
780                 "       .previous\n"                    \
781                 "       .section __ex_table,\"a\"\n"    \
782                 "       .long 2b,3b\n"                  \
783                 "       .previous\n"                    \
784                 : "=a" (to), "=r" (from), "=r" (ret)    \
785                 : "0" (to), "1" (from), "2" (ret)       \
786                 : "D1Ar1", "D0Ar2", "memory")
787
788 /*      rewind 'from' pointer when a fault occurs
789  *
790  *      Rationale:
791  *              A fault occurs while reading from user buffer, which is the
792  *              source. Since the fault is at a single address, we only
793  *              need to rewind by 8 bytes.
794  *              Since we don't write to kernel buffer until we read first,
795  *              the kernel buffer is at the right state and needn't be
796  *              corrected.
797  */
798 #define __asm_copy_from_user_64bit_rapf_loop(to, from, ret, n, id)      \
799         __asm_copy_user_64bit_rapf_loop(to, from, ret, n, id,           \
800                 "SUB    %1, %1, #8\n")
801
802 /*      rewind 'from' pointer when a fault occurs
803  *
804  *      Rationale:
805  *              A fault occurs while reading from user buffer, which is the
806  *              source. Since the fault is at a single address, we only
807  *              need to rewind by 4 bytes.
808  *              Since we don't write to kernel buffer until we read first,
809  *              the kernel buffer is at the right state and needn't be
810  *              corrected.
811  */
812 #define __asm_copy_from_user_32bit_rapf_loop(to, from, ret, n, id)      \
813         __asm_copy_user_32bit_rapf_loop(to, from, ret, n, id,           \
814                 "SUB    %1, %1, #4\n")
815
816
817 /* Copy from user to kernel, zeroing the bytes that were inaccessible in
818    userland.  The return-value is the number of bytes that were
819    inaccessible.  */
820 unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc,
821                                   unsigned long n)
822 {
823         register char *dst asm ("A0.2") = pdst;
824         register const char __user *src asm ("A1.2") = psrc;
825         unsigned long retn = 0;
826
827         if (n == 0)
828                 return 0;
829
830         if ((unsigned long) src & 1) {
831                 __asm_copy_from_user_1(dst, src, retn);
832                 n--;
833         }
834         if ((unsigned long) dst & 1) {
835                 /* Worst case - byte copy */
836                 while (n > 0) {
837                         __asm_copy_from_user_1(dst, src, retn);
838                         n--;
839                         if (retn)
840                                 goto copy_exception_bytes;
841                 }
842         }
843         if (((unsigned long) src & 2) && n >= 2) {
844                 __asm_copy_from_user_2(dst, src, retn);
845                 n -= 2;
846         }
847         if ((unsigned long) dst & 2) {
848                 /* Second worst case - word copy */
849                 while (n >= 2) {
850                         __asm_copy_from_user_2(dst, src, retn);
851                         n -= 2;
852                         if (retn)
853                                 goto copy_exception_bytes;
854                 }
855         }
856
857         /* We only need one check after the unalignment-adjustments,
858            because if both adjustments were done, either both or
859            neither reference had an exception.  */
860         if (retn != 0)
861                 goto copy_exception_bytes;
862
863 #ifdef USE_RAPF
864         /* 64 bit copy loop */
865         if (!(((unsigned long) src | (unsigned long) dst) & 7)) {
866                 if (n >= RAPF_MIN_BUF_SIZE) {
867                         /* Copy using fast 64bit rapf */
868                         __asm_copy_from_user_64bit_rapf_loop(dst, src, retn,
869                                                         n, "64cuz");
870                 }
871                 while (n >= 8) {
872                         __asm_copy_from_user_8x64(dst, src, retn);
873                         n -= 8;
874                         if (retn)
875                                 goto copy_exception_bytes;
876                 }
877         }
878
879         if (n >= RAPF_MIN_BUF_SIZE) {
880                 /* Copy using fast 32bit rapf */
881                 __asm_copy_from_user_32bit_rapf_loop(dst, src, retn,
882                                                 n, "32cuz");
883         }
884 #else
885         /* 64 bit copy loop */
886         if (!(((unsigned long) src | (unsigned long) dst) & 7)) {
887                 while (n >= 8) {
888                         __asm_copy_from_user_8x64(dst, src, retn);
889                         n -= 8;
890                         if (retn)
891                                 goto copy_exception_bytes;
892                 }
893         }
894 #endif
895
896         while (n >= 4) {
897                 __asm_copy_from_user_4(dst, src, retn);
898                 n -= 4;
899
900                 if (retn)
901                         goto copy_exception_bytes;
902         }
903
904         /* If we get here, there were no memory read faults.  */
905         switch (n) {
906                 /* These copies are at least "naturally aligned" (so we don't
907                    have to check each byte), due to the src alignment code.
908                    The *_3 case *will* get the correct count for retn.  */
909         case 0:
910                 /* This case deliberately left in (if you have doubts check the
911                    generated assembly code).  */
912                 break;
913         case 1:
914                 __asm_copy_from_user_1(dst, src, retn);
915                 break;
916         case 2:
917                 __asm_copy_from_user_2(dst, src, retn);
918                 break;
919         case 3:
920                 __asm_copy_from_user_3(dst, src, retn);
921                 break;
922         }
923
924         /* If we get here, retn correctly reflects the number of failing
925            bytes.  */
926         return retn;
927
928  copy_exception_bytes:
929         /* We already have "retn" bytes cleared, and need to clear the
930            remaining "n" bytes.  A non-optimized simple byte-for-byte in-line
931            memset is preferred here, since this isn't speed-critical code and
932            we'd rather have this a leaf-function than calling memset.  */
933         {
934                 char *endp;
935                 for (endp = dst + n; dst < endp; dst++)
936                         *dst = 0;
937         }
938
939         return retn + n;
940 }
941 EXPORT_SYMBOL(__copy_user_zeroing);
942
943 #define __asm_clear_8x64(to, ret) \
944         asm volatile (                                  \
945                 "       MOV  D0Ar2,#0\n"                \
946                 "       MOV  D1Ar1,#0\n"                \
947                 "       SETL [%0],D0Ar2,D1Ar1\n"        \
948                 "2:     SETL [%0++],D0Ar2,D1Ar1\n"      \
949                 "1:\n"                                  \
950                 "       .section .fixup,\"ax\"\n"       \
951                 "3:     ADD  %1,%1,#8\n"                \
952                 "       MOVT    D0Ar2,#HI(1b)\n"        \
953                 "       JUMP    D0Ar2,#LO(1b)\n"        \
954                 "       .previous\n"                    \
955                 "       .section __ex_table,\"a\"\n"    \
956                 "       .long 2b,3b\n"                  \
957                 "       .previous\n"                    \
958                 : "=r" (to), "=r" (ret) \
959                 : "0" (to), "1" (ret)   \
960                 : "D1Ar1", "D0Ar2", "memory")
961
962 /* Zero userspace.  */
963
964 #define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \
965         asm volatile (                                  \
966                 "       MOV D1Ar1,#0\n"                 \
967                         CLEAR                           \
968                 "1:\n"                                  \
969                 "       .section .fixup,\"ax\"\n"       \
970                         FIXUP                           \
971                 "       MOVT    D1Ar1,#HI(1b)\n"        \
972                 "       JUMP    D1Ar1,#LO(1b)\n"        \
973                 "       .previous\n"                    \
974                 "       .section __ex_table,\"a\"\n"    \
975                         TENTRY                          \
976                 "       .previous"                      \
977                 : "=r" (to), "=r" (ret)                 \
978                 : "0" (to), "1" (ret)                   \
979                 : "D1Ar1", "memory")
980
981 #define __asm_clear_1(to, ret) \
982         __asm_clear(to, ret,                    \
983                 "       SETB [%0],D1Ar1\n"      \
984                 "2:     SETB [%0++],D1Ar1\n",   \
985                 "3:     ADD  %1,%1,#1\n",       \
986                 "       .long 2b,3b\n")
987
988 #define __asm_clear_2(to, ret) \
989         __asm_clear(to, ret,                    \
990                 "       SETW [%0],D1Ar1\n"      \
991                 "2:     SETW [%0++],D1Ar1\n",   \
992                 "3:     ADD  %1,%1,#2\n",       \
993                 "       .long 2b,3b\n")
994
995 #define __asm_clear_3(to, ret) \
996         __asm_clear(to, ret,                    \
997                  "2:    SETW [%0++],D1Ar1\n"    \
998                  "      SETB [%0],D1Ar1\n"      \
999                  "3:    SETB [%0++],D1Ar1\n",   \
1000                  "4:    ADD  %1,%1,#2\n"        \
1001                  "5:    ADD  %1,%1,#1\n",       \
1002                  "      .long 2b,4b\n"          \
1003                  "      .long 3b,5b\n")
1004
1005 #define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
1006         __asm_clear(to, ret,                            \
1007                 "       SETD [%0],D1Ar1\n"              \
1008                 "2:     SETD [%0++],D1Ar1\n" CLEAR,     \
1009                 "3:     ADD  %1,%1,#4\n" FIXUP,         \
1010                 "       .long 2b,3b\n" TENTRY)
1011
1012 #define __asm_clear_4(to, ret) \
1013         __asm_clear_4x_cont(to, ret, "", "", "")
1014
1015 #define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
1016         __asm_clear_4x_cont(to, ret,                    \
1017                 "       SETD [%0],D1Ar1\n"              \
1018                 "4:     SETD [%0++],D1Ar1\n" CLEAR,     \
1019                 "5:     ADD  %1,%1,#4\n" FIXUP,         \
1020                 "       .long 4b,5b\n" TENTRY)
1021
1022 #define __asm_clear_8(to, ret) \
1023         __asm_clear_8x_cont(to, ret, "", "", "")
1024
1025 #define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
1026         __asm_clear_8x_cont(to, ret,                    \
1027                 "       SETD [%0],D1Ar1\n"              \
1028                 "6:     SETD [%0++],D1Ar1\n" CLEAR,     \
1029                 "7:     ADD  %1,%1,#4\n" FIXUP,         \
1030                 "       .long 6b,7b\n" TENTRY)
1031
1032 #define __asm_clear_12(to, ret) \
1033         __asm_clear_12x_cont(to, ret, "", "", "")
1034
1035 #define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \
1036         __asm_clear_12x_cont(to, ret,                   \
1037                 "       SETD [%0],D1Ar1\n"              \
1038                 "8:     SETD [%0++],D1Ar1\n" CLEAR,     \
1039                 "9:     ADD  %1,%1,#4\n" FIXUP,         \
1040                 "       .long 8b,9b\n" TENTRY)
1041
1042 #define __asm_clear_16(to, ret) \
1043         __asm_clear_16x_cont(to, ret, "", "", "")
1044
1045 unsigned long __do_clear_user(void __user *pto, unsigned long pn)
1046 {
1047         register char __user *dst asm ("D0Re0") = pto;
1048         register unsigned long n asm ("D1Re0") = pn;
1049         register unsigned long retn asm ("D0Ar6") = 0;
1050
1051         if ((unsigned long) dst & 1) {
1052                 __asm_clear_1(dst, retn);
1053                 n--;
1054         }
1055
1056         if ((unsigned long) dst & 2) {
1057                 __asm_clear_2(dst, retn);
1058                 n -= 2;
1059         }
1060
1061         /* 64 bit copy loop */
1062         if (!((__force unsigned long) dst & 7)) {
1063                 while (n >= 8) {
1064                         __asm_clear_8x64(dst, retn);
1065                         n -= 8;
1066                 }
1067         }
1068
1069         while (n >= 16) {
1070                 __asm_clear_16(dst, retn);
1071                 n -= 16;
1072         }
1073
1074         while (n >= 4) {
1075                 __asm_clear_4(dst, retn);
1076                 n -= 4;
1077         }
1078
1079         switch (n) {
1080         case 0:
1081                 break;
1082         case 1:
1083                 __asm_clear_1(dst, retn);
1084                 break;
1085         case 2:
1086                 __asm_clear_2(dst, retn);
1087                 break;
1088         case 3:
1089                 __asm_clear_3(dst, retn);
1090                 break;
1091         }
1092
1093         return retn;
1094 }
1095 EXPORT_SYMBOL(__do_clear_user);
1096
1097 unsigned char __get_user_asm_b(const void __user *addr, long *err)
1098 {
1099         register unsigned char x asm ("D0Re0") = 0;
1100         asm volatile (
1101                 "       GETB %0,[%2]\n"
1102                 "1:\n"
1103                 "       GETB %0,[%2]\n"
1104                 "2:\n"
1105                 "       .section .fixup,\"ax\"\n"
1106                 "3:     MOV     D0FrT,%3\n"
1107                 "       SETD    [%1],D0FrT\n"
1108                 "       MOVT    D0FrT,#HI(2b)\n"
1109                 "       JUMP    D0FrT,#LO(2b)\n"
1110                 "       .previous\n"
1111                 "       .section __ex_table,\"a\"\n"
1112                 "       .long 1b,3b\n"
1113                 "       .previous\n"
1114                 : "=r" (x)
1115                 : "r" (err), "r" (addr), "P" (-EFAULT)
1116                 : "D0FrT");
1117         return x;
1118 }
1119 EXPORT_SYMBOL(__get_user_asm_b);
1120
1121 unsigned short __get_user_asm_w(const void __user *addr, long *err)
1122 {
1123         register unsigned short x asm ("D0Re0") = 0;
1124         asm volatile (
1125                 "       GETW %0,[%2]\n"
1126                 "1:\n"
1127                 "       GETW %0,[%2]\n"
1128                 "2:\n"
1129                 "       .section .fixup,\"ax\"\n"
1130                 "3:     MOV     D0FrT,%3\n"
1131                 "       SETD    [%1],D0FrT\n"
1132                 "       MOVT    D0FrT,#HI(2b)\n"
1133                 "       JUMP    D0FrT,#LO(2b)\n"
1134                 "       .previous\n"
1135                 "       .section __ex_table,\"a\"\n"
1136                 "       .long 1b,3b\n"
1137                 "       .previous\n"
1138                 : "=r" (x)
1139                 : "r" (err), "r" (addr), "P" (-EFAULT)
1140                 : "D0FrT");
1141         return x;
1142 }
1143 EXPORT_SYMBOL(__get_user_asm_w);
1144
1145 unsigned int __get_user_asm_d(const void __user *addr, long *err)
1146 {
1147         register unsigned int x asm ("D0Re0") = 0;
1148         asm volatile (
1149                 "       GETD %0,[%2]\n"
1150                 "1:\n"
1151                 "       GETD %0,[%2]\n"
1152                 "2:\n"
1153                 "       .section .fixup,\"ax\"\n"
1154                 "3:     MOV     D0FrT,%3\n"
1155                 "       SETD    [%1],D0FrT\n"
1156                 "       MOVT    D0FrT,#HI(2b)\n"
1157                 "       JUMP    D0FrT,#LO(2b)\n"
1158                 "       .previous\n"
1159                 "       .section __ex_table,\"a\"\n"
1160                 "       .long 1b,3b\n"
1161                 "       .previous\n"
1162                 : "=r" (x)
1163                 : "r" (err), "r" (addr), "P" (-EFAULT)
1164                 : "D0FrT");
1165         return x;
1166 }
1167 EXPORT_SYMBOL(__get_user_asm_d);
1168
1169 long __put_user_asm_b(unsigned int x, void __user *addr)
1170 {
1171         register unsigned int err asm ("D0Re0") = 0;
1172         asm volatile (
1173                 "       MOV  %0,#0\n"
1174                 "       SETB [%2],%1\n"
1175                 "1:\n"
1176                 "       SETB [%2],%1\n"
1177                 "2:\n"
1178                 ".section .fixup,\"ax\"\n"
1179                 "3:     MOV     %0,%3\n"
1180                 "       MOVT    D0FrT,#HI(2b)\n"
1181                 "       JUMP    D0FrT,#LO(2b)\n"
1182                 ".previous\n"
1183                 ".section __ex_table,\"a\"\n"
1184                 "       .long 1b,3b\n"
1185                 ".previous"
1186                 : "=r"(err)
1187                 : "d" (x), "a" (addr), "P"(-EFAULT)
1188                 : "D0FrT");
1189         return err;
1190 }
1191 EXPORT_SYMBOL(__put_user_asm_b);
1192
1193 long __put_user_asm_w(unsigned int x, void __user *addr)
1194 {
1195         register unsigned int err asm ("D0Re0") = 0;
1196         asm volatile (
1197                 "       MOV  %0,#0\n"
1198                 "       SETW [%2],%1\n"
1199                 "1:\n"
1200                 "       SETW [%2],%1\n"
1201                 "2:\n"
1202                 ".section .fixup,\"ax\"\n"
1203                 "3:     MOV     %0,%3\n"
1204                 "       MOVT    D0FrT,#HI(2b)\n"
1205                 "       JUMP    D0FrT,#LO(2b)\n"
1206                 ".previous\n"
1207                 ".section __ex_table,\"a\"\n"
1208                 "       .long 1b,3b\n"
1209                 ".previous"
1210                 : "=r"(err)
1211                 : "d" (x), "a" (addr), "P"(-EFAULT)
1212                 : "D0FrT");
1213         return err;
1214 }
1215 EXPORT_SYMBOL(__put_user_asm_w);
1216
1217 long __put_user_asm_d(unsigned int x, void __user *addr)
1218 {
1219         register unsigned int err asm ("D0Re0") = 0;
1220         asm volatile (
1221                 "       MOV  %0,#0\n"
1222                 "       SETD [%2],%1\n"
1223                 "1:\n"
1224                 "       SETD [%2],%1\n"
1225                 "2:\n"
1226                 ".section .fixup,\"ax\"\n"
1227                 "3:     MOV     %0,%3\n"
1228                 "       MOVT    D0FrT,#HI(2b)\n"
1229                 "       JUMP    D0FrT,#LO(2b)\n"
1230                 ".previous\n"
1231                 ".section __ex_table,\"a\"\n"
1232                 "       .long 1b,3b\n"
1233                 ".previous"
1234                 : "=r"(err)
1235                 : "d" (x), "a" (addr), "P"(-EFAULT)
1236                 : "D0FrT");
1237         return err;
1238 }
1239 EXPORT_SYMBOL(__put_user_asm_d);
1240
1241 long __put_user_asm_l(unsigned long long x, void __user *addr)
1242 {
1243         register unsigned int err asm ("D0Re0") = 0;
1244         asm volatile (
1245                 "       MOV  %0,#0\n"
1246                 "       SETL [%2],%1,%t1\n"
1247                 "1:\n"
1248                 "       SETL [%2],%1,%t1\n"
1249                 "2:\n"
1250                 ".section .fixup,\"ax\"\n"
1251                 "3:     MOV     %0,%3\n"
1252                 "       MOVT    D0FrT,#HI(2b)\n"
1253                 "       JUMP    D0FrT,#LO(2b)\n"
1254                 ".previous\n"
1255                 ".section __ex_table,\"a\"\n"
1256                 "       .long 1b,3b\n"
1257                 ".previous"
1258                 : "=r"(err)
1259                 : "d" (x), "a" (addr), "P"(-EFAULT)
1260                 : "D0FrT");
1261         return err;
1262 }
1263 EXPORT_SYMBOL(__put_user_asm_l);
1264
1265 long strnlen_user(const char __user *src, long count)
1266 {
1267         long res;
1268
1269         if (!access_ok(VERIFY_READ, src, 0))
1270                 return 0;
1271
1272         asm volatile (" MOV     D0Ar4, %1\n"
1273                       " MOV     D0Ar6, %2\n"
1274                       "0:\n"
1275                       " SUBS    D0FrT, D0Ar6, #0\n"
1276                       " SUB     D0Ar6, D0Ar6, #1\n"
1277                       " BLE     2f\n"
1278                       " GETB    D0FrT, [D0Ar4+#1++]\n"
1279                       "1:\n"
1280                       " TST     D0FrT, #255\n"
1281                       " BNE     0b\n"
1282                       "2:\n"
1283                       " SUB     %0, %2, D0Ar6\n"
1284                       "3:\n"
1285                       " .section .fixup,\"ax\"\n"
1286                       "4:\n"
1287                       " MOV     %0, #0\n"
1288                       " MOVT    D0FrT,#HI(3b)\n"
1289                       " JUMP    D0FrT,#LO(3b)\n"
1290                       " .previous\n"
1291                       " .section __ex_table,\"a\"\n"
1292                       " .long 1b,4b\n"
1293                       " .previous\n"
1294                       : "=r" (res)
1295                       : "r" (src), "r" (count)
1296                       : "D0FrT", "D0Ar4", "D0Ar6", "cc");
1297
1298         return res;
1299 }
1300 EXPORT_SYMBOL(strnlen_user);
1301
1302 long __strncpy_from_user(char *dst, const char __user *src, long count)
1303 {
1304         long res;
1305
1306         if (count == 0)
1307                 return 0;
1308
1309         /*
1310          * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop.
1311          *  So do we.
1312          *
1313          *  This code is deduced from:
1314          *
1315          *      char tmp2;
1316          *      long tmp1, tmp3;
1317          *      tmp1 = count;
1318          *      while ((*dst++ = (tmp2 = *src++)) != 0
1319          *             && --tmp1)
1320          *        ;
1321          *
1322          *      res = count - tmp1;
1323          *
1324          *  with tweaks.
1325          */
1326
1327         asm volatile (" MOV  %0,%3\n"
1328                       "1:\n"
1329                       " GETB D0FrT,[%2++]\n"
1330                       "2:\n"
1331                       " CMP  D0FrT,#0\n"
1332                       " SETB [%1++],D0FrT\n"
1333                       " BEQ  3f\n"
1334                       " SUBS %0,%0,#1\n"
1335                       " BNZ  1b\n"
1336                       "3:\n"
1337                       " SUB  %0,%3,%0\n"
1338                       "4:\n"
1339                       " .section .fixup,\"ax\"\n"
1340                       "5:\n"
1341                       " MOV  %0,%7\n"
1342                       " MOVT    D0FrT,#HI(4b)\n"
1343                       " JUMP    D0FrT,#LO(4b)\n"
1344                       " .previous\n"
1345                       " .section __ex_table,\"a\"\n"
1346                       " .long 2b,5b\n"
1347                       " .previous"
1348                       : "=r" (res), "=r" (dst), "=r" (src), "=r" (count)
1349                       : "3" (count), "1" (dst), "2" (src), "P" (-EFAULT)
1350                       : "D0FrT", "memory", "cc");
1351
1352         return res;
1353 }
1354 EXPORT_SYMBOL(__strncpy_from_user);