]>
Commit | Line | Data |
---|---|---|
75494230 NP |
1 | /* |
2 | * linux/arch/arm/lib/memmove.S | |
3 | * | |
4 | * Author: Nicolas Pitre | |
5 | * Created: Sep 28, 2005 | |
6 | * Copyright: (C) MontaVista Software Inc. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/linkage.h> | |
14 | #include <asm/assembler.h> | |
207a6cb0 | 15 | #include <asm/unwind.h> |
75494230 | 16 | |
75494230 NP |
17 | .text |
18 | ||
19 | /* | |
20 | * Prototype: void *memmove(void *dest, const void *src, size_t n); | |
21 | * | |
22 | * Note: | |
23 | * | |
24 | * If the memory regions don't overlap, we simply branch to memcpy which is | |
25 | * normally a bit faster. Otherwise the copy is done going downwards. This | |
26 | * is a transposition of the code from copy_template.S but with the copy | |
27 | * occurring in the opposite direction. | |
28 | */ | |
29 | ||
30 | ENTRY(memmove) | |
207a6cb0 | 31 | UNWIND( .fnstart ) |
75494230 NP |
32 | |
33 | subs ip, r0, r1 | |
34 | cmphi r2, ip | |
35 | bls memcpy | |
36 | ||
37 | stmfd sp!, {r0, r4, lr} | |
207a6cb0 LY |
38 | UNWIND( .fnend ) |
39 | ||
40 | UNWIND( .fnstart ) | |
41 | UNWIND( .save {r0, r4, lr} ) @ in first stmfd block | |
75494230 NP |
42 | add r1, r1, r2 |
43 | add r0, r0, r2 | |
44 | subs r2, r2, #4 | |
45 | blt 8f | |
46 | ands ip, r0, #3 | |
47 | PLD( pld [r1, #-4] ) | |
48 | bne 9f | |
49 | ands ip, r1, #3 | |
50 | bne 10f | |
51 | ||
52 | 1: subs r2, r2, #(28) | |
53 | stmfd sp!, {r5 - r8} | |
207a6cb0 LY |
54 | UNWIND( .fnend ) |
55 | ||
56 | UNWIND( .fnstart ) | |
57 | UNWIND( .save {r0, r4, lr} ) | |
58 | UNWIND( .save {r5 - r8} ) @ in second stmfd block | |
75494230 NP |
59 | blt 5f |
60 | ||
2239aff6 | 61 | CALGN( ands ip, r0, #31 ) |
e44fc388 | 62 | CALGN( sbcsne r4, ip, r2 ) @ C is always set here |
75494230 NP |
63 | CALGN( bcs 2f ) |
64 | CALGN( adr r4, 6f ) | |
65 | CALGN( subs r2, r2, ip ) @ C is set here | |
4c4925c1 | 66 | CALGN( rsb ip, ip, #32 ) |
75494230 NP |
67 | CALGN( add pc, r4, ip ) |
68 | ||
69 | PLD( pld [r1, #-4] ) | |
70 | 2: PLD( subs r2, r2, #96 ) | |
71 | PLD( pld [r1, #-32] ) | |
72 | PLD( blt 4f ) | |
73 | PLD( pld [r1, #-64] ) | |
74 | PLD( pld [r1, #-96] ) | |
75 | ||
76 | 3: PLD( pld [r1, #-128] ) | |
77 | 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} | |
78 | subs r2, r2, #32 | |
79 | stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} | |
80 | bge 3b | |
81 | PLD( cmn r2, #96 ) | |
82 | PLD( bge 4b ) | |
83 | ||
84 | 5: ands ip, r2, #28 | |
85 | rsb ip, ip, #32 | |
86 | addne pc, pc, ip @ C is always clear here | |
87 | b 7f | |
fd522a8d | 88 | 6: W(nop) |
8b592783 CM |
89 | W(ldr) r3, [r1, #-4]! |
90 | W(ldr) r4, [r1, #-4]! | |
91 | W(ldr) r5, [r1, #-4]! | |
92 | W(ldr) r6, [r1, #-4]! | |
93 | W(ldr) r7, [r1, #-4]! | |
94 | W(ldr) r8, [r1, #-4]! | |
95 | W(ldr) lr, [r1, #-4]! | |
75494230 NP |
96 | |
97 | add pc, pc, ip | |
98 | nop | |
fd522a8d | 99 | W(nop) |
8b592783 CM |
100 | W(str) r3, [r0, #-4]! |
101 | W(str) r4, [r0, #-4]! | |
102 | W(str) r5, [r0, #-4]! | |
103 | W(str) r6, [r0, #-4]! | |
104 | W(str) r7, [r0, #-4]! | |
105 | W(str) r8, [r0, #-4]! | |
106 | W(str) lr, [r0, #-4]! | |
75494230 NP |
107 | |
108 | CALGN( bcs 2b ) | |
109 | ||
110 | 7: ldmfd sp!, {r5 - r8} | |
207a6cb0 LY |
111 | UNWIND( .fnend ) @ end of second stmfd block |
112 | ||
113 | UNWIND( .fnstart ) | |
114 | UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block | |
75494230 NP |
115 | |
116 | 8: movs r2, r2, lsl #31 | |
e44fc388 SA |
117 | ldrbne r3, [r1, #-1]! |
118 | ldrbcs r4, [r1, #-1]! | |
119 | ldrbcs ip, [r1, #-1] | |
120 | strbne r3, [r0, #-1]! | |
121 | strbcs r4, [r0, #-1]! | |
122 | strbcs ip, [r0, #-1] | |
75494230 NP |
123 | ldmfd sp!, {r0, r4, pc} |
124 | ||
125 | 9: cmp ip, #2 | |
e44fc388 SA |
126 | ldrbgt r3, [r1, #-1]! |
127 | ldrbge r4, [r1, #-1]! | |
75494230 | 128 | ldrb lr, [r1, #-1]! |
e44fc388 SA |
129 | strbgt r3, [r0, #-1]! |
130 | strbge r4, [r0, #-1]! | |
75494230 NP |
131 | subs r2, r2, ip |
132 | strb lr, [r0, #-1]! | |
133 | blt 8b | |
134 | ands ip, r1, #3 | |
135 | beq 1b | |
136 | ||
137 | 10: bic r1, r1, #3 | |
138 | cmp ip, #2 | |
139 | ldr r3, [r1, #0] | |
140 | beq 17f | |
141 | blt 18f | |
207a6cb0 | 142 | UNWIND( .fnend ) |
75494230 NP |
143 | |
144 | ||
145 | .macro backward_copy_shift push pull | |
146 | ||
207a6cb0 LY |
147 | UNWIND( .fnstart ) |
148 | UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block | |
75494230 NP |
149 | subs r2, r2, #28 |
150 | blt 14f | |
151 | ||
2239aff6 | 152 | CALGN( ands ip, r0, #31 ) |
e44fc388 | 153 | CALGN( sbcsne r4, ip, r2 ) @ C is always set here |
75494230 NP |
154 | CALGN( subcc r2, r2, ip ) |
155 | CALGN( bcc 15f ) | |
156 | ||
157 | 11: stmfd sp!, {r5 - r9} | |
207a6cb0 LY |
158 | UNWIND( .fnend ) |
159 | ||
160 | UNWIND( .fnstart ) | |
161 | UNWIND( .save {r0, r4, lr} ) | |
162 | UNWIND( .save {r5 - r9} ) @ in new second stmfd block | |
75494230 NP |
163 | |
164 | PLD( pld [r1, #-4] ) | |
165 | PLD( subs r2, r2, #96 ) | |
166 | PLD( pld [r1, #-32] ) | |
167 | PLD( blt 13f ) | |
168 | PLD( pld [r1, #-64] ) | |
169 | PLD( pld [r1, #-96] ) | |
170 | ||
171 | 12: PLD( pld [r1, #-128] ) | |
172 | 13: ldmdb r1!, {r7, r8, r9, ip} | |
d98b90ea | 173 | mov lr, r3, lspush #\push |
75494230 NP |
174 | subs r2, r2, #32 |
175 | ldmdb r1!, {r3, r4, r5, r6} | |
d98b90ea VK |
176 | orr lr, lr, ip, lspull #\pull |
177 | mov ip, ip, lspush #\push | |
178 | orr ip, ip, r9, lspull #\pull | |
179 | mov r9, r9, lspush #\push | |
180 | orr r9, r9, r8, lspull #\pull | |
181 | mov r8, r8, lspush #\push | |
182 | orr r8, r8, r7, lspull #\pull | |
183 | mov r7, r7, lspush #\push | |
184 | orr r7, r7, r6, lspull #\pull | |
185 | mov r6, r6, lspush #\push | |
186 | orr r6, r6, r5, lspull #\pull | |
187 | mov r5, r5, lspush #\push | |
188 | orr r5, r5, r4, lspull #\pull | |
189 | mov r4, r4, lspush #\push | |
190 | orr r4, r4, r3, lspull #\pull | |
75494230 NP |
191 | stmdb r0!, {r4 - r9, ip, lr} |
192 | bge 12b | |
193 | PLD( cmn r2, #96 ) | |
194 | PLD( bge 13b ) | |
195 | ||
196 | ldmfd sp!, {r5 - r9} | |
207a6cb0 LY |
197 | UNWIND( .fnend ) @ end of the second stmfd block |
198 | ||
199 | UNWIND( .fnstart ) | |
200 | UNWIND( .save {r0, r4, lr} ) @ still in first stmfd block | |
75494230 NP |
201 | |
202 | 14: ands ip, r2, #28 | |
203 | beq 16f | |
204 | ||
d98b90ea | 205 | 15: mov lr, r3, lspush #\push |
75494230 NP |
206 | ldr r3, [r1, #-4]! |
207 | subs ip, ip, #4 | |
d98b90ea | 208 | orr lr, lr, r3, lspull #\pull |
75494230 NP |
209 | str lr, [r0, #-4]! |
210 | bgt 15b | |
211 | CALGN( cmp r2, #0 ) | |
212 | CALGN( bge 11b ) | |
213 | ||
214 | 16: add r1, r1, #(\pull / 8) | |
215 | b 8b | |
207a6cb0 | 216 | UNWIND( .fnend ) |
75494230 NP |
217 | |
218 | .endm | |
219 | ||
220 | ||
221 | backward_copy_shift push=8 pull=24 | |
222 | ||
223 | 17: backward_copy_shift push=16 pull=16 | |
224 | ||
225 | 18: backward_copy_shift push=24 pull=8 | |
226 | ||
93ed3970 | 227 | ENDPROC(memmove) |