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 __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 .Lc2u_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
43 stmfd sp!, {r2, r4 - r7, lr}
47 bne .Lc2u_dest_not_aligned
51 bne .Lc2u_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 .Lc2u_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 .Lc2u_0cpy8lp: ldmia r1!, {r3 - r6}
76 stmia r0!, {r3 - r6} @ Shouldnt fault
79 stmia r0!, {r3 - r6} @ Shouldnt fault
82 .Lc2u_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 .Lc2u_0nowords: teq ip, #0
95 .Lc2u_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 .Lc2u_finished: mov r0, #0
108 ldmfd sp!, {r2, r4 - r7, pc}
110 .Lc2u_src_not_aligned:
116 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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 .Lc2u_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
280 ENDPROC(__copy_to_user)
282 .pushsection .fixup,"ax"
284 9001: ldmfd sp!, {r0, r4 - r7, pc}
287 /* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
288 * Purpose : copy a block from user memory to kernel memory
289 * Params : to - kernel memory
290 * : from - user memory
291 * : n - number of bytes to copy
292 * Returns : Number of bytes NOT copied.
294 .Lcfu_dest_not_aligned:
297 USER( ldrbt r3, [r1], #1) @ May fault
299 USER( ldrgebt r3, [r1], #1) @ May fault
301 USER( ldrgtbt r3, [r1], #1) @ May fault
306 ENTRY(__copy_from_user)
307 stmfd sp!, {r0, r2, r4 - r7, lr}
311 bne .Lcfu_dest_not_aligned
314 bne .Lcfu_src_not_aligned
317 * Seeing as there has to be at least 8 bytes to copy, we can
318 * copy one word, and force a user-mode page fault...
321 .Lcfu_0fupi: subs r2, r2, #4
324 USER( ldrt r3, [r1], #4)
326 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
328 movs ip, ip, lsr #32 - PAGE_SHIFT
331 * ip = max no. of bytes to copy before needing another "strt" insn
339 .Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
341 ldmia r1!, {r3 - r6} @ Shouldnt fault
346 .Lcfu_0rem8lp: cmn ip, #16
347 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
348 stmgeia r0!, {r3 - r6}
350 ldmneia r1!, {r3 - r4} @ Shouldnt fault
351 stmneia r0!, {r3 - r4}
353 ldrnet r3, [r1], #4 @ Shouldnt fault
357 .Lcfu_0nowords: teq ip, #0
359 .Lcfu_nowords: cmp ip, #2
360 USER( ldrbt r3, [r1], #1) @ May fault
362 USER( ldrgebt r3, [r1], #1) @ May fault
364 USER( ldrgtbt r3, [r1], #1) @ May fault
371 .Lcfu_finished: mov r0, #0
373 ldmfd sp!, {r4 - r7, pc}
375 .Lcfu_src_not_aligned:
377 USER( ldrt r7, [r1], #4) @ May fault
381 .Lcfu_1fupi: subs r2, r2, #4
385 USER( ldrt r7, [r1], #4) @ May fault
386 orr r3, r3, r7, push #24
388 mov ip, r1, lsl #32 - PAGE_SHIFT
390 movs ip, ip, lsr #32 - PAGE_SHIFT
398 .Lcfu_1cpy8lp: mov r3, r7, pull #8
399 ldmia r1!, {r4 - r7} @ Shouldnt fault
401 orr r3, r3, r4, push #24
403 orr r4, r4, r5, push #24
405 orr r5, r5, r6, push #24
407 orr r6, r6, r7, push #24
411 .Lcfu_1rem8lp: tst ip, #8
412 movne r3, r7, pull #8
413 ldmneia r1!, {r4, r7} @ Shouldnt fault
414 orrne r3, r3, r4, push #24
415 movne r4, r4, pull #8
416 orrne r4, r4, r7, push #24
417 stmneia r0!, {r3 - r4}
419 movne r3, r7, pull #8
420 USER( ldrnet r7, [r1], #4) @ May fault
421 orrne r3, r3, r7, push #24
425 .Lcfu_1nowords: mov r3, r7, get_byte_1
430 movge r3, r7, get_byte_2
432 movgt r3, r7, get_byte_3
436 .Lcfu_2fupi: subs r2, r2, #4
440 USER( ldrt r7, [r1], #4) @ May fault
441 orr r3, r3, r7, push #16
443 mov ip, r1, lsl #32 - PAGE_SHIFT
445 movs ip, ip, lsr #32 - PAGE_SHIFT
454 .Lcfu_2cpy8lp: mov r3, r7, pull #16
455 ldmia r1!, {r4 - r7} @ Shouldnt fault
457 orr r3, r3, r4, push #16
459 orr r4, r4, r5, push #16
461 orr r5, r5, r6, push #16
463 orr r6, r6, r7, push #16
467 .Lcfu_2rem8lp: tst ip, #8
468 movne r3, r7, pull #16
469 ldmneia r1!, {r4, r7} @ Shouldnt fault
470 orrne r3, r3, r4, push #16
471 movne r4, r4, pull #16
472 orrne r4, r4, r7, push #16
473 stmneia r0!, {r3 - r4}
475 movne r3, r7, pull #16
476 USER( ldrnet r7, [r1], #4) @ May fault
477 orrne r3, r3, r7, push #16
481 .Lcfu_2nowords: mov r3, r7, get_byte_2
486 movge r3, r7, get_byte_3
488 USER( ldrgtbt r3, [r1], #0) @ May fault
492 .Lcfu_3fupi: subs r2, r2, #4
496 USER( ldrt r7, [r1], #4) @ May fault
497 orr r3, r3, r7, push #8
499 mov ip, r1, lsl #32 - PAGE_SHIFT
501 movs ip, ip, lsr #32 - PAGE_SHIFT
509 .Lcfu_3cpy8lp: mov r3, r7, pull #24
510 ldmia r1!, {r4 - r7} @ Shouldnt fault
511 orr r3, r3, r4, push #8
513 orr r4, r4, r5, push #8
515 orr r5, r5, r6, push #8
517 orr r6, r6, r7, push #8
522 .Lcfu_3rem8lp: tst ip, #8
523 movne r3, r7, pull #24
524 ldmneia r1!, {r4, r7} @ Shouldnt fault
525 orrne r3, r3, r4, push #8
526 movne r4, r4, pull #24
527 orrne r4, r4, r7, push #8
528 stmneia r0!, {r3 - r4}
530 movne r3, r7, pull #24
531 USER( ldrnet r7, [r1], #4) @ May fault
532 orrne r3, r3, r7, push #8
536 .Lcfu_3nowords: mov r3, r7, get_byte_3
541 USER( ldrgebt r3, [r1], #1) @ May fault
543 USER( ldrgtbt r3, [r1], #1) @ May fault
546 ENDPROC(__copy_from_user)
548 .pushsection .fixup,"ax"
551 * We took an exception. r0 contains a pointer to
552 * the byte not copied.
554 9001: ldr r2, [sp], #4 @ void *to
555 sub r2, r0, r2 @ bytes copied
556 ldr r1, [sp], #4 @ unsigned long count
557 subs r4, r1, r2 @ bytes left to copy
561 ldmfd sp!, {r4 - r7, pc}