2 * linux/arch/arm/lib/uaccess.S
4 * Copyright (C) 1995, 1996,1997,1998 Russell King
6 * Routines to block copy data to/from user memory
7 * These are highly optimised both for the 4k page size
8 * and for various alignments.
10 #include <linux/linkage.h>
11 #include <asm/assembler.h>
12 #include <asm/errno.h>
18 .section __ex_table,"a"; \
33 /* Prototype: int __arch_copy_to_user(void *to, const char *from, size_t n)
34 * Purpose : copy a block to user memory from kernel memory
35 * Params : to - user memory
36 * : from - kernel memory
37 * : n - number of bytes to copy
38 * Returns : Number of bytes NOT copied.
41 .c2u_dest_not_aligned:
45 USER( strbt r3, [r0], #1) // May fault
47 USER( strgebt r3, [r0], #1) // May fault
49 USER( strgtbt r3, [r0], #1) // May fault
53 ENTRY(__arch_copy_to_user)
54 stmfd sp!, {r2, r4 - r7, lr}
58 bne .c2u_dest_not_aligned
62 bne .c2u_src_not_aligned
64 * Seeing as there has to be at least 8 bytes to copy, we can
65 * copy one word, and force a user-mode page fault...
68 .c2u_0fupi: subs r2, r2, #4
72 USER( strt r3, [r0], #4) // May fault
73 mov ip, r0, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction
75 movs ip, ip, lsr #32 - PAGE_SHIFT
78 * ip = max no. of bytes to copy before needing another "strt" insn
86 .c2u_0cpy8lp: ldmia r1!, {r3 - r6}
87 stmia r0!, {r3 - r6} // Shouldn't fault
89 stmia r0!, {r3 - r6} // Shouldn't fault
92 .c2u_0rem8lp: cmn ip, #16
93 ldmgeia r1!, {r3 - r6}
94 stmgeia r0!, {r3 - r6} // Shouldn't fault
96 ldmneia r1!, {r3 - r4}
97 stmneia r0!, {r3 - r4} // Shouldn't fault
100 strnet r3, [r0], #4 // Shouldn't fault
103 .c2u_0nowords: teq ip, #0
105 .c2u_nowords: cmp ip, #2
107 USER( strbt r3, [r0], #1) // May fault
109 USER( strgebt r3, [r0], #1) // May fault
111 USER( strgtbt r3, [r0], #1) // May fault
117 .c2u_finished: mov r0, #0
118 LOADREGS(fd,sp!,{r2, r4 - r7, pc})
120 .c2u_src_not_aligned:
126 .c2u_1fupi: subs r2, r2, #4
131 orr r3, r3, r7, lsl #24
132 USER( strt r3, [r0], #4) // May fault
133 mov ip, r0, lsl #32 - PAGE_SHIFT
135 movs ip, ip, lsr #32 - PAGE_SHIFT
143 .c2u_1cpy8lp: mov r3, r7, lsr #8
145 orr r3, r3, r4, lsl #24
147 orr r4, r4, r5, lsl #24
149 orr r5, r5, r6, lsl #24
151 orr r6, r6, r7, lsl #24
152 stmia r0!, {r3 - r6} // Shouldn't fault
155 .c2u_1rem8lp: tst ip, #8
157 ldmneia r1!, {r4, r7}
158 orrne r3, r3, r4, lsl #24
160 orrne r4, r4, r7, lsl #24
161 stmneia r0!, {r3 - r4} // Shouldn't fault
165 orrne r3, r3, r7, lsl #24
166 strnet r3, [r0], #4 // Shouldn't fault
169 .c2u_1nowords: mov r3, r7, lsr #8
173 USER( strbt r3, [r0], #1) // May fault
175 USER( strgebt r3, [r0], #1) // May fault
177 USER( strgtbt r3, [r0], #1) // May fault
180 .c2u_2fupi: subs r2, r2, #4
185 orr r3, r3, r7, lsl #16
186 USER( strt r3, [r0], #4) // May fault
187 mov ip, r0, lsl #32 - PAGE_SHIFT
189 movs ip, ip, lsr #32 - PAGE_SHIFT
197 .c2u_2cpy8lp: mov r3, r7, lsr #16
199 orr r3, r3, r4, lsl #16
201 orr r4, r4, r5, lsl #16
203 orr r5, r5, r6, lsl #16
205 orr r6, r6, r7, lsl #16
206 stmia r0!, {r3 - r6} // Shouldn't fault
209 .c2u_2rem8lp: tst ip, #8
210 movne r3, r7, lsr #16
211 ldmneia r1!, {r4, r7}
212 orrne r3, r3, r4, lsl #16
213 movne r4, r4, lsr #16
214 orrne r4, r4, r7, lsl #16
215 stmneia r0!, {r3 - r4} // Shouldn't fault
217 movne r3, r7, lsr #16
219 orrne r3, r3, r7, lsl #16
220 strnet r3, [r0], #4 // Shouldn't fault
223 .c2u_2nowords: mov r3, r7, lsr #16
227 USER( strbt r3, [r0], #1) // May fault
229 USER( strgebt r3, [r0], #1) // May fault
231 USER( strgtbt r3, [r0], #1) // May fault
234 .c2u_3fupi: subs r2, r2, #4
239 orr r3, r3, r7, lsl #8
240 USER( strt r3, [r0], #4) // May fault
241 mov ip, r0, lsl #32 - PAGE_SHIFT
243 movs ip, ip, lsr #32 - PAGE_SHIFT
251 .c2u_3cpy8lp: mov r3, r7, lsr #24
253 orr r3, r3, r4, lsl #8
255 orr r4, r4, r5, lsl #8
257 orr r5, r5, r6, lsl #8
259 orr r6, r6, r7, lsl #8
260 stmia r0!, {r3 - r6} // Shouldn't fault
263 .c2u_3rem8lp: tst ip, #8
264 movne r3, r7, lsr #24
265 ldmneia r1!, {r4, r7}
266 orrne r3, r3, r4, lsl #8
267 movne r4, r4, lsr #24
268 orrne r4, r4, r7, lsl #8
269 stmneia r0!, {r3 - r4} // Shouldn't fault
271 movne r3, r7, lsr #24
273 orrne r3, r3, r7, lsl #8
274 strnet r3, [r0], #4 // Shouldn't fault
277 .c2u_3nowords: mov r3, r7, lsr #24
281 USER( strbt r3, [r0], #1) // May fault
283 USER( strgebt r3, [r0], #1) // May fault
285 USER( strgtbt r3, [r0], #1) // May fault
291 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc})
295 /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
296 * Purpose : copy a block from user memory to kernel memory
297 * Params : to - kernel memory
298 * : from - user memory
299 * : n - number of bytes to copy
300 * Returns : Number of bytes NOT copied.
302 .cfu_dest_not_aligned:
305 USER( ldrbt r3, [r1], #1) // May fault
307 USER( ldrgebt r3, [r1], #1) // May fault
309 USER( ldrgtbt r3, [r1], #1) // May fault
314 ENTRY(__arch_copy_from_user)
315 stmfd sp!, {r0, r2, r4 - r7, lr}
319 bne .cfu_dest_not_aligned
322 bne .cfu_src_not_aligned
324 * Seeing as there has to be at least 8 bytes to copy, we can
325 * copy one word, and force a user-mode page fault...
328 .cfu_0fupi: subs r2, r2, #4
331 USER( ldrt r3, [r1], #4)
333 mov ip, r1, lsl #32 - PAGE_SHIFT // On each page, use a ld/st??t instruction
335 movs ip, ip, lsr #32 - PAGE_SHIFT
338 * ip = max no. of bytes to copy before needing another "strt" insn
346 .cfu_0cpy8lp: ldmia r1!, {r3 - r6} // Shouldn't fault
348 ldmia r1!, {r3 - r6} // Shouldn't fault
352 .cfu_0rem8lp: cmn ip, #16
353 ldmgeia r1!, {r3 - r6} // Shouldn't fault
354 stmgeia r0!, {r3 - r6}
356 ldmneia r1!, {r3 - r4} // Shouldn't fault
357 stmneia r0!, {r3 - r4}
359 ldrnet r3, [r1], #4 // Shouldn't fault
363 .cfu_0nowords: teq ip, #0
365 .cfu_nowords: cmp ip, #2
366 USER( ldrbt r3, [r1], #1) // May fault
368 USER( ldrgebt r3, [r1], #1) // May fault
370 USER( ldrgtbt r3, [r1], #1) // May fault
377 .cfu_finished: mov r0, #0
379 LOADREGS(fd,sp!,{r4 - r7, pc})
381 .cfu_src_not_aligned:
383 USER( ldrt r7, [r1], #4) // May fault
387 .cfu_1fupi: subs r2, r2, #4
391 USER( ldrt r7, [r1], #4) // May fault
392 orr r3, r3, r7, lsl #24
394 mov ip, r1, lsl #32 - PAGE_SHIFT
396 movs ip, ip, lsr #32 - PAGE_SHIFT
404 .cfu_1cpy8lp: mov r3, r7, lsr #8
405 ldmia r1!, {r4 - r7} // Shouldn't fault
406 orr r3, r3, r4, lsl #24
408 orr r4, r4, r5, lsl #24
410 orr r5, r5, r6, lsl #24
412 orr r6, r6, r7, lsl #24
416 .cfu_1rem8lp: tst ip, #8
418 ldmneia r1!, {r4, r7} // Shouldn't fault
419 orrne r3, r3, r4, lsl #24
421 orrne r4, r4, r7, lsl #24
422 stmneia r0!, {r3 - r4}
425 USER( ldrnet r7, [r1], #4) // May fault
426 orrne r3, r3, r7, lsl #24
430 .cfu_1nowords: mov r3, r7, lsr #8
441 .cfu_2fupi: subs r2, r2, #4
445 USER( ldrt r7, [r1], #4) // May fault
446 orr r3, r3, r7, lsl #16
448 mov ip, r1, lsl #32 - PAGE_SHIFT
450 movs ip, ip, lsr #32 - PAGE_SHIFT
458 .cfu_2cpy8lp: mov r3, r7, lsr #16
459 ldmia r1!, {r4 - r7} // Shouldn't fault
460 orr r3, r3, r4, lsl #16
462 orr r4, r4, r5, lsl #16
464 orr r5, r5, r6, lsl #16
466 orr r6, r6, r7, lsl #16
470 .cfu_2rem8lp: tst ip, #8
471 movne r3, r7, lsr #16
472 ldmneia r1!, {r4, r7} // Shouldn't fault
473 orrne r3, r3, r4, lsl #16
474 movne r4, r4, lsr #16
475 orrne r4, r4, r7, lsl #16
476 stmneia r0!, {r3 - r4}
478 movne r3, r7, lsr #16
479 USER( ldrnet r7, [r1], #4) // May fault
480 orrne r3, r3, r7, lsl #16
484 .cfu_2nowords: mov r3, r7, lsr #16
491 USER( ldrgtbt r3, [r1], #0) // May fault
495 .cfu_3fupi: subs r2, r2, #4
499 USER( ldrt r7, [r1], #4) // May fault
500 orr r3, r3, r7, lsl #8
502 mov ip, r1, lsl #32 - PAGE_SHIFT
504 movs ip, ip, lsr #32 - PAGE_SHIFT
512 .cfu_3cpy8lp: mov r3, r7, lsr #24
513 ldmia r1!, {r4 - r7} // Shouldn't fault
514 orr r3, r3, r4, lsl #8
516 orr r4, r4, r5, lsl #8
518 orr r5, r5, r6, lsl #8
520 orr r6, r6, r7, lsl #8
524 .cfu_3rem8lp: tst ip, #8
525 movne r3, r7, lsr #24
526 ldmneia r1!, {r4, r7} // Shouldn't fault
527 orrne r3, r3, r4, lsl #8
528 movne r4, r4, lsr #24
529 orrne r4, r4, r7, lsl #8
530 stmneia r0!, {r3 - r4}
532 movne r3, r7, lsr #24
533 USER( ldrnet r7, [r1], #4) // May fault
534 orrne r3, r3, r7, lsl #8
538 .cfu_3nowords: mov r3, r7, lsr #24
543 USER( ldrget r3, [r1], #0) // May fault
552 /* We took an exception. Zero out the buffer and pretend no
554 9001: ldr r0, [sp], #4
556 bl SYMBOL_NAME(memzero)
557 LOADREGS(fd,sp!, {r0, r4 - r7, pc})
561 /* Prototype: int __arch_clear_user(void *addr, size_t sz)
562 * Purpose : clear some user memory
563 * Params : addr - user memory address to clear
564 * : sz - number of bytes to clear
565 * Returns : number of bytes NOT cleared
567 ENTRY(__arch_clear_user)
575 USER( strbt r2, [r0], #1)
576 USER( strlebt r2, [r0], #1)
577 USER( strltbt r2, [r0], #1)
579 sub r1, r1, ip @ 7 6 5 4 3 2 1
580 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7
581 USER( strplt r2, [r0], #4)
582 USER( strplt r2, [r0], #4)
584 adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3
585 USER( strplt r2, [r0], #4)
586 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x
587 USER( strnebt r2, [r0], #1)
588 USER( strnebt r2, [r0], #1)
589 tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1
590 USER( strnebt r2, [r0], #1)
592 LOADREGS(fd,sp!, {r1, pc})
597 9001: LOADREGS(fd,sp!, {r0, pc})
600 /* Prototype: int __arch_strlen_user(char *str)
601 * Purpose : get length of a string in user memory
602 * Params : str - address of string in user memory
603 * Returns : length of string *including terminator*, or zero on error
605 ENTRY(__arch_strlen_user)
609 USER( ldrbt r1, [r0], #1)
613 LOADREGS(fd,sp!, {pc})
618 LOADREGS(fd,sp!,{pc})
621 /* Prototype: size_t __arch_strncpy_from_user(char *dst, char *src, size_t len)
622 * Purpose : copy a string from user memory to kernel memory
623 * Params : dst - kernel memory destination
624 * : src - user memory source
625 * : len - maximum length of string
626 * Returns : number of characters copied
628 ENTRY(__arch_strncpy_from_user)
633 USER( ldrbt r3, [r1], #1)
638 LOADREGS(fd, sp!, {pc})
641 LOADREGS(fd, sp!, {pc})
650 LOADREGS(fd, sp!, {pc})