GNU Linux-libre 4.14.266-gnu1
[releases.git] / arch / sh / lib / copy_page.S
1 /* SPDX-License-Identifier: GPL-2.0 */
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  * Copyright (C) 2006  Paul Mundt
8  */
9 #include <linux/linkage.h>
10 #include <asm/page.h>
11
12 /*
13  * copy_page
14  * @to: P1 address
15  * @from: P1 address
16  *
17  * void copy_page(void *to, void *from)
18  */
19
20 /*
21  * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch 
22  * r8 --- from + PAGE_SIZE
23  * r9 --- not used
24  * r10 --- to
25  * r11 --- from
26  */
27 ENTRY(copy_page)
28         mov.l   r8,@-r15
29         mov.l   r10,@-r15
30         mov.l   r11,@-r15
31         mov     r4,r10
32         mov     r5,r11
33         mov     r5,r8
34         mov     #(PAGE_SIZE >> 10), r0
35         shll8   r0
36         shll2   r0
37         add     r0,r8
38         !
39 1:      mov.l   @r11+,r0
40         mov.l   @r11+,r1
41         mov.l   @r11+,r2
42         mov.l   @r11+,r3
43         mov.l   @r11+,r4
44         mov.l   @r11+,r5
45         mov.l   @r11+,r6
46         mov.l   @r11+,r7
47 #if defined(CONFIG_CPU_SH4)
48         movca.l r0,@r10
49 #else
50         mov.l   r0,@r10
51 #endif
52         add     #32,r10
53         mov.l   r7,@-r10
54         mov.l   r6,@-r10
55         mov.l   r5,@-r10
56         mov.l   r4,@-r10
57         mov.l   r3,@-r10
58         mov.l   r2,@-r10
59         mov.l   r1,@-r10
60         cmp/eq  r11,r8
61         bf/s    1b
62          add    #28,r10
63         !
64         mov.l   @r15+,r11
65         mov.l   @r15+,r10
66         mov.l   @r15+,r8
67         rts
68          nop
69
70 /*
71  * __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
72  * Return the number of bytes NOT copied
73  */
74 #define EX(...)                 \
75         9999: __VA_ARGS__ ;             \
76         .section __ex_table, "a";       \
77         .long 9999b, 6000f      ;       \
78         .previous
79 #define EX_NO_POP(...)                  \
80         9999: __VA_ARGS__ ;             \
81         .section __ex_table, "a";       \
82         .long 9999b, 6005f      ;       \
83         .previous
84 ENTRY(__copy_user)
85         ! Check if small number of bytes
86         mov     #11,r0
87         mov     r4,r3
88         cmp/gt  r0,r6           ! r6 (len) > r0 (11)
89         bf/s    .L_cleanup_loop_no_pop
90          add    r6,r3           ! last destination address
91
92         ! Calculate bytes needed to align to src
93         mov.l   r11,@-r15
94         neg     r5,r0
95         mov.l   r10,@-r15
96         add     #4,r0
97         mov.l   r9,@-r15
98         and     #3,r0
99         mov.l   r8,@-r15
100         tst     r0,r0
101         bt      2f
102
103 1:
104         ! Copy bytes to long word align src
105 EX(     mov.b   @r5+,r1         )
106         dt      r0
107         add     #-1,r6
108 EX(     mov.b   r1,@r4          )
109         bf/s    1b
110          add    #1,r4
111
112         ! Jump to appropriate routine depending on dest
113 2:      mov     #3,r1
114         mov     r6, r2
115         and     r4,r1
116         shlr2   r2
117         shll2   r1
118         mova    .L_jump_tbl,r0
119         mov.l   @(r0,r1),r1
120         jmp     @r1
121          nop
122
123         .align 2
124 .L_jump_tbl:
125         .long   .L_dest00
126         .long   .L_dest01
127         .long   .L_dest10
128         .long   .L_dest11
129
130 /*
131  * Come here if there are less than 12 bytes to copy
132  *
133  * Keep the branch target close, so the bf/s callee doesn't overflow
134  * and result in a more expensive branch being inserted. This is the
135  * fast-path for small copies, the jump via the jump table will hit the
136  * default slow-path cleanup. -PFM.
137  */
138 .L_cleanup_loop_no_pop:
139         tst     r6,r6           ! Check explicitly for zero
140         bt      1f
141
142 2:
143 EX_NO_POP(      mov.b   @r5+,r0         )
144         dt      r6
145 EX_NO_POP(      mov.b   r0,@r4          )
146         bf/s    2b
147          add    #1,r4
148
149 1:      mov     #0,r0           ! normal return
150 5000:
151
152 # Exception handler:
153 .section .fixup, "ax"
154 6005:
155         mov.l   8000f,r1
156         mov     r3,r0
157         jmp     @r1
158          sub    r4,r0
159         .align  2
160 8000:   .long   5000b
161
162 .previous
163         rts
164          nop
165
166 ! Destination = 00
167
168 .L_dest00:
169         ! Skip the large copy for small transfers
170         mov     #(32+32-4), r0
171         cmp/gt  r6, r0          ! r0 (60) > r6 (len)
172         bt      1f
173
174         ! Align dest to a 32 byte boundary
175         neg     r4,r0
176         add     #0x20, r0
177         and     #0x1f, r0
178         tst     r0, r0
179         bt      2f
180
181         sub     r0, r6
182         shlr2   r0
183 3:
184 EX(     mov.l   @r5+,r1         )
185         dt      r0
186 EX(     mov.l   r1,@r4          )
187         bf/s    3b
188          add    #4,r4
189
190 2:
191 EX(     mov.l   @r5+,r0         )
192 EX(     mov.l   @r5+,r1         )
193 EX(     mov.l   @r5+,r2         )
194 EX(     mov.l   @r5+,r7         )
195 EX(     mov.l   @r5+,r8         )
196 EX(     mov.l   @r5+,r9         )
197 EX(     mov.l   @r5+,r10        )
198 EX(     mov.l   @r5+,r11        )
199 #ifdef CONFIG_CPU_SH4
200 EX(     movca.l r0,@r4          )
201 #else
202 EX(     mov.l   r0,@r4          )
203 #endif
204         add     #-32, r6
205 EX(     mov.l   r1,@(4,r4)      )
206         mov     #32, r0
207 EX(     mov.l   r2,@(8,r4)      )
208         cmp/gt  r6, r0          ! r0 (32) > r6 (len)
209 EX(     mov.l   r7,@(12,r4)     )
210 EX(     mov.l   r8,@(16,r4)     )
211 EX(     mov.l   r9,@(20,r4)     )
212 EX(     mov.l   r10,@(24,r4)    )
213 EX(     mov.l   r11,@(28,r4)    )
214         bf/s    2b
215          add    #32,r4
216
217 1:      mov     r6, r0
218         shlr2   r0
219         tst     r0, r0
220         bt      .L_cleanup
221 1:
222 EX(     mov.l   @r5+,r1         )
223         dt      r0
224 EX(     mov.l   r1,@r4          )
225         bf/s    1b
226          add    #4,r4
227
228         bra     .L_cleanup
229          nop
230
231 ! Destination = 10
232
233 .L_dest10:
234         mov     r2,r7
235         shlr2   r7
236         shlr    r7
237         tst     r7,r7
238         mov     #7,r0
239         bt/s    1f
240          and    r0,r2
241 2:
242         dt      r7
243 #ifdef CONFIG_CPU_LITTLE_ENDIAN
244 EX(     mov.l   @r5+,r0         )
245 EX(     mov.l   @r5+,r1         )
246 EX(     mov.l   @r5+,r8         )
247 EX(     mov.l   @r5+,r9         )
248 EX(     mov.l   @r5+,r10        )
249 EX(     mov.w   r0,@r4          )
250         add     #2,r4
251         xtrct   r1,r0
252         xtrct   r8,r1
253         xtrct   r9,r8
254         xtrct   r10,r9
255
256 EX(     mov.l   r0,@r4          )
257 EX(     mov.l   r1,@(4,r4)      )
258 EX(     mov.l   r8,@(8,r4)      )
259 EX(     mov.l   r9,@(12,r4)     )
260
261 EX(     mov.l   @r5+,r1         )
262 EX(     mov.l   @r5+,r8         )
263 EX(     mov.l   @r5+,r0         )
264         xtrct   r1,r10
265         xtrct   r8,r1
266         xtrct   r0,r8
267         shlr16  r0
268 EX(     mov.l   r10,@(16,r4)    )
269 EX(     mov.l   r1,@(20,r4)     )
270 EX(     mov.l   r8,@(24,r4)     )
271 EX(     mov.w   r0,@(28,r4)     )
272         bf/s    2b
273          add    #30,r4
274 #else
275 EX(     mov.l   @(28,r5),r0     )
276 EX(     mov.l   @(24,r5),r8     )
277 EX(     mov.l   @(20,r5),r9     )
278 EX(     mov.l   @(16,r5),r10    )
279 EX(     mov.w   r0,@(30,r4)     )
280         add     #-2,r4
281         xtrct   r8,r0
282         xtrct   r9,r8
283         xtrct   r10,r9
284 EX(     mov.l   r0,@(28,r4)     )
285 EX(     mov.l   r8,@(24,r4)     )
286 EX(     mov.l   r9,@(20,r4)     )
287
288 EX(     mov.l   @(12,r5),r0     )
289 EX(     mov.l   @(8,r5),r8      )
290         xtrct   r0,r10
291 EX(     mov.l   @(4,r5),r9      )
292         mov.l   r10,@(16,r4)
293 EX(     mov.l   @r5,r10         )
294         xtrct   r8,r0
295         xtrct   r9,r8
296         xtrct   r10,r9
297 EX(     mov.l   r0,@(12,r4)     )
298 EX(     mov.l   r8,@(8,r4)      )
299         swap.w  r10,r0
300 EX(     mov.l   r9,@(4,r4)      )
301 EX(     mov.w   r0,@(2,r4)      )
302
303         add     #32,r5
304         bf/s    2b
305          add    #34,r4
306 #endif
307         tst     r2,r2
308         bt      .L_cleanup
309
310 1:      ! Read longword, write two words per iteration
311 EX(     mov.l   @r5+,r0         )
312         dt      r2
313 #ifdef CONFIG_CPU_LITTLE_ENDIAN
314 EX(     mov.w   r0,@r4          )
315         shlr16  r0
316 EX(     mov.w   r0,@(2,r4)      )
317 #else
318 EX(     mov.w   r0,@(2,r4)      )
319         shlr16  r0
320 EX(     mov.w   r0,@r4          )
321 #endif
322         bf/s    1b
323          add    #4,r4
324
325         bra     .L_cleanup
326          nop
327
328 ! Destination = 01 or 11
329
330 .L_dest01:
331 .L_dest11:
332         ! Read longword, write byte, word, byte per iteration
333 EX(     mov.l   @r5+,r0         )
334         dt      r2
335 #ifdef CONFIG_CPU_LITTLE_ENDIAN
336 EX(     mov.b   r0,@r4          )
337         shlr8   r0
338         add     #1,r4
339 EX(     mov.w   r0,@r4          )
340         shlr16  r0
341 EX(     mov.b   r0,@(2,r4)      )
342         bf/s    .L_dest01
343          add    #3,r4
344 #else
345 EX(     mov.b   r0,@(3,r4)      )
346         shlr8   r0
347         swap.w  r0,r7
348 EX(     mov.b   r7,@r4          )
349         add     #1,r4
350 EX(     mov.w   r0,@r4          )
351         bf/s    .L_dest01
352          add    #3,r4
353 #endif
354
355 ! Cleanup last few bytes
356 .L_cleanup:
357         mov     r6,r0
358         and     #3,r0
359         tst     r0,r0
360         bt      .L_exit
361         mov     r0,r6
362
363 .L_cleanup_loop:
364 EX(     mov.b   @r5+,r0         )
365         dt      r6
366 EX(     mov.b   r0,@r4          )
367         bf/s    .L_cleanup_loop
368          add    #1,r4
369
370 .L_exit:
371         mov     #0,r0           ! normal return
372
373 5000:
374
375 # Exception handler:
376 .section .fixup, "ax"
377 6000:
378         mov.l   8000f,r1
379         mov     r3,r0
380         jmp     @r1
381          sub    r4,r0
382         .align  2
383 8000:   .long   5000b
384
385 .previous
386         mov.l   @r15+,r8
387         mov.l   @r15+,r9
388         mov.l   @r15+,r10
389         rts
390          mov.l  @r15+,r11