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
283 9001: ldmfd sp!, {r0, r4 - r7, pc}
286 /* Prototype: unsigned long __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 .Lcfu_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(__copy_from_user)
306 stmfd sp!, {r0, r2, r4 - r7, lr}
310 bne .Lcfu_dest_not_aligned
313 bne .Lcfu_src_not_aligned
316 * Seeing as there has to be at least 8 bytes to copy, we can
317 * copy one word, and force a user-mode page fault...
320 .Lcfu_0fupi: subs r2, r2, #4
323 USER( ldrt r3, [r1], #4)
325 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
327 movs ip, ip, lsr #32 - PAGE_SHIFT
330 * ip = max no. of bytes to copy before needing another "strt" insn
338 .Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
340 ldmia r1!, {r3 - r6} @ Shouldnt fault
345 .Lcfu_0rem8lp: cmn ip, #16
346 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
347 stmgeia r0!, {r3 - r6}
349 ldmneia r1!, {r3 - r4} @ Shouldnt fault
350 stmneia r0!, {r3 - r4}
352 ldrnet r3, [r1], #4 @ Shouldnt fault
356 .Lcfu_0nowords: teq ip, #0
358 .Lcfu_nowords: cmp ip, #2
359 USER( ldrbt r3, [r1], #1) @ May fault
361 USER( ldrgebt r3, [r1], #1) @ May fault
363 USER( ldrgtbt r3, [r1], #1) @ May fault
370 .Lcfu_finished: mov r0, #0
372 ldmfd sp!, {r4 - r7, pc}
374 .Lcfu_src_not_aligned:
376 USER( ldrt r7, [r1], #4) @ May fault
380 .Lcfu_1fupi: subs r2, r2, #4
384 USER( ldrt r7, [r1], #4) @ May fault
385 orr r3, r3, r7, push #24
387 mov ip, r1, lsl #32 - PAGE_SHIFT
389 movs ip, ip, lsr #32 - PAGE_SHIFT
397 .Lcfu_1cpy8lp: mov r3, r7, pull #8
398 ldmia r1!, {r4 - r7} @ Shouldnt fault
400 orr r3, r3, r4, push #24
402 orr r4, r4, r5, push #24
404 orr r5, r5, r6, push #24
406 orr r6, r6, r7, push #24
410 .Lcfu_1rem8lp: tst ip, #8
411 movne r3, r7, pull #8
412 ldmneia r1!, {r4, r7} @ Shouldnt fault
413 orrne r3, r3, r4, push #24
414 movne r4, r4, pull #8
415 orrne r4, r4, r7, push #24
416 stmneia r0!, {r3 - r4}
418 movne r3, r7, pull #8
419 USER( ldrnet r7, [r1], #4) @ May fault
420 orrne r3, r3, r7, push #24
424 .Lcfu_1nowords: mov r3, r7, get_byte_1
429 movge r3, r7, get_byte_2
431 movgt r3, r7, get_byte_3
435 .Lcfu_2fupi: subs r2, r2, #4
439 USER( ldrt r7, [r1], #4) @ May fault
440 orr r3, r3, r7, push #16
442 mov ip, r1, lsl #32 - PAGE_SHIFT
444 movs ip, ip, lsr #32 - PAGE_SHIFT
453 .Lcfu_2cpy8lp: mov r3, r7, pull #16
454 ldmia r1!, {r4 - r7} @ Shouldnt fault
456 orr r3, r3, r4, push #16
458 orr r4, r4, r5, push #16
460 orr r5, r5, r6, push #16
462 orr r6, r6, r7, push #16
466 .Lcfu_2rem8lp: tst ip, #8
467 movne r3, r7, pull #16
468 ldmneia r1!, {r4, r7} @ Shouldnt fault
469 orrne r3, r3, r4, push #16
470 movne r4, r4, pull #16
471 orrne r4, r4, r7, push #16
472 stmneia r0!, {r3 - r4}
474 movne r3, r7, pull #16
475 USER( ldrnet r7, [r1], #4) @ May fault
476 orrne r3, r3, r7, push #16
480 .Lcfu_2nowords: mov r3, r7, get_byte_2
485 movge r3, r7, get_byte_3
487 USER( ldrgtbt r3, [r1], #0) @ May fault
491 .Lcfu_3fupi: subs r2, r2, #4
495 USER( ldrt r7, [r1], #4) @ May fault
496 orr r3, r3, r7, push #8
498 mov ip, r1, lsl #32 - PAGE_SHIFT
500 movs ip, ip, lsr #32 - PAGE_SHIFT
508 .Lcfu_3cpy8lp: mov r3, r7, pull #24
509 ldmia r1!, {r4 - r7} @ Shouldnt fault
510 orr r3, r3, r4, push #8
512 orr r4, r4, r5, push #8
514 orr r5, r5, r6, push #8
516 orr r6, r6, r7, push #8
521 .Lcfu_3rem8lp: tst ip, #8
522 movne r3, r7, pull #24
523 ldmneia r1!, {r4, r7} @ Shouldnt fault
524 orrne r3, r3, r4, push #8
525 movne r4, r4, pull #24
526 orrne r4, r4, r7, push #8
527 stmneia r0!, {r3 - r4}
529 movne r3, r7, pull #24
530 USER( ldrnet r7, [r1], #4) @ May fault
531 orrne r3, r3, r7, push #8
535 .Lcfu_3nowords: mov r3, r7, get_byte_3
540 USER( ldrgebt r3, [r1], #1) @ May fault
542 USER( ldrgtbt r3, [r1], #1) @ May fault
549 * We took an exception. r0 contains a pointer to
550 * the byte not copied.
552 9001: ldr r2, [sp], #4 @ void *to
553 sub r2, r0, r2 @ bytes copied
554 ldr r1, [sp], #4 @ unsigned long count
555 subs r4, r1, r2 @ bytes left to copy
559 ldmfd sp!, {r4 - r7, pc}