blob: fee9f6f88adb5eddf11f78ac8345423256381757 [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
Russell King02fcb972006-06-21 14:44:52 +010022/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 * 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000030.Lc2u_dest_not_aligned:
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000040 b .Lc2u_dest_aligned
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Russell King02fcb972006-06-21 14:44:52 +010042ENTRY(__copy_to_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 stmfd sp!, {r2, r4 - r7, lr}
44 cmp r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000045 blt .Lc2u_not_enough
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 ands ip, r0, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000047 bne .Lc2u_dest_not_aligned
48.Lc2u_dest_aligned:
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50 ands ip, r1, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000051 bne .Lc2u_src_not_aligned
Linus Torvalds1da177e2005-04-16 15:20:36 -070052/*
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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000057.Lc2u_0fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000059 bmi .Lc2u_0nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000065 beq .Lc2u_0fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -070066/*
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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000073 blt .Lc2u_0rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000075.Lc2u_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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000080 bpl .Lc2u_0cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000082.Lc2u_0rem8lp: cmn ip, #16
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +000092 beq .Lc2u_0fupi
93.Lc2u_0nowords: teq ip, #0
94 beq .Lc2u_finished
95.Lc2u_nowords: cmp ip, #2
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000102 b .Lc2u_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000104.Lc2u_not_enough:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 movs ip, r2
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000106 bne .Lc2u_nowords
107.Lc2u_finished: mov r0, #0
Russell King1b93a712006-06-25 11:23:45 +0100108 ldmfd sp!, {r2, r4 - r7, pc}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000110.Lc2u_src_not_aligned:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 bic r1, r1, #3
112 ldr r7, [r1], #4
113 cmp ip, #2
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000114 bgt .Lc2u_3fupi
115 beq .Lc2u_2fupi
116.Lc2u_1fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000118 bmi .Lc2u_1nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000126 beq .Lc2u_1fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 cmp r2, ip
128 movlt ip, r2
129 sub r2, r2, ip
130 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000131 blt .Lc2u_1rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000133.Lc2u_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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000144 bpl .Lc2u_1cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000146.Lc2u_1rem8lp: tst ip, #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000159 beq .Lc2u_1fupi
160.Lc2u_1nowords: mov r3, r7, get_byte_1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 teq ip, #0
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000162 beq .Lc2u_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000169 b .Lc2u_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000171.Lc2u_2fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000173 bmi .Lc2u_2nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000181 beq .Lc2u_2fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 cmp r2, ip
183 movlt ip, r2
184 sub r2, r2, ip
185 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000186 blt .Lc2u_2rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000188.Lc2u_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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000199 bpl .Lc2u_2cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000201.Lc2u_2rem8lp: tst ip, #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000214 beq .Lc2u_2fupi
215.Lc2u_2nowords: mov r3, r7, get_byte_2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 teq ip, #0
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000217 beq .Lc2u_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000224 b .Lc2u_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000226.Lc2u_3fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000228 bmi .Lc2u_3nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000236 beq .Lc2u_3fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 cmp r2, ip
238 movlt ip, r2
239 sub r2, r2, ip
240 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000241 blt .Lc2u_3rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000243.Lc2u_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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000254 bpl .Lc2u_3cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000256.Lc2u_3rem8lp: tst ip, #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000269 beq .Lc2u_3fupi
270.Lc2u_3nowords: mov r3, r7, get_byte_3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 teq ip, #0
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000272 beq .Lc2u_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 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
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000279 b .Lc2u_finished
Catalin Marinas93ed3972008-08-28 11:22:32 +0100280ENDPROC(__copy_to_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Russell King42604152010-04-19 10:15:03 +0100282 .pushsection .fixup,"ax"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 .align 0
Russell King1b93a712006-06-25 11:23:45 +01002849001: ldmfd sp!, {r0, r4 - r7, pc}
Russell King42604152010-04-19 10:15:03 +0100285 .popsection
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Russell King02fcb972006-06-21 14:44:52 +0100287/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 * 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.
293 */
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000294.Lcfu_dest_not_aligned:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 rsb ip, ip, #4
296 cmp ip, #2
297USER( ldrbt r3, [r1], #1) @ May fault
298 strb r3, [r0], #1
299USER( ldrgebt r3, [r1], #1) @ May fault
300 strgeb r3, [r0], #1
301USER( ldrgtbt r3, [r1], #1) @ May fault
302 strgtb r3, [r0], #1
303 sub r2, r2, ip
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000304 b .Lcfu_dest_aligned
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Russell King02fcb972006-06-21 14:44:52 +0100306ENTRY(__copy_from_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 stmfd sp!, {r0, r2, r4 - r7, lr}
308 cmp r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000309 blt .Lcfu_not_enough
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 ands ip, r0, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000311 bne .Lcfu_dest_not_aligned
312.Lcfu_dest_aligned:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 ands ip, r1, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000314 bne .Lcfu_src_not_aligned
315
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316/*
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...
319 */
320
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000321.Lcfu_0fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000323 bmi .Lcfu_0nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324USER( ldrt r3, [r1], #4)
325 str r3, [r0], #4
326 mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction
327 rsb ip, ip, #0
328 movs ip, ip, lsr #32 - PAGE_SHIFT
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000329 beq .Lcfu_0fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330/*
331 * ip = max no. of bytes to copy before needing another "strt" insn
332 */
333 cmp r2, ip
334 movlt ip, r2
335 sub r2, r2, ip
336 subs ip, ip, #32
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000337 blt .Lcfu_0rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000339.Lcfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 stmia r0!, {r3 - r6}
341 ldmia r1!, {r3 - r6} @ Shouldnt fault
342 subs ip, ip, #32
343 stmia r0!, {r3 - r6}
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000344 bpl .Lcfu_0cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000346.Lcfu_0rem8lp: cmn ip, #16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 ldmgeia r1!, {r3 - r6} @ Shouldnt fault
348 stmgeia r0!, {r3 - r6}
349 tst ip, #8
350 ldmneia r1!, {r3 - r4} @ Shouldnt fault
351 stmneia r0!, {r3 - r4}
352 tst ip, #4
353 ldrnet r3, [r1], #4 @ Shouldnt fault
354 strne r3, [r0], #4
355 ands ip, ip, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000356 beq .Lcfu_0fupi
357.Lcfu_0nowords: teq ip, #0
358 beq .Lcfu_finished
359.Lcfu_nowords: cmp ip, #2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360USER( ldrbt r3, [r1], #1) @ May fault
361 strb r3, [r0], #1
362USER( ldrgebt r3, [r1], #1) @ May fault
363 strgeb r3, [r0], #1
364USER( ldrgtbt r3, [r1], #1) @ May fault
365 strgtb r3, [r0], #1
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000366 b .Lcfu_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000368.Lcfu_not_enough:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 movs ip, r2
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000370 bne .Lcfu_nowords
371.Lcfu_finished: mov r0, #0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 add sp, sp, #8
Russell King1b93a712006-06-25 11:23:45 +0100373 ldmfd sp!, {r4 - r7, pc}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000375.Lcfu_src_not_aligned:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 bic r1, r1, #3
377USER( ldrt r7, [r1], #4) @ May fault
378 cmp ip, #2
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000379 bgt .Lcfu_3fupi
380 beq .Lcfu_2fupi
381.Lcfu_1fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000383 bmi .Lcfu_1nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 mov r3, r7, pull #8
385USER( ldrt r7, [r1], #4) @ May fault
386 orr r3, r3, r7, push #24
387 str r3, [r0], #4
388 mov ip, r1, lsl #32 - PAGE_SHIFT
389 rsb ip, ip, #0
390 movs ip, ip, lsr #32 - PAGE_SHIFT
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000391 beq .Lcfu_1fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 cmp r2, ip
393 movlt ip, r2
394 sub r2, r2, ip
395 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000396 blt .Lcfu_1rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000398.Lcfu_1cpy8lp: mov r3, r7, pull #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 ldmia r1!, {r4 - r7} @ Shouldnt fault
400 subs ip, ip, #16
401 orr r3, r3, r4, push #24
402 mov r4, r4, pull #8
403 orr r4, r4, r5, push #24
404 mov r5, r5, pull #8
405 orr r5, r5, r6, push #24
406 mov r6, r6, pull #8
407 orr r6, r6, r7, push #24
408 stmia r0!, {r3 - r6}
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000409 bpl .Lcfu_1cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000411.Lcfu_1rem8lp: tst ip, #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 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}
418 tst ip, #4
419 movne r3, r7, pull #8
420USER( ldrnet r7, [r1], #4) @ May fault
421 orrne r3, r3, r7, push #24
422 strne r3, [r0], #4
423 ands ip, ip, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000424 beq .Lcfu_1fupi
425.Lcfu_1nowords: mov r3, r7, get_byte_1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 teq ip, #0
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000427 beq .Lcfu_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 cmp ip, #2
429 strb r3, [r0], #1
430 movge r3, r7, get_byte_2
431 strgeb r3, [r0], #1
432 movgt r3, r7, get_byte_3
433 strgtb r3, [r0], #1
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000434 b .Lcfu_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000436.Lcfu_2fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000438 bmi .Lcfu_2nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 mov r3, r7, pull #16
440USER( ldrt r7, [r1], #4) @ May fault
441 orr r3, r3, r7, push #16
442 str r3, [r0], #4
443 mov ip, r1, lsl #32 - PAGE_SHIFT
444 rsb ip, ip, #0
445 movs ip, ip, lsr #32 - PAGE_SHIFT
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000446 beq .Lcfu_2fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 cmp r2, ip
448 movlt ip, r2
449 sub r2, r2, ip
450 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000451 blt .Lcfu_2rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000453
454.Lcfu_2cpy8lp: mov r3, r7, pull #16
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 ldmia r1!, {r4 - r7} @ Shouldnt fault
456 subs ip, ip, #16
457 orr r3, r3, r4, push #16
458 mov r4, r4, pull #16
459 orr r4, r4, r5, push #16
460 mov r5, r5, pull #16
461 orr r5, r5, r6, push #16
462 mov r6, r6, pull #16
463 orr r6, r6, r7, push #16
464 stmia r0!, {r3 - r6}
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000465 bpl .Lcfu_2cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000467.Lcfu_2rem8lp: tst ip, #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 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}
474 tst ip, #4
475 movne r3, r7, pull #16
476USER( ldrnet r7, [r1], #4) @ May fault
477 orrne r3, r3, r7, push #16
478 strne r3, [r0], #4
479 ands ip, ip, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000480 beq .Lcfu_2fupi
481.Lcfu_2nowords: mov r3, r7, get_byte_2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 teq ip, #0
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000483 beq .Lcfu_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 cmp ip, #2
485 strb r3, [r0], #1
486 movge r3, r7, get_byte_3
487 strgeb r3, [r0], #1
488USER( ldrgtbt r3, [r1], #0) @ May fault
489 strgtb r3, [r0], #1
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000490 b .Lcfu_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000492.Lcfu_3fupi: subs r2, r2, #4
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 addmi ip, r2, #4
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000494 bmi .Lcfu_3nowords
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 mov r3, r7, pull #24
496USER( ldrt r7, [r1], #4) @ May fault
497 orr r3, r3, r7, push #8
498 str r3, [r0], #4
499 mov ip, r1, lsl #32 - PAGE_SHIFT
500 rsb ip, ip, #0
501 movs ip, ip, lsr #32 - PAGE_SHIFT
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000502 beq .Lcfu_3fupi
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 cmp r2, ip
504 movlt ip, r2
505 sub r2, r2, ip
506 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000507 blt .Lcfu_3rem8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000509.Lcfu_3cpy8lp: mov r3, r7, pull #24
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 ldmia r1!, {r4 - r7} @ Shouldnt fault
511 orr r3, r3, r4, push #8
512 mov r4, r4, pull #24
513 orr r4, r4, r5, push #8
514 mov r5, r5, pull #24
515 orr r5, r5, r6, push #8
516 mov r6, r6, pull #24
517 orr r6, r6, r7, push #8
518 stmia r0!, {r3 - r6}
519 subs ip, ip, #16
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000520 bpl .Lcfu_3cpy8lp
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000522.Lcfu_3rem8lp: tst ip, #8
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 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}
529 tst ip, #4
530 movne r3, r7, pull #24
531USER( ldrnet r7, [r1], #4) @ May fault
532 orrne r3, r3, r7, push #8
533 strne r3, [r0], #4
534 ands ip, ip, #3
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000535 beq .Lcfu_3fupi
536.Lcfu_3nowords: mov r3, r7, get_byte_3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 teq ip, #0
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000538 beq .Lcfu_finished
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 cmp ip, #2
540 strb r3, [r0], #1
541USER( ldrgebt r3, [r1], #1) @ May fault
542 strgeb r3, [r0], #1
543USER( ldrgtbt r3, [r1], #1) @ May fault
544 strgtb r3, [r0], #1
Nicolas Pitre7ba11a92005-11-11 21:51:47 +0000545 b .Lcfu_finished
Catalin Marinas93ed3972008-08-28 11:22:32 +0100546ENDPROC(__copy_from_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547
Russell King42604152010-04-19 10:15:03 +0100548 .pushsection .fixup,"ax"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 .align 0
550 /*
551 * We took an exception. r0 contains a pointer to
552 * the byte not copied.
553 */
5549001: 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
558 movne r1, r4
559 blne __memzero
560 mov r0, r4
Russell King1b93a712006-06-25 11:23:45 +0100561 ldmfd sp!, {r4 - r7, pc}
Russell King42604152010-04-19 10:15:03 +0100562 .popsection
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563