[PATCH] uml: move libc code out of mem_user.c and tempfile.c
[linux-2.6] / arch / arm26 / lib / uaccess-user.S
1 /*
2  *  linux/arch/arm26/lib/uaccess-user.S
3  *
4  *  Copyright (C) 1995, 1996,1997,1998 Russell King
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  *  Routines to block copy data to/from user memory
11  *   These are highly optimised both for the 4k page size
12  *   and for various alignments.
13  */
14 #include <linux/linkage.h>
15 #include <asm/assembler.h>
16 #include <asm/errno.h>
17 #include <asm/page.h>
18
19                 .text
20
21 //FIXME - surely this can be done in C not asm, removing the problem of keeping C and asm in sync? (this is a struct uaccess_t)
22                 .globl  uaccess_user
23 uaccess_user:
24                 .word   uaccess_user_put_byte
25                 .word   uaccess_user_get_byte
26                 .word   uaccess_user_put_half
27                 .word   uaccess_user_get_half
28                 .word   uaccess_user_put_word
29                 .word   uaccess_user_get_word
30                 .word   uaccess_user_put_dword
31                 .word   uaccess_user_copy_from_user
32                 .word   uaccess_user_copy_to_user
33                 .word   uaccess_user_clear_user
34                 .word   uaccess_user_strncpy_from_user
35                 .word   uaccess_user_strnlen_user
36
37
38 @ In : r0 = x, r1 = addr, r2 = error
39 @ Out: r2 = error
40 uaccess_user_put_byte:
41                 stmfd   sp!, {lr}
42 USER(           strbt   r0, [r1])
43                 ldmfd   sp!, {pc}^
44
45 @ In : r0 = x, r1 = addr, r2 = error
46 @ Out: r2 = error
47 uaccess_user_put_half:
48                 stmfd   sp!, {lr}
49 USER(           strbt   r0, [r1], #1)
50                 mov     r0, r0, lsr #8
51 USER(           strbt   r0, [r1])
52                 ldmfd   sp!, {pc}^
53
54 @ In : r0 = x, r1 = addr, r2 = error
55 @ Out: r2 = error
56 uaccess_user_put_word:
57                 stmfd   sp!, {lr}
58 USER(           strt    r0, [r1])
59                 ldmfd   sp!, {pc}^
60
61 @ In : r0 = x, r1 = addr, r2 = error
62 @ Out: r2 = error
63 uaccess_user_put_dword:
64                 stmfd   sp!, {lr}
65 USER(           strt    r0, [r1], #4)
66 USER(           strt    r0, [r1], #0)
67                 ldmfd   sp!, {pc}^
68
69 9001:           mov     r2, #-EFAULT
70                 ldmfd   sp!, {pc}^
71
72
73 @ In : r0 = addr, r1 = error
74 @ Out: r0 = x, r1 = error
75 uaccess_user_get_byte:
76                 stmfd   sp!, {lr}
77 USER(           ldrbt   r0, [r0])
78                 ldmfd   sp!, {pc}^
79
80 @ In : r0 = addr, r1 = error
81 @ Out: r0 = x, r1 = error
82 uaccess_user_get_half:
83                 stmfd   sp!, {lr}
84 USER(           ldrt    r0, [r0])
85                 mov     r0, r0, lsl #16
86                 mov     r0, r0, lsr #16
87                 ldmfd   sp!, {pc}^
88
89 @ In : r0 = addr, r1 = error
90 @ Out: r0 = x, r1 = error
91 uaccess_user_get_word:
92                 stmfd   sp!, {lr}
93 USER(           ldrt    r0, [r0])
94                 ldmfd   sp!, {pc}^
95
96 9001:           mov     r1, #-EFAULT
97                 ldmfd   sp!, {pc}^
98
99 /* Prototype: int uaccess_user_copy_to_user(void *to, const char *from, size_t n)
100  * Purpose  : copy a block to user memory from kernel memory
101  * Params   : to   - user memory
102  *          : from - kernel memory
103  *          : n    - number of bytes to copy
104  * Returns  : Number of bytes NOT copied.
105  */
106
107 .c2u_dest_not_aligned:
108                 rsb     ip, ip, #4
109                 cmp     ip, #2
110                 ldrb    r3, [r1], #1
111 USER(           strbt   r3, [r0], #1)                   @ May fault
112                 ldrgeb  r3, [r1], #1
113 USER(           strgebt r3, [r0], #1)                   @ May fault
114                 ldrgtb  r3, [r1], #1
115 USER(           strgtbt r3, [r0], #1)                   @ May fault
116                 sub     r2, r2, ip
117                 b       .c2u_dest_aligned
118
119 ENTRY(uaccess_user_copy_to_user)
120                 stmfd   sp!, {r2, r4 - r7, lr}
121                 cmp     r2, #4
122                 blt     .c2u_not_enough
123                 ands    ip, r0, #3
124                 bne     .c2u_dest_not_aligned
125 .c2u_dest_aligned:
126
127                 ands    ip, r1, #3
128                 bne     .c2u_src_not_aligned
129 /*
130  * Seeing as there has to be at least 8 bytes to copy, we can
131  * copy one word, and force a user-mode page fault...
132  */
133
134 .c2u_0fupi:     subs    r2, r2, #4
135                 addmi   ip, r2, #4
136                 bmi     .c2u_0nowords
137                 ldr     r3, [r1], #4
138 USER(           strt    r3, [r0], #4)                   @ May fault
139                 mov     ip, r0, lsl #32 - PAGE_SHIFT    @ On each page, use a ld/st??t instruction
140                 rsb     ip, ip, #0
141                 movs    ip, ip, lsr #32 - PAGE_SHIFT
142                 beq     .c2u_0fupi
143 /*
144  * ip = max no. of bytes to copy before needing another "strt" insn
145  */
146                 cmp     r2, ip
147                 movlt   ip, r2
148                 sub     r2, r2, ip
149                 subs    ip, ip, #32
150                 blt     .c2u_0rem8lp
151
152 .c2u_0cpy8lp:   ldmia   r1!, {r3 - r6}
153                 stmia   r0!, {r3 - r6}                  @ Shouldnt fault
154                 ldmia   r1!, {r3 - r6}
155                 stmia   r0!, {r3 - r6}                  @ Shouldnt fault
156                 subs    ip, ip, #32
157                 bpl     .c2u_0cpy8lp
158 .c2u_0rem8lp:   cmn     ip, #16
159                 ldmgeia r1!, {r3 - r6}
160                 stmgeia r0!, {r3 - r6}                  @ Shouldnt fault
161                 tst     ip, #8
162                 ldmneia r1!, {r3 - r4}
163                 stmneia r0!, {r3 - r4}                  @ Shouldnt fault
164                 tst     ip, #4
165                 ldrne   r3, [r1], #4
166                 strnet  r3, [r0], #4                    @ Shouldnt fault
167                 ands    ip, ip, #3
168                 beq     .c2u_0fupi
169 .c2u_0nowords:  teq     ip, #0
170                 beq     .c2u_finished
171 .c2u_nowords:   cmp     ip, #2
172                 ldrb    r3, [r1], #1
173 USER(           strbt   r3, [r0], #1)                   @ May fault
174                 ldrgeb  r3, [r1], #1
175 USER(           strgebt r3, [r0], #1)                   @ May fault
176                 ldrgtb  r3, [r1], #1
177 USER(           strgtbt r3, [r0], #1)                   @ May fault
178                 b       .c2u_finished
179
180 .c2u_not_enough:
181                 movs    ip, r2
182                 bne     .c2u_nowords
183 .c2u_finished:  mov     r0, #0
184                 LOADREGS(fd,sp!,{r2, r4 - r7, pc})
185
186 .c2u_src_not_aligned:
187                 bic     r1, r1, #3
188                 ldr     r7, [r1], #4
189                 cmp     ip, #2
190                 bgt     .c2u_3fupi
191                 beq     .c2u_2fupi
192 .c2u_1fupi:     subs    r2, r2, #4
193                 addmi   ip, r2, #4
194                 bmi     .c2u_1nowords
195                 mov     r3, r7, pull #8
196                 ldr     r7, [r1], #4
197                 orr     r3, r3, r7, push #24
198 USER(           strt    r3, [r0], #4)                   @ May fault
199                 mov     ip, r0, lsl #32 - PAGE_SHIFT
200                 rsb     ip, ip, #0
201                 movs    ip, ip, lsr #32 - PAGE_SHIFT
202                 beq     .c2u_1fupi
203                 cmp     r2, ip
204                 movlt   ip, r2
205                 sub     r2, r2, ip
206                 subs    ip, ip, #16
207                 blt     .c2u_1rem8lp
208
209 .c2u_1cpy8lp:   mov     r3, r7, pull #8
210                 ldmia   r1!, {r4 - r7}
211                 orr     r3, r3, r4, push #24
212                 mov     r4, r4, pull #8
213                 orr     r4, r4, r5, push #24
214                 mov     r5, r5, pull #8
215                 orr     r5, r5, r6, push #24
216                 mov     r6, r6, pull #8
217                 orr     r6, r6, r7, push #24
218                 stmia   r0!, {r3 - r6}                  @ Shouldnt fault
219                 subs    ip, ip, #16
220                 bpl     .c2u_1cpy8lp
221 .c2u_1rem8lp:   tst     ip, #8
222                 movne   r3, r7, pull #8
223                 ldmneia r1!, {r4, r7}
224                 orrne   r3, r3, r4, push #24
225                 movne   r4, r4, pull #8
226                 orrne   r4, r4, r7, push #24
227                 stmneia r0!, {r3 - r4}                  @ Shouldnt fault
228                 tst     ip, #4
229                 movne   r3, r7, pull #8
230                 ldrne   r7, [r1], #4
231                 orrne   r3, r3, r7, push #24
232                 strnet  r3, [r0], #4                    @ Shouldnt fault
233                 ands    ip, ip, #3
234                 beq     .c2u_1fupi
235 .c2u_1nowords:  mov     r3, r7, lsr #byte(1)
236                 teq     ip, #0
237                 beq     .c2u_finished
238                 cmp     ip, #2
239 USER(           strbt   r3, [r0], #1)                   @ May fault
240                 movge   r3, r7, lsr #byte(2)
241 USER(           strgebt r3, [r0], #1)                   @ May fault
242                 movgt   r3, r7, lsr #byte(3)
243 USER(           strgtbt r3, [r0], #1)                   @ May fault
244                 b       .c2u_finished
245
246 .c2u_2fupi:     subs    r2, r2, #4
247                 addmi   ip, r2, #4
248                 bmi     .c2u_2nowords
249                 mov     r3, r7, pull #16
250                 ldr     r7, [r1], #4
251                 orr     r3, r3, r7, push #16
252 USER(           strt    r3, [r0], #4)                   @ May fault
253                 mov     ip, r0, lsl #32 - PAGE_SHIFT
254                 rsb     ip, ip, #0
255                 movs    ip, ip, lsr #32 - PAGE_SHIFT
256                 beq     .c2u_2fupi
257                 cmp     r2, ip
258                 movlt   ip, r2
259                 sub     r2, r2, ip
260                 subs    ip, ip, #16
261                 blt     .c2u_2rem8lp
262
263 .c2u_2cpy8lp:   mov     r3, r7, pull #16
264                 ldmia   r1!, {r4 - r7}
265                 orr     r3, r3, r4, push #16
266                 mov     r4, r4, pull #16
267                 orr     r4, r4, r5, push #16
268                 mov     r5, r5, pull #16
269                 orr     r5, r5, r6, push #16
270                 mov     r6, r6, pull #16
271                 orr     r6, r6, r7, push #16
272                 stmia   r0!, {r3 - r6}                  @ Shouldnt fault
273                 subs    ip, ip, #16
274                 bpl     .c2u_2cpy8lp
275 .c2u_2rem8lp:   tst     ip, #8
276                 movne   r3, r7, pull #16
277                 ldmneia r1!, {r4, r7}
278                 orrne   r3, r3, r4, push #16
279                 movne   r4, r4, pull #16
280                 orrne   r4, r4, r7, push #16
281                 stmneia r0!, {r3 - r4}                  @ Shouldnt fault
282                 tst     ip, #4
283                 movne   r3, r7, pull #16
284                 ldrne   r7, [r1], #4
285                 orrne   r3, r3, r7, push #16
286                 strnet  r3, [r0], #4                    @ Shouldnt fault
287                 ands    ip, ip, #3
288                 beq     .c2u_2fupi
289 .c2u_2nowords:  mov     r3, r7, lsr #byte(2)
290                 teq     ip, #0
291                 beq     .c2u_finished
292                 cmp     ip, #2
293 USER(           strbt   r3, [r0], #1)                   @ May fault
294                 movge   r3, r7, lsr #byte(3)
295 USER(           strgebt r3, [r0], #1)                   @ May fault
296                 ldrgtb  r3, [r1], #0
297 USER(           strgtbt r3, [r0], #1)                   @ May fault
298                 b       .c2u_finished
299
300 .c2u_3fupi:     subs    r2, r2, #4
301                 addmi   ip, r2, #4
302                 bmi     .c2u_3nowords
303                 mov     r3, r7, pull #24
304                 ldr     r7, [r1], #4
305                 orr     r3, r3, r7, push #8
306 USER(           strt    r3, [r0], #4)                   @ May fault
307                 mov     ip, r0, lsl #32 - PAGE_SHIFT
308                 rsb     ip, ip, #0
309                 movs    ip, ip, lsr #32 - PAGE_SHIFT
310                 beq     .c2u_3fupi
311                 cmp     r2, ip
312                 movlt   ip, r2
313                 sub     r2, r2, ip
314                 subs    ip, ip, #16
315                 blt     .c2u_3rem8lp
316
317 .c2u_3cpy8lp:   mov     r3, r7, pull #24
318                 ldmia   r1!, {r4 - r7}
319                 orr     r3, r3, r4, push #8
320                 mov     r4, r4, pull #24
321                 orr     r4, r4, r5, push #8
322                 mov     r5, r5, pull #24
323                 orr     r5, r5, r6, push #8
324                 mov     r6, r6, pull #24
325                 orr     r6, r6, r7, push #8
326                 stmia   r0!, {r3 - r6}                  @ Shouldnt fault
327                 subs    ip, ip, #16
328                 bpl     .c2u_3cpy8lp
329 .c2u_3rem8lp:   tst     ip, #8
330                 movne   r3, r7, pull #24
331                 ldmneia r1!, {r4, r7}
332                 orrne   r3, r3, r4, push #8
333                 movne   r4, r4, pull #24
334                 orrne   r4, r4, r7, push #8
335                 stmneia r0!, {r3 - r4}                  @ Shouldnt fault
336                 tst     ip, #4
337                 movne   r3, r7, pull #24
338                 ldrne   r7, [r1], #4
339                 orrne   r3, r3, r7, push #8
340                 strnet  r3, [r0], #4                    @ Shouldnt fault
341                 ands    ip, ip, #3
342                 beq     .c2u_3fupi
343 .c2u_3nowords:  mov     r3, r7, lsr #byte(3)
344                 teq     ip, #0
345                 beq     .c2u_finished
346                 cmp     ip, #2
347 USER(           strbt   r3, [r0], #1)                   @ May fault
348                 ldrgeb  r3, [r1], #1
349 USER(           strgebt r3, [r0], #1)                   @ May fault
350                 ldrgtb  r3, [r1], #0
351 USER(           strgtbt r3, [r0], #1)                   @ May fault
352                 b       .c2u_finished
353
354                 .section .fixup,"ax"
355                 .align  0
356 9001:           LOADREGS(fd,sp!, {r0, r4 - r7, pc})
357                 .previous
358
359 /* Prototype: unsigned long uaccess_user_copy_from_user(void *to,const void *from,unsigned long n);
360  * Purpose  : copy a block from user memory to kernel memory
361  * Params   : to   - kernel memory
362  *          : from - user memory
363  *          : n    - number of bytes to copy
364  * Returns  : Number of bytes NOT copied.
365  */
366 .cfu_dest_not_aligned:
367                 rsb     ip, ip, #4
368                 cmp     ip, #2
369 USER(           ldrbt   r3, [r1], #1)                   @ May fault
370                 strb    r3, [r0], #1
371 USER(           ldrgebt r3, [r1], #1)                   @ May fault
372                 strgeb  r3, [r0], #1
373 USER(           ldrgtbt r3, [r1], #1)                   @ May fault
374                 strgtb  r3, [r0], #1
375                 sub     r2, r2, ip
376                 b       .cfu_dest_aligned
377
378 ENTRY(uaccess_user_copy_from_user)
379                 stmfd   sp!, {r0, r2, r4 - r7, lr}
380                 cmp     r2, #4
381                 blt     .cfu_not_enough
382                 ands    ip, r0, #3
383                 bne     .cfu_dest_not_aligned
384 .cfu_dest_aligned:
385                 ands    ip, r1, #3
386                 bne     .cfu_src_not_aligned
387 /*
388  * Seeing as there has to be at least 8 bytes to copy, we can
389  * copy one word, and force a user-mode page fault...
390  */
391
392 .cfu_0fupi:     subs    r2, r2, #4
393                 addmi   ip, r2, #4
394                 bmi     .cfu_0nowords
395 USER(           ldrt    r3, [r1], #4)
396                 str     r3, [r0], #4
397                 mov     ip, r1, lsl #32 - PAGE_SHIFT    @ On each page, use a ld/st??t instruction
398                 rsb     ip, ip, #0
399                 movs    ip, ip, lsr #32 - PAGE_SHIFT
400                 beq     .cfu_0fupi
401 /*
402  * ip = max no. of bytes to copy before needing another "strt" insn
403  */
404                 cmp     r2, ip
405                 movlt   ip, r2
406                 sub     r2, r2, ip
407                 subs    ip, ip, #32
408                 blt     .cfu_0rem8lp
409
410 .cfu_0cpy8lp:   ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
411                 stmia   r0!, {r3 - r6}
412                 ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
413                 stmia   r0!, {r3 - r6}
414                 subs    ip, ip, #32
415                 bpl     .cfu_0cpy8lp
416 .cfu_0rem8lp:   cmn     ip, #16
417                 ldmgeia r1!, {r3 - r6}                  @ Shouldnt fault
418                 stmgeia r0!, {r3 - r6}
419                 tst     ip, #8
420                 ldmneia r1!, {r3 - r4}                  @ Shouldnt fault
421                 stmneia r0!, {r3 - r4}
422                 tst     ip, #4
423                 ldrnet  r3, [r1], #4                    @ Shouldnt fault
424                 strne   r3, [r0], #4
425                 ands    ip, ip, #3
426                 beq     .cfu_0fupi
427 .cfu_0nowords:  teq     ip, #0
428                 beq     .cfu_finished
429 .cfu_nowords:   cmp     ip, #2
430 USER(           ldrbt   r3, [r1], #1)                   @ May fault
431                 strb    r3, [r0], #1
432 USER(           ldrgebt r3, [r1], #1)                   @ May fault
433                 strgeb  r3, [r0], #1
434 USER(           ldrgtbt r3, [r1], #1)                   @ May fault
435                 strgtb  r3, [r0], #1
436                 b       .cfu_finished
437
438 .cfu_not_enough:
439                 movs    ip, r2
440                 bne     .cfu_nowords
441 .cfu_finished:  mov     r0, #0
442                 add     sp, sp, #8
443                 LOADREGS(fd,sp!,{r4 - r7, pc})
444
445 .cfu_src_not_aligned:
446                 bic     r1, r1, #3
447 USER(           ldrt    r7, [r1], #4)                   @ May fault
448                 cmp     ip, #2
449                 bgt     .cfu_3fupi
450                 beq     .cfu_2fupi
451 .cfu_1fupi:     subs    r2, r2, #4
452                 addmi   ip, r2, #4
453                 bmi     .cfu_1nowords
454                 mov     r3, r7, pull #8
455 USER(           ldrt    r7, [r1], #4)                   @ May fault
456                 orr     r3, r3, r7, push #24
457                 str     r3, [r0], #4
458                 mov     ip, r1, lsl #32 - PAGE_SHIFT
459                 rsb     ip, ip, #0
460                 movs    ip, ip, lsr #32 - PAGE_SHIFT
461                 beq     .cfu_1fupi
462                 cmp     r2, ip
463                 movlt   ip, r2
464                 sub     r2, r2, ip
465                 subs    ip, ip, #16
466                 blt     .cfu_1rem8lp
467
468 .cfu_1cpy8lp:   mov     r3, r7, pull #8
469                 ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
470                 orr     r3, r3, r4, push #24
471                 mov     r4, r4, pull #8
472                 orr     r4, r4, r5, push #24
473                 mov     r5, r5, pull #8
474                 orr     r5, r5, r6, push #24
475                 mov     r6, r6, pull #8
476                 orr     r6, r6, r7, push #24
477                 stmia   r0!, {r3 - r6}
478                 subs    ip, ip, #16
479                 bpl     .cfu_1cpy8lp
480 .cfu_1rem8lp:   tst     ip, #8
481                 movne   r3, r7, pull #8
482                 ldmneia r1!, {r4, r7}                   @ Shouldnt fault
483                 orrne   r3, r3, r4, push #24
484                 movne   r4, r4, pull #8
485                 orrne   r4, r4, r7, push #24
486                 stmneia r0!, {r3 - r4}
487                 tst     ip, #4
488                 movne   r3, r7, pull #8
489 USER(           ldrnet  r7, [r1], #4)                   @ May fault
490                 orrne   r3, r3, r7, push #24
491                 strne   r3, [r0], #4
492                 ands    ip, ip, #3
493                 beq     .cfu_1fupi
494 .cfu_1nowords:  mov     r3, r7, lsr #byte(1)
495                 teq     ip, #0
496                 beq     .cfu_finished
497                 cmp     ip, #2
498                 strb    r3, [r0], #1
499                 movge   r3, r7, lsr #byte(2)
500                 strgeb  r3, [r0], #1
501                 movgt   r3, r7, lsr #byte(3)
502                 strgtb  r3, [r0], #1
503                 b       .cfu_finished
504
505 .cfu_2fupi:     subs    r2, r2, #4
506                 addmi   ip, r2, #4
507                 bmi     .cfu_2nowords
508                 mov     r3, r7, pull #16
509 USER(           ldrt    r7, [r1], #4)                   @ May fault
510                 orr     r3, r3, r7, push #16
511                 str     r3, [r0], #4
512                 mov     ip, r1, lsl #32 - PAGE_SHIFT
513                 rsb     ip, ip, #0
514                 movs    ip, ip, lsr #32 - PAGE_SHIFT
515                 beq     .cfu_2fupi
516                 cmp     r2, ip
517                 movlt   ip, r2
518                 sub     r2, r2, ip
519                 subs    ip, ip, #16
520                 blt     .cfu_2rem8lp
521
522 .cfu_2cpy8lp:   mov     r3, r7, pull #16
523                 ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
524                 orr     r3, r3, r4, push #16
525                 mov     r4, r4, pull #16
526                 orr     r4, r4, r5, push #16
527                 mov     r5, r5, pull #16
528                 orr     r5, r5, r6, push #16
529                 mov     r6, r6, pull #16
530                 orr     r6, r6, r7, push #16
531                 stmia   r0!, {r3 - r6}
532                 subs    ip, ip, #16
533                 bpl     .cfu_2cpy8lp
534 .cfu_2rem8lp:   tst     ip, #8
535                 movne   r3, r7, pull #16
536                 ldmneia r1!, {r4, r7}                   @ Shouldnt fault
537                 orrne   r3, r3, r4, push #16
538                 movne   r4, r4, pull #16
539                 orrne   r4, r4, r7, push #16
540                 stmneia r0!, {r3 - r4}
541                 tst     ip, #4
542                 movne   r3, r7, pull #16
543 USER(           ldrnet  r7, [r1], #4)                   @ May fault
544                 orrne   r3, r3, r7, push #16
545                 strne   r3, [r0], #4
546                 ands    ip, ip, #3
547                 beq     .cfu_2fupi
548 .cfu_2nowords:  mov     r3, r7, lsr #byte(2)
549                 teq     ip, #0
550                 beq     .cfu_finished
551                 cmp     ip, #2
552                 strb    r3, [r0], #1
553                 movge   r3, r7, lsr #byte(3)
554                 strgeb  r3, [r0], #1
555 USER(           ldrgtbt r3, [r1], #0)                   @ May fault
556                 strgtb  r3, [r0], #1
557                 b       .cfu_finished
558
559 .cfu_3fupi:     subs    r2, r2, #4
560                 addmi   ip, r2, #4
561                 bmi     .cfu_3nowords
562                 mov     r3, r7, pull #24
563 USER(           ldrt    r7, [r1], #4)                   @ May fault
564                 orr     r3, r3, r7, push #8
565                 str     r3, [r0], #4
566                 mov     ip, r1, lsl #32 - PAGE_SHIFT
567                 rsb     ip, ip, #0
568                 movs    ip, ip, lsr #32 - PAGE_SHIFT
569                 beq     .cfu_3fupi
570                 cmp     r2, ip
571                 movlt   ip, r2
572                 sub     r2, r2, ip
573                 subs    ip, ip, #16
574                 blt     .cfu_3rem8lp
575
576 .cfu_3cpy8lp:   mov     r3, r7, pull #24
577                 ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
578                 orr     r3, r3, r4, push #8
579                 mov     r4, r4, pull #24
580                 orr     r4, r4, r5, push #8
581                 mov     r5, r5, pull #24
582                 orr     r5, r5, r6, push #8
583                 mov     r6, r6, pull #24
584                 orr     r6, r6, r7, push #8
585                 stmia   r0!, {r3 - r6}
586                 subs    ip, ip, #16
587                 bpl     .cfu_3cpy8lp
588 .cfu_3rem8lp:   tst     ip, #8
589                 movne   r3, r7, pull #24
590                 ldmneia r1!, {r4, r7}                   @ Shouldnt fault
591                 orrne   r3, r3, r4, push #8
592                 movne   r4, r4, pull #24
593                 orrne   r4, r4, r7, push #8
594                 stmneia r0!, {r3 - r4}
595                 tst     ip, #4
596                 movne   r3, r7, pull #24
597 USER(           ldrnet  r7, [r1], #4)                   @ May fault
598                 orrne   r3, r3, r7, push #8
599                 strne   r3, [r0], #4
600                 ands    ip, ip, #3
601                 beq     .cfu_3fupi
602 .cfu_3nowords:  mov     r3, r7, lsr #byte(3)
603                 teq     ip, #0
604                 beq     .cfu_finished
605                 cmp     ip, #2
606                 strb    r3, [r0], #1
607 USER(           ldrgebt r3, [r1], #1)                   @ May fault
608                 strgeb  r3, [r0], #1
609 USER(           ldrgtbt r3, [r1], #1)                   @ May fault
610                 strgtb  r3, [r0], #1
611                 b       .cfu_finished
612
613                 .section .fixup,"ax"
614                 .align  0
615                 /*
616                  * We took an exception.  r0 contains a pointer to
617                  * the byte not copied.
618                  */
619 9001:           ldr     r2, [sp], #4                    @ void *to
620                 sub     r2, r0, r2                      @ bytes copied
621                 ldr     r1, [sp], #4                    @ unsigned long count
622                 subs    r4, r1, r2                      @ bytes left to copy
623                 movne   r1, r4
624                 blne    __memzero
625                 mov     r0, r4
626                 LOADREGS(fd,sp!, {r4 - r7, pc})
627                 .previous
628
629 /* Prototype: int uaccess_user_clear_user(void *addr, size_t sz)
630  * Purpose  : clear some user memory
631  * Params   : addr - user memory address to clear
632  *          : sz   - number of bytes to clear
633  * Returns  : number of bytes NOT cleared
634  */
635 ENTRY(uaccess_user_clear_user)
636                 stmfd   sp!, {r1, lr}
637                 mov     r2, #0
638                 cmp     r1, #4
639                 blt     2f
640                 ands    ip, r0, #3
641                 beq     1f
642                 cmp     ip, #2
643 USER(           strbt   r2, [r0], #1)
644 USER(           strlebt r2, [r0], #1)
645 USER(           strltbt r2, [r0], #1)
646                 rsb     ip, ip, #4
647                 sub     r1, r1, ip              @  7  6  5  4  3  2  1
648 1:              subs    r1, r1, #8              @ -1 -2 -3 -4 -5 -6 -7
649 USER(           strplt  r2, [r0], #4)
650 USER(           strplt  r2, [r0], #4)
651                 bpl     1b
652                 adds    r1, r1, #4              @  3  2  1  0 -1 -2 -3
653 USER(           strplt  r2, [r0], #4)
654 2:              tst     r1, #2                  @ 1x 1x 0x 0x 1x 1x 0x
655 USER(           strnebt r2, [r0], #1)
656 USER(           strnebt r2, [r0], #1)
657                 tst     r1, #1                  @ x1 x0 x1 x0 x1 x0 x1
658 USER(           strnebt r2, [r0], #1)
659                 mov     r0, #0
660                 LOADREGS(fd,sp!, {r1, pc})
661
662                 .section .fixup,"ax"
663                 .align  0
664 9001:           LOADREGS(fd,sp!, {r0, pc})
665                 .previous
666
667 /*
668  * Copy a string from user space to kernel space.
669  *  r0 = dst, r1 = src, r2 = byte length
670  * returns the number of characters copied (strlen of copied string),
671  *  -EFAULT on exception, or "len" if we fill the whole buffer
672  */
673 ENTRY(uaccess_user_strncpy_from_user)
674         save_lr
675         mov     ip, r1
676 1:      subs    r2, r2, #1
677 USER(   ldrplbt r3, [r1], #1)
678         bmi     2f
679         strb    r3, [r0], #1
680         teq     r3, #0
681         bne     1b
682         sub     r1, r1, #1      @ take NUL character out of count
683 2:      sub     r0, r1, ip
684         restore_pc
685
686         .section .fixup,"ax"
687         .align  0
688 9001:   mov     r3, #0
689         strb    r3, [r0, #0]    @ null terminate
690         mov     r0, #-EFAULT
691         restore_pc
692         .previous
693
694 /* Prototype: unsigned long uaccess_user_strnlen_user(const char *str, long n)
695  * Purpose  : get length of a string in user memory
696  * Params   : str - address of string in user memory
697  * Returns  : length of string *including terminator*
698  *            or zero on exception, or n + 1 if too long
699  */
700 ENTRY(uaccess_user_strnlen_user)
701         save_lr
702         mov     r2, r0
703 1:
704 USER(   ldrbt   r3, [r0], #1)
705         teq     r3, #0
706         beq     2f
707         subs    r1, r1, #1
708         bne     1b
709         add     r0, r0, #1
710 2:      sub     r0, r0, r2
711         restore_pc
712
713         .section .fixup,"ax"
714         .align  0
715 9001:   mov     r0, #0
716         restore_pc
717         .previous
718