blob: 3d8409daa4beafc06d762248a85230fc5e3d6524 [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)
Stuart Menefy023ef182007-09-28 12:36:35 +0900144 ! Check if small number of bytes
145 mov #11,r0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 mov r4,r3
Stuart Menefy023ef182007-09-28 12:36:35 +0900147 cmp/gt r0,r6 ! r6 (len) > r0 (11)
148 bf/s .L_cleanup_loop_no_pop
149 add r6,r3 ! last destination address
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Stuart Menefy023ef182007-09-28 12:36:35 +0900151 ! 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
1621:
163 ! Copy bytes to long word align src
164EX( mov.b @r5+,r1 )
165 dt r0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 add #-1,r6
Stuart Menefy023ef182007-09-28 12:36:35 +0900167EX( mov.b r1,@r4 )
168 bf/s 1b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 add #1,r4
170
Stuart Menefy023ef182007-09-28 12:36:35 +0900171 ! Jump to appropriate routine depending on dest
1722: mov #3,r1
173 mov r6, r2
174 and r4,r1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 shlr2 r2
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 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
Stuart Menefy023ef182007-09-28 12:36:35 +0900189/*
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
2012:
202EX( mov.b @r5+,r0 )
203 dt r6
204EX( mov.b r0,@r4 )
205 bf/s 2b
206 add #1,r4
207
2081: mov #0,r0 ! normal return
2095000:
210
211# Exception handler:
212.section .fixup, "ax"
2136000:
214 mov.l 8000f,r1
215 mov r3,r0
216 jmp @r1
217 sub r4,r0
218 .align 2
2198000: .long 5000b
220
221.previous
222 rts
223 nop
224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225! Destination = 00
226
227.L_dest00:
Stuart Menefy023ef182007-09-28 12:36:35 +0900228 ! 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
2423:
243EX( mov.l @r5+,r1 )
244 dt r0
245EX( mov.l r1,@r4 )
246 bf/s 3b
247 add #4,r4
248
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492:
250EX( mov.l @r5+,r0 )
Stuart Menefy023ef182007-09-28 12:36:35 +0900251EX( mov.l @r5+,r1 )
252EX( mov.l @r5+,r2 )
253EX( mov.l @r5+,r7 )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254EX( mov.l @r5+,r8 )
255EX( mov.l @r5+,r9 )
256EX( mov.l @r5+,r10 )
Stuart Menefy023ef182007-09-28 12:36:35 +0900257EX( mov.l @r5+,r11 )
Stuart Menefy0e670682007-11-02 12:14:09 +0900258#ifdef CONFIG_CPU_SH4
Stuart Menefy023ef182007-09-28 12:36:35 +0900259EX( movca.l r0,@r4 )
Stuart Menefy0e670682007-11-02 12:14:09 +0900260#else
261EX( mov.l r0,@r4 )
262#endif
Stuart Menefy023ef182007-09-28 12:36:35 +0900263 add #-32, r6
264EX( mov.l r1,@(4,r4) )
265 mov #32, r0
266EX( mov.l r2,@(8,r4) )
267 cmp/gt r6, r0 ! r0 (32) > r6 (len)
268EX( mov.l r7,@(12,r4) )
269EX( mov.l r8,@(16,r4) )
270EX( mov.l r9,@(20,r4) )
271EX( mov.l r10,@(24,r4) )
272EX( mov.l r11,@(28,r4) )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 bf/s 2b
274 add #32,r4
Stuart Menefy023ef182007-09-28 12:36:35 +0900275
2761: mov r6, r0
277 shlr2 r0
278 tst r0, r0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 bt .L_cleanup
2801:
Stuart Menefy023ef182007-09-28 12:36:35 +0900281EX( mov.l @r5+,r1 )
282 dt r0
283EX( mov.l r1,@r4 )
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 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
3002:
301 dt r7
Stuart Menefy023ef182007-09-28 12:36:35 +0900302#ifdef CONFIG_CPU_LITTLE_ENDIAN
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303EX( mov.l @r5+,r0 )
304EX( mov.l @r5+,r1 )
305EX( mov.l @r5+,r8 )
306EX( mov.l @r5+,r9 )
307EX( mov.l @r5+,r10 )
308EX( 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
315EX( mov.l r0,@r4 )
316EX( mov.l r1,@(4,r4) )
317EX( mov.l r8,@(8,r4) )
318EX( mov.l r9,@(12,r4) )
319
320EX( mov.l @r5+,r1 )
321EX( mov.l @r5+,r8 )
322EX( mov.l @r5+,r0 )
323 xtrct r1,r10
324 xtrct r8,r1
325 xtrct r0,r8
326 shlr16 r0
327EX( mov.l r10,@(16,r4) )
328EX( mov.l r1,@(20,r4) )
329EX( mov.l r8,@(24,r4) )
330EX( mov.w r0,@(28,r4) )
331 bf/s 2b
332 add #30,r4
333#else
334EX( mov.l @(28,r5),r0 )
335EX( mov.l @(24,r5),r8 )
336EX( mov.l @(20,r5),r9 )
337EX( mov.l @(16,r5),r10 )
338EX( mov.w r0,@(30,r4) )
339 add #-2,r4
340 xtrct r8,r0
341 xtrct r9,r8
342 xtrct r10,r9
343EX( mov.l r0,@(28,r4) )
344EX( mov.l r8,@(24,r4) )
345EX( mov.l r9,@(20,r4) )
346
347EX( mov.l @(12,r5),r0 )
348EX( mov.l @(8,r5),r8 )
349 xtrct r0,r10
350EX( mov.l @(4,r5),r9 )
351 mov.l r10,@(16,r4)
352EX( mov.l @r5,r10 )
353 xtrct r8,r0
354 xtrct r9,r8
355 xtrct r10,r9
356EX( mov.l r0,@(12,r4) )
357EX( mov.l r8,@(8,r4) )
358 swap.w r10,r0
359EX( mov.l r9,@(4,r4) )
360EX( 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
3691: ! Read longword, write two words per iteration
370EX( mov.l @r5+,r0 )
371 dt r2
Stuart Menefy023ef182007-09-28 12:36:35 +0900372#ifdef CONFIG_CPU_LITTLE_ENDIAN
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373EX( mov.w r0,@r4 )
374 shlr16 r0
375EX( mov.w r0,@(2,r4) )
376#else
377EX( mov.w r0,@(2,r4) )
378 shlr16 r0
379EX( 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
392EX( mov.l @r5+,r0 )
393 dt r2
Stuart Menefy023ef182007-09-28 12:36:35 +0900394#ifdef CONFIG_CPU_LITTLE_ENDIAN
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395EX( mov.b r0,@r4 )
396 shlr8 r0
397 add #1,r4
398EX( mov.w r0,@r4 )
399 shlr16 r0
400EX( mov.b r0,@(2,r4) )
401 bf/s .L_dest01
402 add #3,r4
403#else
404EX( mov.b r0,@(3,r4) )
405 shlr8 r0
406 swap.w r0,r7
407EX( mov.b r7,@r4 )
408 add #1,r4
409EX( 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:
423EX( mov.b @r5+,r0 )
424 dt r6
425EX( mov.b r0,@r4 )
426 bf/s .L_cleanup_loop
427 add #1,r4
428
429.L_exit:
430 mov #0,r0 ! normal return
Stuart Menefy023ef182007-09-28 12:36:35 +0900431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325000:
433
434# Exception handler:
435.section .fixup, "ax"
4366000:
437 mov.l 8000f,r1
438 mov r3,r0
439 jmp @r1
440 sub r4,r0
441 .align 2
4428000: .long 5000b
443
444.previous
445 mov.l @r15+,r8
446 mov.l @r15+,r9
Stuart Menefy023ef182007-09-28 12:36:35 +0900447 mov.l @r15+,r10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 rts
Stuart Menefy023ef182007-09-28 12:36:35 +0900449 mov.l @r15+,r11