]> err.no Git - linux-2.6/blob - arch/sh/mm/copy_page.S
Merge branch 'sg' of git://git.kernel.dk/linux-2.6-block
[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         .align 2
133 .Lpsz:  .long   PAGE_SIZE
134 /*
135  * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
136  * Return the number of bytes NOT copied
137  */
138 #define EX(...)                 \
139         9999: __VA_ARGS__ ;             \
140         .section __ex_table, "a";       \
141         .long 9999b, 6000f      ;       \
142         .previous
143 ENTRY(__copy_user)
144         ! Check if small number of bytes
145         mov     #11,r0
146         mov     r4,r3
147         cmp/gt  r0,r6           ! r6 (len) > r0 (11)
148         bf/s    .L_cleanup_loop_no_pop
149          add    r6,r3           ! last destination address
150
151         ! Calculate bytes needed to align to src
152         mov.l   r11,@-r15
153         neg     r5,r0
154         mov.l   r10,@-r15
155         add     #4,r0
156         mov.l   r9,@-r15
157         and     #3,r0
158         mov.l   r8,@-r15
159         tst     r0,r0
160         bt      2f
161
162 1:
163         ! Copy bytes to long word align src
164 EX(     mov.b   @r5+,r1         )
165         dt      r0
166         add     #-1,r6
167 EX(     mov.b   r1,@r4          )
168         bf/s    1b
169          add    #1,r4
170
171         ! Jump to appropriate routine depending on dest
172 2:      mov     #3,r1
173         mov     r6, r2
174         and     r4,r1
175         shlr2   r2
176         shll2   r1
177         mova    .L_jump_tbl,r0
178         mov.l   @(r0,r1),r1
179         jmp     @r1
180          nop
181
182         .align 2
183 .L_jump_tbl:
184         .long   .L_dest00
185         .long   .L_dest01
186         .long   .L_dest10
187         .long   .L_dest11
188
189 /*
190  * Come here if there are less than 12 bytes to copy
191  *
192  * Keep the branch target close, so the bf/s callee doesn't overflow
193  * and result in a more expensive branch being inserted. This is the
194  * fast-path for small copies, the jump via the jump table will hit the
195  * default slow-path cleanup. -PFM.
196  */
197 .L_cleanup_loop_no_pop:
198         tst     r6,r6           ! Check explicitly for zero
199         bt      1f
200
201 2:
202 EX(     mov.b   @r5+,r0         )
203         dt      r6
204 EX(     mov.b   r0,@r4          )
205         bf/s    2b
206          add    #1,r4
207
208 1:      mov     #0,r0           ! normal return
209 5000:
210
211 # Exception handler:
212 .section .fixup, "ax"
213 6000:
214         mov.l   8000f,r1
215         mov     r3,r0
216         jmp     @r1
217          sub    r4,r0
218         .align  2
219 8000:   .long   5000b
220
221 .previous
222         rts
223          nop
224
225 ! Destination = 00
226
227 .L_dest00:
228         ! Skip the large copy for small transfers
229         mov     #(32+32-4), r0
230         cmp/gt  r6, r0          ! r0 (60) > r6 (len)
231         bt      1f
232
233         ! Align dest to a 32 byte boundary
234         neg     r4,r0
235         add     #0x20, r0
236         and     #0x1f, r0
237         tst     r0, r0
238         bt      2f
239
240         sub     r0, r6
241         shlr2   r0
242 3:
243 EX(     mov.l   @r5+,r1         )
244         dt      r0
245 EX(     mov.l   r1,@r4          )
246         bf/s    3b
247          add    #4,r4
248
249 2:
250 EX(     mov.l   @r5+,r0         )
251 EX(     mov.l   @r5+,r1         )
252 EX(     mov.l   @r5+,r2         )
253 EX(     mov.l   @r5+,r7         )
254 EX(     mov.l   @r5+,r8         )
255 EX(     mov.l   @r5+,r9         )
256 EX(     mov.l   @r5+,r10        )
257 EX(     mov.l   @r5+,r11        )
258 #ifdef CONFIG_CPU_SH4
259 EX(     movca.l r0,@r4          )
260 #else
261 EX(     mov.l   r0,@r4          )
262 #endif
263         add     #-32, r6
264 EX(     mov.l   r1,@(4,r4)      )
265         mov     #32, r0
266 EX(     mov.l   r2,@(8,r4)      )
267         cmp/gt  r6, r0          ! r0 (32) > r6 (len)
268 EX(     mov.l   r7,@(12,r4)     )
269 EX(     mov.l   r8,@(16,r4)     )
270 EX(     mov.l   r9,@(20,r4)     )
271 EX(     mov.l   r10,@(24,r4)    )
272 EX(     mov.l   r11,@(28,r4)    )
273         bf/s    2b
274          add    #32,r4
275
276 1:      mov     r6, r0
277         shlr2   r0
278         tst     r0, r0
279         bt      .L_cleanup
280 1:
281 EX(     mov.l   @r5+,r1         )
282         dt      r0
283 EX(     mov.l   r1,@r4          )
284         bf/s    1b
285          add    #4,r4
286
287         bra     .L_cleanup
288          nop
289
290 ! Destination = 10
291
292 .L_dest10:
293         mov     r2,r7
294         shlr2   r7
295         shlr    r7
296         tst     r7,r7
297         mov     #7,r0
298         bt/s    1f
299          and    r0,r2
300 2:
301         dt      r7
302 #ifdef CONFIG_CPU_LITTLE_ENDIAN
303 EX(     mov.l   @r5+,r0         )
304 EX(     mov.l   @r5+,r1         )
305 EX(     mov.l   @r5+,r8         )
306 EX(     mov.l   @r5+,r9         )
307 EX(     mov.l   @r5+,r10        )
308 EX(     mov.w   r0,@r4          )
309         add     #2,r4
310         xtrct   r1,r0
311         xtrct   r8,r1
312         xtrct   r9,r8
313         xtrct   r10,r9
314
315 EX(     mov.l   r0,@r4          )
316 EX(     mov.l   r1,@(4,r4)      )
317 EX(     mov.l   r8,@(8,r4)      )
318 EX(     mov.l   r9,@(12,r4)     )
319
320 EX(     mov.l   @r5+,r1         )
321 EX(     mov.l   @r5+,r8         )
322 EX(     mov.l   @r5+,r0         )
323         xtrct   r1,r10
324         xtrct   r8,r1
325         xtrct   r0,r8
326         shlr16  r0
327 EX(     mov.l   r10,@(16,r4)    )
328 EX(     mov.l   r1,@(20,r4)     )
329 EX(     mov.l   r8,@(24,r4)     )
330 EX(     mov.w   r0,@(28,r4)     )
331         bf/s    2b
332          add    #30,r4
333 #else
334 EX(     mov.l   @(28,r5),r0     )
335 EX(     mov.l   @(24,r5),r8     )
336 EX(     mov.l   @(20,r5),r9     )
337 EX(     mov.l   @(16,r5),r10    )
338 EX(     mov.w   r0,@(30,r4)     )
339         add     #-2,r4
340         xtrct   r8,r0
341         xtrct   r9,r8
342         xtrct   r10,r9
343 EX(     mov.l   r0,@(28,r4)     )
344 EX(     mov.l   r8,@(24,r4)     )
345 EX(     mov.l   r9,@(20,r4)     )
346
347 EX(     mov.l   @(12,r5),r0     )
348 EX(     mov.l   @(8,r5),r8      )
349         xtrct   r0,r10
350 EX(     mov.l   @(4,r5),r9      )
351         mov.l   r10,@(16,r4)
352 EX(     mov.l   @r5,r10         )
353         xtrct   r8,r0
354         xtrct   r9,r8
355         xtrct   r10,r9
356 EX(     mov.l   r0,@(12,r4)     )
357 EX(     mov.l   r8,@(8,r4)      )
358         swap.w  r10,r0
359 EX(     mov.l   r9,@(4,r4)      )
360 EX(     mov.w   r0,@(2,r4)      )
361
362         add     #32,r5
363         bf/s    2b
364          add    #34,r4
365 #endif
366         tst     r2,r2
367         bt      .L_cleanup
368
369 1:      ! Read longword, write two words per iteration
370 EX(     mov.l   @r5+,r0         )
371         dt      r2
372 #ifdef CONFIG_CPU_LITTLE_ENDIAN
373 EX(     mov.w   r0,@r4          )
374         shlr16  r0
375 EX(     mov.w   r0,@(2,r4)      )
376 #else
377 EX(     mov.w   r0,@(2,r4)      )
378         shlr16  r0
379 EX(     mov.w   r0,@r4          )
380 #endif
381         bf/s    1b
382          add    #4,r4
383
384         bra     .L_cleanup
385          nop
386
387 ! Destination = 01 or 11
388
389 .L_dest01:
390 .L_dest11:
391         ! Read longword, write byte, word, byte per iteration
392 EX(     mov.l   @r5+,r0         )
393         dt      r2
394 #ifdef CONFIG_CPU_LITTLE_ENDIAN
395 EX(     mov.b   r0,@r4          )
396         shlr8   r0
397         add     #1,r4
398 EX(     mov.w   r0,@r4          )
399         shlr16  r0
400 EX(     mov.b   r0,@(2,r4)      )
401         bf/s    .L_dest01
402          add    #3,r4
403 #else
404 EX(     mov.b   r0,@(3,r4)      )
405         shlr8   r0
406         swap.w  r0,r7
407 EX(     mov.b   r7,@r4          )
408         add     #1,r4
409 EX(     mov.w   r0,@r4          )
410         bf/s    .L_dest01
411          add    #3,r4
412 #endif
413
414 ! Cleanup last few bytes
415 .L_cleanup:
416         mov     r6,r0
417         and     #3,r0
418         tst     r0,r0
419         bt      .L_exit
420         mov     r0,r6
421
422 .L_cleanup_loop:
423 EX(     mov.b   @r5+,r0         )
424         dt      r6
425 EX(     mov.b   r0,@r4          )
426         bf/s    .L_cleanup_loop
427          add    #1,r4
428
429 .L_exit:
430         mov     #0,r0           ! normal return
431
432 5000:
433
434 # Exception handler:
435 .section .fixup, "ax"
436 6000:
437         mov.l   8000f,r1
438         mov     r3,r0
439         jmp     @r1
440          sub    r4,r0
441         .align  2
442 8000:   .long   5000b
443
444 .previous
445         mov.l   @r15+,r8
446         mov.l   @r15+,r9
447         mov.l   @r15+,r10
448         rts
449          mov.l  @r15+,r11