Merge branch 'master'
[pandora-kernel.git] / arch / arm / lib / uaccess.S
1 /*
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
34 USER(           strbt   r3, [r0], #1)                   @ May fault
35                 ldrgeb  r3, [r1], #1
36 USER(           strgebt r3, [r0], #1)                   @ May fault
37                 ldrgtb  r3, [r1], #1
38 USER(           strgtbt r3, [r0], #1)                   @ May fault
39                 sub     r2, r2, ip
40                 b       .c2u_dest_aligned
41
42 ENTRY(__arch_copy_to_user)
43                 stmfd   sp!, {r2, r4 - r7, lr}
44                 cmp     r2, #4
45                 blt     .c2u_not_enough
46                 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
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
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
74
75 .c2u_0cpy8lp:   ldmia   r1!, {r3 - r6}
76                 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
81
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
97 USER(           strbt   r3, [r0], #1)                   @ May fault
98                 ldrgeb  r3, [r1], #1
99 USER(           strgebt r3, [r0], #1)                   @ May fault
100                 ldrgtb  r3, [r1], #1
101 USER(           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
122 USER(           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
132
133 .c2u_1cpy8lp:   mov     r3, r7, pull #8
134                 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
145
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
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
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
177 USER(           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
187
188 .c2u_2cpy8lp:   mov     r3, r7, pull #16
189                 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
200
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
219 USER(           strbt   r3, [r0], #1)                   @ May fault
220                 movge   r3, r7, get_byte_3
221 USER(           strgebt r3, [r0], #1)                   @ May fault
222                 ldrgtb  r3, [r1], #0
223 USER(           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
232 USER(           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
242
243 .c2u_3cpy8lp:   mov     r3, r7, pull #24
244                 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
255
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
274 USER(           strbt   r3, [r0], #1)                   @ May fault
275                 ldrgeb  r3, [r1], #1
276 USER(           strgebt r3, [r0], #1)                   @ May fault
277                 ldrgtb  r3, [r1], #0
278 USER(           strgtbt r3, [r0], #1)                   @ May fault
279                 b       .c2u_finished
280
281                 .section .fixup,"ax"
282                 .align  0
283 9001:           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
296 USER(           ldrbt   r3, [r1], #1)                   @ May fault
297                 strb    r3, [r0], #1
298 USER(           ldrgebt r3, [r1], #1)                   @ May fault
299                 strgeb  r3, [r0], #1
300 USER(           ldrgtbt r3, [r1], #1)                   @ May fault
301                 strgtb  r3, [r0], #1
302                 sub     r2, r2, ip
303                 b       .cfu_dest_aligned
304
305 ENTRY(__arch_copy_from_user)
306                 stmfd   sp!, {r0, r2, r4 - r7, lr}
307                 cmp     r2, #4
308                 blt     .cfu_not_enough
309                 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
322 USER(           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
336
337 .cfu_0cpy8lp:   ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
338                 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
343
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
358 USER(           ldrbt   r3, [r1], #1)                   @ May fault
359                 strb    r3, [r0], #1
360 USER(           ldrgebt r3, [r1], #1)                   @ May fault
361                 strgeb  r3, [r0], #1
362 USER(           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
375 USER(           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
383 USER(           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
395
396 .cfu_1cpy8lp:   mov     r3, r7, pull #8
397                 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
408
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
418 USER(           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
438 USER(           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
450
451 .cfu_2cpy8lp:   mov     r3, r7, pull #16
452                 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
463
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
473 USER(           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
485 USER(           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
493 USER(           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
505
506 .cfu_3cpy8lp:   mov     r3, r7, pull #24
507                 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
518
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
528 USER(           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
538 USER(           ldrgebt r3, [r1], #1)                   @ May fault
539                 strgeb  r3, [r0], #1
540 USER(           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                  */
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
554                 movne   r1, r4
555                 blne    __memzero
556                 mov     r0, r4
557                 LOADREGS(fd,sp!, {r4 - r7, pc})
558                 .previous
559