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}
47 bne .c2u_dest_not_aligned
51 bne .c2u_src_not_aligned
53 * Seeing as there has to be at least 8 bytes to copy, we can
54 * copy one word, and force a user-mode page fault...
57 .c2u_0fupi: subs r2, r2, #4
61 USER( strt r3, [r0], #4) @ May fault
62 mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
64 movs ip, ip, lsr #32 - PAGE_SHIFT
67 * ip = max no. of bytes to copy before needing another "strt" insn
75 .c2u_0cpy8lp: ldmia r1!, {r3 - r6}
76 stmia r0!, {r3 - r6} @ Shouldnt fault
78 stmia r0!, {r3 - r6} @ Shouldnt fault
81 .c2u_0rem8lp: cmn ip, #16
82 ldmgeia r1!, {r3 - r6}
83 stmgeia r0!, {r3 - r6} @ Shouldnt fault
85 ldmneia r1!, {r3 - r4}
86 stmneia r0!, {r3 - r4} @ Shouldnt fault
89 strnet r3, [r0], #4 @ Shouldnt fault
92 .c2u_0nowords: teq ip, #0
94 .c2u_nowords: cmp ip, #2
96 USER( strbt r3, [r0], #1) @ May fault
98 USER( strgebt r3, [r0], #1) @ May fault
100 USER( strgtbt r3, [r0], #1) @ May fault
106 .c2u_finished: mov r0, #0
107 LOADREGS(fd,sp!,{r2, r4 - r7, pc})
109 .c2u_src_not_aligned:
115 .c2u_1fupi: subs r2, r2, #4
120 orr r3, r3, r7, lsl #24
121 USER( strt r3, [r0], #4) @ May fault
122 mov ip, r0, lsl #32 - PAGE_SHIFT
124 movs ip, ip, lsr #32 - PAGE_SHIFT
132 .c2u_1cpy8lp: mov r3, r7, lsr #8
134 orr r3, r3, r4, lsl #24
136 orr r4, r4, r5, lsl #24
138 orr r5, r5, r6, lsl #24
140 orr r6, r6, r7, lsl #24
141 stmia r0!, {r3 - r6} @ Shouldnt fault
144 .c2u_1rem8lp: tst ip, #8
146 ldmneia r1!, {r4, r7}
147 orrne r3, r3, r4, lsl #24
149 orrne r4, r4, r7, lsl #24
150 stmneia r0!, {r3 - r4} @ Shouldnt fault
154 orrne r3, r3, r7, lsl #24
155 strnet r3, [r0], #4 @ Shouldnt fault
158 .c2u_1nowords: mov r3, r7, lsr #8
162 USER( strbt r3, [r0], #1) @ May fault
164 USER( strgebt r3, [r0], #1) @ May fault
166 USER( strgtbt r3, [r0], #1) @ May fault
169 .c2u_2fupi: subs r2, r2, #4
174 orr r3, r3, r7, lsl #16
175 USER( strt r3, [r0], #4) @ May fault
176 mov ip, r0, lsl #32 - PAGE_SHIFT
178 movs ip, ip, lsr #32 - PAGE_SHIFT
186 .c2u_2cpy8lp: mov r3, r7, lsr #16
188 orr r3, r3, r4, lsl #16
190 orr r4, r4, r5, lsl #16
192 orr r5, r5, r6, lsl #16
194 orr r6, r6, r7, lsl #16
195 stmia r0!, {r3 - r6} @ Shouldnt fault
198 .c2u_2rem8lp: tst ip, #8
199 movne r3, r7, lsr #16
200 ldmneia r1!, {r4, r7}
201 orrne r3, r3, r4, lsl #16
202 movne r4, r4, lsr #16
203 orrne r4, r4, r7, lsl #16
204 stmneia r0!, {r3 - r4} @ Shouldnt fault
206 movne r3, r7, lsr #16
208 orrne r3, r3, r7, lsl #16
209 strnet r3, [r0], #4 @ Shouldnt fault
212 .c2u_2nowords: mov r3, r7, lsr #16
216 USER( strbt r3, [r0], #1) @ May fault
218 USER( strgebt r3, [r0], #1) @ May fault
220 USER( strgtbt r3, [r0], #1) @ May fault
223 .c2u_3fupi: subs r2, r2, #4
228 orr r3, r3, r7, lsl #8
229 USER( strt r3, [r0], #4) @ May fault
230 mov ip, r0, lsl #32 - PAGE_SHIFT
232 movs ip, ip, lsr #32 - PAGE_SHIFT
240 .c2u_3cpy8lp: mov r3, r7, lsr #24
242 orr r3, r3, r4, lsl #8
244 orr r4, r4, r5, lsl #8
246 orr r5, r5, r6, lsl #8
248 orr r6, r6, r7, lsl #8
249 stmia r0!, {r3 - r6} @ Shouldnt fault
252 .c2u_3rem8lp: tst ip, #8
253 movne r3, r7, lsr #24
254 ldmneia r1!, {r4, r7}
255 orrne r3, r3, r4, lsl #8
256 movne r4, r4, lsr #24
257 orrne r4, r4, r7, lsl #8
258 stmneia r0!, {r3 - r4} @ Shouldnt fault
260 movne r3, r7, lsr #24
262 orrne r3, r3, r7, lsl #8
263 strnet r3, [r0], #4 @ Shouldnt fault
266 .c2u_3nowords: mov r3, r7, lsr #24
270 USER( strbt r3, [r0], #1) @ May fault
272 USER( strgebt r3, [r0], #1) @ May fault
274 USER( strgtbt r3, [r0], #1) @ May fault
279 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc})
282 /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
283 * Purpose : copy a block from user memory to kernel memory
284 * Params : to - kernel memory
285 * : from - user memory
286 * : n - number of bytes to copy
287 * Returns : Number of bytes NOT copied.
289 .cfu_dest_not_aligned:
292 USER( ldrbt r3, [r1], #1) @ May fault
294 USER( ldrgebt r3, [r1], #1) @ May fault
296 USER( ldrgtbt r3, [r1], #1) @ May fault
301 ENTRY(__arch_copy_from_user)
302 stmfd sp!, {r0, r2, r4 - r7, lr}
306 bne .cfu_dest_not_aligned
309 bne .cfu_src_not_aligned
311 * Seeing as there has to be at least 8 bytes to copy, we can
312 * copy one word, and force a user-mode page fault...
315 .cfu_0fupi: subs r2, r2, #4
318 USER( ldrt r3, [r1], #4)
320 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
322 movs ip, ip, lsr #32 - PAGE_SHIFT
325 * ip = max no. of bytes to copy before needing another "strt" insn
333 .cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
335 ldmia r1!, {r3 - r6} @ Shouldnt fault
339 .cfu_0rem8lp: cmn ip, #16
340 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
341 stmgeia r0!, {r3 - r6}
343 ldmneia r1!, {r3 - r4} @ Shouldnt fault
344 stmneia r0!, {r3 - r4}
346 ldrnet r3, [r1], #4 @ Shouldnt fault
350 .cfu_0nowords: teq ip, #0
352 .cfu_nowords: cmp ip, #2
353 USER( ldrbt r3, [r1], #1) @ May fault
355 USER( ldrgebt r3, [r1], #1) @ May fault
357 USER( ldrgtbt r3, [r1], #1) @ May fault
364 .cfu_finished: mov r0, #0
366 LOADREGS(fd,sp!,{r4 - r7, pc})
368 .cfu_src_not_aligned:
370 USER( ldrt r7, [r1], #4) @ May fault
374 .cfu_1fupi: subs r2, r2, #4
378 USER( ldrt r7, [r1], #4) @ May fault
379 orr r3, r3, r7, lsl #24
381 mov ip, r1, lsl #32 - PAGE_SHIFT
383 movs ip, ip, lsr #32 - PAGE_SHIFT
391 .cfu_1cpy8lp: mov r3, r7, lsr #8
392 ldmia r1!, {r4 - r7} @ Shouldnt fault
393 orr r3, r3, r4, lsl #24
395 orr r4, r4, r5, lsl #24
397 orr r5, r5, r6, lsl #24
399 orr r6, r6, r7, lsl #24
403 .cfu_1rem8lp: tst ip, #8
405 ldmneia r1!, {r4, r7} @ Shouldnt fault
406 orrne r3, r3, r4, lsl #24
408 orrne r4, r4, r7, lsl #24
409 stmneia r0!, {r3 - r4}
412 USER( ldrnet r7, [r1], #4) @ May fault
413 orrne r3, r3, r7, lsl #24
417 .cfu_1nowords: mov r3, r7, lsr #8
428 .cfu_2fupi: subs r2, r2, #4
432 USER( ldrt r7, [r1], #4) @ May fault
433 orr r3, r3, r7, lsl #16
435 mov ip, r1, lsl #32 - PAGE_SHIFT
437 movs ip, ip, lsr #32 - PAGE_SHIFT
445 .cfu_2cpy8lp: mov r3, r7, lsr #16
446 ldmia r1!, {r4 - r7} @ Shouldnt fault
447 orr r3, r3, r4, lsl #16
449 orr r4, r4, r5, lsl #16
451 orr r5, r5, r6, lsl #16
453 orr r6, r6, r7, lsl #16
457 .cfu_2rem8lp: tst ip, #8
458 movne r3, r7, lsr #16
459 ldmneia r1!, {r4, r7} @ Shouldnt fault
460 orrne r3, r3, r4, lsl #16
461 movne r4, r4, lsr #16
462 orrne r4, r4, r7, lsl #16
463 stmneia r0!, {r3 - r4}
465 movne r3, r7, lsr #16
466 USER( ldrnet r7, [r1], #4) @ May fault
467 orrne r3, r3, r7, lsl #16
471 .cfu_2nowords: mov r3, r7, lsr #16
478 USER( ldrgtbt r3, [r1], #0) @ May fault
482 .cfu_3fupi: subs r2, r2, #4
486 USER( ldrt r7, [r1], #4) @ May fault
487 orr r3, r3, r7, lsl #8
489 mov ip, r1, lsl #32 - PAGE_SHIFT
491 movs ip, ip, lsr #32 - PAGE_SHIFT
499 .cfu_3cpy8lp: mov r3, r7, lsr #24
500 ldmia r1!, {r4 - r7} @ Shouldnt fault
501 orr r3, r3, r4, lsl #8
503 orr r4, r4, r5, lsl #8
505 orr r5, r5, r6, lsl #8
507 orr r6, r6, r7, lsl #8
511 .cfu_3rem8lp: tst ip, #8
512 movne r3, r7, lsr #24
513 ldmneia r1!, {r4, r7} @ Shouldnt fault
514 orrne r3, r3, r4, lsl #8
515 movne r4, r4, lsr #24
516 orrne r4, r4, r7, lsl #8
517 stmneia r0!, {r3 - r4}
519 movne r3, r7, lsr #24
520 USER( ldrnet r7, [r1], #4) @ May fault
521 orrne r3, r3, r7, lsl #8
525 .cfu_3nowords: mov r3, r7, lsr #24
530 USER( ldrget r3, [r1], #0) @ May fault
539 * We took an exception. r0 contains a pointer to
540 * the byte not copied.
542 9001: ldr r2, [sp], #4 @ void *to
543 sub r2, r0, r2 @ bytes copied
544 ldr r1, [sp], #4 @ unsigned long count
545 subs r4, r1, r2 @ bytes left to copy
547 blne SYMBOL_NAME(__memzero)
549 LOADREGS(fd,sp!, {r4 - r7, pc})
552 /* Prototype: int __arch_clear_user(void *addr, size_t sz)
553 * Purpose : clear some user memory
554 * Params : addr - user memory address to clear
555 * : sz - number of bytes to clear
556 * Returns : number of bytes NOT cleared
558 ENTRY(__arch_clear_user)
566 USER( strbt r2, [r0], #1)
567 USER( strlebt r2, [r0], #1)
568 USER( strltbt r2, [r0], #1)
570 sub r1, r1, ip @ 7 6 5 4 3 2 1
571 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7
572 USER( strplt r2, [r0], #4)
573 USER( strplt r2, [r0], #4)
575 adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3
576 USER( strplt r2, [r0], #4)
577 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x
578 USER( strnebt r2, [r0], #1)
579 USER( strnebt r2, [r0], #1)
580 tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1
581 USER( strnebt r2, [r0], #1)
583 LOADREGS(fd,sp!, {r1, pc})
587 9001: LOADREGS(fd,sp!, {r0, pc})