1/* $Id: copy_page.S,v 1.1.1.1.2.6 2003/03/23 15:30:58 sugioka Exp $
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 *
8 */
9#include <linux/linkage.h>
10
11/*
12 * copy_page
13 * @to: P1 address
14 * @from: P1 address
15 *
16 * void copy_page(void *to, void *from)
17 */
18
19/*
20 * r0, r1, r2, r3, r4, r5, r6, r7 --- scratch
21 * r8 --- from + 4096
22 * r9 --- not used
23 * r10 --- to
24 * r11 --- from
25 */
26ENTRY(copy_page)
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.w	.L4096,r0
34	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(__sh3__)
45	mov.l	r0,@r10
46#elif defined(__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(__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(__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 + 4096
84 * 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
97	mov.w	.L4096,r0
98	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
132.L4096:	.word	4096
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
142ENTRY(__copy_user)
143	tst	r6,r6		! Check explicitly for zero
144	bf	1f
145	rts
146	 mov	#0,r0		! normal return
1471:
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
1582:
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
168EX(	mov.b	@r5+,r0		)
169	dt	r1
170EX(	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
2082:
209EX(	mov.l	@r5+,r0		)
210EX(	mov.l	@r5+,r8		)
211EX(	mov.l	@r5+,r9		)
212EX(	mov.l	@r5+,r10	)
213EX(	mov.l	r0,@r4		)
214EX(	mov.l	r8,@(4,r4)	)
215EX(	mov.l	r9,@(8,r4)	)
216EX(	mov.l	r10,@(12,r4)	)
217EX(	mov.l	@r5+,r0		)
218EX(	mov.l	@r5+,r8		)
219EX(	mov.l	@r5+,r9		)
220EX(	mov.l	@r5+,r10	)
221	dt	r7
222EX(	mov.l	r0,@(16,r4)	)
223EX(	mov.l	r8,@(20,r4)	)
224EX(	mov.l	r9,@(24,r4)	)
225EX(	mov.l	r10,@(28,r4)	)
226	bf/s	2b
227	 add	#32,r4
228	tst	r2,r2
229	bt	.L_cleanup
2301:
231EX(	mov.l	@r5+,r0		)
232	dt	r2
233EX(	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
2502:
251	dt	r7
252#ifdef __LITTLE_ENDIAN__
253EX(	mov.l	@r5+,r0		)
254EX(	mov.l	@r5+,r1		)
255EX(	mov.l	@r5+,r8		)
256EX(	mov.l	@r5+,r9		)
257EX(	mov.l	@r5+,r10	)
258EX(	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
265EX(	mov.l	r0,@r4		)
266EX(	mov.l	r1,@(4,r4)	)
267EX(	mov.l	r8,@(8,r4)	)
268EX(	mov.l	r9,@(12,r4)	)
269
270EX(	mov.l	@r5+,r1		)
271EX(	mov.l	@r5+,r8		)
272EX(	mov.l	@r5+,r0		)
273	xtrct	r1,r10
274	xtrct	r8,r1
275	xtrct	r0,r8
276	shlr16	r0
277EX(	mov.l	r10,@(16,r4)	)
278EX(	mov.l	r1,@(20,r4)	)
279EX(	mov.l	r8,@(24,r4)	)
280EX(	mov.w	r0,@(28,r4)	)
281	bf/s	2b
282	 add	#30,r4
283#else
284EX(	mov.l	@(28,r5),r0	)
285EX(	mov.l	@(24,r5),r8	)
286EX(	mov.l	@(20,r5),r9	)
287EX(	mov.l	@(16,r5),r10	)
288EX(	mov.w	r0,@(30,r4)	)
289	add	#-2,r4
290	xtrct	r8,r0
291	xtrct	r9,r8
292	xtrct	r10,r9
293EX(	mov.l	r0,@(28,r4)	)
294EX(	mov.l	r8,@(24,r4)	)
295EX(	mov.l	r9,@(20,r4)	)
296
297EX(	mov.l	@(12,r5),r0	)
298EX(	mov.l	@(8,r5),r8	)
299	xtrct	r0,r10
300EX(	mov.l	@(4,r5),r9	)
301	mov.l	r10,@(16,r4)
302EX(	mov.l	@r5,r10		)
303	xtrct	r8,r0
304	xtrct	r9,r8
305	xtrct	r10,r9
306EX(	mov.l	r0,@(12,r4)	)
307EX(	mov.l	r8,@(8,r4)	)
308	swap.w	r10,r0
309EX(	mov.l	r9,@(4,r4)	)
310EX(	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
3191:	! Read longword, write two words per iteration
320EX(	mov.l	@r5+,r0		)
321	dt	r2
322#ifdef __LITTLE_ENDIAN__
323EX(	mov.w	r0,@r4		)
324	shlr16	r0
325EX(	mov.w 	r0,@(2,r4)	)
326#else
327EX(	mov.w	r0,@(2,r4)	)
328	shlr16	r0
329EX(	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
342EX(	mov.l	@r5+,r0		)
343	dt	r2
344#ifdef __LITTLE_ENDIAN__
345EX(	mov.b	r0,@r4		)
346	shlr8	r0
347	add	#1,r4
348EX(	mov.w	r0,@r4		)
349	shlr16	r0
350EX(	mov.b	r0,@(2,r4)	)
351	bf/s	.L_dest01
352	 add	#3,r4
353#else
354EX(	mov.b	r0,@(3,r4)	)
355	shlr8	r0
356	swap.w	r0,r7
357EX(	mov.b	r7,@r4		)
358	add	#1,r4
359EX(	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:
373EX(	mov.b	@r5+,r0		)
374	dt	r6
375EX(	mov.b	r0,@r4		)
376	bf/s	.L_cleanup_loop
377	 add	#1,r4
378
379.L_exit:
380	mov	#0,r0		! normal return
3815000:
382
383# Exception handler:
384.section .fixup, "ax"
3856000:
386	mov.l	8000f,r1
387	mov	r3,r0
388	jmp	@r1
389	 sub	r4,r0
390	.align	2
3918000:	.long	5000b
392
393.previous
394	mov.l	@r15+,r8
395	mov.l	@r15+,r9
396	rts
397	 mov.l	@r15+,r10
398