blob: 1addffe117c384725b1aca311f1e0d34d025f591 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: copy_page.S,v 1.8 2003/08/25 17:03:10 lethal Exp $
2 *
3 * copy_page, __copy_user_page, __copy_user implementation of SuperH
4 *
5 * Copyright (C) 2001 Niibe Yutaka & Kaz Kojima
6 * Copyright (C) 2002 Toshinobu Sugioka
7 *
8 */
9#include <linux/linkage.h>
10
11/*
12 * copy_page_slow
13 * @to: P1 address
14 * @from: P1 address
15 *
16 * void copy_page_slow(void *to, void *from)
17 */
18
19/*
20 * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
21 * r8 --- from + 4096
22 * r9 --- not used
23 * r10 --- to
24 * r11 --- from
25 */
26ENTRY(copy_page_slow)
27 mov.l r8,@-r15
28 mov.l r10,@-r15
29 mov.l r11,@-r15
30 mov r4,r10
31 mov r5,r11
32 mov r5,r8
33 mov.w .L4096,r0
34 add r0,r8
35 !
361: mov.l @r11+,r0
37 mov.l @r11+,r1
38 mov.l @r11+,r2
39 mov.l @r11+,r3
40 mov.l @r11+,r4
41 mov.l @r11+,r5
42 mov.l @r11+,r6
43 mov.l @r11+,r7
44#if defined(CONFIG_CPU_SH3)
45 mov.l r0,@r10
46#elif defined(CONFIG_CPU_SH4)
47 movca.l r0,@r10
48 mov r10,r0
49#endif
50 add #32,r10
51 mov.l r7,@-r10
52 mov.l r6,@-r10
53 mov.l r5,@-r10
54 mov.l r4,@-r10
55 mov.l r3,@-r10
56 mov.l r2,@-r10
57 mov.l r1,@-r10
58#if defined(CONFIG_CPU_SH4)
59 ocbwb @r0
60#endif
61 cmp/eq r11,r8
62 bf/s 1b
63 add #28,r10
64 !
65 mov.l @r15+,r11
66 mov.l @r15+,r10
67 mov.l @r15+,r8
68 rts
69 nop
70
71#if defined(CONFIG_CPU_SH4)
72/*
73 * __copy_user_page
74 * @to: P1 address (with same color)
75 * @from: P1 address
76 * @orig_to: P1 address
77 *
78 * void __copy_user_page(void *to, void *from, void *orig_to)
79 */
80
81/*
82 * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
83 * r8 --- from + 4096
84 * r9 --- orig_to
85 * r10 --- to
86 * r11 --- from
87 */
88ENTRY(__copy_user_page)
89 mov.l r8,@-r15
90 mov.l r9,@-r15
91 mov.l r10,@-r15
92 mov.l r11,@-r15
93 mov r4,r10
94 mov r5,r11
95 mov r6,r9
96 mov r5,r8
97 mov.w .L4096,r0
98 add r0,r8
99 !
1001: ocbi @r9
101 add #32,r9
102 mov.l @r11+,r0
103 mov.l @r11+,r1
104 mov.l @r11+,r2
105 mov.l @r11+,r3
106 mov.l @r11+,r4
107 mov.l @r11+,r5
108 mov.l @r11+,r6
109 mov.l @r11+,r7
110 movca.l r0,@r10
111 mov r10,r0
112 add #32,r10
113 mov.l r7,@-r10
114 mov.l r6,@-r10
115 mov.l r5,@-r10
116 mov.l r4,@-r10
117 mov.l r3,@-r10
118 mov.l r2,@-r10
119 mov.l r1,@-r10
120 ocbwb @r0
121 cmp/eq r11,r8
122 bf/s 1b
123 add #28,r10
124 !
125 mov.l @r15+,r11
126 mov.l @r15+,r10
127 mov.l @r15+,r9
128 mov.l @r15+,r8
129 rts
130 nop
131#endif
132.L4096: .word 4096
133/*
134 * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
135 * Return the number of bytes NOT copied
136 */
137#define EX(...) \
138 9999: __VA_ARGS__ ; \
139 .section __ex_table, "a"; \
140 .long 9999b, 6000f ; \
141 .previous
142ENTRY(__copy_user)
143 tst r6,r6 ! Check explicitly for zero
144 bf 1f
145 rts
146 mov #0,r0 ! normal return
1471:
148 mov.l r10,@-r15
149 mov.l r9,@-r15
150 mov.l r8,@-r15
151 mov r4,r3
152 add r6,r3 ! last destination address
153 mov #12,r0 ! Check if small number of bytes
154 cmp/gt r0,r6
155 bt 2f
156 bra .L_cleanup_loop
157 nop
1582:
159 neg r5,r0 ! Calculate bytes needed to align source
160 add #4,r0
161 and #3,r0
162 tst r0,r0
163 bt .L_jump
164 mov r0,r1
165
166.L_loop1:
167 ! Copy bytes to align source
168EX( mov.b @r5+,r0 )
169 dt r1
170EX( mov.b r0,@r4 )
171 add #-1,r6
172 bf/s .L_loop1
173 add #1,r4
174
175.L_jump:
176 mov r6,r2 ! Calculate number of longwords to copy
177 shlr2 r2
178 tst r2,r2
179 bt .L_cleanup
180
181 mov r4,r0 ! Jump to appropriate routine
182 and #3,r0
183 mov r0,r1
184 shll2 r1
185 mova .L_jump_tbl,r0
186 mov.l @(r0,r1),r1
187 jmp @r1
188 nop
189
190 .align 2
191.L_jump_tbl:
192 .long .L_dest00
193 .long .L_dest01
194 .long .L_dest10
195 .long .L_dest11
196
197! Destination = 00
198
199.L_dest00:
200 mov r2,r7
201 shlr2 r7
202 shlr r7
203 tst r7,r7
204 mov #7,r0
205 bt/s 1f
206 and r0,r2
207 .align 2
2082:
209EX( mov.l @r5+,r0 )
210EX( mov.l @r5+,r8 )
211EX( mov.l @r5+,r9 )
212EX( mov.l @r5+,r10 )
213EX( mov.l r0,@r4 )
214EX( mov.l r8,@(4,r4) )
215EX( mov.l r9,@(8,r4) )
216EX( mov.l r10,@(12,r4) )
217EX( mov.l @r5+,r0 )
218EX( mov.l @r5+,r8 )
219EX( mov.l @r5+,r9 )
220EX( mov.l @r5+,r10 )
221 dt r7
222EX( mov.l r0,@(16,r4) )
223EX( mov.l r8,@(20,r4) )
224EX( mov.l r9,@(24,r4) )
225EX( mov.l r10,@(28,r4) )
226 bf/s 2b
227 add #32,r4
228 tst r2,r2
229 bt .L_cleanup
2301:
231EX( mov.l @r5+,r0 )
232 dt r2
233EX( mov.l r0,@r4 )
234 bf/s 1b
235 add #4,r4
236
237 bra .L_cleanup
238 nop
239
240! Destination = 10
241
242.L_dest10:
243 mov r2,r7
244 shlr2 r7
245 shlr r7
246 tst r7,r7
247 mov #7,r0
248 bt/s 1f
249 and r0,r2
2502:
251 dt r7
252#ifdef __LITTLE_ENDIAN__
253EX( mov.l @r5+,r0 )
254EX( mov.l @r5+,r1 )
255EX( mov.l @r5+,r8 )
256EX( mov.l @r5+,r9 )
257EX( mov.l @r5+,r10 )
258EX( mov.w r0,@r4 )
259 add #2,r4
260 xtrct r1,r0
261 xtrct r8,r1
262 xtrct r9,r8
263 xtrct r10,r9
264
265EX( mov.l r0,@r4 )
266EX( mov.l r1,@(4,r4) )
267EX( mov.l r8,@(8,r4) )
268EX( mov.l r9,@(12,r4) )
269
270EX( mov.l @r5+,r1 )
271EX( mov.l @r5+,r8 )
272EX( mov.l @r5+,r0 )
273 xtrct r1,r10
274 xtrct r8,r1
275 xtrct r0,r8
276 shlr16 r0
277EX( mov.l r10,@(16,r4) )
278EX( mov.l r1,@(20,r4) )
279EX( mov.l r8,@(24,r4) )
280EX( mov.w r0,@(28,r4) )
281 bf/s 2b
282 add #30,r4
283#else
284EX( mov.l @(28,r5),r0 )
285EX( mov.l @(24,r5),r8 )
286EX( mov.l @(20,r5),r9 )
287EX( mov.l @(16,r5),r10 )
288EX( mov.w r0,@(30,r4) )
289 add #-2,r4
290 xtrct r8,r0
291 xtrct r9,r8
292 xtrct r10,r9
293EX( mov.l r0,@(28,r4) )
294EX( mov.l r8,@(24,r4) )
295EX( mov.l r9,@(20,r4) )
296
297EX( mov.l @(12,r5),r0 )
298EX( mov.l @(8,r5),r8 )
299 xtrct r0,r10
300EX( mov.l @(4,r5),r9 )
301 mov.l r10,@(16,r4)
302EX( mov.l @r5,r10 )
303 xtrct r8,r0
304 xtrct r9,r8
305 xtrct r10,r9
306EX( mov.l r0,@(12,r4) )
307EX( mov.l r8,@(8,r4) )
308 swap.w r10,r0
309EX( mov.l r9,@(4,r4) )
310EX( mov.w r0,@(2,r4) )
311
312 add #32,r5
313 bf/s 2b
314 add #34,r4
315#endif
316 tst r2,r2
317 bt .L_cleanup
318
3191: ! Read longword, write two words per iteration
320EX( mov.l @r5+,r0 )
321 dt r2
322#ifdef __LITTLE_ENDIAN__
323EX( mov.w r0,@r4 )
324 shlr16 r0
325EX( mov.w r0,@(2,r4) )
326#else
327EX( mov.w r0,@(2,r4) )
328 shlr16 r0
329EX( mov.w r0,@r4 )
330#endif
331 bf/s 1b
332 add #4,r4
333
334 bra .L_cleanup
335 nop
336
337! Destination = 01 or 11
338
339.L_dest01:
340.L_dest11:
341 ! Read longword, write byte, word, byte per iteration
342EX( mov.l @r5+,r0 )
343 dt r2
344#ifdef __LITTLE_ENDIAN__
345EX( mov.b r0,@r4 )
346 shlr8 r0
347 add #1,r4
348EX( mov.w r0,@r4 )
349 shlr16 r0
350EX( mov.b r0,@(2,r4) )
351 bf/s .L_dest01
352 add #3,r4
353#else
354EX( mov.b r0,@(3,r4) )
355 shlr8 r0
356 swap.w r0,r7
357EX( mov.b r7,@r4 )
358 add #1,r4
359EX( mov.w r0,@r4 )
360 bf/s .L_dest01
361 add #3,r4
362#endif
363
364! Cleanup last few bytes
365.L_cleanup:
366 mov r6,r0
367 and #3,r0
368 tst r0,r0
369 bt .L_exit
370 mov r0,r6
371
372.L_cleanup_loop:
373EX( mov.b @r5+,r0 )
374 dt r6
375EX( mov.b r0,@r4 )
376 bf/s .L_cleanup_loop
377 add #1,r4
378
379.L_exit:
380 mov #0,r0 ! normal return
3815000:
382
383# Exception handler:
384.section .fixup, "ax"
3856000:
386 mov.l 8000f,r1
387 mov r3,r0
388 jmp @r1
389 sub r4,r0
390 .align 2
3918000: .long 5000b
392
393.previous
394 mov.l @r15+,r8
395 mov.l @r15+,r9
396 rts
397 mov.l @r15+,r10