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
79 stmia r0!, {r3 - r6} @ Shouldnt fault
82 .c2u_0rem8lp: cmn ip, #16
83 ldmgeia r1!, {r3 - r6}
84 stmgeia r0!, {r3 - r6} @ Shouldnt fault
86 ldmneia r1!, {r3 - r4}
87 stmneia r0!, {r3 - r4} @ Shouldnt fault
90 strnet r3, [r0], #4 @ Shouldnt fault
93 .c2u_0nowords: teq ip, #0
95 .c2u_nowords: cmp ip, #2
97 USER( strbt r3, [r0], #1) @ May fault
99 USER( strgebt r3, [r0], #1) @ May fault
101 USER( strgtbt r3, [r0], #1) @ May fault
107 .c2u_finished: mov r0, #0
108 LOADREGS(fd,sp!,{r2, r4 - r7, pc})
110 .c2u_src_not_aligned:
116 .c2u_1fupi: subs r2, r2, #4
121 orr r3, r3, r7, push #24
122 USER( strt r3, [r0], #4) @ May fault
123 mov ip, r0, lsl #32 - PAGE_SHIFT
125 movs ip, ip, lsr #32 - PAGE_SHIFT
133 .c2u_1cpy8lp: mov r3, r7, pull #8
136 orr r3, r3, r4, push #24
138 orr r4, r4, r5, push #24
140 orr r5, r5, r6, push #24
142 orr r6, r6, r7, push #24
143 stmia r0!, {r3 - r6} @ Shouldnt fault
146 .c2u_1rem8lp: tst ip, #8
147 movne r3, r7, pull #8
148 ldmneia r1!, {r4, r7}
149 orrne r3, r3, r4, push #24
150 movne r4, r4, pull #8
151 orrne r4, r4, r7, push #24
152 stmneia r0!, {r3 - r4} @ Shouldnt fault
154 movne r3, r7, pull #8
156 orrne r3, r3, r7, push #24
157 strnet r3, [r0], #4 @ Shouldnt fault
160 .c2u_1nowords: mov r3, r7, get_byte_1
164 USER( strbt r3, [r0], #1) @ May fault
165 movge r3, r7, get_byte_2
166 USER( strgebt r3, [r0], #1) @ May fault
167 movgt r3, r7, get_byte_3
168 USER( strgtbt r3, [r0], #1) @ May fault
171 .c2u_2fupi: subs r2, r2, #4
176 orr r3, r3, r7, push #16
177 USER( strt r3, [r0], #4) @ May fault
178 mov ip, r0, lsl #32 - PAGE_SHIFT
180 movs ip, ip, lsr #32 - PAGE_SHIFT
188 .c2u_2cpy8lp: mov r3, r7, pull #16
191 orr r3, r3, r4, push #16
193 orr r4, r4, r5, push #16
195 orr r5, r5, r6, push #16
197 orr r6, r6, r7, push #16
198 stmia r0!, {r3 - r6} @ Shouldnt fault
201 .c2u_2rem8lp: tst ip, #8
202 movne r3, r7, pull #16
203 ldmneia r1!, {r4, r7}
204 orrne r3, r3, r4, push #16
205 movne r4, r4, pull #16
206 orrne r4, r4, r7, push #16
207 stmneia r0!, {r3 - r4} @ Shouldnt fault
209 movne r3, r7, pull #16
211 orrne r3, r3, r7, push #16
212 strnet r3, [r0], #4 @ Shouldnt fault
215 .c2u_2nowords: mov r3, r7, get_byte_2
219 USER( strbt r3, [r0], #1) @ May fault
220 movge r3, r7, get_byte_3
221 USER( strgebt r3, [r0], #1) @ May fault
223 USER( strgtbt r3, [r0], #1) @ May fault
226 .c2u_3fupi: subs r2, r2, #4
231 orr r3, r3, r7, push #8
232 USER( strt r3, [r0], #4) @ May fault
233 mov ip, r0, lsl #32 - PAGE_SHIFT
235 movs ip, ip, lsr #32 - PAGE_SHIFT
243 .c2u_3cpy8lp: mov r3, r7, pull #24
246 orr r3, r3, r4, push #8
248 orr r4, r4, r5, push #8
250 orr r5, r5, r6, push #8
252 orr r6, r6, r7, push #8
253 stmia r0!, {r3 - r6} @ Shouldnt fault
256 .c2u_3rem8lp: tst ip, #8
257 movne r3, r7, pull #24
258 ldmneia r1!, {r4, r7}
259 orrne r3, r3, r4, push #8
260 movne r4, r4, pull #24
261 orrne r4, r4, r7, push #8
262 stmneia r0!, {r3 - r4} @ Shouldnt fault
264 movne r3, r7, pull #24
266 orrne r3, r3, r7, push #8
267 strnet r3, [r0], #4 @ Shouldnt fault
270 .c2u_3nowords: mov r3, r7, get_byte_3
274 USER( strbt r3, [r0], #1) @ May fault
276 USER( strgebt r3, [r0], #1) @ May fault
278 USER( strgtbt r3, [r0], #1) @ May fault
283 9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc})
286 /* Prototype: unsigned long __arch_copy_from_user(void *to,const void *from,unsigned long n);
287 * Purpose : copy a block from user memory to kernel memory
288 * Params : to - kernel memory
289 * : from - user memory
290 * : n - number of bytes to copy
291 * Returns : Number of bytes NOT copied.
293 .cfu_dest_not_aligned:
296 USER( ldrbt r3, [r1], #1) @ May fault
298 USER( ldrgebt r3, [r1], #1) @ May fault
300 USER( ldrgtbt r3, [r1], #1) @ May fault
305 ENTRY(__arch_copy_from_user)
306 stmfd sp!, {r0, r2, r4 - r7, lr}
310 bne .cfu_dest_not_aligned
313 bne .cfu_src_not_aligned
315 * Seeing as there has to be at least 8 bytes to copy, we can
316 * copy one word, and force a user-mode page fault...
319 .cfu_0fupi: subs r2, r2, #4
322 USER( ldrt r3, [r1], #4)
324 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
326 movs ip, ip, lsr #32 - PAGE_SHIFT
329 * ip = max no. of bytes to copy before needing another "strt" insn
337 .cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
339 ldmia r1!, {r3 - r6} @ Shouldnt fault
344 .cfu_0rem8lp: cmn ip, #16
345 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
346 stmgeia r0!, {r3 - r6}
348 ldmneia r1!, {r3 - r4} @ Shouldnt fault
349 stmneia r0!, {r3 - r4}
351 ldrnet r3, [r1], #4 @ Shouldnt fault
355 .cfu_0nowords: teq ip, #0
357 .cfu_nowords: cmp ip, #2
358 USER( ldrbt r3, [r1], #1) @ May fault
360 USER( ldrgebt r3, [r1], #1) @ May fault
362 USER( ldrgtbt r3, [r1], #1) @ May fault
369 .cfu_finished: mov r0, #0
371 LOADREGS(fd,sp!,{r4 - r7, pc})
373 .cfu_src_not_aligned:
375 USER( ldrt r7, [r1], #4) @ May fault
379 .cfu_1fupi: subs r2, r2, #4
383 USER( ldrt r7, [r1], #4) @ May fault
384 orr r3, r3, r7, push #24
386 mov ip, r1, lsl #32 - PAGE_SHIFT
388 movs ip, ip, lsr #32 - PAGE_SHIFT
396 .cfu_1cpy8lp: mov r3, r7, pull #8
397 ldmia r1!, {r4 - r7} @ Shouldnt fault
399 orr r3, r3, r4, push #24
401 orr r4, r4, r5, push #24
403 orr r5, r5, r6, push #24
405 orr r6, r6, r7, push #24
409 .cfu_1rem8lp: tst ip, #8
410 movne r3, r7, pull #8
411 ldmneia r1!, {r4, r7} @ Shouldnt fault
412 orrne r3, r3, r4, push #24
413 movne r4, r4, pull #8
414 orrne r4, r4, r7, push #24
415 stmneia r0!, {r3 - r4}
417 movne r3, r7, pull #8
418 USER( ldrnet r7, [r1], #4) @ May fault
419 orrne r3, r3, r7, push #24
423 .cfu_1nowords: mov r3, r7, get_byte_1
428 movge r3, r7, get_byte_2
430 movgt r3, r7, get_byte_3
434 .cfu_2fupi: subs r2, r2, #4
438 USER( ldrt r7, [r1], #4) @ May fault
439 orr r3, r3, r7, push #16
441 mov ip, r1, lsl #32 - PAGE_SHIFT
443 movs ip, ip, lsr #32 - PAGE_SHIFT
451 .cfu_2cpy8lp: mov r3, r7, pull #16
452 ldmia r1!, {r4 - r7} @ Shouldnt fault
454 orr r3, r3, r4, push #16
456 orr r4, r4, r5, push #16
458 orr r5, r5, r6, push #16
460 orr r6, r6, r7, push #16
464 .cfu_2rem8lp: tst ip, #8
465 movne r3, r7, pull #16
466 ldmneia r1!, {r4, r7} @ Shouldnt fault
467 orrne r3, r3, r4, push #16
468 movne r4, r4, pull #16
469 orrne r4, r4, r7, push #16
470 stmneia r0!, {r3 - r4}
472 movne r3, r7, pull #16
473 USER( ldrnet r7, [r1], #4) @ May fault
474 orrne r3, r3, r7, push #16
478 .cfu_2nowords: mov r3, r7, get_byte_2
483 movge r3, r7, get_byte_3
485 USER( ldrgtbt r3, [r1], #0) @ May fault
489 .cfu_3fupi: subs r2, r2, #4
493 USER( ldrt r7, [r1], #4) @ May fault
494 orr r3, r3, r7, push #8
496 mov ip, r1, lsl #32 - PAGE_SHIFT
498 movs ip, ip, lsr #32 - PAGE_SHIFT
506 .cfu_3cpy8lp: mov r3, r7, pull #24
507 ldmia r1!, {r4 - r7} @ Shouldnt fault
508 orr r3, r3, r4, push #8
510 orr r4, r4, r5, push #8
512 orr r5, r5, r6, push #8
514 orr r6, r6, r7, push #8
519 .cfu_3rem8lp: tst ip, #8
520 movne r3, r7, pull #24
521 ldmneia r1!, {r4, r7} @ Shouldnt fault
522 orrne r3, r3, r4, push #8
523 movne r4, r4, pull #24
524 orrne r4, r4, r7, push #8
525 stmneia r0!, {r3 - r4}
527 movne r3, r7, pull #24
528 USER( ldrnet r7, [r1], #4) @ May fault
529 orrne r3, r3, r7, push #8
533 .cfu_3nowords: mov r3, r7, get_byte_3
538 USER( ldrgebt r3, [r1], #1) @ May fault
540 USER( ldrgtbt r3, [r1], #1) @ May fault
547 * We took an exception. r0 contains a pointer to
548 * the byte not copied.
550 9001: ldr r2, [sp], #4 @ void *to
551 sub r2, r0, r2 @ bytes copied
552 ldr r1, [sp], #4 @ unsigned long count
553 subs r4, r1, r2 @ bytes left to copy
557 LOADREGS(fd,sp!, {r4 - r7, pc})