diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-02 00:32:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-02 00:32:14 -0500 |
commit | 7f36b1e9582c06d0ddef5f2416c9b17017647d1f (patch) | |
tree | f83cbcef623476b9b8a14f7a0cc66eb92552a651 /arch/arm/lib/copy_template.S | |
parent | 0e016b9fa134d79341cca5e336ccbcea066d5f81 (diff) | |
parent | 73ee723e4c6d179c2e9496cc4caf160a18d95603 (diff) |
Merge master.kernel.org:/home/rmk/linux-2.6-arm
Diffstat (limited to 'arch/arm/lib/copy_template.S')
-rw-r--r-- | arch/arm/lib/copy_template.S | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S new file mode 100644 index 000000000000..838e435e4922 --- /dev/null +++ b/arch/arm/lib/copy_template.S | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/lib/copy_template.s | ||
3 | * | ||
4 | * Code template for optimized memory copy functions | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Sep 28, 2005 | ||
8 | * Copyright: MontaVista Software, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * This can be used to enable code to cacheline align the source pointer. | ||
17 | * Experiments on tested architectures (StrongARM and XScale) didn't show | ||
18 | * this a worthwhile thing to do. That might be different in the future. | ||
19 | */ | ||
20 | //#define CALGN(code...) code | ||
21 | #define CALGN(code...) | ||
22 | |||
23 | /* | ||
24 | * Theory of operation | ||
25 | * ------------------- | ||
26 | * | ||
27 | * This file provides the core code for a forward memory copy used in | ||
28 | * the implementation of memcopy(), copy_to_user() and copy_from_user(). | ||
29 | * | ||
30 | * The including file must define the following accessor macros | ||
31 | * according to the need of the given function: | ||
32 | * | ||
33 | * ldr1w ptr reg abort | ||
34 | * | ||
35 | * This loads one word from 'ptr', stores it in 'reg' and increments | ||
36 | * 'ptr' to the next word. The 'abort' argument is used for fixup tables. | ||
37 | * | ||
38 | * ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
39 | * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
40 | * | ||
41 | * This loads four or eight words starting from 'ptr', stores them | ||
42 | * in provided registers and increments 'ptr' past those words. | ||
43 | * The'abort' argument is used for fixup tables. | ||
44 | * | ||
45 | * ldr1b ptr reg cond abort | ||
46 | * | ||
47 | * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte. | ||
48 | * It also must apply the condition code if provided, otherwise the | ||
49 | * "al" condition is assumed by default. | ||
50 | * | ||
51 | * str1w ptr reg abort | ||
52 | * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
53 | * str1b ptr reg cond abort | ||
54 | * | ||
55 | * Same as their ldr* counterparts, but data is stored to 'ptr' location | ||
56 | * rather than being loaded. | ||
57 | * | ||
58 | * enter reg1 reg2 | ||
59 | * | ||
60 | * Preserve the provided registers on the stack plus any additional | ||
61 | * data as needed by the implementation including this code. Called | ||
62 | * upon code entry. | ||
63 | * | ||
64 | * exit reg1 reg2 | ||
65 | * | ||
66 | * Restore registers with the values previously saved with the | ||
67 | * 'preserv' macro. Called upon code termination. | ||
68 | */ | ||
69 | |||
70 | |||
71 | enter r4, lr | ||
72 | |||
73 | subs r2, r2, #4 | ||
74 | blt 8f | ||
75 | ands ip, r0, #3 | ||
76 | PLD( pld [r1, #0] ) | ||
77 | bne 9f | ||
78 | ands ip, r1, #3 | ||
79 | bne 10f | ||
80 | |||
81 | 1: subs r2, r2, #(28) | ||
82 | stmfd sp!, {r5 - r8} | ||
83 | blt 5f | ||
84 | |||
85 | CALGN( ands ip, r1, #31 ) | ||
86 | CALGN( rsb r3, ip, #32 ) | ||
87 | CALGN( sbcnes r4, r3, r2 ) @ C is always set here | ||
88 | CALGN( bcs 2f ) | ||
89 | CALGN( adr r4, 6f ) | ||
90 | CALGN( subs r2, r2, r3 ) @ C gets set | ||
91 | CALGN( add pc, r4, ip ) | ||
92 | |||
93 | PLD( pld [r1, #0] ) | ||
94 | 2: PLD( subs r2, r2, #96 ) | ||
95 | PLD( pld [r1, #28] ) | ||
96 | PLD( blt 4f ) | ||
97 | PLD( pld [r1, #60] ) | ||
98 | PLD( pld [r1, #92] ) | ||
99 | |||
100 | 3: PLD( pld [r1, #124] ) | ||
101 | 4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f | ||
102 | subs r2, r2, #32 | ||
103 | str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f | ||
104 | bge 3b | ||
105 | PLD( cmn r2, #96 ) | ||
106 | PLD( bge 4b ) | ||
107 | |||
108 | 5: ands ip, r2, #28 | ||
109 | rsb ip, ip, #32 | ||
110 | addne pc, pc, ip @ C is always clear here | ||
111 | b 7f | ||
112 | 6: nop | ||
113 | ldr1w r1, r3, abort=20f | ||
114 | ldr1w r1, r4, abort=20f | ||
115 | ldr1w r1, r5, abort=20f | ||
116 | ldr1w r1, r6, abort=20f | ||
117 | ldr1w r1, r7, abort=20f | ||
118 | ldr1w r1, r8, abort=20f | ||
119 | ldr1w r1, lr, abort=20f | ||
120 | |||
121 | add pc, pc, ip | ||
122 | nop | ||
123 | nop | ||
124 | str1w r0, r3, abort=20f | ||
125 | str1w r0, r4, abort=20f | ||
126 | str1w r0, r5, abort=20f | ||
127 | str1w r0, r6, abort=20f | ||
128 | str1w r0, r7, abort=20f | ||
129 | str1w r0, r8, abort=20f | ||
130 | str1w r0, lr, abort=20f | ||
131 | |||
132 | CALGN( bcs 2b ) | ||
133 | |||
134 | 7: ldmfd sp!, {r5 - r8} | ||
135 | |||
136 | 8: movs r2, r2, lsl #31 | ||
137 | ldr1b r1, r3, ne, abort=21f | ||
138 | ldr1b r1, r4, cs, abort=21f | ||
139 | ldr1b r1, ip, cs, abort=21f | ||
140 | str1b r0, r3, ne, abort=21f | ||
141 | str1b r0, r4, cs, abort=21f | ||
142 | str1b r0, ip, cs, abort=21f | ||
143 | |||
144 | exit r4, pc | ||
145 | |||
146 | 9: rsb ip, ip, #4 | ||
147 | cmp ip, #2 | ||
148 | ldr1b r1, r3, gt, abort=21f | ||
149 | ldr1b r1, r4, ge, abort=21f | ||
150 | ldr1b r1, lr, abort=21f | ||
151 | str1b r0, r3, gt, abort=21f | ||
152 | str1b r0, r4, ge, abort=21f | ||
153 | subs r2, r2, ip | ||
154 | str1b r0, lr, abort=21f | ||
155 | blt 8b | ||
156 | ands ip, r1, #3 | ||
157 | beq 1b | ||
158 | |||
159 | 10: bic r1, r1, #3 | ||
160 | cmp ip, #2 | ||
161 | ldr1w r1, lr, abort=21f | ||
162 | beq 17f | ||
163 | bgt 18f | ||
164 | |||
165 | |||
166 | .macro forward_copy_shift pull push | ||
167 | |||
168 | subs r2, r2, #28 | ||
169 | blt 14f | ||
170 | |||
171 | CALGN( ands ip, r1, #31 ) | ||
172 | CALGN( rsb ip, ip, #32 ) | ||
173 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
174 | CALGN( subcc r2, r2, ip ) | ||
175 | CALGN( bcc 15f ) | ||
176 | |||
177 | 11: stmfd sp!, {r5 - r9} | ||
178 | |||
179 | PLD( pld [r1, #0] ) | ||
180 | PLD( subs r2, r2, #96 ) | ||
181 | PLD( pld [r1, #28] ) | ||
182 | PLD( blt 13f ) | ||
183 | PLD( pld [r1, #60] ) | ||
184 | PLD( pld [r1, #92] ) | ||
185 | |||
186 | 12: PLD( pld [r1, #124] ) | ||
187 | 13: ldr4w r1, r4, r5, r6, r7, abort=19f | ||
188 | mov r3, lr, pull #\pull | ||
189 | subs r2, r2, #32 | ||
190 | ldr4w r1, r8, r9, ip, lr, abort=19f | ||
191 | orr r3, r3, r4, push #\push | ||
192 | mov r4, r4, pull #\pull | ||
193 | orr r4, r4, r5, push #\push | ||
194 | mov r5, r5, pull #\pull | ||
195 | orr r5, r5, r6, push #\push | ||
196 | mov r6, r6, pull #\pull | ||
197 | orr r6, r6, r7, push #\push | ||
198 | mov r7, r7, pull #\pull | ||
199 | orr r7, r7, r8, push #\push | ||
200 | mov r8, r8, pull #\pull | ||
201 | orr r8, r8, r9, push #\push | ||
202 | mov r9, r9, pull #\pull | ||
203 | orr r9, r9, ip, push #\push | ||
204 | mov ip, ip, pull #\pull | ||
205 | orr ip, ip, lr, push #\push | ||
206 | str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f | ||
207 | bge 12b | ||
208 | PLD( cmn r2, #96 ) | ||
209 | PLD( bge 13b ) | ||
210 | |||
211 | ldmfd sp!, {r5 - r9} | ||
212 | |||
213 | 14: ands ip, r2, #28 | ||
214 | beq 16f | ||
215 | |||
216 | 15: mov r3, lr, pull #\pull | ||
217 | ldr1w r1, lr, abort=21f | ||
218 | subs ip, ip, #4 | ||
219 | orr r3, r3, lr, push #\push | ||
220 | str1w r0, r3, abort=21f | ||
221 | bgt 15b | ||
222 | CALGN( cmp r2, #0 ) | ||
223 | CALGN( bge 11b ) | ||
224 | |||
225 | 16: sub r1, r1, #(\push / 8) | ||
226 | b 8b | ||
227 | |||
228 | .endm | ||
229 | |||
230 | |||
231 | forward_copy_shift pull=8 push=24 | ||
232 | |||
233 | 17: forward_copy_shift pull=16 push=16 | ||
234 | |||
235 | 18: forward_copy_shift pull=24 push=8 | ||
236 | |||
237 | |||
238 | /* | ||
239 | * Abort preanble and completion macros. | ||
240 | * If a fixup handler is required then those macros must surround it. | ||
241 | * It is assumed that the fixup code will handle the private part of | ||
242 | * the exit macro. | ||
243 | */ | ||
244 | |||
245 | .macro copy_abort_preamble | ||
246 | 19: ldmfd sp!, {r5 - r9} | ||
247 | b 21f | ||
248 | 20: ldmfd sp!, {r5 - r8} | ||
249 | 21: | ||
250 | .endm | ||
251 | |||
252 | .macro copy_abort_end | ||
253 | ldmfd sp!, {r4, pc} | ||
254 | .endm | ||
255 | |||