blob: 5c908b1cb8ed5db3eeabfb89f7f659f99d2d6f76 [file] [log] [blame]
Russell King080fc662012-08-13 11:44:13 +01001/*
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#include <asm/domain.h>
18
19 .text
20
21#define PAGE_SHIFT 12
22
23/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
24 * Purpose : copy a block to user memory from kernel memory
25 * Params : to - user memory
26 * : from - kernel memory
27 * : n - number of bytes to copy
28 * Returns : Number of bytes NOT copied.
29 */
30
31.Lc2u_dest_not_aligned:
32 rsb ip, ip, #4
33 cmp ip, #2
34 ldrb r3, [r1], #1
35USER( TUSER( strb) r3, [r0], #1) @ May fault
36 ldrgeb r3, [r1], #1
37USER( TUSER( strgeb) r3, [r0], #1) @ May fault
38 ldrgtb r3, [r1], #1
39USER( TUSER( strgtb) r3, [r0], #1) @ May fault
40 sub r2, r2, ip
41 b .Lc2u_dest_aligned
42
43ENTRY(__copy_to_user)
44 stmfd sp!, {r2, r4 - r7, lr}
45 cmp r2, #4
46 blt .Lc2u_not_enough
47 ands ip, r0, #3
48 bne .Lc2u_dest_not_aligned
49.Lc2u_dest_aligned:
50
51 ands ip, r1, #3
52 bne .Lc2u_src_not_aligned
53/*
54 * Seeing as there has to be at least 8 bytes to copy, we can
55 * copy one word, and force a user-mode page fault...
56 */
57
58.Lc2u_0fupi: subs r2, r2, #4
59 addmi ip, r2, #4
60 bmi .Lc2u_0nowords
61 ldr r3, [r1], #4
62USER( TUSER( str) r3, [r0], #4) @ May fault
63 mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
64 rsb ip, ip, #0
65 movs ip, ip, lsr #32 - PAGE_SHIFT
66 beq .Lc2u_0fupi
67/*
68 * ip = max no. of bytes to copy before needing another "strt" insn
69 */
70 cmp r2, ip
71 movlt ip, r2
72 sub r2, r2, ip
73 subs ip, ip, #32
74 blt .Lc2u_0rem8lp
75
76.Lc2u_0cpy8lp: ldmia r1!, {r3 - r6}
77 stmia r0!, {r3 - r6} @ Shouldnt fault
78 ldmia r1!, {r3 - r6}
79 subs ip, ip, #32
80 stmia r0!, {r3 - r6} @ Shouldnt fault
81 bpl .Lc2u_0cpy8lp
82
83.Lc2u_0rem8lp: cmn ip, #16
84 ldmgeia r1!, {r3 - r6}
85 stmgeia r0!, {r3 - r6} @ Shouldnt fault
86 tst ip, #8
87 ldmneia r1!, {r3 - r4}
88 stmneia r0!, {r3 - r4} @ Shouldnt fault
89 tst ip, #4
90 ldrne r3, [r1], #4
91 TUSER( strne) r3, [r0], #4 @ Shouldnt fault
92 ands ip, ip, #3
93 beq .Lc2u_0fupi
94.Lc2u_0nowords: teq ip, #0
95 beq .Lc2u_finished
96.Lc2u_nowords: cmp ip, #2
97 ldrb r3, [r1], #1
98USER( TUSER( strb) r3, [r0], #1) @ May fault
99 ldrgeb r3, [r1], #1
100USER( TUSER( strgeb) r3, [r0], #1) @ May fault
101 ldrgtb r3, [r1], #1
102USER( TUSER( strgtb) r3, [r0], #1) @ May fault
103 b .Lc2u_finished
104
105.Lc2u_not_enough:
106 movs ip, r2
107 bne .Lc2u_nowords
108.Lc2u_finished: mov r0, #0
109 ldmfd sp!, {r2, r4 - r7, pc}
110
111.Lc2u_src_not_aligned:
112 bic r1, r1, #3
113 ldr r7, [r1], #4
114 cmp ip, #2
115 bgt .Lc2u_3fupi
116 beq .Lc2u_2fupi
117.Lc2u_1fupi: subs r2, r2, #4
118 addmi ip, r2, #4
119 bmi .Lc2u_1nowords
120 mov r3, r7, pull #8
121 ldr r7, [r1], #4
122 orr r3, r3, r7, push #24
123USER( TUSER( str) r3, [r0], #4) @ May fault
124 mov ip, r0, lsl #32 - PAGE_SHIFT
125 rsb ip, ip, #0
126 movs ip, ip, lsr #32 - PAGE_SHIFT
127 beq .Lc2u_1fupi
128 cmp r2, ip
129 movlt ip, r2
130 sub r2, r2, ip
131 subs ip, ip, #16
132 blt .Lc2u_1rem8lp
133
134.Lc2u_1cpy8lp: mov r3, r7, pull #8
135 ldmia r1!, {r4 - r7}
136 subs ip, ip, #16
137 orr r3, r3, r4, push #24
138 mov r4, r4, pull #8
139 orr r4, r4, r5, push #24
140 mov r5, r5, pull #8
141 orr r5, r5, r6, push #24
142 mov r6, r6, pull #8
143 orr r6, r6, r7, push #24
144 stmia r0!, {r3 - r6} @ Shouldnt fault
145 bpl .Lc2u_1cpy8lp
146
147.Lc2u_1rem8lp: tst ip, #8
148 movne r3, r7, pull #8
149 ldmneia r1!, {r4, r7}
150 orrne r3, r3, r4, push #24
151 movne r4, r4, pull #8
152 orrne r4, r4, r7, push #24
153 stmneia r0!, {r3 - r4} @ Shouldnt fault
154 tst ip, #4
155 movne r3, r7, pull #8
156 ldrne r7, [r1], #4
157 orrne r3, r3, r7, push #24
158 TUSER( strne) r3, [r0], #4 @ Shouldnt fault
159 ands ip, ip, #3
160 beq .Lc2u_1fupi
161.Lc2u_1nowords: mov r3, r7, get_byte_1
162 teq ip, #0
163 beq .Lc2u_finished
164 cmp ip, #2
165USER( TUSER( strb) r3, [r0], #1) @ May fault
166 movge r3, r7, get_byte_2
167USER( TUSER( strgeb) r3, [r0], #1) @ May fault
168 movgt r3, r7, get_byte_3
169USER( TUSER( strgtb) r3, [r0], #1) @ May fault
170 b .Lc2u_finished
171
172.Lc2u_2fupi: subs r2, r2, #4
173 addmi ip, r2, #4
174 bmi .Lc2u_2nowords
175 mov r3, r7, pull #16
176 ldr r7, [r1], #4
177 orr r3, r3, r7, push #16
178USER( TUSER( str) r3, [r0], #4) @ May fault
179 mov ip, r0, lsl #32 - PAGE_SHIFT
180 rsb ip, ip, #0
181 movs ip, ip, lsr #32 - PAGE_SHIFT
182 beq .Lc2u_2fupi
183 cmp r2, ip
184 movlt ip, r2
185 sub r2, r2, ip
186 subs ip, ip, #16
187 blt .Lc2u_2rem8lp
188
189.Lc2u_2cpy8lp: mov r3, r7, pull #16
190 ldmia r1!, {r4 - r7}
191 subs ip, ip, #16
192 orr r3, r3, r4, push #16
193 mov r4, r4, pull #16
194 orr r4, r4, r5, push #16
195 mov r5, r5, pull #16
196 orr r5, r5, r6, push #16
197 mov r6, r6, pull #16
198 orr r6, r6, r7, push #16
199 stmia r0!, {r3 - r6} @ Shouldnt fault
200 bpl .Lc2u_2cpy8lp
201
202.Lc2u_2rem8lp: tst ip, #8
203 movne r3, r7, pull #16
204 ldmneia r1!, {r4, r7}
205 orrne r3, r3, r4, push #16
206 movne r4, r4, pull #16
207 orrne r4, r4, r7, push #16
208 stmneia r0!, {r3 - r4} @ Shouldnt fault
209 tst ip, #4
210 movne r3, r7, pull #16
211 ldrne r7, [r1], #4
212 orrne r3, r3, r7, push #16
213 TUSER( strne) r3, [r0], #4 @ Shouldnt fault
214 ands ip, ip, #3
215 beq .Lc2u_2fupi
216.Lc2u_2nowords: mov r3, r7, get_byte_2
217 teq ip, #0
218 beq .Lc2u_finished
219 cmp ip, #2
220USER( TUSER( strb) r3, [r0], #1) @ May fault
221 movge r3, r7, get_byte_3
222USER( TUSER( strgeb) r3, [r0], #1) @ May fault
223 ldrgtb r3, [r1], #0
224USER( TUSER( strgtb) r3, [r0], #1) @ May fault
225 b .Lc2u_finished
226
227.Lc2u_3fupi: subs r2, r2, #4
228 addmi ip, r2, #4
229 bmi .Lc2u_3nowords
230 mov r3, r7, pull #24
231 ldr r7, [r1], #4
232 orr r3, r3, r7, push #8
233USER( TUSER( str) r3, [r0], #4) @ May fault
234 mov ip, r0, lsl #32 - PAGE_SHIFT
235 rsb ip, ip, #0
236 movs ip, ip, lsr #32 - PAGE_SHIFT
237 beq .Lc2u_3fupi
238 cmp r2, ip
239 movlt ip, r2
240 sub r2, r2, ip
241 subs ip, ip, #16
242 blt .Lc2u_3rem8lp
243
244.Lc2u_3cpy8lp: mov r3, r7, pull #24
245 ldmia r1!, {r4 - r7}
246 subs ip, ip, #16
247 orr r3, r3, r4, push #8
248 mov r4, r4, pull #24
249 orr r4, r4, r5, push #8
250 mov r5, r5, pull #24
251 orr r5, r5, r6, push #8
252 mov r6, r6, pull #24
253 orr r6, r6, r7, push #8
254 stmia r0!, {r3 - r6} @ Shouldnt fault
255 bpl .Lc2u_3cpy8lp
256
257.Lc2u_3rem8lp: tst ip, #8
258 movne r3, r7, pull #24
259 ldmneia r1!, {r4, r7}
260 orrne r3, r3, r4, push #8
261 movne r4, r4, pull #24
262 orrne r4, r4, r7, push #8
263 stmneia r0!, {r3 - r4} @ Shouldnt fault
264 tst ip, #4
265 movne r3, r7, pull #24
266 ldrne r7, [r1], #4
267 orrne r3, r3, r7, push #8
268 TUSER( strne) r3, [r0], #4 @ Shouldnt fault
269 ands ip, ip, #3
270 beq .Lc2u_3fupi
271.Lc2u_3nowords: mov r3, r7, get_byte_3
272 teq ip, #0
273 beq .Lc2u_finished
274 cmp ip, #2
275USER( TUSER( strb) r3, [r0], #1) @ May fault
276 ldrgeb r3, [r1], #1
277USER( TUSER( strgeb) r3, [r0], #1) @ May fault
278 ldrgtb r3, [r1], #0
279USER( TUSER( strgtb) r3, [r0], #1) @ May fault
280 b .Lc2u_finished
281ENDPROC(__copy_to_user)
282
283 .pushsection .fixup,"ax"
284 .align 0
2859001: ldmfd sp!, {r0, r4 - r7, pc}
286 .popsection
287
288/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
289 * Purpose : copy a block from user memory to kernel memory
290 * Params : to - kernel memory
291 * : from - user memory
292 * : n - number of bytes to copy
293 * Returns : Number of bytes NOT copied.
294 */
295.Lcfu_dest_not_aligned:
296 rsb ip, ip, #4
297 cmp ip, #2
298USER( TUSER( ldrb) r3, [r1], #1) @ May fault
299 strb r3, [r0], #1
300USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault
301 strgeb r3, [r0], #1
302USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault
303 strgtb r3, [r0], #1
304 sub r2, r2, ip
305 b .Lcfu_dest_aligned
306
307ENTRY(__copy_from_user)
308 stmfd sp!, {r0, r2, r4 - r7, lr}
309 cmp r2, #4
310 blt .Lcfu_not_enough
311 ands ip, r0, #3
312 bne .Lcfu_dest_not_aligned
313.Lcfu_dest_aligned:
314 ands ip, r1, #3
315 bne .Lcfu_src_not_aligned
316
317/*
318 * Seeing as there has to be at least 8 bytes to copy, we can
319 * copy one word, and force a user-mode page fault...
320 */
321
322.Lcfu_0fupi: subs r2, r2, #4
323 addmi ip, r2, #4
324 bmi .Lcfu_0nowords
325USER( TUSER( ldr) r3, [r1], #4)
326 str r3, [r0], #4
327 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
328 rsb ip, ip, #0
329 movs ip, ip, lsr #32 - PAGE_SHIFT
330 beq .Lcfu_0fupi
331/*
332 * ip = max no. of bytes to copy before needing another "strt" insn
333 */
334 cmp r2, ip
335 movlt ip, r2
336 sub r2, r2, ip
337 subs ip, ip, #32
338 blt .Lcfu_0rem8lp
339
340.Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
341 stmia r0!, {r3 - r6}
342 ldmia r1!, {r3 - r6} @ Shouldnt fault
343 subs ip, ip, #32
344 stmia r0!, {r3 - r6}
345 bpl .Lcfu_0cpy8lp
346
347.Lcfu_0rem8lp: cmn ip, #16
348 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
349 stmgeia r0!, {r3 - r6}
350 tst ip, #8
351 ldmneia r1!, {r3 - r4} @ Shouldnt fault
352 stmneia r0!, {r3 - r4}
353 tst ip, #4
354 TUSER( ldrne) r3, [r1], #4 @ Shouldnt fault
355 strne r3, [r0], #4
356 ands ip, ip, #3
357 beq .Lcfu_0fupi
358.Lcfu_0nowords: teq ip, #0
359 beq .Lcfu_finished
360.Lcfu_nowords: cmp ip, #2
361USER( TUSER( ldrb) r3, [r1], #1) @ May fault
362 strb r3, [r0], #1
363USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault
364 strgeb r3, [r0], #1
365USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault
366 strgtb r3, [r0], #1
367 b .Lcfu_finished
368
369.Lcfu_not_enough:
370 movs ip, r2
371 bne .Lcfu_nowords
372.Lcfu_finished: mov r0, #0
373 add sp, sp, #8
374 ldmfd sp!, {r4 - r7, pc}
375
376.Lcfu_src_not_aligned:
377 bic r1, r1, #3
378USER( TUSER( ldr) r7, [r1], #4) @ May fault
379 cmp ip, #2
380 bgt .Lcfu_3fupi
381 beq .Lcfu_2fupi
382.Lcfu_1fupi: subs r2, r2, #4
383 addmi ip, r2, #4
384 bmi .Lcfu_1nowords
385 mov r3, r7, pull #8
386USER( TUSER( ldr) r7, [r1], #4) @ May fault
387 orr r3, r3, r7, push #24
388 str r3, [r0], #4
389 mov ip, r1, lsl #32 - PAGE_SHIFT
390 rsb ip, ip, #0
391 movs ip, ip, lsr #32 - PAGE_SHIFT
392 beq .Lcfu_1fupi
393 cmp r2, ip
394 movlt ip, r2
395 sub r2, r2, ip
396 subs ip, ip, #16
397 blt .Lcfu_1rem8lp
398
399.Lcfu_1cpy8lp: mov r3, r7, pull #8
400 ldmia r1!, {r4 - r7} @ Shouldnt fault
401 subs ip, ip, #16
402 orr r3, r3, r4, push #24
403 mov r4, r4, pull #8
404 orr r4, r4, r5, push #24
405 mov r5, r5, pull #8
406 orr r5, r5, r6, push #24
407 mov r6, r6, pull #8
408 orr r6, r6, r7, push #24
409 stmia r0!, {r3 - r6}
410 bpl .Lcfu_1cpy8lp
411
412.Lcfu_1rem8lp: tst ip, #8
413 movne r3, r7, pull #8
414 ldmneia r1!, {r4, r7} @ Shouldnt fault
415 orrne r3, r3, r4, push #24
416 movne r4, r4, pull #8
417 orrne r4, r4, r7, push #24
418 stmneia r0!, {r3 - r4}
419 tst ip, #4
420 movne r3, r7, pull #8
421USER( TUSER( ldrne) r7, [r1], #4) @ May fault
422 orrne r3, r3, r7, push #24
423 strne r3, [r0], #4
424 ands ip, ip, #3
425 beq .Lcfu_1fupi
426.Lcfu_1nowords: mov r3, r7, get_byte_1
427 teq ip, #0
428 beq .Lcfu_finished
429 cmp ip, #2
430 strb r3, [r0], #1
431 movge r3, r7, get_byte_2
432 strgeb r3, [r0], #1
433 movgt r3, r7, get_byte_3
434 strgtb r3, [r0], #1
435 b .Lcfu_finished
436
437.Lcfu_2fupi: subs r2, r2, #4
438 addmi ip, r2, #4
439 bmi .Lcfu_2nowords
440 mov r3, r7, pull #16
441USER( TUSER( ldr) r7, [r1], #4) @ May fault
442 orr r3, r3, r7, push #16
443 str r3, [r0], #4
444 mov ip, r1, lsl #32 - PAGE_SHIFT
445 rsb ip, ip, #0
446 movs ip, ip, lsr #32 - PAGE_SHIFT
447 beq .Lcfu_2fupi
448 cmp r2, ip
449 movlt ip, r2
450 sub r2, r2, ip
451 subs ip, ip, #16
452 blt .Lcfu_2rem8lp
453
454
455.Lcfu_2cpy8lp: mov r3, r7, pull #16
456 ldmia r1!, {r4 - r7} @ Shouldnt fault
457 subs ip, ip, #16
458 orr r3, r3, r4, push #16
459 mov r4, r4, pull #16
460 orr r4, r4, r5, push #16
461 mov r5, r5, pull #16
462 orr r5, r5, r6, push #16
463 mov r6, r6, pull #16
464 orr r6, r6, r7, push #16
465 stmia r0!, {r3 - r6}
466 bpl .Lcfu_2cpy8lp
467
468.Lcfu_2rem8lp: tst ip, #8
469 movne r3, r7, pull #16
470 ldmneia r1!, {r4, r7} @ Shouldnt fault
471 orrne r3, r3, r4, push #16
472 movne r4, r4, pull #16
473 orrne r4, r4, r7, push #16
474 stmneia r0!, {r3 - r4}
475 tst ip, #4
476 movne r3, r7, pull #16
477USER( TUSER( ldrne) r7, [r1], #4) @ May fault
478 orrne r3, r3, r7, push #16
479 strne r3, [r0], #4
480 ands ip, ip, #3
481 beq .Lcfu_2fupi
482.Lcfu_2nowords: mov r3, r7, get_byte_2
483 teq ip, #0
484 beq .Lcfu_finished
485 cmp ip, #2
486 strb r3, [r0], #1
487 movge r3, r7, get_byte_3
488 strgeb r3, [r0], #1
489USER( TUSER( ldrgtb) r3, [r1], #0) @ May fault
490 strgtb r3, [r0], #1
491 b .Lcfu_finished
492
493.Lcfu_3fupi: subs r2, r2, #4
494 addmi ip, r2, #4
495 bmi .Lcfu_3nowords
496 mov r3, r7, pull #24
497USER( TUSER( ldr) r7, [r1], #4) @ May fault
498 orr r3, r3, r7, push #8
499 str r3, [r0], #4
500 mov ip, r1, lsl #32 - PAGE_SHIFT
501 rsb ip, ip, #0
502 movs ip, ip, lsr #32 - PAGE_SHIFT
503 beq .Lcfu_3fupi
504 cmp r2, ip
505 movlt ip, r2
506 sub r2, r2, ip
507 subs ip, ip, #16
508 blt .Lcfu_3rem8lp
509
510.Lcfu_3cpy8lp: mov r3, r7, pull #24
511 ldmia r1!, {r4 - r7} @ Shouldnt fault
512 orr r3, r3, r4, push #8
513 mov r4, r4, pull #24
514 orr r4, r4, r5, push #8
515 mov r5, r5, pull #24
516 orr r5, r5, r6, push #8
517 mov r6, r6, pull #24
518 orr r6, r6, r7, push #8
519 stmia r0!, {r3 - r6}
520 subs ip, ip, #16
521 bpl .Lcfu_3cpy8lp
522
523.Lcfu_3rem8lp: tst ip, #8
524 movne r3, r7, pull #24
525 ldmneia r1!, {r4, r7} @ Shouldnt fault
526 orrne r3, r3, r4, push #8
527 movne r4, r4, pull #24
528 orrne r4, r4, r7, push #8
529 stmneia r0!, {r3 - r4}
530 tst ip, #4
531 movne r3, r7, pull #24
532USER( TUSER( ldrne) r7, [r1], #4) @ May fault
533 orrne r3, r3, r7, push #8
534 strne r3, [r0], #4
535 ands ip, ip, #3
536 beq .Lcfu_3fupi
537.Lcfu_3nowords: mov r3, r7, get_byte_3
538 teq ip, #0
539 beq .Lcfu_finished
540 cmp ip, #2
541 strb r3, [r0], #1
542USER( TUSER( ldrgeb) r3, [r1], #1) @ May fault
543 strgeb r3, [r0], #1
544USER( TUSER( ldrgtb) r3, [r1], #1) @ May fault
545 strgtb r3, [r0], #1
546 b .Lcfu_finished
547ENDPROC(__copy_from_user)
548
549 .pushsection .fixup,"ax"
550 .align 0
551 /*
552 * We took an exception. r0 contains a pointer to
553 * the byte not copied.
554 */
5559001: ldr r2, [sp], #4 @ void *to
556 sub r2, r0, r2 @ bytes copied
557 ldr r1, [sp], #4 @ unsigned long count
558 subs r4, r1, r2 @ bytes left to copy
559 movne r1, r4
560 blne __memzero
561 mov r0, r4
562 ldmfd sp!, {r4 - r7, pc}
563 .popsection
564