blob: ae039f2da16271c75e3013b97fa8a523a3b97621 [file] [log] [blame]
Paul Mundt510c72ad2006-11-27 12:06:26 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * 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
Paul Mundt510c72ad2006-11-27 12:06:26 +09006 * Copyright (C) 2006 Paul Mundt
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8#include <linux/linkage.h>
Paul Mundt510c72ad2006-11-27 12:06:26 +09009#include <asm/page.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010
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
Paul Mundt510c72ad2006-11-27 12:06:26 +090021 * r8 --- from + PAGE_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 * 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
Paul Mundt510c72ad2006-11-27 12:06:26 +090033 mov.l .Lpsz,r0
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 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
Paul Mundt510c72ad2006-11-27 12:06:26 +090083 * r8 --- from + PAGE_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 * 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
Paul Mundt510c72ad2006-11-27 12:06:26 +090097 mov.l .Lpsz,r0
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 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
Paul Mundt0d08b5f2007-05-14 10:49:40 +0900132 .align 2
Paul Mundt510c72ad2006-11-27 12:06:26 +0900133.Lpsz: .long PAGE_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134/*
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
143ENTRY(__copy_user)
144 tst r6,r6 ! Check explicitly for zero
145 bf 1f
146 rts
147 mov #0,r0 ! normal return
1481:
149 mov.l r10,@-r15
150 mov.l r9,@-r15
151 mov.l r8,@-r15
152 mov r4,r3
153 add r6,r3 ! last destination address
154 mov #12,r0 ! Check if small number of bytes
155 cmp/gt r0,r6
156 bt 2f
157 bra .L_cleanup_loop
158 nop
1592:
160 neg r5,r0 ! Calculate bytes needed to align source
161 add #4,r0
162 and #3,r0
163 tst r0,r0
164 bt .L_jump
165 mov r0,r1
166
167.L_loop1:
168 ! Copy bytes to align source
169EX( mov.b @r5+,r0 )
170 dt r1
171EX( mov.b r0,@r4 )
172 add #-1,r6
173 bf/s .L_loop1
174 add #1,r4
175
176.L_jump:
177 mov r6,r2 ! Calculate number of longwords to copy
178 shlr2 r2
179 tst r2,r2
180 bt .L_cleanup
181
182 mov r4,r0 ! Jump to appropriate routine
183 and #3,r0
184 mov r0,r1
185 shll2 r1
186 mova .L_jump_tbl,r0
187 mov.l @(r0,r1),r1
188 jmp @r1
189 nop
190
191 .align 2
192.L_jump_tbl:
193 .long .L_dest00
194 .long .L_dest01
195 .long .L_dest10
196 .long .L_dest11
197
198! Destination = 00
199
200.L_dest00:
201 mov r2,r7
202 shlr2 r7
203 shlr r7
204 tst r7,r7
205 mov #7,r0
206 bt/s 1f
207 and r0,r2
208 .align 2
2092:
210EX( mov.l @r5+,r0 )
211EX( mov.l @r5+,r8 )
212EX( mov.l @r5+,r9 )
213EX( mov.l @r5+,r10 )
214EX( mov.l r0,@r4 )
215EX( mov.l r8,@(4,r4) )
216EX( mov.l r9,@(8,r4) )
217EX( mov.l r10,@(12,r4) )
218EX( mov.l @r5+,r0 )
219EX( mov.l @r5+,r8 )
220EX( mov.l @r5+,r9 )
221EX( mov.l @r5+,r10 )
222 dt r7
223EX( mov.l r0,@(16,r4) )
224EX( mov.l r8,@(20,r4) )
225EX( mov.l r9,@(24,r4) )
226EX( mov.l r10,@(28,r4) )
227 bf/s 2b
228 add #32,r4
229 tst r2,r2
230 bt .L_cleanup
2311:
232EX( mov.l @r5+,r0 )
233 dt r2
234EX( mov.l r0,@r4 )
235 bf/s 1b
236 add #4,r4
237
238 bra .L_cleanup
239 nop
240
241! Destination = 10
242
243.L_dest10:
244 mov r2,r7
245 shlr2 r7
246 shlr r7
247 tst r7,r7
248 mov #7,r0
249 bt/s 1f
250 and r0,r2
2512:
252 dt r7
253#ifdef __LITTLE_ENDIAN__
254EX( mov.l @r5+,r0 )
255EX( mov.l @r5+,r1 )
256EX( mov.l @r5+,r8 )
257EX( mov.l @r5+,r9 )
258EX( mov.l @r5+,r10 )
259EX( mov.w r0,@r4 )
260 add #2,r4
261 xtrct r1,r0
262 xtrct r8,r1
263 xtrct r9,r8
264 xtrct r10,r9
265
266EX( mov.l r0,@r4 )
267EX( mov.l r1,@(4,r4) )
268EX( mov.l r8,@(8,r4) )
269EX( mov.l r9,@(12,r4) )
270
271EX( mov.l @r5+,r1 )
272EX( mov.l @r5+,r8 )
273EX( mov.l @r5+,r0 )
274 xtrct r1,r10
275 xtrct r8,r1
276 xtrct r0,r8
277 shlr16 r0
278EX( mov.l r10,@(16,r4) )
279EX( mov.l r1,@(20,r4) )
280EX( mov.l r8,@(24,r4) )
281EX( mov.w r0,@(28,r4) )
282 bf/s 2b
283 add #30,r4
284#else
285EX( mov.l @(28,r5),r0 )
286EX( mov.l @(24,r5),r8 )
287EX( mov.l @(20,r5),r9 )
288EX( mov.l @(16,r5),r10 )
289EX( mov.w r0,@(30,r4) )
290 add #-2,r4
291 xtrct r8,r0
292 xtrct r9,r8
293 xtrct r10,r9
294EX( mov.l r0,@(28,r4) )
295EX( mov.l r8,@(24,r4) )
296EX( mov.l r9,@(20,r4) )
297
298EX( mov.l @(12,r5),r0 )
299EX( mov.l @(8,r5),r8 )
300 xtrct r0,r10
301EX( mov.l @(4,r5),r9 )
302 mov.l r10,@(16,r4)
303EX( mov.l @r5,r10 )
304 xtrct r8,r0
305 xtrct r9,r8
306 xtrct r10,r9
307EX( mov.l r0,@(12,r4) )
308EX( mov.l r8,@(8,r4) )
309 swap.w r10,r0
310EX( mov.l r9,@(4,r4) )
311EX( mov.w r0,@(2,r4) )
312
313 add #32,r5
314 bf/s 2b
315 add #34,r4
316#endif
317 tst r2,r2
318 bt .L_cleanup
319
3201: ! Read longword, write two words per iteration
321EX( mov.l @r5+,r0 )
322 dt r2
323#ifdef __LITTLE_ENDIAN__
324EX( mov.w r0,@r4 )
325 shlr16 r0
326EX( mov.w r0,@(2,r4) )
327#else
328EX( mov.w r0,@(2,r4) )
329 shlr16 r0
330EX( mov.w r0,@r4 )
331#endif
332 bf/s 1b
333 add #4,r4
334
335 bra .L_cleanup
336 nop
337
338! Destination = 01 or 11
339
340.L_dest01:
341.L_dest11:
342 ! Read longword, write byte, word, byte per iteration
343EX( mov.l @r5+,r0 )
344 dt r2
345#ifdef __LITTLE_ENDIAN__
346EX( mov.b r0,@r4 )
347 shlr8 r0
348 add #1,r4
349EX( mov.w r0,@r4 )
350 shlr16 r0
351EX( mov.b r0,@(2,r4) )
352 bf/s .L_dest01
353 add #3,r4
354#else
355EX( mov.b r0,@(3,r4) )
356 shlr8 r0
357 swap.w r0,r7
358EX( mov.b r7,@r4 )
359 add #1,r4
360EX( mov.w r0,@r4 )
361 bf/s .L_dest01
362 add #3,r4
363#endif
364
365! Cleanup last few bytes
366.L_cleanup:
367 mov r6,r0
368 and #3,r0
369 tst r0,r0
370 bt .L_exit
371 mov r0,r6
372
373.L_cleanup_loop:
374EX( mov.b @r5+,r0 )
375 dt r6
376EX( mov.b r0,@r4 )
377 bf/s .L_cleanup_loop
378 add #1,r4
379
380.L_exit:
381 mov #0,r0 ! normal return
3825000:
383
384# Exception handler:
385.section .fixup, "ax"
3866000:
387 mov.l 8000f,r1
388 mov r3,r0
389 jmp @r1
390 sub r4,r0
391 .align 2
3928000: .long 5000b
393
394.previous
395 mov.l @r15+,r8
396 mov.l @r15+,r9
397 rts
398 mov.l @r15+,r10