Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[linux-2.6] / arch / sh / mm / copy_page.S
1 /*
2  * copy_page, __copy_user_page, __copy_user implementation of SuperH
3  *
4  * Copyright (C) 2001  Niibe Yutaka & Kaz Kojima
5  * Copyright (C) 2002  Toshinobu Sugioka
6  * Copyright (C) 2006  Paul Mundt
7  */
8 #include <linux/linkage.h>
9 #include <asm/page.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 + PAGE_SIZE
22  * r9 --- not used
23  * r10 --- to
24  * r11 --- from
25  */
26 ENTRY(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.l   .Lpsz,r0
34         add     r0,r8
35         !
36 1:      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 + PAGE_SIZE
84  * r9 --- orig_to
85  * r10 --- to
86  * r11 --- from
87  */
88 ENTRY(__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.l   .Lpsz,r0
98         add     r0,r8
99         !
100 1:      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 .Lpsz:  .long   PAGE_SIZE
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
142 ENTRY(__copy_user)
143         tst     r6,r6           ! Check explicitly for zero
144         bf      1f
145         rts
146          mov    #0,r0           ! normal return
147 1:
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
158 2:
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
168 EX(     mov.b   @r5+,r0         )
169         dt      r1
170 EX(     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
208 2:
209 EX(     mov.l   @r5+,r0         )
210 EX(     mov.l   @r5+,r8         )
211 EX(     mov.l   @r5+,r9         )
212 EX(     mov.l   @r5+,r10        )
213 EX(     mov.l   r0,@r4          )
214 EX(     mov.l   r8,@(4,r4)      )
215 EX(     mov.l   r9,@(8,r4)      )
216 EX(     mov.l   r10,@(12,r4)    )
217 EX(     mov.l   @r5+,r0         )
218 EX(     mov.l   @r5+,r8         )
219 EX(     mov.l   @r5+,r9         )
220 EX(     mov.l   @r5+,r10        )
221         dt      r7
222 EX(     mov.l   r0,@(16,r4)     )
223 EX(     mov.l   r8,@(20,r4)     )
224 EX(     mov.l   r9,@(24,r4)     )
225 EX(     mov.l   r10,@(28,r4)    )
226         bf/s    2b
227          add    #32,r4
228         tst     r2,r2
229         bt      .L_cleanup
230 1:
231 EX(     mov.l   @r5+,r0         )
232         dt      r2
233 EX(     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
250 2:
251         dt      r7
252 #ifdef __LITTLE_ENDIAN__
253 EX(     mov.l   @r5+,r0         )
254 EX(     mov.l   @r5+,r1         )
255 EX(     mov.l   @r5+,r8         )
256 EX(     mov.l   @r5+,r9         )
257 EX(     mov.l   @r5+,r10        )
258 EX(     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
265 EX(     mov.l   r0,@r4          )
266 EX(     mov.l   r1,@(4,r4)      )
267 EX(     mov.l   r8,@(8,r4)      )
268 EX(     mov.l   r9,@(12,r4)     )
269
270 EX(     mov.l   @r5+,r1         )
271 EX(     mov.l   @r5+,r8         )
272 EX(     mov.l   @r5+,r0         )
273         xtrct   r1,r10
274         xtrct   r8,r1
275         xtrct   r0,r8
276         shlr16  r0
277 EX(     mov.l   r10,@(16,r4)    )
278 EX(     mov.l   r1,@(20,r4)     )
279 EX(     mov.l   r8,@(24,r4)     )
280 EX(     mov.w   r0,@(28,r4)     )
281         bf/s    2b
282          add    #30,r4
283 #else
284 EX(     mov.l   @(28,r5),r0     )
285 EX(     mov.l   @(24,r5),r8     )
286 EX(     mov.l   @(20,r5),r9     )
287 EX(     mov.l   @(16,r5),r10    )
288 EX(     mov.w   r0,@(30,r4)     )
289         add     #-2,r4
290         xtrct   r8,r0
291         xtrct   r9,r8
292         xtrct   r10,r9
293 EX(     mov.l   r0,@(28,r4)     )
294 EX(     mov.l   r8,@(24,r4)     )
295 EX(     mov.l   r9,@(20,r4)     )
296
297 EX(     mov.l   @(12,r5),r0     )
298 EX(     mov.l   @(8,r5),r8      )
299         xtrct   r0,r10
300 EX(     mov.l   @(4,r5),r9      )
301         mov.l   r10,@(16,r4)
302 EX(     mov.l   @r5,r10         )
303         xtrct   r8,r0
304         xtrct   r9,r8
305         xtrct   r10,r9
306 EX(     mov.l   r0,@(12,r4)     )
307 EX(     mov.l   r8,@(8,r4)      )
308         swap.w  r10,r0
309 EX(     mov.l   r9,@(4,r4)      )
310 EX(     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
319 1:      ! Read longword, write two words per iteration
320 EX(     mov.l   @r5+,r0         )
321         dt      r2
322 #ifdef __LITTLE_ENDIAN__
323 EX(     mov.w   r0,@r4          )
324         shlr16  r0
325 EX(     mov.w   r0,@(2,r4)      )
326 #else
327 EX(     mov.w   r0,@(2,r4)      )
328         shlr16  r0
329 EX(     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
342 EX(     mov.l   @r5+,r0         )
343         dt      r2
344 #ifdef __LITTLE_ENDIAN__
345 EX(     mov.b   r0,@r4          )
346         shlr8   r0
347         add     #1,r4
348 EX(     mov.w   r0,@r4          )
349         shlr16  r0
350 EX(     mov.b   r0,@(2,r4)      )
351         bf/s    .L_dest01
352          add    #3,r4
353 #else
354 EX(     mov.b   r0,@(3,r4)      )
355         shlr8   r0
356         swap.w  r0,r7
357 EX(     mov.b   r7,@r4          )
358         add     #1,r4
359 EX(     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:
373 EX(     mov.b   @r5+,r0         )
374         dt      r6
375 EX(     mov.b   r0,@r4          )
376         bf/s    .L_cleanup_loop
377          add    #1,r4
378
379 .L_exit:
380         mov     #0,r0           ! normal return
381 5000:
382
383 # Exception handler:
384 .section .fixup, "ax"
385 6000:
386         mov.l   8000f,r1
387         mov     r3,r0
388         jmp     @r1
389          sub    r4,r0
390         .align  2
391 8000:   .long   5000b
392
393 .previous
394         mov.l   @r15+,r8
395         mov.l   @r15+,r9
396         rts
397          mov.l  @r15+,r10