blob: 6f1b5b49fe4c877851aec5ab7e4a515d4e9ba334 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/arch/arm/lib/uaccess.S
3 *
4 * Copyright (C) 1995, 1996,1997,1998 Russell King
5 *
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.
9 *
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.
13 */
14#include <linux/linkage.h>
15#include <asm/assembler.h>
16#include <asm/errno.h>
17
18 .text
19
20#define PAGE_SHIFT 12
21
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.
28 */
29
30.c2u_dest_not_aligned:
31 rsb ip, ip, #4
32 cmp ip, #2
33 ldrb r3, [r1], #1
34USER( strbt r3, [r0], #1) @ May fault
35 ldrgeb r3, [r1], #1
36USER( strgebt r3, [r0], #1) @ May fault
37 ldrgtb r3, [r1], #1
38USER( strgtbt r3, [r0], #1) @ May fault
39 sub r2, r2, ip
40 b .c2u_dest_aligned
41
42ENTRY(__arch_copy_to_user)
43 stmfd sp!, {r2, r4 - r7, lr}
44 cmp r2, #4
45 blt .c2u_not_enough
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 ands ip, r0, #3
47 bne .c2u_dest_not_aligned
48.c2u_dest_aligned:
49
50 ands ip, r1, #3
51 bne .c2u_src_not_aligned
52/*
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...
55 */
56
57.c2u_0fupi: subs r2, r2, #4
58 addmi ip, r2, #4
59 bmi .c2u_0nowords
60 ldr r3, [r1], #4
61USER( strt r3, [r0], #4) @ May fault
62 mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
63 rsb ip, ip, #0
64 movs ip, ip, lsr #32 - PAGE_SHIFT
65 beq .c2u_0fupi
66/*
67 * ip = max no. of bytes to copy before needing another "strt" insn
68 */
69 cmp r2, ip
70 movlt ip, r2
71 sub r2, r2, ip
72 subs ip, ip, #32
73 blt .c2u_0rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +000075.c2u_0cpy8lp: ldmia r1!, {r3 - r6}
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 stmia r0!, {r3 - r6} @ Shouldnt fault
77 ldmia r1!, {r3 - r6}
78 subs ip, ip, #32
79 stmia r0!, {r3 - r6} @ Shouldnt fault
80 bpl .c2u_0cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82.c2u_0rem8lp: cmn ip, #16
83 ldmgeia r1!, {r3 - r6}
84 stmgeia r0!, {r3 - r6} @ Shouldnt fault
85 tst ip, #8
86 ldmneia r1!, {r3 - r4}
87 stmneia r0!, {r3 - r4} @ Shouldnt fault
88 tst ip, #4
89 ldrne r3, [r1], #4
90 strnet r3, [r0], #4 @ Shouldnt fault
91 ands ip, ip, #3
92 beq .c2u_0fupi
93.c2u_0nowords: teq ip, #0
94 beq .c2u_finished
95.c2u_nowords: cmp ip, #2
96 ldrb r3, [r1], #1
97USER( strbt r3, [r0], #1) @ May fault
98 ldrgeb r3, [r1], #1
99USER( strgebt r3, [r0], #1) @ May fault
100 ldrgtb r3, [r1], #1
101USER( strgtbt r3, [r0], #1) @ May fault
102 b .c2u_finished
103
104.c2u_not_enough:
105 movs ip, r2
106 bne .c2u_nowords
107.c2u_finished: mov r0, #0
108 LOADREGS(fd,sp!,{r2, r4 - r7, pc})
109
110.c2u_src_not_aligned:
111 bic r1, r1, #3
112 ldr r7, [r1], #4
113 cmp ip, #2
114 bgt .c2u_3fupi
115 beq .c2u_2fupi
116.c2u_1fupi: subs r2, r2, #4
117 addmi ip, r2, #4
118 bmi .c2u_1nowords
119 mov r3, r7, pull #8
120 ldr r7, [r1], #4
121 orr r3, r3, r7, push #24
122USER( strt r3, [r0], #4) @ May fault
123 mov ip, r0, lsl #32 - PAGE_SHIFT
124 rsb ip, ip, #0
125 movs ip, ip, lsr #32 - PAGE_SHIFT
126 beq .c2u_1fupi
127 cmp r2, ip
128 movlt ip, r2
129 sub r2, r2, ip
130 subs ip, ip, #16
131 blt .c2u_1rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000133.c2u_1cpy8lp: mov r3, r7, pull #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 ldmia r1!, {r4 - r7}
135 subs ip, ip, #16
136 orr r3, r3, r4, push #24
137 mov r4, r4, pull #8
138 orr r4, r4, r5, push #24
139 mov r5, r5, pull #8
140 orr r5, r5, r6, push #24
141 mov r6, r6, pull #8
142 orr r6, r6, r7, push #24
143 stmia r0!, {r3 - r6} @ Shouldnt fault
144 bpl .c2u_1cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
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
153 tst ip, #4
154 movne r3, r7, pull #8
155 ldrne r7, [r1], #4
156 orrne r3, r3, r7, push #24
157 strnet r3, [r0], #4 @ Shouldnt fault
158 ands ip, ip, #3
159 beq .c2u_1fupi
160.c2u_1nowords: mov r3, r7, get_byte_1
161 teq ip, #0
162 beq .c2u_finished
163 cmp ip, #2
164USER( strbt r3, [r0], #1) @ May fault
165 movge r3, r7, get_byte_2
166USER( strgebt r3, [r0], #1) @ May fault
167 movgt r3, r7, get_byte_3
168USER( strgtbt r3, [r0], #1) @ May fault
169 b .c2u_finished
170
171.c2u_2fupi: subs r2, r2, #4
172 addmi ip, r2, #4
173 bmi .c2u_2nowords
174 mov r3, r7, pull #16
175 ldr r7, [r1], #4
176 orr r3, r3, r7, push #16
177USER( strt r3, [r0], #4) @ May fault
178 mov ip, r0, lsl #32 - PAGE_SHIFT
179 rsb ip, ip, #0
180 movs ip, ip, lsr #32 - PAGE_SHIFT
181 beq .c2u_2fupi
182 cmp r2, ip
183 movlt ip, r2
184 sub r2, r2, ip
185 subs ip, ip, #16
186 blt .c2u_2rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000188.c2u_2cpy8lp: mov r3, r7, pull #16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 ldmia r1!, {r4 - r7}
190 subs ip, ip, #16
191 orr r3, r3, r4, push #16
192 mov r4, r4, pull #16
193 orr r4, r4, r5, push #16
194 mov r5, r5, pull #16
195 orr r5, r5, r6, push #16
196 mov r6, r6, pull #16
197 orr r6, r6, r7, push #16
198 stmia r0!, {r3 - r6} @ Shouldnt fault
199 bpl .c2u_2cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
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
208 tst ip, #4
209 movne r3, r7, pull #16
210 ldrne r7, [r1], #4
211 orrne r3, r3, r7, push #16
212 strnet r3, [r0], #4 @ Shouldnt fault
213 ands ip, ip, #3
214 beq .c2u_2fupi
215.c2u_2nowords: mov r3, r7, get_byte_2
216 teq ip, #0
217 beq .c2u_finished
218 cmp ip, #2
219USER( strbt r3, [r0], #1) @ May fault
220 movge r3, r7, get_byte_3
221USER( strgebt r3, [r0], #1) @ May fault
222 ldrgtb r3, [r1], #0
223USER( strgtbt r3, [r0], #1) @ May fault
224 b .c2u_finished
225
226.c2u_3fupi: subs r2, r2, #4
227 addmi ip, r2, #4
228 bmi .c2u_3nowords
229 mov r3, r7, pull #24
230 ldr r7, [r1], #4
231 orr r3, r3, r7, push #8
232USER( strt r3, [r0], #4) @ May fault
233 mov ip, r0, lsl #32 - PAGE_SHIFT
234 rsb ip, ip, #0
235 movs ip, ip, lsr #32 - PAGE_SHIFT
236 beq .c2u_3fupi
237 cmp r2, ip
238 movlt ip, r2
239 sub r2, r2, ip
240 subs ip, ip, #16
241 blt .c2u_3rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000243.c2u_3cpy8lp: mov r3, r7, pull #24
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 ldmia r1!, {r4 - r7}
245 subs ip, ip, #16
246 orr r3, r3, r4, push #8
247 mov r4, r4, pull #24
248 orr r4, r4, r5, push #8
249 mov r5, r5, pull #24
250 orr r5, r5, r6, push #8
251 mov r6, r6, pull #24
252 orr r6, r6, r7, push #8
253 stmia r0!, {r3 - r6} @ Shouldnt fault
254 bpl .c2u_3cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
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
263 tst ip, #4
264 movne r3, r7, pull #24
265 ldrne r7, [r1], #4
266 orrne r3, r3, r7, push #8
267 strnet r3, [r0], #4 @ Shouldnt fault
268 ands ip, ip, #3
269 beq .c2u_3fupi
270.c2u_3nowords: mov r3, r7, get_byte_3
271 teq ip, #0
272 beq .c2u_finished
273 cmp ip, #2
274USER( strbt r3, [r0], #1) @ May fault
275 ldrgeb r3, [r1], #1
276USER( strgebt r3, [r0], #1) @ May fault
277 ldrgtb r3, [r1], #0
278USER( strgtbt r3, [r0], #1) @ May fault
279 b .c2u_finished
280
281 .section .fixup,"ax"
282 .align 0
2839001: LOADREGS(fd,sp!, {r0, r4 - r7, pc})
284 .previous
285
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.
292 */
293.cfu_dest_not_aligned:
294 rsb ip, ip, #4
295 cmp ip, #2
296USER( ldrbt r3, [r1], #1) @ May fault
297 strb r3, [r0], #1
298USER( ldrgebt r3, [r1], #1) @ May fault
299 strgeb r3, [r0], #1
300USER( ldrgtbt r3, [r1], #1) @ May fault
301 strgtb r3, [r0], #1
302 sub r2, r2, ip
303 b .cfu_dest_aligned
304
305ENTRY(__arch_copy_from_user)
306 stmfd sp!, {r0, r2, r4 - r7, lr}
307 cmp r2, #4
308 blt .cfu_not_enough
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 ands ip, r0, #3
310 bne .cfu_dest_not_aligned
311.cfu_dest_aligned:
312 ands ip, r1, #3
313 bne .cfu_src_not_aligned
314/*
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...
317 */
318
319.cfu_0fupi: subs r2, r2, #4
320 addmi ip, r2, #4
321 bmi .cfu_0nowords
322USER( ldrt r3, [r1], #4)
323 str r3, [r0], #4
324 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
325 rsb ip, ip, #0
326 movs ip, ip, lsr #32 - PAGE_SHIFT
327 beq .cfu_0fupi
328/*
329 * ip = max no. of bytes to copy before needing another "strt" insn
330 */
331 cmp r2, ip
332 movlt ip, r2
333 sub r2, r2, ip
334 subs ip, ip, #32
335 blt .cfu_0rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000337.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 stmia r0!, {r3 - r6}
339 ldmia r1!, {r3 - r6} @ Shouldnt fault
340 subs ip, ip, #32
341 stmia r0!, {r3 - r6}
342 bpl .cfu_0cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344.cfu_0rem8lp: cmn ip, #16
345 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
346 stmgeia r0!, {r3 - r6}
347 tst ip, #8
348 ldmneia r1!, {r3 - r4} @ Shouldnt fault
349 stmneia r0!, {r3 - r4}
350 tst ip, #4
351 ldrnet r3, [r1], #4 @ Shouldnt fault
352 strne r3, [r0], #4
353 ands ip, ip, #3
354 beq .cfu_0fupi
355.cfu_0nowords: teq ip, #0
356 beq .cfu_finished
357.cfu_nowords: cmp ip, #2
358USER( ldrbt r3, [r1], #1) @ May fault
359 strb r3, [r0], #1
360USER( ldrgebt r3, [r1], #1) @ May fault
361 strgeb r3, [r0], #1
362USER( ldrgtbt r3, [r1], #1) @ May fault
363 strgtb r3, [r0], #1
364 b .cfu_finished
365
366.cfu_not_enough:
367 movs ip, r2
368 bne .cfu_nowords
369.cfu_finished: mov r0, #0
370 add sp, sp, #8
371 LOADREGS(fd,sp!,{r4 - r7, pc})
372
373.cfu_src_not_aligned:
374 bic r1, r1, #3
375USER( ldrt r7, [r1], #4) @ May fault
376 cmp ip, #2
377 bgt .cfu_3fupi
378 beq .cfu_2fupi
379.cfu_1fupi: subs r2, r2, #4
380 addmi ip, r2, #4
381 bmi .cfu_1nowords
382 mov r3, r7, pull #8
383USER( ldrt r7, [r1], #4) @ May fault
384 orr r3, r3, r7, push #24
385 str r3, [r0], #4
386 mov ip, r1, lsl #32 - PAGE_SHIFT
387 rsb ip, ip, #0
388 movs ip, ip, lsr #32 - PAGE_SHIFT
389 beq .cfu_1fupi
390 cmp r2, ip
391 movlt ip, r2
392 sub r2, r2, ip
393 subs ip, ip, #16
394 blt .cfu_1rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000396.cfu_1cpy8lp: mov r3, r7, pull #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 ldmia r1!, {r4 - r7} @ Shouldnt fault
398 subs ip, ip, #16
399 orr r3, r3, r4, push #24
400 mov r4, r4, pull #8
401 orr r4, r4, r5, push #24
402 mov r5, r5, pull #8
403 orr r5, r5, r6, push #24
404 mov r6, r6, pull #8
405 orr r6, r6, r7, push #24
406 stmia r0!, {r3 - r6}
407 bpl .cfu_1cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408
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}
416 tst ip, #4
417 movne r3, r7, pull #8
418USER( ldrnet r7, [r1], #4) @ May fault
419 orrne r3, r3, r7, push #24
420 strne r3, [r0], #4
421 ands ip, ip, #3
422 beq .cfu_1fupi
423.cfu_1nowords: mov r3, r7, get_byte_1
424 teq ip, #0
425 beq .cfu_finished
426 cmp ip, #2
427 strb r3, [r0], #1
428 movge r3, r7, get_byte_2
429 strgeb r3, [r0], #1
430 movgt r3, r7, get_byte_3
431 strgtb r3, [r0], #1
432 b .cfu_finished
433
434.cfu_2fupi: subs r2, r2, #4
435 addmi ip, r2, #4
436 bmi .cfu_2nowords
437 mov r3, r7, pull #16
438USER( ldrt r7, [r1], #4) @ May fault
439 orr r3, r3, r7, push #16
440 str r3, [r0], #4
441 mov ip, r1, lsl #32 - PAGE_SHIFT
442 rsb ip, ip, #0
443 movs ip, ip, lsr #32 - PAGE_SHIFT
444 beq .cfu_2fupi
445 cmp r2, ip
446 movlt ip, r2
447 sub r2, r2, ip
448 subs ip, ip, #16
449 blt .cfu_2rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000451.cfu_2cpy8lp: mov r3, r7, pull #16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 ldmia r1!, {r4 - r7} @ Shouldnt fault
453 subs ip, ip, #16
454 orr r3, r3, r4, push #16
455 mov r4, r4, pull #16
456 orr r4, r4, r5, push #16
457 mov r5, r5, pull #16
458 orr r5, r5, r6, push #16
459 mov r6, r6, pull #16
460 orr r6, r6, r7, push #16
461 stmia r0!, {r3 - r6}
462 bpl .cfu_2cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
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}
471 tst ip, #4
472 movne r3, r7, pull #16
473USER( ldrnet r7, [r1], #4) @ May fault
474 orrne r3, r3, r7, push #16
475 strne r3, [r0], #4
476 ands ip, ip, #3
477 beq .cfu_2fupi
478.cfu_2nowords: mov r3, r7, get_byte_2
479 teq ip, #0
480 beq .cfu_finished
481 cmp ip, #2
482 strb r3, [r0], #1
483 movge r3, r7, get_byte_3
484 strgeb r3, [r0], #1
485USER( ldrgtbt r3, [r1], #0) @ May fault
486 strgtb r3, [r0], #1
487 b .cfu_finished
488
489.cfu_3fupi: subs r2, r2, #4
490 addmi ip, r2, #4
491 bmi .cfu_3nowords
492 mov r3, r7, pull #24
493USER( ldrt r7, [r1], #4) @ May fault
494 orr r3, r3, r7, push #8
495 str r3, [r0], #4
496 mov ip, r1, lsl #32 - PAGE_SHIFT
497 rsb ip, ip, #0
498 movs ip, ip, lsr #32 - PAGE_SHIFT
499 beq .cfu_3fupi
500 cmp r2, ip
501 movlt ip, r2
502 sub r2, r2, ip
503 subs ip, ip, #16
504 blt .cfu_3rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505
Nicolas Pitre73f0f7c2005-11-04 17:15:43 +0000506.cfu_3cpy8lp: mov r3, r7, pull #24
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 ldmia r1!, {r4 - r7} @ Shouldnt fault
508 orr r3, r3, r4, push #8
509 mov r4, r4, pull #24
510 orr r4, r4, r5, push #8
511 mov r5, r5, pull #24
512 orr r5, r5, r6, push #8
513 mov r6, r6, pull #24
514 orr r6, r6, r7, push #8
515 stmia r0!, {r3 - r6}
516 subs ip, ip, #16
517 bpl .cfu_3cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518
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}
526 tst ip, #4
527 movne r3, r7, pull #24
528USER( ldrnet r7, [r1], #4) @ May fault
529 orrne r3, r3, r7, push #8
530 strne r3, [r0], #4
531 ands ip, ip, #3
532 beq .cfu_3fupi
533.cfu_3nowords: mov r3, r7, get_byte_3
534 teq ip, #0
535 beq .cfu_finished
536 cmp ip, #2
537 strb r3, [r0], #1
538USER( ldrgebt r3, [r1], #1) @ May fault
539 strgeb r3, [r0], #1
540USER( ldrgtbt r3, [r1], #1) @ May fault
541 strgtb r3, [r0], #1
542 b .cfu_finished
543
544 .section .fixup,"ax"
545 .align 0
546 /*
547 * We took an exception. r0 contains a pointer to
548 * the byte not copied.
549 */
5509001: 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
554 movne r1, r4
555 blne __memzero
556 mov r0, r4
557 LOADREGS(fd,sp!, {r4 - r7, pc})
558 .previous
559