1129198Scognet/*	$NetBSD: bcopyinout_xscale.S,v 1.3 2003/12/15 09:27:18 scw Exp $	*/
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright 2003 Wasabi Systems, Inc.
5129198Scognet * All rights reserved.
6129198Scognet *
7129198Scognet * Written by Steve C. Woodford for Wasabi Systems, Inc.
8129198Scognet *
9129198Scognet * Redistribution and use in source and binary forms, with or without
10129198Scognet * modification, are permitted provided that the following conditions
11129198Scognet * are met:
12129198Scognet * 1. Redistributions of source code must retain the above copyright
13129198Scognet *    notice, this list of conditions and the following disclaimer.
14129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
15129198Scognet *    notice, this list of conditions and the following disclaimer in the
16129198Scognet *    documentation and/or other materials provided with the distribution.
17129198Scognet * 3. All advertising materials mentioning features or use of this software
18129198Scognet *    must display the following acknowledgement:
19129198Scognet *      This product includes software developed for the NetBSD Project by
20129198Scognet *      Wasabi Systems, Inc.
21129198Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22129198Scognet *    or promote products derived from this software without specific prior
23129198Scognet *    written permission.
24129198Scognet *
25129198Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26129198Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27129198Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28129198Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29129198Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30129198Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31129198Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32129198Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33129198Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34129198Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35129198Scognet * POSSIBILITY OF SUCH DAMAGE.
36129198Scognet */
37129198Scognet
38129198Scognet#include <machine/asm.h>
39129198Scognet__FBSDID("$FreeBSD$");
40129198Scognet
41129198Scognet	.text
42129198Scognet	.align	0
43129198Scognet
44239268Sgonzo#ifdef _ARM_ARCH_6
45239268Sgonzo#define GET_PCB(tmp) \
46239268Sgonzo	mrc p15, 0, tmp, c13, c0, 4; \
47266159Sian	add	tmp, tmp, #(TD_PCB)
48129198Scognet#else
49129198Scognet.Lcurpcb:
50129198Scognet	.word	_C_LABEL(__pcpu) + PC_CURPCB
51239268Sgonzo#define GET_PCB(tmp) \
52239268Sgonzo	ldr	tmp, .Lcurpcb
53129198Scognet#endif
54129198Scognet
55129198Scognet/*
56129198Scognet * r0 = user space address
57129198Scognet * r1 = kernel space address
58129198Scognet * r2 = length
59129198Scognet *
60129198Scognet * Copies bytes from user space to kernel space
61129198Scognet */
62129198ScognetENTRY(copyin)
63129198Scognet	cmp	r2, #0x00
64129198Scognet	movle	r0, #0x00
65129198Scognet	movle	pc, lr			/* Bail early if length is <= 0 */
66129198Scognet
67150864Scognet	ldr	r3, .L_arm_memcpy
68150864Scognet	ldr	r3, [r3]
69150864Scognet	cmp	r3, #0
70150864Scognet	beq	.Lnormal
71150864Scognet	ldr	r3, .L_min_memcpy_size
72150864Scognet	ldr	r3, [r3]
73150864Scognet	cmp	r2, r3
74150864Scognet	blt	.Lnormal
75150864Scognet	stmfd	sp!, {r0-r2, r4, lr}
76150864Scognet	mov     r3, r0
77150864Scognet	mov     r0, r1
78150864Scognet	mov     r1, r3
79150864Scognet	mov     r3, #2 /* SRC_IS_USER */
80150864Scognet	ldr	r4, .L_arm_memcpy
81150864Scognet	mov	lr, pc
82150864Scognet	ldr	pc, [r4]
83150864Scognet	cmp     r0, #0
84150864Scognet	ldmfd   sp!, {r0-r2, r4, lr}
85150864Scognet	moveq	r0, #0
86150864Scognet	RETeq
87150864Scognet
88150864Scognet.Lnormal:
89129198Scognet	stmfd	sp!, {r10-r11, lr}
90129198Scognet
91239268Sgonzo	GET_PCB(r10)
92129198Scognet	ldr	r10, [r10]
93129198Scognet
94129198Scognet	mov	r3, #0x00
95129198Scognet	adr	ip, .Lcopyin_fault
96129198Scognet	ldr	r11, [r10, #PCB_ONFAULT]
97129198Scognet	str	ip, [r10, #PCB_ONFAULT]
98129198Scognet	bl	.Lcopyin_guts
99129198Scognet	str	r11, [r10, #PCB_ONFAULT]
100129198Scognet	mov	r0, #0x00
101129198Scognet	ldmfd	sp!, {r10-r11, pc}
102129198Scognet
103129198Scognet.Lcopyin_fault:
104239033Sandrew	ldr	r0, =EFAULT
105129198Scognet	str	r11, [r10, #PCB_ONFAULT]
106129198Scognet	cmp	r3, #0x00
107129198Scognet	ldmgtfd	sp!, {r4-r7}		/* r3 > 0 Restore r4-r7 */
108129198Scognet	ldmltfd	sp!, {r4-r9}		/* r3 < 0 Restore r4-r9 */
109129198Scognet	ldmfd	sp!, {r10-r11, pc}
110129198Scognet
111129198Scognet.Lcopyin_guts:
112129198Scognet	pld	[r0]
113129198Scognet	/* Word-align the destination buffer */
114129198Scognet	ands	ip, r1, #0x03		/* Already word aligned? */
115129198Scognet	beq	.Lcopyin_wordaligned	/* Yup */
116129198Scognet	rsb	ip, ip, #0x04
117129198Scognet	cmp	r2, ip			/* Enough bytes left to align it? */
118129198Scognet	blt	.Lcopyin_l4_2		/* Nope. Just copy bytewise */
119129198Scognet	sub	r2, r2, ip
120129198Scognet	rsbs	ip, ip, #0x03
121129198Scognet	addne	pc, pc, ip, lsl #3
122129198Scognet	nop
123129198Scognet	ldrbt	ip, [r0], #0x01
124129198Scognet	strb	ip, [r1], #0x01
125129198Scognet	ldrbt	ip, [r0], #0x01
126129198Scognet	strb	ip, [r1], #0x01
127129198Scognet	ldrbt	ip, [r0], #0x01
128129198Scognet	strb	ip, [r1], #0x01
129129198Scognet	cmp	r2, #0x00		/* All done? */
130137463Scognet	RETeq
131129198Scognet
132129198Scognet	/* Destination buffer is now word aligned */
133129198Scognet.Lcopyin_wordaligned:
134129198Scognet	ands	ip, r0, #0x03		/* Is src also word-aligned? */
135129198Scognet	bne	.Lcopyin_bad_align	/* Nope. Things just got bad */
136129198Scognet	cmp	r2, #0x08		/* Less than 8 bytes remaining? */
137129198Scognet	blt	.Lcopyin_w_less_than8
138129198Scognet
139129198Scognet	/* Quad-align the destination buffer */
140129198Scognet	tst	r1, #0x07		/* Already quad aligned? */
141129198Scognet	ldrnet	ip, [r0], #0x04
142153273Scognet	strne	ip, [r1], #0x04
143153273Scognet	subne	r2, r2, #0x04
144129198Scognet	stmfd	sp!, {r4-r9}		/* Free up some registers */
145129198Scognet	mov	r3, #-1			/* Signal restore r4-r9 */
146129198Scognet
147129198Scognet	/* Destination buffer quad aligned, source is word aligned */
148129198Scognet	subs	r2, r2, #0x80
149129198Scognet	blt	.Lcopyin_w_lessthan128
150129198Scognet
151129198Scognet	/* Copy 128 bytes at a time */
152129198Scognet.Lcopyin_w_loop128:
153129198Scognet	ldrt	r4, [r0], #0x04		/* LD:00-03 */
154129198Scognet	ldrt	r5, [r0], #0x04		/* LD:04-07 */
155129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x20 */
156129198Scognet	ldrt	r6, [r0], #0x04		/* LD:08-0b */
157129198Scognet	ldrt	r7, [r0], #0x04		/* LD:0c-0f */
158129198Scognet	ldrt	r8, [r0], #0x04		/* LD:10-13 */
159129198Scognet	ldrt	r9, [r0], #0x04		/* LD:14-17 */
160129198Scognet	strd	r4, [r1], #0x08		/* ST:00-07 */
161129198Scognet	ldrt	r4, [r0], #0x04		/* LD:18-1b */
162129198Scognet	ldrt	r5, [r0], #0x04		/* LD:1c-1f */
163129198Scognet	strd	r6, [r1], #0x08		/* ST:08-0f */
164129198Scognet	ldrt	r6, [r0], #0x04		/* LD:20-23 */
165129198Scognet	ldrt	r7, [r0], #0x04		/* LD:24-27 */
166129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x40 */
167129198Scognet	strd	r8, [r1], #0x08		/* ST:10-17 */
168129198Scognet	ldrt	r8, [r0], #0x04		/* LD:28-2b */
169129198Scognet	ldrt	r9, [r0], #0x04		/* LD:2c-2f */
170129198Scognet	strd	r4, [r1], #0x08		/* ST:18-1f */
171129198Scognet	ldrt	r4, [r0], #0x04		/* LD:30-33 */
172129198Scognet	ldrt	r5, [r0], #0x04		/* LD:34-37 */
173129198Scognet	strd	r6, [r1], #0x08		/* ST:20-27 */
174129198Scognet	ldrt	r6, [r0], #0x04		/* LD:38-3b */
175129198Scognet	ldrt	r7, [r0], #0x04		/* LD:3c-3f */
176129198Scognet	strd	r8, [r1], #0x08		/* ST:28-2f */
177129198Scognet	ldrt	r8, [r0], #0x04		/* LD:40-43 */
178129198Scognet	ldrt	r9, [r0], #0x04		/* LD:44-47 */
179129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x60 */
180129198Scognet	strd	r4, [r1], #0x08		/* ST:30-37 */
181129198Scognet	ldrt	r4, [r0], #0x04		/* LD:48-4b */
182129198Scognet	ldrt	r5, [r0], #0x04		/* LD:4c-4f */
183129198Scognet	strd	r6, [r1], #0x08		/* ST:38-3f */
184129198Scognet	ldrt	r6, [r0], #0x04		/* LD:50-53 */
185129198Scognet	ldrt	r7, [r0], #0x04		/* LD:54-57 */
186129198Scognet	strd	r8, [r1], #0x08		/* ST:40-47 */
187129198Scognet	ldrt	r8, [r0], #0x04		/* LD:58-5b */
188129198Scognet	ldrt	r9, [r0], #0x04		/* LD:5c-5f */
189129198Scognet	strd	r4, [r1], #0x08		/* ST:48-4f */
190129198Scognet	ldrt	r4, [r0], #0x04		/* LD:60-63 */
191129198Scognet	ldrt	r5, [r0], #0x04		/* LD:64-67 */
192129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x80 */
193129198Scognet	strd	r6, [r1], #0x08		/* ST:50-57 */
194129198Scognet	ldrt	r6, [r0], #0x04		/* LD:68-6b */
195129198Scognet	ldrt	r7, [r0], #0x04		/* LD:6c-6f */
196129198Scognet	strd	r8, [r1], #0x08		/* ST:58-5f */
197129198Scognet	ldrt	r8, [r0], #0x04		/* LD:70-73 */
198129198Scognet	ldrt	r9, [r0], #0x04		/* LD:74-77 */
199129198Scognet	strd	r4, [r1], #0x08		/* ST:60-67 */
200129198Scognet	ldrt	r4, [r0], #0x04		/* LD:78-7b */
201129198Scognet	ldrt	r5, [r0], #0x04		/* LD:7c-7f */
202129198Scognet	strd	r6, [r1], #0x08		/* ST:68-6f */
203129198Scognet	strd	r8, [r1], #0x08		/* ST:70-77 */
204129198Scognet	subs	r2, r2, #0x80
205129198Scognet	strd	r4, [r1], #0x08		/* ST:78-7f */
206129198Scognet	bge	.Lcopyin_w_loop128
207129198Scognet
208129198Scognet.Lcopyin_w_lessthan128:
209129198Scognet	adds	r2, r2, #0x80		/* Adjust for extra sub */
210129198Scognet	ldmeqfd	sp!, {r4-r9}
211137463Scognet	RETeq
212129198Scognet	subs	r2, r2, #0x20
213129198Scognet	blt	.Lcopyin_w_lessthan32
214129198Scognet
215129198Scognet	/* Copy 32 bytes at a time */
216129198Scognet.Lcopyin_w_loop32:
217129198Scognet	ldrt	r4, [r0], #0x04
218129198Scognet	ldrt	r5, [r0], #0x04
219129198Scognet	pld	[r0, #0x18]
220129198Scognet	ldrt	r6, [r0], #0x04
221129198Scognet	ldrt	r7, [r0], #0x04
222129198Scognet	ldrt	r8, [r0], #0x04
223129198Scognet	ldrt	r9, [r0], #0x04
224129198Scognet	strd	r4, [r1], #0x08
225129198Scognet	ldrt	r4, [r0], #0x04
226129198Scognet	ldrt	r5, [r0], #0x04
227129198Scognet	strd	r6, [r1], #0x08
228129198Scognet	strd	r8, [r1], #0x08
229129198Scognet	subs	r2, r2, #0x20
230129198Scognet	strd	r4, [r1], #0x08
231129198Scognet	bge	.Lcopyin_w_loop32
232129198Scognet
233129198Scognet.Lcopyin_w_lessthan32:
234129198Scognet	adds	r2, r2, #0x20		/* Adjust for extra sub */
235129198Scognet	ldmeqfd	sp!, {r4-r9}
236137463Scognet	RETeq				/* Return now if done */
237129198Scognet
238129198Scognet	and	r4, r2, #0x18
239129198Scognet	rsb	r5, r4, #0x18
240129198Scognet	subs	r2, r2, r4
241129198Scognet	add	pc, pc, r5, lsl #1
242129198Scognet	nop
243129198Scognet
244129198Scognet	/* At least 24 bytes remaining */
245129198Scognet	ldrt	r4, [r0], #0x04
246129198Scognet	ldrt	r5, [r0], #0x04
247129198Scognet	nop
248129198Scognet	strd	r4, [r1], #0x08
249129198Scognet
250129198Scognet	/* At least 16 bytes remaining */
251129198Scognet	ldrt	r4, [r0], #0x04
252129198Scognet	ldrt	r5, [r0], #0x04
253129198Scognet	nop
254129198Scognet	strd	r4, [r1], #0x08
255129198Scognet
256129198Scognet	/* At least 8 bytes remaining */
257129198Scognet	ldrt	r4, [r0], #0x04
258129198Scognet	ldrt	r5, [r0], #0x04
259129198Scognet	nop
260129198Scognet	strd	r4, [r1], #0x08
261129198Scognet
262129198Scognet	/* Less than 8 bytes remaining */
263129198Scognet	ldmfd	sp!, {r4-r9}
264137463Scognet	RETeq				/* Return now if done */
265129198Scognet	mov	r3, #0x00
266129198Scognet
267129198Scognet.Lcopyin_w_less_than8:
268129198Scognet	subs	r2, r2, #0x04
269129198Scognet	ldrget	ip, [r0], #0x04
270129198Scognet	strge	ip, [r1], #0x04
271137463Scognet	RETeq				/* Return now if done */
272129198Scognet	addlt	r2, r2, #0x04
273129198Scognet	ldrbt	ip, [r0], #0x01
274129198Scognet	cmp	r2, #0x02
275129198Scognet	ldrgebt	r2, [r0], #0x01
276129198Scognet	strb	ip, [r1], #0x01
277129198Scognet	ldrgtbt	ip, [r0]
278129198Scognet	strgeb	r2, [r1], #0x01
279129198Scognet	strgtb	ip, [r1]
280137463Scognet	RET
281129198Scognet
282129198Scognet/*
283129198Scognet * At this point, it has not been possible to word align both buffers.
284129198Scognet * The destination buffer (r1) is word aligned, but the source buffer
285129198Scognet * (r0) is not.
286129198Scognet */
287129198Scognet.Lcopyin_bad_align:
288129198Scognet	stmfd	sp!, {r4-r7}
289129198Scognet	mov	r3, #0x01
290129198Scognet	bic	r0, r0, #0x03
291129198Scognet	cmp	ip, #2
292129198Scognet	ldrt	ip, [r0], #0x04
293129198Scognet	bgt	.Lcopyin_bad3
294129198Scognet	beq	.Lcopyin_bad2
295129198Scognet	b	.Lcopyin_bad1
296129198Scognet
297129198Scognet.Lcopyin_bad1_loop16:
298129198Scognet#ifdef __ARMEB__
299129198Scognet	mov	r4, ip, lsl #8
300129198Scognet#else
301129198Scognet	mov	r4, ip, lsr #8
302129198Scognet#endif
303129198Scognet	ldrt	r5, [r0], #0x04
304129198Scognet	pld	[r0, #0x018]
305129198Scognet	ldrt	r6, [r0], #0x04
306129198Scognet	ldrt	r7, [r0], #0x04
307129198Scognet	ldrt	ip, [r0], #0x04
308129198Scognet#ifdef __ARMEB__
309129198Scognet	orr	r4, r4, r5, lsr #24
310129198Scognet	mov	r5, r5, lsl #8
311129198Scognet	orr	r5, r5, r6, lsr #24
312129198Scognet	mov	r6, r6, lsl #8
313129198Scognet	orr	r6, r6, r7, lsr #24
314129198Scognet	mov	r7, r7, lsl #8
315129198Scognet	orr	r7, r7, ip, lsr #24
316129198Scognet#else
317129198Scognet	orr	r4, r4, r5, lsl #24
318129198Scognet	mov	r5, r5, lsr #8
319129198Scognet	orr	r5, r5, r6, lsl #24
320129198Scognet	mov	r6, r6, lsr #8
321129198Scognet	orr	r6, r6, r7, lsl #24
322129198Scognet	mov	r7, r7, lsr #8
323129198Scognet	orr	r7, r7, ip, lsl #24
324129198Scognet#endif
325129198Scognet	str	r4, [r1], #0x04
326129198Scognet	str	r5, [r1], #0x04
327129198Scognet	str	r6, [r1], #0x04
328129198Scognet	str	r7, [r1], #0x04
329129198Scognet.Lcopyin_bad1:
330236991Simp	subs	r2, r2, #0x10
331129198Scognet	bge	.Lcopyin_bad1_loop16
332129198Scognet
333236991Simp	adds	r2, r2, #0x10
334129198Scognet	ldmeqfd	sp!, {r4-r7}
335137463Scognet	RETeq				/* Return now if done */
336129198Scognet	subs	r2, r2, #0x04
337129198Scognet	sublt	r0, r0, #0x03
338129198Scognet	blt	.Lcopyin_l4
339129198Scognet
340129198Scognet.Lcopyin_bad1_loop4:
341129198Scognet#ifdef __ARMEB__
342129198Scognet	mov	r4, ip, lsl #8
343129198Scognet#else
344129198Scognet	mov	r4, ip, lsr #8
345129198Scognet#endif
346129198Scognet	ldrt	ip, [r0], #0x04
347129198Scognet	subs	r2, r2, #0x04
348129198Scognet#ifdef __ARMEB__
349129198Scognet	orr	r4, r4, ip, lsr #24
350129198Scognet#else
351129198Scognet	orr	r4, r4, ip, lsl #24
352129198Scognet#endif
353129198Scognet	str	r4, [r1], #0x04
354129198Scognet	bge	.Lcopyin_bad1_loop4
355129198Scognet	sub	r0, r0, #0x03
356129198Scognet	b	.Lcopyin_l4
357129198Scognet
358129198Scognet.Lcopyin_bad2_loop16:
359129198Scognet#ifdef __ARMEB__
360129198Scognet	mov	r4, ip, lsl #16
361129198Scognet#else
362129198Scognet	mov	r4, ip, lsr #16
363129198Scognet#endif
364129198Scognet	ldrt	r5, [r0], #0x04
365129198Scognet	pld	[r0, #0x018]
366129198Scognet	ldrt	r6, [r0], #0x04
367129198Scognet	ldrt	r7, [r0], #0x04
368129198Scognet	ldrt	ip, [r0], #0x04
369129198Scognet#ifdef __ARMEB__
370129198Scognet	orr	r4, r4, r5, lsr #16
371129198Scognet	mov	r5, r5, lsl #16
372129198Scognet	orr	r5, r5, r6, lsr #16
373129198Scognet	mov	r6, r6, lsl #16
374129198Scognet	orr	r6, r6, r7, lsr #16
375129198Scognet	mov	r7, r7, lsl #16
376129198Scognet	orr	r7, r7, ip, lsr #16
377129198Scognet#else
378129198Scognet	orr	r4, r4, r5, lsl #16
379129198Scognet	mov	r5, r5, lsr #16
380129198Scognet	orr	r5, r5, r6, lsl #16
381129198Scognet	mov	r6, r6, lsr #16
382129198Scognet	orr	r6, r6, r7, lsl #16
383129198Scognet	mov	r7, r7, lsr #16
384129198Scognet	orr	r7, r7, ip, lsl #16
385129198Scognet#endif
386129198Scognet	str	r4, [r1], #0x04
387129198Scognet	str	r5, [r1], #0x04
388129198Scognet	str	r6, [r1], #0x04
389129198Scognet	str	r7, [r1], #0x04
390129198Scognet.Lcopyin_bad2:
391236991Simp	subs	r2, r2, #0x10
392129198Scognet	bge	.Lcopyin_bad2_loop16
393129198Scognet
394236991Simp	adds	r2, r2, #0x10
395129198Scognet	ldmeqfd	sp!, {r4-r7}
396137463Scognet	RETeq				/* Return now if done */
397129198Scognet	subs	r2, r2, #0x04
398129198Scognet	sublt	r0, r0, #0x02
399129198Scognet	blt	.Lcopyin_l4
400129198Scognet
401129198Scognet.Lcopyin_bad2_loop4:
402129198Scognet#ifdef __ARMEB__
403129198Scognet	mov	r4, ip, lsl #16
404129198Scognet#else
405129198Scognet	mov	r4, ip, lsr #16
406129198Scognet#endif
407129198Scognet	ldrt	ip, [r0], #0x04
408129198Scognet	subs	r2, r2, #0x04
409129198Scognet#ifdef __ARMEB__
410129198Scognet	orr	r4, r4, ip, lsr #16
411129198Scognet#else
412129198Scognet	orr	r4, r4, ip, lsl #16
413129198Scognet#endif
414129198Scognet	str	r4, [r1], #0x04
415129198Scognet	bge	.Lcopyin_bad2_loop4
416129198Scognet	sub	r0, r0, #0x02
417129198Scognet	b	.Lcopyin_l4
418129198Scognet
419129198Scognet.Lcopyin_bad3_loop16:
420129198Scognet#ifdef __ARMEB__
421129198Scognet	mov	r4, ip, lsl #24
422129198Scognet#else
423129198Scognet	mov	r4, ip, lsr #24
424129198Scognet#endif
425129198Scognet	ldrt	r5, [r0], #0x04
426129198Scognet	pld	[r0, #0x018]
427129198Scognet	ldrt	r6, [r0], #0x04
428129198Scognet	ldrt	r7, [r0], #0x04
429129198Scognet	ldrt	ip, [r0], #0x04
430129198Scognet#ifdef __ARMEB__
431129198Scognet	orr	r4, r4, r5, lsr #8
432129198Scognet	mov	r5, r5, lsl #24
433129198Scognet	orr	r5, r5, r6, lsr #8
434129198Scognet	mov	r6, r6, lsl #24
435129198Scognet	orr	r6, r6, r7, lsr #8
436129198Scognet	mov	r7, r7, lsl #24
437129198Scognet	orr	r7, r7, ip, lsr #8
438129198Scognet#else
439129198Scognet	orr	r4, r4, r5, lsl #8
440129198Scognet	mov	r5, r5, lsr #24
441129198Scognet	orr	r5, r5, r6, lsl #8
442129198Scognet	mov	r6, r6, lsr #24
443129198Scognet	orr	r6, r6, r7, lsl #8
444129198Scognet	mov	r7, r7, lsr #24
445129198Scognet	orr	r7, r7, ip, lsl #8
446129198Scognet#endif
447129198Scognet	str	r4, [r1], #0x04
448129198Scognet	str	r5, [r1], #0x04
449129198Scognet	str	r6, [r1], #0x04
450129198Scognet	str	r7, [r1], #0x04
451129198Scognet.Lcopyin_bad3:
452236991Simp	subs	r2, r2, #0x10
453129198Scognet	bge	.Lcopyin_bad3_loop16
454129198Scognet
455236991Simp	adds	r2, r2, #0x10
456129198Scognet	ldmeqfd	sp!, {r4-r7}
457137463Scognet	RETeq				/* Return now if done */
458129198Scognet	subs	r2, r2, #0x04
459129198Scognet	sublt	r0, r0, #0x01
460129198Scognet	blt	.Lcopyin_l4
461129198Scognet
462129198Scognet.Lcopyin_bad3_loop4:
463129198Scognet#ifdef __ARMEB__
464129198Scognet	mov	r4, ip, lsl #24
465129198Scognet#else
466129198Scognet	mov	r4, ip, lsr #24
467129198Scognet#endif
468129198Scognet	ldrt	ip, [r0], #0x04
469129198Scognet	subs	r2, r2, #0x04
470129198Scognet#ifdef __ARMEB__
471129198Scognet	orr	r4, r4, ip, lsr #8
472129198Scognet#else
473129198Scognet	orr	r4, r4, ip, lsl #8
474129198Scognet#endif
475129198Scognet	str	r4, [r1], #0x04
476129198Scognet	bge	.Lcopyin_bad3_loop4
477129198Scognet	sub	r0, r0, #0x01
478129198Scognet
479129198Scognet.Lcopyin_l4:
480129198Scognet	ldmfd	sp!, {r4-r7}
481129198Scognet	mov	r3, #0x00
482129198Scognet	adds	r2, r2, #0x04
483137463Scognet	RETeq
484129198Scognet.Lcopyin_l4_2:
485129198Scognet	rsbs	r2, r2, #0x03
486129198Scognet	addne	pc, pc, r2, lsl #3
487129198Scognet	nop
488129198Scognet	ldrbt	ip, [r0], #0x01
489129198Scognet	strb	ip, [r1], #0x01
490129198Scognet	ldrbt	ip, [r0], #0x01
491129198Scognet	strb	ip, [r1], #0x01
492129198Scognet	ldrbt	ip, [r0]
493129198Scognet	strb	ip, [r1]
494137463Scognet	RET
495248361SandrewEND(copyin)
496129198Scognet
497129198Scognet/*
498129198Scognet * r0 = kernel space address
499129198Scognet * r1 = user space address
500129198Scognet * r2 = length
501129198Scognet *
502129198Scognet * Copies bytes from kernel space to user space
503129198Scognet */
504129198ScognetENTRY(copyout)
505129198Scognet	cmp	r2, #0x00
506129198Scognet	movle	r0, #0x00
507129198Scognet	movle	pc, lr			/* Bail early if length is <= 0 */
508129198Scognet
509150864Scognet	ldr	r3, .L_arm_memcpy
510150864Scognet	ldr	r3, [r3]
511150864Scognet	cmp	r3, #0
512150864Scognet	beq	.Lnormale
513150864Scognet	ldr	r3, .L_min_memcpy_size
514150864Scognet	ldr	r3, [r3]
515150864Scognet	cmp	r2, r3
516150864Scognet	blt	.Lnormale
517150864Scognet	stmfd	sp!, {r0-r2, r4, lr}
518150864Scognet	mov     r3, r0
519150864Scognet	mov     r0, r1
520150864Scognet	mov     r1, r3
521150864Scognet	mov     r3, #1 /* DST_IS_USER */
522150864Scognet	ldr	r4, .L_arm_memcpy
523150864Scognet	mov	lr, pc
524150864Scognet	ldr	pc, [r4]
525150864Scognet	cmp     r0, #0
526150864Scognet	ldmfd   sp!, {r0-r2, r4, lr}
527150864Scognet	moveq	r0, #0
528150864Scognet	RETeq
529150864Scognet
530150864Scognet.Lnormale:
531129198Scognet	stmfd	sp!, {r10-r11, lr}
532129198Scognet
533239268Sgonzo	GET_PCB(r10)
534129198Scognet	ldr	r10, [r10]
535129198Scognet
536129198Scognet	mov	r3, #0x00
537129198Scognet	adr	ip, .Lcopyout_fault
538129198Scognet	ldr	r11, [r10, #PCB_ONFAULT]
539129198Scognet	str	ip, [r10, #PCB_ONFAULT]
540129198Scognet	bl	.Lcopyout_guts
541129198Scognet	str	r11, [r10, #PCB_ONFAULT]
542129198Scognet	mov	r0, #0x00
543129198Scognet	ldmfd	sp!, {r10-r11, pc}
544129198Scognet
545129198Scognet.Lcopyout_fault:
546239033Sandrew	ldr	r0, =EFAULT
547129198Scognet	str	r11, [r10, #PCB_ONFAULT]
548129198Scognet	cmp	r3, #0x00
549129198Scognet	ldmgtfd	sp!, {r4-r7}		/* r3 > 0 Restore r4-r7 */
550129198Scognet	ldmltfd	sp!, {r4-r9}		/* r3 < 0 Restore r4-r9 */
551129198Scognet	ldmfd	sp!, {r10-r11, pc}
552129198Scognet
553129198Scognet.Lcopyout_guts:
554129198Scognet	pld	[r0]
555129198Scognet	/* Word-align the destination buffer */
556129198Scognet	ands	ip, r1, #0x03		/* Already word aligned? */
557129198Scognet	beq	.Lcopyout_wordaligned	/* Yup */
558129198Scognet	rsb	ip, ip, #0x04
559129198Scognet	cmp	r2, ip			/* Enough bytes left to align it? */
560129198Scognet	blt	.Lcopyout_l4_2		/* Nope. Just copy bytewise */
561129198Scognet	sub	r2, r2, ip
562129198Scognet	rsbs	ip, ip, #0x03
563129198Scognet	addne	pc, pc, ip, lsl #3
564129198Scognet	nop
565129198Scognet	ldrb	ip, [r0], #0x01
566129198Scognet	strbt	ip, [r1], #0x01
567129198Scognet	ldrb	ip, [r0], #0x01
568129198Scognet	strbt	ip, [r1], #0x01
569129198Scognet	ldrb	ip, [r0], #0x01
570129198Scognet	strbt	ip, [r1], #0x01
571129198Scognet	cmp	r2, #0x00		/* All done? */
572137463Scognet	RETeq
573129198Scognet
574129198Scognet	/* Destination buffer is now word aligned */
575129198Scognet.Lcopyout_wordaligned:
576129198Scognet	ands	ip, r0, #0x03		/* Is src also word-aligned? */
577129198Scognet	bne	.Lcopyout_bad_align	/* Nope. Things just got bad */
578129198Scognet	cmp	r2, #0x08		/* Less than 8 bytes remaining? */
579129198Scognet	blt	.Lcopyout_w_less_than8
580129198Scognet
581129198Scognet	/* Quad-align the destination buffer */
582153273Scognet	tst	r0, #0x07		/* Already quad aligned? */
583129198Scognet	ldrne	ip, [r0], #0x04
584153273Scognet	subne	r2, r2, #0x04
585153273Scognet	strnet	ip, [r1], #0x04
586153273Scognet
587129198Scognet	stmfd	sp!, {r4-r9}		/* Free up some registers */
588129198Scognet	mov	r3, #-1			/* Signal restore r4-r9 */
589129198Scognet
590153273Scognet	/* Destination buffer word aligned, source is quad aligned */
591129198Scognet	subs	r2, r2, #0x80
592129198Scognet	blt	.Lcopyout_w_lessthan128
593129198Scognet
594129198Scognet	/* Copy 128 bytes at a time */
595129198Scognet.Lcopyout_w_loop128:
596153273Scognet	ldrd	r4, [r0], #0x08		/* LD:00-07 */
597129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x20 */
598153273Scognet	ldrd	r6, [r0], #0x08		/* LD:08-0f */
599153273Scognet	ldrd	r8, [r0], #0x08		/* LD:10-17 */
600129198Scognet	strt	r4, [r1], #0x04		/* ST:00-03 */
601129198Scognet	strt	r5, [r1], #0x04		/* ST:04-07 */
602153273Scognet	ldrd	r4, [r0], #0x08		/* LD:18-1f */
603129198Scognet	strt	r6, [r1], #0x04		/* ST:08-0b */
604129198Scognet	strt	r7, [r1], #0x04		/* ST:0c-0f */
605153273Scognet	ldrd	r6, [r0], #0x08		/* LD:20-27 */
606129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x40 */
607129198Scognet	strt	r8, [r1], #0x04		/* ST:10-13 */
608129198Scognet	strt	r9, [r1], #0x04		/* ST:14-17 */
609153273Scognet	ldrd	r8, [r0], #0x08		/* LD:28-2f */
610129198Scognet	strt	r4, [r1], #0x04		/* ST:18-1b */
611129198Scognet	strt	r5, [r1], #0x04		/* ST:1c-1f */
612153273Scognet	ldrd	r4, [r0], #0x08		/* LD:30-37 */
613129198Scognet	strt	r6, [r1], #0x04		/* ST:20-23 */
614129198Scognet	strt	r7, [r1], #0x04		/* ST:24-27 */
615153273Scognet	ldrd	r6, [r0], #0x08		/* LD:38-3f */
616129198Scognet	strt	r8, [r1], #0x04		/* ST:28-2b */
617129198Scognet	strt	r9, [r1], #0x04		/* ST:2c-2f */
618153273Scognet	ldrd	r8, [r0], #0x08		/* LD:40-47 */
619129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x60 */
620129198Scognet	strt	r4, [r1], #0x04		/* ST:30-33 */
621129198Scognet	strt	r5, [r1], #0x04		/* ST:34-37 */
622153273Scognet	ldrd	r4, [r0], #0x08		/* LD:48-4f */
623129198Scognet	strt	r6, [r1], #0x04		/* ST:38-3b */
624129198Scognet	strt	r7, [r1], #0x04		/* ST:3c-3f */
625153273Scognet	ldrd	r6, [r0], #0x08		/* LD:50-57 */
626129198Scognet	strt	r8, [r1], #0x04		/* ST:40-43 */
627129198Scognet	strt	r9, [r1], #0x04		/* ST:44-47 */
628153273Scognet	ldrd	r8, [r0], #0x08		/* LD:58-4f */
629129198Scognet	strt	r4, [r1], #0x04		/* ST:48-4b */
630129198Scognet	strt	r5, [r1], #0x04		/* ST:4c-4f */
631153273Scognet	ldrd	r4, [r0], #0x08		/* LD:60-67 */
632129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x80 */
633129198Scognet	strt	r6, [r1], #0x04		/* ST:50-53 */
634129198Scognet	strt	r7, [r1], #0x04		/* ST:54-57 */
635153273Scognet	ldrd	r6, [r0], #0x08		/* LD:68-6f */
636129198Scognet	strt	r8, [r1], #0x04		/* ST:58-5b */
637129198Scognet	strt	r9, [r1], #0x04		/* ST:5c-5f */
638153273Scognet	ldrd	r8, [r0], #0x08		/* LD:70-77 */
639129198Scognet	strt	r4, [r1], #0x04		/* ST:60-63 */
640129198Scognet	strt	r5, [r1], #0x04		/* ST:64-67 */
641153273Scognet	ldrd	r4, [r0], #0x08		/* LD:78-7f */
642129198Scognet	strt	r6, [r1], #0x04		/* ST:68-6b */
643129198Scognet	strt	r7, [r1], #0x04		/* ST:6c-6f */
644129198Scognet	strt	r8, [r1], #0x04		/* ST:70-73 */
645129198Scognet	strt	r9, [r1], #0x04		/* ST:74-77 */
646129198Scognet	subs	r2, r2, #0x80
647129198Scognet	strt	r4, [r1], #0x04		/* ST:78-7b */
648129198Scognet	strt	r5, [r1], #0x04		/* ST:7c-7f */
649129198Scognet	bge	.Lcopyout_w_loop128
650129198Scognet
651129198Scognet.Lcopyout_w_lessthan128:
652129198Scognet	adds	r2, r2, #0x80		/* Adjust for extra sub */
653129198Scognet	ldmeqfd	sp!, {r4-r9}
654137463Scognet	RETeq				/* Return now if done */
655129198Scognet	subs	r2, r2, #0x20
656129198Scognet	blt	.Lcopyout_w_lessthan32
657129198Scognet
658129198Scognet	/* Copy 32 bytes at a time */
659129198Scognet.Lcopyout_w_loop32:
660153273Scognet	ldrd	r4, [r0], #0x08
661129198Scognet	pld	[r0, #0x18]
662153273Scognet	ldrd	r6, [r0], #0x08
663153273Scognet	ldrd	r8, [r0], #0x08
664129198Scognet	strt	r4, [r1], #0x04
665129198Scognet	strt	r5, [r1], #0x04
666153273Scognet	ldrd	r4, [r0], #0x08
667129198Scognet	strt	r6, [r1], #0x04
668129198Scognet	strt	r7, [r1], #0x04
669129198Scognet	strt	r8, [r1], #0x04
670129198Scognet	strt	r9, [r1], #0x04
671129198Scognet	subs	r2, r2, #0x20
672129198Scognet	strt	r4, [r1], #0x04
673129198Scognet	strt	r5, [r1], #0x04
674129198Scognet	bge	.Lcopyout_w_loop32
675129198Scognet
676129198Scognet.Lcopyout_w_lessthan32:
677129198Scognet	adds	r2, r2, #0x20		/* Adjust for extra sub */
678129198Scognet	ldmeqfd	sp!, {r4-r9}
679137463Scognet	RETeq				/* Return now if done */
680129198Scognet
681129198Scognet	and	r4, r2, #0x18
682129198Scognet	rsb	r5, r4, #0x18
683129198Scognet	subs	r2, r2, r4
684129198Scognet	add	pc, pc, r5, lsl #1
685129198Scognet	nop
686129198Scognet
687129198Scognet	/* At least 24 bytes remaining */
688153273Scognet	ldrd	r4, [r0], #0x08
689129198Scognet	strt	r4, [r1], #0x04
690129198Scognet	strt	r5, [r1], #0x04
691153273Scognet	nop
692129198Scognet
693129198Scognet	/* At least 16 bytes remaining */
694153273Scognet	ldrd	r4, [r0], #0x08
695129198Scognet	strt	r4, [r1], #0x04
696129198Scognet	strt	r5, [r1], #0x04
697153273Scognet	nop
698129198Scognet
699129198Scognet	/* At least 8 bytes remaining */
700153273Scognet	ldrd	r4, [r0], #0x08
701129198Scognet	strt	r4, [r1], #0x04
702129198Scognet	strt	r5, [r1], #0x04
703153273Scognet	nop
704129198Scognet
705129198Scognet	/* Less than 8 bytes remaining */
706129198Scognet	ldmfd	sp!, {r4-r9}
707137463Scognet	RETeq				/* Return now if done */
708129198Scognet	mov	r3, #0x00
709129198Scognet
710129198Scognet.Lcopyout_w_less_than8:
711129198Scognet	subs	r2, r2, #0x04
712129198Scognet	ldrge	ip, [r0], #0x04
713129198Scognet	strget	ip, [r1], #0x04
714137463Scognet	RETeq				/* Return now if done */
715129198Scognet	addlt	r2, r2, #0x04
716129198Scognet	ldrb	ip, [r0], #0x01
717129198Scognet	cmp	r2, #0x02
718129198Scognet	ldrgeb	r2, [r0], #0x01
719129198Scognet	strbt	ip, [r1], #0x01
720129198Scognet	ldrgtb	ip, [r0]
721129198Scognet	strgebt	r2, [r1], #0x01
722129198Scognet	strgtbt	ip, [r1]
723137463Scognet	RET
724129198Scognet
725129198Scognet/*
726129198Scognet * At this point, it has not been possible to word align both buffers.
727129198Scognet * The destination buffer (r1) is word aligned, but the source buffer
728129198Scognet * (r0) is not.
729129198Scognet */
730129198Scognet.Lcopyout_bad_align:
731129198Scognet	stmfd	sp!, {r4-r7}
732129198Scognet	mov	r3, #0x01
733129198Scognet	bic	r0, r0, #0x03
734129198Scognet	cmp	ip, #2
735129198Scognet	ldr	ip, [r0], #0x04
736129198Scognet	bgt	.Lcopyout_bad3
737129198Scognet	beq	.Lcopyout_bad2
738129198Scognet	b	.Lcopyout_bad1
739129198Scognet
740129198Scognet.Lcopyout_bad1_loop16:
741129198Scognet#ifdef	__ARMEB__
742129198Scognet	mov	r4, ip, lsl #8
743129198Scognet#else
744129198Scognet	mov	r4, ip, lsr #8
745129198Scognet#endif
746129198Scognet	ldr	r5, [r0], #0x04
747129198Scognet	pld	[r0, #0x018]
748129198Scognet	ldr	r6, [r0], #0x04
749129198Scognet	ldr	r7, [r0], #0x04
750129198Scognet	ldr	ip, [r0], #0x04
751129198Scognet#ifdef	__ARMEB__
752129198Scognet	orr	r4, r4, r5, lsr #24
753129198Scognet	mov	r5, r5, lsl #8
754129198Scognet	orr	r5, r5, r6, lsr #24
755129198Scognet	mov	r6, r6, lsl #8
756129198Scognet	orr	r6, r6, r7, lsr #24
757129198Scognet	mov	r7, r7, lsl #8
758129198Scognet	orr	r7, r7, ip, lsr #24
759129198Scognet#else
760129198Scognet	orr	r4, r4, r5, lsl #24
761129198Scognet	mov	r5, r5, lsr #8
762129198Scognet	orr	r5, r5, r6, lsl #24
763129198Scognet	mov	r6, r6, lsr #8
764129198Scognet	orr	r6, r6, r7, lsl #24
765129198Scognet	mov	r7, r7, lsr #8
766129198Scognet	orr	r7, r7, ip, lsl #24
767129198Scognet#endif
768129198Scognet	strt	r4, [r1], #0x04
769129198Scognet	strt	r5, [r1], #0x04
770129198Scognet	strt	r6, [r1], #0x04
771129198Scognet	strt	r7, [r1], #0x04
772129198Scognet.Lcopyout_bad1:
773236991Simp	subs	r2, r2, #0x10
774129198Scognet	bge	.Lcopyout_bad1_loop16
775129198Scognet
776236991Simp	adds	r2, r2, #0x10
777129198Scognet	ldmeqfd	sp!, {r4-r7}
778137463Scognet	RETeq				/* Return now if done */
779129198Scognet	subs	r2, r2, #0x04
780129198Scognet	sublt	r0, r0, #0x03
781129198Scognet	blt	.Lcopyout_l4
782129198Scognet
783129198Scognet.Lcopyout_bad1_loop4:
784129198Scognet#ifdef __ARMEB__
785129198Scognet	mov	r4, ip, lsl #8
786129198Scognet#else
787129198Scognet	mov	r4, ip, lsr #8
788129198Scognet#endif
789129198Scognet	ldr	ip, [r0], #0x04
790129198Scognet	subs	r2, r2, #0x04
791129198Scognet#ifdef __ARMEB__
792129198Scognet	orr	r4, r4, ip, lsr #24
793129198Scognet#else
794129198Scognet	orr	r4, r4, ip, lsl #24
795129198Scognet#endif
796129198Scognet	strt	r4, [r1], #0x04
797129198Scognet	bge	.Lcopyout_bad1_loop4
798129198Scognet	sub	r0, r0, #0x03
799129198Scognet	b	.Lcopyout_l4
800129198Scognet
801129198Scognet.Lcopyout_bad2_loop16:
802129198Scognet#ifdef __ARMEB__
803129198Scognet	mov	r4, ip, lsl #16
804129198Scognet#else
805129198Scognet	mov	r4, ip, lsr #16
806129198Scognet#endif
807129198Scognet	ldr	r5, [r0], #0x04
808129198Scognet	pld	[r0, #0x018]
809129198Scognet	ldr	r6, [r0], #0x04
810129198Scognet	ldr	r7, [r0], #0x04
811129198Scognet	ldr	ip, [r0], #0x04
812129198Scognet#ifdef __ARMEB__
813129198Scognet	orr	r4, r4, r5, lsr #16
814129198Scognet	mov	r5, r5, lsl #16
815129198Scognet	orr	r5, r5, r6, lsr #16
816129198Scognet	mov	r6, r6, lsl #16
817129198Scognet	orr	r6, r6, r7, lsr #16
818129198Scognet	mov	r7, r7, lsl #16
819129198Scognet	orr	r7, r7, ip, lsr #16
820129198Scognet#else
821129198Scognet	orr	r4, r4, r5, lsl #16
822129198Scognet	mov	r5, r5, lsr #16
823129198Scognet	orr	r5, r5, r6, lsl #16
824129198Scognet	mov	r6, r6, lsr #16
825129198Scognet	orr	r6, r6, r7, lsl #16
826129198Scognet	mov	r7, r7, lsr #16
827129198Scognet	orr	r7, r7, ip, lsl #16
828129198Scognet#endif
829129198Scognet	strt	r4, [r1], #0x04
830129198Scognet	strt	r5, [r1], #0x04
831129198Scognet	strt	r6, [r1], #0x04
832129198Scognet	strt	r7, [r1], #0x04
833129198Scognet.Lcopyout_bad2:
834236991Simp	subs	r2, r2, #0x10
835129198Scognet	bge	.Lcopyout_bad2_loop16
836129198Scognet
837236991Simp	adds	r2, r2, #0x10
838129198Scognet	ldmeqfd	sp!, {r4-r7}
839137463Scognet	RETeq				/* Return now if done */
840129198Scognet	subs	r2, r2, #0x04
841129198Scognet	sublt	r0, r0, #0x02
842129198Scognet	blt	.Lcopyout_l4
843129198Scognet
844129198Scognet.Lcopyout_bad2_loop4:
845129198Scognet#ifdef __ARMEB__
846129198Scognet	mov	r4, ip, lsl #16
847129198Scognet#else
848129198Scognet	mov	r4, ip, lsr #16
849129198Scognet#endif
850129198Scognet	ldr	ip, [r0], #0x04
851129198Scognet	subs	r2, r2, #0x04
852129198Scognet#ifdef __ARMEB__
853129198Scognet	orr	r4, r4, ip, lsr #16
854129198Scognet#else
855129198Scognet	orr	r4, r4, ip, lsl #16
856129198Scognet#endif
857129198Scognet	strt	r4, [r1], #0x04
858129198Scognet	bge	.Lcopyout_bad2_loop4
859129198Scognet	sub	r0, r0, #0x02
860129198Scognet	b	.Lcopyout_l4
861129198Scognet
862129198Scognet.Lcopyout_bad3_loop16:
863129198Scognet#ifdef __ARMEB__
864129198Scognet	mov	r4, ip, lsl #24
865129198Scognet#else
866129198Scognet	mov	r4, ip, lsr #24
867129198Scognet#endif
868129198Scognet	ldr	r5, [r0], #0x04
869129198Scognet	pld	[r0, #0x018]
870129198Scognet	ldr	r6, [r0], #0x04
871129198Scognet	ldr	r7, [r0], #0x04
872129198Scognet	ldr	ip, [r0], #0x04
873129198Scognet#ifdef __ARMEB__
874129198Scognet	orr	r4, r4, r5, lsr #8
875129198Scognet	mov	r5, r5, lsl #24
876129198Scognet	orr	r5, r5, r6, lsr #8
877129198Scognet	mov	r6, r6, lsl #24
878129198Scognet	orr	r6, r6, r7, lsr #8
879129198Scognet	mov	r7, r7, lsl #24
880129198Scognet	orr	r7, r7, ip, lsr #8
881129198Scognet#else
882129198Scognet	orr	r4, r4, r5, lsl #8
883129198Scognet	mov	r5, r5, lsr #24
884129198Scognet	orr	r5, r5, r6, lsl #8
885129198Scognet	mov	r6, r6, lsr #24
886129198Scognet	orr	r6, r6, r7, lsl #8
887129198Scognet	mov	r7, r7, lsr #24
888129198Scognet	orr	r7, r7, ip, lsl #8
889129198Scognet#endif
890129198Scognet	strt	r4, [r1], #0x04
891129198Scognet	strt	r5, [r1], #0x04
892129198Scognet	strt	r6, [r1], #0x04
893129198Scognet	strt	r7, [r1], #0x04
894129198Scognet.Lcopyout_bad3:
895236991Simp	subs	r2, r2, #0x10
896129198Scognet	bge	.Lcopyout_bad3_loop16
897129198Scognet
898236991Simp	adds	r2, r2, #0x10
899129198Scognet	ldmeqfd	sp!, {r4-r7}
900137463Scognet	RETeq				/* Return now if done */
901129198Scognet	subs	r2, r2, #0x04
902129198Scognet	sublt	r0, r0, #0x01
903129198Scognet	blt	.Lcopyout_l4
904129198Scognet
905129198Scognet.Lcopyout_bad3_loop4:
906129198Scognet#ifdef __ARMEB__
907129198Scognet	mov	r4, ip, lsl #24
908129198Scognet#else
909129198Scognet	mov	r4, ip, lsr #24
910129198Scognet#endif
911129198Scognet	ldr	ip, [r0], #0x04
912129198Scognet	subs	r2, r2, #0x04
913129198Scognet#ifdef __ARMEB__
914129198Scognet	orr	r4, r4, ip, lsr #8
915129198Scognet#else
916129198Scognet	orr	r4, r4, ip, lsl #8
917129198Scognet#endif
918129198Scognet	strt	r4, [r1], #0x04
919129198Scognet	bge	.Lcopyout_bad3_loop4
920129198Scognet	sub	r0, r0, #0x01
921129198Scognet
922129198Scognet.Lcopyout_l4:
923129198Scognet	ldmfd	sp!, {r4-r7}
924129198Scognet	mov	r3, #0x00
925129198Scognet	adds	r2, r2, #0x04
926137463Scognet	RETeq
927129198Scognet.Lcopyout_l4_2:
928129198Scognet	rsbs	r2, r2, #0x03
929129198Scognet	addne	pc, pc, r2, lsl #3
930129198Scognet	nop
931129198Scognet	ldrb	ip, [r0], #0x01
932129198Scognet	strbt	ip, [r1], #0x01
933129198Scognet	ldrb	ip, [r0], #0x01
934129198Scognet	strbt	ip, [r1], #0x01
935129198Scognet	ldrb	ip, [r0]
936129198Scognet	strbt	ip, [r1]
937137463Scognet	RET
938248361SandrewEND(copyout)
939248361Sandrew
940