2 * linux/arch/arm/lib/uaccess.S
4 * Copyright (C) 1995, 1996,1997,1998 Russell King
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.
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.
14 #include <linux/linkage.h>
15 #include <asm/assembler.h>
16 #include <asm/errno.h>
22 /* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n)
23 * Purpose : copy a block to user memory from kernel memory
24 * Params : to - user memory
25 * : from - kernel memory
26 * : n - number of bytes to copy
27 * Returns : Number of bytes NOT copied.
30 .c2u_dest_not_aligned:
34 USER( strbt r3, [r0], #1) @ May fault
36 USER( strgebt r3, [r0], #1) @ May fault
38 USER( strgtbt r3, [r0], #1) @ May fault
42 ENTRY(__arch_copy_to_user)
43 stmfd sp!, {r2, r4 - r7, lr}
49 bne .c2u_dest_not_aligned
53 bne .c2u_src_not_aligned
55 * Seeing as there has to be at least 8 bytes to copy, we can
56 * copy one word, and force a user-mode page fault...
59 .c2u_0fupi: subs r2, r2, #4
63 USER( strt r3, [r0], #4) @ May fault
64 mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
66 movs ip, ip, lsr #32 - PAGE_SHIFT
69 * ip = max no. of bytes to copy before needing another "strt" insn
78 PLD( subs ip, ip, #64 )
79 PLD( blt .c2u_0cpynopld )
86 .c2u_0cpynopld: ldmia r1!, {r3 - r6}
87 stmia r0!, {r3 - r6} @ Shouldnt fault
90 stmia r0!, {r3 - r6} @ Shouldnt fault
93 PLD( bge .c2u_0cpynopld )
94 PLD( add ip, ip, #64 )
96 .c2u_0rem8lp: cmn ip, #16
97 ldmgeia r1!, {r3 - r6}
98 stmgeia r0!, {r3 - r6} @ Shouldnt fault
100 ldmneia r1!, {r3 - r4}
101 stmneia r0!, {r3 - r4} @ Shouldnt fault
104 strnet r3, [r0], #4 @ Shouldnt fault
107 .c2u_0nowords: teq ip, #0
109 .c2u_nowords: cmp ip, #2
111 USER( strbt r3, [r0], #1) @ May fault
113 USER( strgebt r3, [r0], #1) @ May fault
115 USER( strgtbt r3, [r0], #1) @ May fault
121 .c2u_finished: mov r0, #0
122 LOADREGS(fd,sp!,{r2, r4 - r7, pc})
124 .c2u_src_not_aligned:
130 .c2u_1fupi: subs r2, r2, #4
135 orr r3, r3, r7, push #24
136 USER( strt r3, [r0], #4) @ May fault
137 mov ip, r0, lsl #32 - PAGE_SHIFT
139 movs ip, ip, lsr #32 - PAGE_SHIFT
148 PLD( subs ip, ip, #32 )
149 PLD( blt .c2u_1cpynopld )
156 .c2u_1cpynopld: mov r3, r7, pull #8
159 orr r3, r3, r4, push #24
161 orr r4, r4, r5, push #24
163 orr r5, r5, r6, push #24
165 orr r6, r6, r7, push #24
166 stmia r0!, {r3 - r6} @ Shouldnt fault
169 PLD( bge .c2u_1cpynopld )
170 PLD( add ip, ip, #32 )
172 .c2u_1rem8lp: tst ip, #8
173 movne r3, r7, pull #8
174 ldmneia r1!, {r4, r7}
175 orrne r3, r3, r4, push #24
176 movne r4, r4, pull #8
177 orrne r4, r4, r7, push #24
178 stmneia r0!, {r3 - r4} @ Shouldnt fault
180 movne r3, r7, pull #8
182 orrne r3, r3, r7, push #24
183 strnet r3, [r0], #4 @ Shouldnt fault
186 .c2u_1nowords: mov r3, r7, get_byte_1
190 USER( strbt r3, [r0], #1) @ May fault
191 movge r3, r7, get_byte_2
192 USER( strgebt r3, [r0], #1) @ May fault
193 movgt r3, r7, get_byte_3
194 USER( strgtbt r3, [r0], #1) @ May fault
197 .c2u_2fupi: subs r2, r2, #4
202 orr r3, r3, r7, push #16
203 USER( strt r3, [r0], #4) @ May fault
204 mov ip, r0, lsl #32 - PAGE_SHIFT
206 movs ip, ip, lsr #32 - PAGE_SHIFT
215 PLD( subs ip, ip, #32 )
216 PLD( blt .c2u_2cpynopld )
223 .c2u_2cpynopld: mov r3, r7, pull #16
226 orr r3, r3, r4, push #16
228 orr r4, r4, r5, push #16
230 orr r5, r5, r6, push #16
232 orr r6, r6, r7, push #16
233 stmia r0!, {r3 - r6} @ Shouldnt fault
236 PLD( bge .c2u_2cpynopld )
237 PLD( add ip, ip, #32 )
239 .c2u_2rem8lp: tst ip, #8
240 movne r3, r7, pull #16
241 ldmneia r1!, {r4, r7}
242 orrne r3, r3, r4, push #16
243 movne r4, r4, pull #16
244 orrne r4, r4, r7, push #16
245 stmneia r0!, {r3 - r4} @ Shouldnt fault
247 movne r3, r7, pull #16
249 orrne r3, r3, r7, push #16
250 strnet r3, [r0], #4 @ Shouldnt fault
253 .c2u_2nowords: mov r3, r7, get_byte_2
257 USER( strbt r3, [r0], #1) @ May fault
258 movge r3, r7, get_byte_3
259 USER( strgebt r3, [r0], #1) @ May fault
261 USER( strgtbt r3, [r0], #1) @ May fault
264 .c2u_3fupi: subs r2, r2, #4
269 orr r3, r3, r7, push #8
270 USER( strt r3, [r0], #4) @ May fault
271 mov ip, r0, lsl #32 - PAGE_SHIFT
273 movs ip, ip, lsr #32 - PAGE_SHIFT
282 PLD( subs ip, ip, #32 )
283 PLD( blt .c2u_3cpynopld )
290 .c2u_3cpynopld: mov r3, r7, pull #24
293 orr r3, r3, r4, push #8
295 orr r4, r4, r5, push #8
297 orr r5, r5, r6, push #8
299 orr r6, r6, r7, push #8
300 stmia r0!, {r3 - r6} @ Shouldnt fault
303 PLD( bge .c2u_3cpynopld )
304 PLD( add ip, ip, #32 )
306 .c2u_3rem8lp: tst ip, #8
307 movne r3, r7, pull #24
308 ldmneia r1!, {r4, r7}
309 orrne r3, r3, r4, push #8
310 movne r4, r4, pull #24
311 orrne r4, r4, r7, push #8
312 stmneia r0!, {r3 - r4} @ Shouldnt fault
314 movne r3, r7, pull #24
316 orrne r3, r3, r7, push #8
317 strnet r3, [r0], #4 @ Shouldnt fault
320 .c2u_3nowords: mov r3, r7, get_byte_3
324 USER( strbt r3, [r0], #1) @ May fault
326 USER( strgebt r3, [r0], #1) @ May fault
328 USER( strgtbt r3, [r0], #1) @ May fault
333 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc})
336 /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
337 * Purpose : copy a block from user memory to kernel memory
338 * Params : to - kernel memory
339 * : from - user memory
340 * : n - number of bytes to copy
341 * Returns : Number of bytes NOT copied.
343 .cfu_dest_not_aligned:
346 USER( ldrbt r3, [r1], #1) @ May fault
348 USER( ldrgebt r3, [r1], #1) @ May fault
350 USER( ldrgtbt r3, [r1], #1) @ May fault
355 ENTRY(__arch_copy_from_user)
356 stmfd sp!, {r0, r2, r4 - r7, lr}
362 bne .cfu_dest_not_aligned
365 bne .cfu_src_not_aligned
367 * Seeing as there has to be at least 8 bytes to copy, we can
368 * copy one word, and force a user-mode page fault...
371 .cfu_0fupi: subs r2, r2, #4
374 USER( ldrt r3, [r1], #4)
376 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
378 movs ip, ip, lsr #32 - PAGE_SHIFT
381 * ip = max no. of bytes to copy before needing another "strt" insn
390 PLD( subs ip, ip, #64 )
391 PLD( blt .cfu_0cpynopld )
398 .cfu_0cpynopld: ldmia r1!, {r3 - r6} @ Shouldnt fault
400 ldmia r1!, {r3 - r6} @ Shouldnt fault
405 PLD( bge .cfu_0cpynopld )
406 PLD( add ip, ip, #64 )
408 .cfu_0rem8lp: cmn ip, #16
409 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
410 stmgeia r0!, {r3 - r6}
412 ldmneia r1!, {r3 - r4} @ Shouldnt fault
413 stmneia r0!, {r3 - r4}
415 ldrnet r3, [r1], #4 @ Shouldnt fault
419 .cfu_0nowords: teq ip, #0
421 .cfu_nowords: cmp ip, #2
422 USER( ldrbt r3, [r1], #1) @ May fault
424 USER( ldrgebt r3, [r1], #1) @ May fault
426 USER( ldrgtbt r3, [r1], #1) @ May fault
433 .cfu_finished: mov r0, #0
435 LOADREGS(fd,sp!,{r4 - r7, pc})
437 .cfu_src_not_aligned:
439 USER( ldrt r7, [r1], #4) @ May fault
443 .cfu_1fupi: subs r2, r2, #4
447 USER( ldrt r7, [r1], #4) @ May fault
448 orr r3, r3, r7, push #24
450 mov ip, r1, lsl #32 - PAGE_SHIFT
452 movs ip, ip, lsr #32 - PAGE_SHIFT
461 PLD( subs ip, ip, #32 )
462 PLD( blt .cfu_1cpynopld )
469 .cfu_1cpynopld: mov r3, r7, pull #8
470 ldmia r1!, {r4 - r7} @ Shouldnt fault
472 orr r3, r3, r4, push #24
474 orr r4, r4, r5, push #24
476 orr r5, r5, r6, push #24
478 orr r6, r6, r7, push #24
482 PLD( bge .cfu_1cpynopld )
483 PLD( add ip, ip, #32 )
485 .cfu_1rem8lp: tst ip, #8
486 movne r3, r7, pull #8
487 ldmneia r1!, {r4, r7} @ Shouldnt fault
488 orrne r3, r3, r4, push #24
489 movne r4, r4, pull #8
490 orrne r4, r4, r7, push #24
491 stmneia r0!, {r3 - r4}
493 movne r3, r7, pull #8
494 USER( ldrnet r7, [r1], #4) @ May fault
495 orrne r3, r3, r7, push #24
499 .cfu_1nowords: mov r3, r7, get_byte_1
504 movge r3, r7, get_byte_2
506 movgt r3, r7, get_byte_3
510 .cfu_2fupi: subs r2, r2, #4
514 USER( ldrt r7, [r1], #4) @ May fault
515 orr r3, r3, r7, push #16
517 mov ip, r1, lsl #32 - PAGE_SHIFT
519 movs ip, ip, lsr #32 - PAGE_SHIFT
528 PLD( subs ip, ip, #32 )
529 PLD( blt .cfu_2cpynopld )
536 .cfu_2cpynopld: mov r3, r7, pull #16
537 ldmia r1!, {r4 - r7} @ Shouldnt fault
539 orr r3, r3, r4, push #16
541 orr r4, r4, r5, push #16
543 orr r5, r5, r6, push #16
545 orr r6, r6, r7, push #16
549 PLD( bge .cfu_2cpynopld )
550 PLD( add ip, ip, #32 )
552 .cfu_2rem8lp: tst ip, #8
553 movne r3, r7, pull #16
554 ldmneia r1!, {r4, r7} @ Shouldnt fault
555 orrne r3, r3, r4, push #16
556 movne r4, r4, pull #16
557 orrne r4, r4, r7, push #16
558 stmneia r0!, {r3 - r4}
560 movne r3, r7, pull #16
561 USER( ldrnet r7, [r1], #4) @ May fault
562 orrne r3, r3, r7, push #16
566 .cfu_2nowords: mov r3, r7, get_byte_2
571 movge r3, r7, get_byte_3
573 USER( ldrgtbt r3, [r1], #0) @ May fault
577 .cfu_3fupi: subs r2, r2, #4
581 USER( ldrt r7, [r1], #4) @ May fault
582 orr r3, r3, r7, push #8
584 mov ip, r1, lsl #32 - PAGE_SHIFT
586 movs ip, ip, lsr #32 - PAGE_SHIFT
595 PLD( subs ip, ip, #32 )
596 PLD( blt .cfu_3cpynopld )
603 .cfu_3cpynopld: mov r3, r7, pull #24
604 ldmia r1!, {r4 - r7} @ Shouldnt fault
605 orr r3, r3, r4, push #8
607 orr r4, r4, r5, push #8
609 orr r5, r5, r6, push #8
611 orr r6, r6, r7, push #8
616 PLD( bge .cfu_3cpynopld )
617 PLD( add ip, ip, #32 )
619 .cfu_3rem8lp: tst ip, #8
620 movne r3, r7, pull #24
621 ldmneia r1!, {r4, r7} @ Shouldnt fault
622 orrne r3, r3, r4, push #8
623 movne r4, r4, pull #24
624 orrne r4, r4, r7, push #8
625 stmneia r0!, {r3 - r4}
627 movne r3, r7, pull #24
628 USER( ldrnet r7, [r1], #4) @ May fault
629 orrne r3, r3, r7, push #8
633 .cfu_3nowords: mov r3, r7, get_byte_3
638 USER( ldrgebt r3, [r1], #1) @ May fault
640 USER( ldrgtbt r3, [r1], #1) @ May fault
647 * We took an exception. r0 contains a pointer to
648 * the byte not copied.
650 9001: ldr r2, [sp], #4 @ void *to
651 sub r2, r0, r2 @ bytes copied
652 ldr r1, [sp], #4 @ unsigned long count
653 subs r4, r1, r2 @ bytes left to copy
657 LOADREGS(fd,sp!, {r4 - r7, pc})
660 /* Prototype: int __arch_clear_user(void *addr, size_t sz)
661 * Purpose : clear some user memory
662 * Params : addr - user memory address to clear
663 * : sz - number of bytes to clear
664 * Returns : number of bytes NOT cleared
666 ENTRY(__arch_clear_user)
674 USER( strbt r2, [r0], #1)
675 USER( strlebt r2, [r0], #1)
676 USER( strltbt r2, [r0], #1)
678 sub r1, r1, ip @ 7 6 5 4 3 2 1
679 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7
680 USER( strplt r2, [r0], #4)
681 USER( strplt r2, [r0], #4)
683 adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3
684 USER( strplt r2, [r0], #4)
685 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x
686 USER( strnebt r2, [r0], #1)
687 USER( strnebt r2, [r0], #1)
688 tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1
689 USER( strnebt r2, [r0], #1)
691 LOADREGS(fd,sp!, {r1, pc})
695 9001: LOADREGS(fd,sp!, {r0, pc})