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
41275418Sandrew	.syntax	unified
42129198Scognet	.text
43276596Sian	.align	2
44129198Scognet
45284264Sandrew#if __ARM_ARCH >= 6
46239268Sgonzo#define GET_PCB(tmp) \
47239268Sgonzo	mrc p15, 0, tmp, c13, c0, 4; \
48261415Scognet	add	tmp, tmp, #(TD_PCB)
49129198Scognet#else
50129198Scognet.Lcurpcb:
51129198Scognet	.word	_C_LABEL(__pcpu) + PC_CURPCB
52239268Sgonzo#define GET_PCB(tmp) \
53239268Sgonzo	ldr	tmp, .Lcurpcb
54129198Scognet#endif
55129198Scognet
56129198Scognet/*
57129198Scognet * r0 = user space address
58129198Scognet * r1 = kernel space address
59129198Scognet * r2 = length
60129198Scognet *
61129198Scognet * Copies bytes from user space to kernel space
62129198Scognet */
63129198ScognetENTRY(copyin)
64129198Scognet	cmp	r2, #0x00
65129198Scognet	movle	r0, #0x00
66129198Scognet	movle	pc, lr			/* Bail early if length is <= 0 */
67129198Scognet
68289372Skib	adds	r3, r0, r2
69289372Skib	movcs	r0, #EFAULT
70289372Skib	RETc(cs)
71289372Skib
72289372Skib	ldr	r12, =(VM_MAXUSER_ADDRESS + 1)
73289372Skib	cmp	r3, r12
74289372Skib	movcs	r0, #EFAULT
75289372Skib	RETc(cs)
76289372Skib
77150864Scognet	ldr	r3, .L_arm_memcpy
78150864Scognet	ldr	r3, [r3]
79150864Scognet	cmp	r3, #0
80150864Scognet	beq	.Lnormal
81150864Scognet	ldr	r3, .L_min_memcpy_size
82150864Scognet	ldr	r3, [r3]
83150864Scognet	cmp	r2, r3
84150864Scognet	blt	.Lnormal
85150864Scognet	stmfd	sp!, {r0-r2, r4, lr}
86150864Scognet	mov     r3, r0
87150864Scognet	mov     r0, r1
88150864Scognet	mov     r1, r3
89150864Scognet	mov     r3, #2 /* SRC_IS_USER */
90150864Scognet	ldr	r4, .L_arm_memcpy
91150864Scognet	mov	lr, pc
92150864Scognet	ldr	pc, [r4]
93150864Scognet	cmp     r0, #0
94150864Scognet	ldmfd   sp!, {r0-r2, r4, lr}
95150864Scognet	moveq	r0, #0
96150864Scognet	RETeq
97283366Sandrew
98150864Scognet.Lnormal:
99129198Scognet	stmfd	sp!, {r10-r11, lr}
100129198Scognet
101239268Sgonzo	GET_PCB(r10)
102129198Scognet	ldr	r10, [r10]
103129198Scognet
104129198Scognet	mov	r3, #0x00
105129198Scognet	adr	ip, .Lcopyin_fault
106129198Scognet	ldr	r11, [r10, #PCB_ONFAULT]
107129198Scognet	str	ip, [r10, #PCB_ONFAULT]
108129198Scognet	bl	.Lcopyin_guts
109129198Scognet	str	r11, [r10, #PCB_ONFAULT]
110129198Scognet	mov	r0, #0x00
111129198Scognet	ldmfd	sp!, {r10-r11, pc}
112129198Scognet
113129198Scognet.Lcopyin_fault:
114239033Sandrew	ldr	r0, =EFAULT
115129198Scognet	str	r11, [r10, #PCB_ONFAULT]
116129198Scognet	cmp	r3, #0x00
117275418Sandrew	ldmfdgt	sp!, {r4-r7}		/* r3 > 0 Restore r4-r7 */
118275418Sandrew	ldmfdlt	sp!, {r4-r9}		/* r3 < 0 Restore r4-r9 */
119129198Scognet	ldmfd	sp!, {r10-r11, pc}
120129198Scognet
121129198Scognet.Lcopyin_guts:
122129198Scognet	pld	[r0]
123129198Scognet	/* Word-align the destination buffer */
124129198Scognet	ands	ip, r1, #0x03		/* Already word aligned? */
125129198Scognet	beq	.Lcopyin_wordaligned	/* Yup */
126129198Scognet	rsb	ip, ip, #0x04
127129198Scognet	cmp	r2, ip			/* Enough bytes left to align it? */
128129198Scognet	blt	.Lcopyin_l4_2		/* Nope. Just copy bytewise */
129129198Scognet	sub	r2, r2, ip
130129198Scognet	rsbs	ip, ip, #0x03
131129198Scognet	addne	pc, pc, ip, lsl #3
132129198Scognet	nop
133129198Scognet	ldrbt	ip, [r0], #0x01
134129198Scognet	strb	ip, [r1], #0x01
135129198Scognet	ldrbt	ip, [r0], #0x01
136129198Scognet	strb	ip, [r1], #0x01
137129198Scognet	ldrbt	ip, [r0], #0x01
138129198Scognet	strb	ip, [r1], #0x01
139129198Scognet	cmp	r2, #0x00		/* All done? */
140137463Scognet	RETeq
141129198Scognet
142129198Scognet	/* Destination buffer is now word aligned */
143129198Scognet.Lcopyin_wordaligned:
144129198Scognet	ands	ip, r0, #0x03		/* Is src also word-aligned? */
145129198Scognet	bne	.Lcopyin_bad_align	/* Nope. Things just got bad */
146129198Scognet	cmp	r2, #0x08		/* Less than 8 bytes remaining? */
147129198Scognet	blt	.Lcopyin_w_less_than8
148129198Scognet
149129198Scognet	/* Quad-align the destination buffer */
150129198Scognet	tst	r1, #0x07		/* Already quad aligned? */
151275418Sandrew	ldrtne	ip, [r0], #0x04
152153273Scognet	strne	ip, [r1], #0x04
153153273Scognet	subne	r2, r2, #0x04
154129198Scognet	stmfd	sp!, {r4-r9}		/* Free up some registers */
155129198Scognet	mov	r3, #-1			/* Signal restore r4-r9 */
156129198Scognet
157129198Scognet	/* Destination buffer quad aligned, source is word aligned */
158129198Scognet	subs	r2, r2, #0x80
159129198Scognet	blt	.Lcopyin_w_lessthan128
160129198Scognet
161129198Scognet	/* Copy 128 bytes at a time */
162129198Scognet.Lcopyin_w_loop128:
163129198Scognet	ldrt	r4, [r0], #0x04		/* LD:00-03 */
164129198Scognet	ldrt	r5, [r0], #0x04		/* LD:04-07 */
165129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x20 */
166129198Scognet	ldrt	r6, [r0], #0x04		/* LD:08-0b */
167129198Scognet	ldrt	r7, [r0], #0x04		/* LD:0c-0f */
168129198Scognet	ldrt	r8, [r0], #0x04		/* LD:10-13 */
169129198Scognet	ldrt	r9, [r0], #0x04		/* LD:14-17 */
170129198Scognet	strd	r4, [r1], #0x08		/* ST:00-07 */
171129198Scognet	ldrt	r4, [r0], #0x04		/* LD:18-1b */
172129198Scognet	ldrt	r5, [r0], #0x04		/* LD:1c-1f */
173129198Scognet	strd	r6, [r1], #0x08		/* ST:08-0f */
174129198Scognet	ldrt	r6, [r0], #0x04		/* LD:20-23 */
175129198Scognet	ldrt	r7, [r0], #0x04		/* LD:24-27 */
176129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x40 */
177129198Scognet	strd	r8, [r1], #0x08		/* ST:10-17 */
178129198Scognet	ldrt	r8, [r0], #0x04		/* LD:28-2b */
179129198Scognet	ldrt	r9, [r0], #0x04		/* LD:2c-2f */
180129198Scognet	strd	r4, [r1], #0x08		/* ST:18-1f */
181129198Scognet	ldrt	r4, [r0], #0x04		/* LD:30-33 */
182129198Scognet	ldrt	r5, [r0], #0x04		/* LD:34-37 */
183129198Scognet	strd	r6, [r1], #0x08		/* ST:20-27 */
184129198Scognet	ldrt	r6, [r0], #0x04		/* LD:38-3b */
185129198Scognet	ldrt	r7, [r0], #0x04		/* LD:3c-3f */
186129198Scognet	strd	r8, [r1], #0x08		/* ST:28-2f */
187129198Scognet	ldrt	r8, [r0], #0x04		/* LD:40-43 */
188129198Scognet	ldrt	r9, [r0], #0x04		/* LD:44-47 */
189129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x60 */
190129198Scognet	strd	r4, [r1], #0x08		/* ST:30-37 */
191129198Scognet	ldrt	r4, [r0], #0x04		/* LD:48-4b */
192129198Scognet	ldrt	r5, [r0], #0x04		/* LD:4c-4f */
193129198Scognet	strd	r6, [r1], #0x08		/* ST:38-3f */
194129198Scognet	ldrt	r6, [r0], #0x04		/* LD:50-53 */
195129198Scognet	ldrt	r7, [r0], #0x04		/* LD:54-57 */
196129198Scognet	strd	r8, [r1], #0x08		/* ST:40-47 */
197129198Scognet	ldrt	r8, [r0], #0x04		/* LD:58-5b */
198129198Scognet	ldrt	r9, [r0], #0x04		/* LD:5c-5f */
199129198Scognet	strd	r4, [r1], #0x08		/* ST:48-4f */
200129198Scognet	ldrt	r4, [r0], #0x04		/* LD:60-63 */
201129198Scognet	ldrt	r5, [r0], #0x04		/* LD:64-67 */
202129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x80 */
203129198Scognet	strd	r6, [r1], #0x08		/* ST:50-57 */
204129198Scognet	ldrt	r6, [r0], #0x04		/* LD:68-6b */
205129198Scognet	ldrt	r7, [r0], #0x04		/* LD:6c-6f */
206129198Scognet	strd	r8, [r1], #0x08		/* ST:58-5f */
207129198Scognet	ldrt	r8, [r0], #0x04		/* LD:70-73 */
208129198Scognet	ldrt	r9, [r0], #0x04		/* LD:74-77 */
209129198Scognet	strd	r4, [r1], #0x08		/* ST:60-67 */
210129198Scognet	ldrt	r4, [r0], #0x04		/* LD:78-7b */
211129198Scognet	ldrt	r5, [r0], #0x04		/* LD:7c-7f */
212129198Scognet	strd	r6, [r1], #0x08		/* ST:68-6f */
213129198Scognet	strd	r8, [r1], #0x08		/* ST:70-77 */
214129198Scognet	subs	r2, r2, #0x80
215129198Scognet	strd	r4, [r1], #0x08		/* ST:78-7f */
216129198Scognet	bge	.Lcopyin_w_loop128
217129198Scognet
218129198Scognet.Lcopyin_w_lessthan128:
219129198Scognet	adds	r2, r2, #0x80		/* Adjust for extra sub */
220275418Sandrew	ldmfdeq	sp!, {r4-r9}
221137463Scognet	RETeq
222129198Scognet	subs	r2, r2, #0x20
223129198Scognet	blt	.Lcopyin_w_lessthan32
224129198Scognet
225129198Scognet	/* Copy 32 bytes at a time */
226129198Scognet.Lcopyin_w_loop32:
227129198Scognet	ldrt	r4, [r0], #0x04
228129198Scognet	ldrt	r5, [r0], #0x04
229129198Scognet	pld	[r0, #0x18]
230129198Scognet	ldrt	r6, [r0], #0x04
231129198Scognet	ldrt	r7, [r0], #0x04
232129198Scognet	ldrt	r8, [r0], #0x04
233129198Scognet	ldrt	r9, [r0], #0x04
234129198Scognet	strd	r4, [r1], #0x08
235129198Scognet	ldrt	r4, [r0], #0x04
236129198Scognet	ldrt	r5, [r0], #0x04
237129198Scognet	strd	r6, [r1], #0x08
238129198Scognet	strd	r8, [r1], #0x08
239129198Scognet	subs	r2, r2, #0x20
240129198Scognet	strd	r4, [r1], #0x08
241129198Scognet	bge	.Lcopyin_w_loop32
242129198Scognet
243129198Scognet.Lcopyin_w_lessthan32:
244129198Scognet	adds	r2, r2, #0x20		/* Adjust for extra sub */
245275418Sandrew	ldmfdeq	sp!, {r4-r9}
246137463Scognet	RETeq				/* Return now if done */
247129198Scognet
248129198Scognet	and	r4, r2, #0x18
249129198Scognet	rsb	r5, r4, #0x18
250129198Scognet	subs	r2, r2, r4
251129198Scognet	add	pc, pc, r5, lsl #1
252129198Scognet	nop
253129198Scognet
254129198Scognet	/* At least 24 bytes remaining */
255129198Scognet	ldrt	r4, [r0], #0x04
256129198Scognet	ldrt	r5, [r0], #0x04
257129198Scognet	nop
258129198Scognet	strd	r4, [r1], #0x08
259129198Scognet
260129198Scognet	/* At least 16 bytes remaining */
261129198Scognet	ldrt	r4, [r0], #0x04
262129198Scognet	ldrt	r5, [r0], #0x04
263129198Scognet	nop
264129198Scognet	strd	r4, [r1], #0x08
265129198Scognet
266129198Scognet	/* At least 8 bytes remaining */
267129198Scognet	ldrt	r4, [r0], #0x04
268129198Scognet	ldrt	r5, [r0], #0x04
269129198Scognet	nop
270129198Scognet	strd	r4, [r1], #0x08
271129198Scognet
272129198Scognet	/* Less than 8 bytes remaining */
273129198Scognet	ldmfd	sp!, {r4-r9}
274137463Scognet	RETeq				/* Return now if done */
275129198Scognet	mov	r3, #0x00
276129198Scognet
277129198Scognet.Lcopyin_w_less_than8:
278129198Scognet	subs	r2, r2, #0x04
279275418Sandrew	ldrtge	ip, [r0], #0x04
280129198Scognet	strge	ip, [r1], #0x04
281137463Scognet	RETeq				/* Return now if done */
282129198Scognet	addlt	r2, r2, #0x04
283129198Scognet	ldrbt	ip, [r0], #0x01
284129198Scognet	cmp	r2, #0x02
285275418Sandrew	ldrbtge	r2, [r0], #0x01
286129198Scognet	strb	ip, [r1], #0x01
287275418Sandrew	ldrbtgt	ip, [r0]
288275418Sandrew	strbge	r2, [r1], #0x01
289275418Sandrew	strbgt	ip, [r1]
290137463Scognet	RET
291129198Scognet
292129198Scognet/*
293129198Scognet * At this point, it has not been possible to word align both buffers.
294129198Scognet * The destination buffer (r1) is word aligned, but the source buffer
295129198Scognet * (r0) is not.
296129198Scognet */
297129198Scognet.Lcopyin_bad_align:
298129198Scognet	stmfd	sp!, {r4-r7}
299129198Scognet	mov	r3, #0x01
300129198Scognet	bic	r0, r0, #0x03
301129198Scognet	cmp	ip, #2
302129198Scognet	ldrt	ip, [r0], #0x04
303129198Scognet	bgt	.Lcopyin_bad3
304129198Scognet	beq	.Lcopyin_bad2
305129198Scognet	b	.Lcopyin_bad1
306129198Scognet
307129198Scognet.Lcopyin_bad1_loop16:
308129198Scognet#ifdef __ARMEB__
309129198Scognet	mov	r4, ip, lsl #8
310129198Scognet#else
311129198Scognet	mov	r4, ip, lsr #8
312129198Scognet#endif
313129198Scognet	ldrt	r5, [r0], #0x04
314129198Scognet	pld	[r0, #0x018]
315129198Scognet	ldrt	r6, [r0], #0x04
316129198Scognet	ldrt	r7, [r0], #0x04
317129198Scognet	ldrt	ip, [r0], #0x04
318129198Scognet#ifdef __ARMEB__
319129198Scognet	orr	r4, r4, r5, lsr #24
320129198Scognet	mov	r5, r5, lsl #8
321129198Scognet	orr	r5, r5, r6, lsr #24
322129198Scognet	mov	r6, r6, lsl #8
323129198Scognet	orr	r6, r6, r7, lsr #24
324129198Scognet	mov	r7, r7, lsl #8
325129198Scognet	orr	r7, r7, ip, lsr #24
326129198Scognet#else
327129198Scognet	orr	r4, r4, r5, lsl #24
328129198Scognet	mov	r5, r5, lsr #8
329129198Scognet	orr	r5, r5, r6, lsl #24
330129198Scognet	mov	r6, r6, lsr #8
331129198Scognet	orr	r6, r6, r7, lsl #24
332129198Scognet	mov	r7, r7, lsr #8
333129198Scognet	orr	r7, r7, ip, lsl #24
334129198Scognet#endif
335129198Scognet	str	r4, [r1], #0x04
336129198Scognet	str	r5, [r1], #0x04
337129198Scognet	str	r6, [r1], #0x04
338129198Scognet	str	r7, [r1], #0x04
339129198Scognet.Lcopyin_bad1:
340236991Simp	subs	r2, r2, #0x10
341129198Scognet	bge	.Lcopyin_bad1_loop16
342129198Scognet
343236991Simp	adds	r2, r2, #0x10
344275418Sandrew	ldmfdeq	sp!, {r4-r7}
345137463Scognet	RETeq				/* Return now if done */
346129198Scognet	subs	r2, r2, #0x04
347129198Scognet	sublt	r0, r0, #0x03
348129198Scognet	blt	.Lcopyin_l4
349129198Scognet
350129198Scognet.Lcopyin_bad1_loop4:
351129198Scognet#ifdef __ARMEB__
352129198Scognet	mov	r4, ip, lsl #8
353129198Scognet#else
354129198Scognet	mov	r4, ip, lsr #8
355129198Scognet#endif
356129198Scognet	ldrt	ip, [r0], #0x04
357129198Scognet	subs	r2, r2, #0x04
358129198Scognet#ifdef __ARMEB__
359129198Scognet	orr	r4, r4, ip, lsr #24
360129198Scognet#else
361129198Scognet	orr	r4, r4, ip, lsl #24
362129198Scognet#endif
363129198Scognet	str	r4, [r1], #0x04
364129198Scognet	bge	.Lcopyin_bad1_loop4
365129198Scognet	sub	r0, r0, #0x03
366129198Scognet	b	.Lcopyin_l4
367129198Scognet
368129198Scognet.Lcopyin_bad2_loop16:
369129198Scognet#ifdef __ARMEB__
370129198Scognet	mov	r4, ip, lsl #16
371129198Scognet#else
372129198Scognet	mov	r4, ip, lsr #16
373129198Scognet#endif
374129198Scognet	ldrt	r5, [r0], #0x04
375129198Scognet	pld	[r0, #0x018]
376129198Scognet	ldrt	r6, [r0], #0x04
377129198Scognet	ldrt	r7, [r0], #0x04
378129198Scognet	ldrt	ip, [r0], #0x04
379129198Scognet#ifdef __ARMEB__
380129198Scognet	orr	r4, r4, r5, lsr #16
381129198Scognet	mov	r5, r5, lsl #16
382129198Scognet	orr	r5, r5, r6, lsr #16
383129198Scognet	mov	r6, r6, lsl #16
384129198Scognet	orr	r6, r6, r7, lsr #16
385129198Scognet	mov	r7, r7, lsl #16
386129198Scognet	orr	r7, r7, ip, lsr #16
387129198Scognet#else
388129198Scognet	orr	r4, r4, r5, lsl #16
389129198Scognet	mov	r5, r5, lsr #16
390129198Scognet	orr	r5, r5, r6, lsl #16
391129198Scognet	mov	r6, r6, lsr #16
392129198Scognet	orr	r6, r6, r7, lsl #16
393129198Scognet	mov	r7, r7, lsr #16
394129198Scognet	orr	r7, r7, ip, lsl #16
395129198Scognet#endif
396129198Scognet	str	r4, [r1], #0x04
397129198Scognet	str	r5, [r1], #0x04
398129198Scognet	str	r6, [r1], #0x04
399129198Scognet	str	r7, [r1], #0x04
400129198Scognet.Lcopyin_bad2:
401236991Simp	subs	r2, r2, #0x10
402129198Scognet	bge	.Lcopyin_bad2_loop16
403129198Scognet
404236991Simp	adds	r2, r2, #0x10
405275418Sandrew	ldmfdeq	sp!, {r4-r7}
406137463Scognet	RETeq				/* Return now if done */
407129198Scognet	subs	r2, r2, #0x04
408129198Scognet	sublt	r0, r0, #0x02
409129198Scognet	blt	.Lcopyin_l4
410129198Scognet
411129198Scognet.Lcopyin_bad2_loop4:
412129198Scognet#ifdef __ARMEB__
413129198Scognet	mov	r4, ip, lsl #16
414129198Scognet#else
415129198Scognet	mov	r4, ip, lsr #16
416129198Scognet#endif
417129198Scognet	ldrt	ip, [r0], #0x04
418129198Scognet	subs	r2, r2, #0x04
419129198Scognet#ifdef __ARMEB__
420129198Scognet	orr	r4, r4, ip, lsr #16
421129198Scognet#else
422129198Scognet	orr	r4, r4, ip, lsl #16
423129198Scognet#endif
424129198Scognet	str	r4, [r1], #0x04
425129198Scognet	bge	.Lcopyin_bad2_loop4
426129198Scognet	sub	r0, r0, #0x02
427129198Scognet	b	.Lcopyin_l4
428129198Scognet
429129198Scognet.Lcopyin_bad3_loop16:
430129198Scognet#ifdef __ARMEB__
431129198Scognet	mov	r4, ip, lsl #24
432129198Scognet#else
433129198Scognet	mov	r4, ip, lsr #24
434129198Scognet#endif
435129198Scognet	ldrt	r5, [r0], #0x04
436129198Scognet	pld	[r0, #0x018]
437129198Scognet	ldrt	r6, [r0], #0x04
438129198Scognet	ldrt	r7, [r0], #0x04
439129198Scognet	ldrt	ip, [r0], #0x04
440129198Scognet#ifdef __ARMEB__
441129198Scognet	orr	r4, r4, r5, lsr #8
442129198Scognet	mov	r5, r5, lsl #24
443129198Scognet	orr	r5, r5, r6, lsr #8
444129198Scognet	mov	r6, r6, lsl #24
445129198Scognet	orr	r6, r6, r7, lsr #8
446129198Scognet	mov	r7, r7, lsl #24
447129198Scognet	orr	r7, r7, ip, lsr #8
448129198Scognet#else
449129198Scognet	orr	r4, r4, r5, lsl #8
450129198Scognet	mov	r5, r5, lsr #24
451129198Scognet	orr	r5, r5, r6, lsl #8
452129198Scognet	mov	r6, r6, lsr #24
453129198Scognet	orr	r6, r6, r7, lsl #8
454129198Scognet	mov	r7, r7, lsr #24
455129198Scognet	orr	r7, r7, ip, lsl #8
456129198Scognet#endif
457129198Scognet	str	r4, [r1], #0x04
458129198Scognet	str	r5, [r1], #0x04
459129198Scognet	str	r6, [r1], #0x04
460129198Scognet	str	r7, [r1], #0x04
461129198Scognet.Lcopyin_bad3:
462236991Simp	subs	r2, r2, #0x10
463129198Scognet	bge	.Lcopyin_bad3_loop16
464129198Scognet
465236991Simp	adds	r2, r2, #0x10
466275418Sandrew	ldmfdeq	sp!, {r4-r7}
467137463Scognet	RETeq				/* Return now if done */
468129198Scognet	subs	r2, r2, #0x04
469129198Scognet	sublt	r0, r0, #0x01
470129198Scognet	blt	.Lcopyin_l4
471129198Scognet
472129198Scognet.Lcopyin_bad3_loop4:
473129198Scognet#ifdef __ARMEB__
474129198Scognet	mov	r4, ip, lsl #24
475129198Scognet#else
476129198Scognet	mov	r4, ip, lsr #24
477129198Scognet#endif
478129198Scognet	ldrt	ip, [r0], #0x04
479129198Scognet	subs	r2, r2, #0x04
480129198Scognet#ifdef __ARMEB__
481129198Scognet	orr	r4, r4, ip, lsr #8
482129198Scognet#else
483129198Scognet	orr	r4, r4, ip, lsl #8
484129198Scognet#endif
485129198Scognet	str	r4, [r1], #0x04
486129198Scognet	bge	.Lcopyin_bad3_loop4
487129198Scognet	sub	r0, r0, #0x01
488129198Scognet
489129198Scognet.Lcopyin_l4:
490129198Scognet	ldmfd	sp!, {r4-r7}
491129198Scognet	mov	r3, #0x00
492129198Scognet	adds	r2, r2, #0x04
493137463Scognet	RETeq
494129198Scognet.Lcopyin_l4_2:
495129198Scognet	rsbs	r2, r2, #0x03
496129198Scognet	addne	pc, pc, r2, lsl #3
497129198Scognet	nop
498129198Scognet	ldrbt	ip, [r0], #0x01
499129198Scognet	strb	ip, [r1], #0x01
500129198Scognet	ldrbt	ip, [r0], #0x01
501129198Scognet	strb	ip, [r1], #0x01
502129198Scognet	ldrbt	ip, [r0]
503129198Scognet	strb	ip, [r1]
504137463Scognet	RET
505248361SandrewEND(copyin)
506129198Scognet
507129198Scognet/*
508129198Scognet * r0 = kernel space address
509129198Scognet * r1 = user space address
510129198Scognet * r2 = length
511129198Scognet *
512129198Scognet * Copies bytes from kernel space to user space
513129198Scognet */
514129198ScognetENTRY(copyout)
515129198Scognet	cmp	r2, #0x00
516129198Scognet	movle	r0, #0x00
517129198Scognet	movle	pc, lr			/* Bail early if length is <= 0 */
518129198Scognet
519289372Skib	adds	r3, r1, r2
520289372Skib	movcs	r0, #EFAULT
521289372Skib	RETc(cs)
522289372Skib
523289372Skib	ldr	r12, =(VM_MAXUSER_ADDRESS + 1)
524289372Skib	cmp	r3, r12
525289372Skib	movcs	r0, #EFAULT
526289372Skib	RETc(cs)
527289372Skib
528150864Scognet	ldr	r3, .L_arm_memcpy
529150864Scognet	ldr	r3, [r3]
530150864Scognet	cmp	r3, #0
531150864Scognet	beq	.Lnormale
532150864Scognet	ldr	r3, .L_min_memcpy_size
533150864Scognet	ldr	r3, [r3]
534150864Scognet	cmp	r2, r3
535150864Scognet	blt	.Lnormale
536150864Scognet	stmfd	sp!, {r0-r2, r4, lr}
537150864Scognet	mov     r3, r0
538150864Scognet	mov     r0, r1
539150864Scognet	mov     r1, r3
540150864Scognet	mov     r3, #1 /* DST_IS_USER */
541150864Scognet	ldr	r4, .L_arm_memcpy
542150864Scognet	mov	lr, pc
543150864Scognet	ldr	pc, [r4]
544150864Scognet	cmp     r0, #0
545150864Scognet	ldmfd   sp!, {r0-r2, r4, lr}
546150864Scognet	moveq	r0, #0
547150864Scognet	RETeq
548283366Sandrew
549283366Sandrew.Lnormale:
550129198Scognet	stmfd	sp!, {r10-r11, lr}
551129198Scognet
552239268Sgonzo	GET_PCB(r10)
553129198Scognet	ldr	r10, [r10]
554129198Scognet
555129198Scognet	mov	r3, #0x00
556129198Scognet	adr	ip, .Lcopyout_fault
557129198Scognet	ldr	r11, [r10, #PCB_ONFAULT]
558129198Scognet	str	ip, [r10, #PCB_ONFAULT]
559129198Scognet	bl	.Lcopyout_guts
560129198Scognet	str	r11, [r10, #PCB_ONFAULT]
561129198Scognet	mov	r0, #0x00
562129198Scognet	ldmfd	sp!, {r10-r11, pc}
563129198Scognet
564129198Scognet.Lcopyout_fault:
565239033Sandrew	ldr	r0, =EFAULT
566129198Scognet	str	r11, [r10, #PCB_ONFAULT]
567129198Scognet	cmp	r3, #0x00
568275418Sandrew	ldmfdgt	sp!, {r4-r7}		/* r3 > 0 Restore r4-r7 */
569275418Sandrew	ldmfdlt	sp!, {r4-r9}		/* r3 < 0 Restore r4-r9 */
570129198Scognet	ldmfd	sp!, {r10-r11, pc}
571129198Scognet
572129198Scognet.Lcopyout_guts:
573129198Scognet	pld	[r0]
574129198Scognet	/* Word-align the destination buffer */
575129198Scognet	ands	ip, r1, #0x03		/* Already word aligned? */
576129198Scognet	beq	.Lcopyout_wordaligned	/* Yup */
577129198Scognet	rsb	ip, ip, #0x04
578129198Scognet	cmp	r2, ip			/* Enough bytes left to align it? */
579129198Scognet	blt	.Lcopyout_l4_2		/* Nope. Just copy bytewise */
580129198Scognet	sub	r2, r2, ip
581129198Scognet	rsbs	ip, ip, #0x03
582129198Scognet	addne	pc, pc, ip, lsl #3
583129198Scognet	nop
584129198Scognet	ldrb	ip, [r0], #0x01
585129198Scognet	strbt	ip, [r1], #0x01
586129198Scognet	ldrb	ip, [r0], #0x01
587129198Scognet	strbt	ip, [r1], #0x01
588129198Scognet	ldrb	ip, [r0], #0x01
589129198Scognet	strbt	ip, [r1], #0x01
590129198Scognet	cmp	r2, #0x00		/* All done? */
591137463Scognet	RETeq
592129198Scognet
593129198Scognet	/* Destination buffer is now word aligned */
594129198Scognet.Lcopyout_wordaligned:
595129198Scognet	ands	ip, r0, #0x03		/* Is src also word-aligned? */
596129198Scognet	bne	.Lcopyout_bad_align	/* Nope. Things just got bad */
597129198Scognet	cmp	r2, #0x08		/* Less than 8 bytes remaining? */
598129198Scognet	blt	.Lcopyout_w_less_than8
599129198Scognet
600129198Scognet	/* Quad-align the destination buffer */
601153273Scognet	tst	r0, #0x07		/* Already quad aligned? */
602129198Scognet	ldrne	ip, [r0], #0x04
603153273Scognet	subne	r2, r2, #0x04
604275418Sandrew	strtne	ip, [r1], #0x04
605283366Sandrew
606129198Scognet	stmfd	sp!, {r4-r9}		/* Free up some registers */
607129198Scognet	mov	r3, #-1			/* Signal restore r4-r9 */
608129198Scognet
609153273Scognet	/* Destination buffer word aligned, source is quad aligned */
610129198Scognet	subs	r2, r2, #0x80
611129198Scognet	blt	.Lcopyout_w_lessthan128
612129198Scognet
613129198Scognet	/* Copy 128 bytes at a time */
614129198Scognet.Lcopyout_w_loop128:
615153273Scognet	ldrd	r4, [r0], #0x08		/* LD:00-07 */
616129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x20 */
617153273Scognet	ldrd	r6, [r0], #0x08		/* LD:08-0f */
618153273Scognet	ldrd	r8, [r0], #0x08		/* LD:10-17 */
619129198Scognet	strt	r4, [r1], #0x04		/* ST:00-03 */
620129198Scognet	strt	r5, [r1], #0x04		/* ST:04-07 */
621153273Scognet	ldrd	r4, [r0], #0x08		/* LD:18-1f */
622129198Scognet	strt	r6, [r1], #0x04		/* ST:08-0b */
623129198Scognet	strt	r7, [r1], #0x04		/* ST:0c-0f */
624153273Scognet	ldrd	r6, [r0], #0x08		/* LD:20-27 */
625129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x40 */
626129198Scognet	strt	r8, [r1], #0x04		/* ST:10-13 */
627129198Scognet	strt	r9, [r1], #0x04		/* ST:14-17 */
628153273Scognet	ldrd	r8, [r0], #0x08		/* LD:28-2f */
629129198Scognet	strt	r4, [r1], #0x04		/* ST:18-1b */
630129198Scognet	strt	r5, [r1], #0x04		/* ST:1c-1f */
631153273Scognet	ldrd	r4, [r0], #0x08		/* LD:30-37 */
632129198Scognet	strt	r6, [r1], #0x04		/* ST:20-23 */
633129198Scognet	strt	r7, [r1], #0x04		/* ST:24-27 */
634153273Scognet	ldrd	r6, [r0], #0x08		/* LD:38-3f */
635129198Scognet	strt	r8, [r1], #0x04		/* ST:28-2b */
636129198Scognet	strt	r9, [r1], #0x04		/* ST:2c-2f */
637153273Scognet	ldrd	r8, [r0], #0x08		/* LD:40-47 */
638129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x60 */
639129198Scognet	strt	r4, [r1], #0x04		/* ST:30-33 */
640129198Scognet	strt	r5, [r1], #0x04		/* ST:34-37 */
641153273Scognet	ldrd	r4, [r0], #0x08		/* LD:48-4f */
642129198Scognet	strt	r6, [r1], #0x04		/* ST:38-3b */
643129198Scognet	strt	r7, [r1], #0x04		/* ST:3c-3f */
644153273Scognet	ldrd	r6, [r0], #0x08		/* LD:50-57 */
645129198Scognet	strt	r8, [r1], #0x04		/* ST:40-43 */
646129198Scognet	strt	r9, [r1], #0x04		/* ST:44-47 */
647153273Scognet	ldrd	r8, [r0], #0x08		/* LD:58-4f */
648129198Scognet	strt	r4, [r1], #0x04		/* ST:48-4b */
649129198Scognet	strt	r5, [r1], #0x04		/* ST:4c-4f */
650153273Scognet	ldrd	r4, [r0], #0x08		/* LD:60-67 */
651129198Scognet	pld	[r0, #0x18]		/* Prefetch 0x80 */
652129198Scognet	strt	r6, [r1], #0x04		/* ST:50-53 */
653129198Scognet	strt	r7, [r1], #0x04		/* ST:54-57 */
654153273Scognet	ldrd	r6, [r0], #0x08		/* LD:68-6f */
655129198Scognet	strt	r8, [r1], #0x04		/* ST:58-5b */
656129198Scognet	strt	r9, [r1], #0x04		/* ST:5c-5f */
657153273Scognet	ldrd	r8, [r0], #0x08		/* LD:70-77 */
658129198Scognet	strt	r4, [r1], #0x04		/* ST:60-63 */
659129198Scognet	strt	r5, [r1], #0x04		/* ST:64-67 */
660153273Scognet	ldrd	r4, [r0], #0x08		/* LD:78-7f */
661129198Scognet	strt	r6, [r1], #0x04		/* ST:68-6b */
662129198Scognet	strt	r7, [r1], #0x04		/* ST:6c-6f */
663129198Scognet	strt	r8, [r1], #0x04		/* ST:70-73 */
664129198Scognet	strt	r9, [r1], #0x04		/* ST:74-77 */
665129198Scognet	subs	r2, r2, #0x80
666129198Scognet	strt	r4, [r1], #0x04		/* ST:78-7b */
667129198Scognet	strt	r5, [r1], #0x04		/* ST:7c-7f */
668129198Scognet	bge	.Lcopyout_w_loop128
669129198Scognet
670129198Scognet.Lcopyout_w_lessthan128:
671129198Scognet	adds	r2, r2, #0x80		/* Adjust for extra sub */
672275418Sandrew	ldmfdeq	sp!, {r4-r9}
673137463Scognet	RETeq				/* Return now if done */
674129198Scognet	subs	r2, r2, #0x20
675129198Scognet	blt	.Lcopyout_w_lessthan32
676129198Scognet
677129198Scognet	/* Copy 32 bytes at a time */
678129198Scognet.Lcopyout_w_loop32:
679153273Scognet	ldrd	r4, [r0], #0x08
680129198Scognet	pld	[r0, #0x18]
681153273Scognet	ldrd	r6, [r0], #0x08
682153273Scognet	ldrd	r8, [r0], #0x08
683129198Scognet	strt	r4, [r1], #0x04
684129198Scognet	strt	r5, [r1], #0x04
685153273Scognet	ldrd	r4, [r0], #0x08
686129198Scognet	strt	r6, [r1], #0x04
687129198Scognet	strt	r7, [r1], #0x04
688129198Scognet	strt	r8, [r1], #0x04
689129198Scognet	strt	r9, [r1], #0x04
690129198Scognet	subs	r2, r2, #0x20
691129198Scognet	strt	r4, [r1], #0x04
692129198Scognet	strt	r5, [r1], #0x04
693129198Scognet	bge	.Lcopyout_w_loop32
694129198Scognet
695129198Scognet.Lcopyout_w_lessthan32:
696129198Scognet	adds	r2, r2, #0x20		/* Adjust for extra sub */
697275418Sandrew	ldmfdeq	sp!, {r4-r9}
698137463Scognet	RETeq				/* Return now if done */
699129198Scognet
700129198Scognet	and	r4, r2, #0x18
701129198Scognet	rsb	r5, r4, #0x18
702129198Scognet	subs	r2, r2, r4
703129198Scognet	add	pc, pc, r5, lsl #1
704129198Scognet	nop
705129198Scognet
706129198Scognet	/* At least 24 bytes remaining */
707153273Scognet	ldrd	r4, [r0], #0x08
708129198Scognet	strt	r4, [r1], #0x04
709129198Scognet	strt	r5, [r1], #0x04
710153273Scognet	nop
711129198Scognet
712129198Scognet	/* At least 16 bytes remaining */
713153273Scognet	ldrd	r4, [r0], #0x08
714129198Scognet	strt	r4, [r1], #0x04
715129198Scognet	strt	r5, [r1], #0x04
716153273Scognet	nop
717129198Scognet
718129198Scognet	/* At least 8 bytes remaining */
719153273Scognet	ldrd	r4, [r0], #0x08
720129198Scognet	strt	r4, [r1], #0x04
721129198Scognet	strt	r5, [r1], #0x04
722153273Scognet	nop
723129198Scognet
724129198Scognet	/* Less than 8 bytes remaining */
725129198Scognet	ldmfd	sp!, {r4-r9}
726137463Scognet	RETeq				/* Return now if done */
727129198Scognet	mov	r3, #0x00
728129198Scognet
729129198Scognet.Lcopyout_w_less_than8:
730129198Scognet	subs	r2, r2, #0x04
731129198Scognet	ldrge	ip, [r0], #0x04
732275418Sandrew	strtge	ip, [r1], #0x04
733137463Scognet	RETeq				/* Return now if done */
734129198Scognet	addlt	r2, r2, #0x04
735129198Scognet	ldrb	ip, [r0], #0x01
736129198Scognet	cmp	r2, #0x02
737275418Sandrew	ldrbge	r2, [r0], #0x01
738129198Scognet	strbt	ip, [r1], #0x01
739275418Sandrew	ldrbgt	ip, [r0]
740275418Sandrew	strbtge	r2, [r1], #0x01
741275418Sandrew	strbtgt	ip, [r1]
742137463Scognet	RET
743129198Scognet
744129198Scognet/*
745129198Scognet * At this point, it has not been possible to word align both buffers.
746129198Scognet * The destination buffer (r1) is word aligned, but the source buffer
747129198Scognet * (r0) is not.
748129198Scognet */
749129198Scognet.Lcopyout_bad_align:
750129198Scognet	stmfd	sp!, {r4-r7}
751129198Scognet	mov	r3, #0x01
752129198Scognet	bic	r0, r0, #0x03
753129198Scognet	cmp	ip, #2
754129198Scognet	ldr	ip, [r0], #0x04
755129198Scognet	bgt	.Lcopyout_bad3
756129198Scognet	beq	.Lcopyout_bad2
757129198Scognet	b	.Lcopyout_bad1
758129198Scognet
759129198Scognet.Lcopyout_bad1_loop16:
760129198Scognet#ifdef	__ARMEB__
761129198Scognet	mov	r4, ip, lsl #8
762129198Scognet#else
763129198Scognet	mov	r4, ip, lsr #8
764129198Scognet#endif
765129198Scognet	ldr	r5, [r0], #0x04
766129198Scognet	pld	[r0, #0x018]
767129198Scognet	ldr	r6, [r0], #0x04
768129198Scognet	ldr	r7, [r0], #0x04
769129198Scognet	ldr	ip, [r0], #0x04
770129198Scognet#ifdef	__ARMEB__
771129198Scognet	orr	r4, r4, r5, lsr #24
772129198Scognet	mov	r5, r5, lsl #8
773129198Scognet	orr	r5, r5, r6, lsr #24
774129198Scognet	mov	r6, r6, lsl #8
775129198Scognet	orr	r6, r6, r7, lsr #24
776129198Scognet	mov	r7, r7, lsl #8
777129198Scognet	orr	r7, r7, ip, lsr #24
778129198Scognet#else
779129198Scognet	orr	r4, r4, r5, lsl #24
780129198Scognet	mov	r5, r5, lsr #8
781129198Scognet	orr	r5, r5, r6, lsl #24
782129198Scognet	mov	r6, r6, lsr #8
783129198Scognet	orr	r6, r6, r7, lsl #24
784129198Scognet	mov	r7, r7, lsr #8
785129198Scognet	orr	r7, r7, ip, lsl #24
786129198Scognet#endif
787129198Scognet	strt	r4, [r1], #0x04
788129198Scognet	strt	r5, [r1], #0x04
789129198Scognet	strt	r6, [r1], #0x04
790129198Scognet	strt	r7, [r1], #0x04
791129198Scognet.Lcopyout_bad1:
792236991Simp	subs	r2, r2, #0x10
793129198Scognet	bge	.Lcopyout_bad1_loop16
794129198Scognet
795236991Simp	adds	r2, r2, #0x10
796275418Sandrew	ldmfdeq	sp!, {r4-r7}
797137463Scognet	RETeq				/* Return now if done */
798129198Scognet	subs	r2, r2, #0x04
799129198Scognet	sublt	r0, r0, #0x03
800129198Scognet	blt	.Lcopyout_l4
801129198Scognet
802129198Scognet.Lcopyout_bad1_loop4:
803129198Scognet#ifdef __ARMEB__
804129198Scognet	mov	r4, ip, lsl #8
805129198Scognet#else
806129198Scognet	mov	r4, ip, lsr #8
807129198Scognet#endif
808129198Scognet	ldr	ip, [r0], #0x04
809129198Scognet	subs	r2, r2, #0x04
810129198Scognet#ifdef __ARMEB__
811129198Scognet	orr	r4, r4, ip, lsr #24
812129198Scognet#else
813129198Scognet	orr	r4, r4, ip, lsl #24
814129198Scognet#endif
815129198Scognet	strt	r4, [r1], #0x04
816129198Scognet	bge	.Lcopyout_bad1_loop4
817129198Scognet	sub	r0, r0, #0x03
818129198Scognet	b	.Lcopyout_l4
819129198Scognet
820129198Scognet.Lcopyout_bad2_loop16:
821129198Scognet#ifdef __ARMEB__
822129198Scognet	mov	r4, ip, lsl #16
823129198Scognet#else
824129198Scognet	mov	r4, ip, lsr #16
825129198Scognet#endif
826129198Scognet	ldr	r5, [r0], #0x04
827129198Scognet	pld	[r0, #0x018]
828129198Scognet	ldr	r6, [r0], #0x04
829129198Scognet	ldr	r7, [r0], #0x04
830129198Scognet	ldr	ip, [r0], #0x04
831129198Scognet#ifdef __ARMEB__
832129198Scognet	orr	r4, r4, r5, lsr #16
833129198Scognet	mov	r5, r5, lsl #16
834129198Scognet	orr	r5, r5, r6, lsr #16
835129198Scognet	mov	r6, r6, lsl #16
836129198Scognet	orr	r6, r6, r7, lsr #16
837129198Scognet	mov	r7, r7, lsl #16
838129198Scognet	orr	r7, r7, ip, lsr #16
839129198Scognet#else
840129198Scognet	orr	r4, r4, r5, lsl #16
841129198Scognet	mov	r5, r5, lsr #16
842129198Scognet	orr	r5, r5, r6, lsl #16
843129198Scognet	mov	r6, r6, lsr #16
844129198Scognet	orr	r6, r6, r7, lsl #16
845129198Scognet	mov	r7, r7, lsr #16
846129198Scognet	orr	r7, r7, ip, lsl #16
847129198Scognet#endif
848129198Scognet	strt	r4, [r1], #0x04
849129198Scognet	strt	r5, [r1], #0x04
850129198Scognet	strt	r6, [r1], #0x04
851129198Scognet	strt	r7, [r1], #0x04
852129198Scognet.Lcopyout_bad2:
853236991Simp	subs	r2, r2, #0x10
854129198Scognet	bge	.Lcopyout_bad2_loop16
855129198Scognet
856236991Simp	adds	r2, r2, #0x10
857275418Sandrew	ldmfdeq	sp!, {r4-r7}
858137463Scognet	RETeq				/* Return now if done */
859129198Scognet	subs	r2, r2, #0x04
860129198Scognet	sublt	r0, r0, #0x02
861129198Scognet	blt	.Lcopyout_l4
862129198Scognet
863129198Scognet.Lcopyout_bad2_loop4:
864129198Scognet#ifdef __ARMEB__
865129198Scognet	mov	r4, ip, lsl #16
866129198Scognet#else
867129198Scognet	mov	r4, ip, lsr #16
868129198Scognet#endif
869129198Scognet	ldr	ip, [r0], #0x04
870129198Scognet	subs	r2, r2, #0x04
871129198Scognet#ifdef __ARMEB__
872129198Scognet	orr	r4, r4, ip, lsr #16
873129198Scognet#else
874129198Scognet	orr	r4, r4, ip, lsl #16
875129198Scognet#endif
876129198Scognet	strt	r4, [r1], #0x04
877129198Scognet	bge	.Lcopyout_bad2_loop4
878129198Scognet	sub	r0, r0, #0x02
879129198Scognet	b	.Lcopyout_l4
880129198Scognet
881129198Scognet.Lcopyout_bad3_loop16:
882129198Scognet#ifdef __ARMEB__
883129198Scognet	mov	r4, ip, lsl #24
884129198Scognet#else
885129198Scognet	mov	r4, ip, lsr #24
886129198Scognet#endif
887129198Scognet	ldr	r5, [r0], #0x04
888129198Scognet	pld	[r0, #0x018]
889129198Scognet	ldr	r6, [r0], #0x04
890129198Scognet	ldr	r7, [r0], #0x04
891129198Scognet	ldr	ip, [r0], #0x04
892129198Scognet#ifdef __ARMEB__
893129198Scognet	orr	r4, r4, r5, lsr #8
894129198Scognet	mov	r5, r5, lsl #24
895129198Scognet	orr	r5, r5, r6, lsr #8
896129198Scognet	mov	r6, r6, lsl #24
897129198Scognet	orr	r6, r6, r7, lsr #8
898129198Scognet	mov	r7, r7, lsl #24
899129198Scognet	orr	r7, r7, ip, lsr #8
900129198Scognet#else
901129198Scognet	orr	r4, r4, r5, lsl #8
902129198Scognet	mov	r5, r5, lsr #24
903129198Scognet	orr	r5, r5, r6, lsl #8
904129198Scognet	mov	r6, r6, lsr #24
905129198Scognet	orr	r6, r6, r7, lsl #8
906129198Scognet	mov	r7, r7, lsr #24
907129198Scognet	orr	r7, r7, ip, lsl #8
908129198Scognet#endif
909129198Scognet	strt	r4, [r1], #0x04
910129198Scognet	strt	r5, [r1], #0x04
911129198Scognet	strt	r6, [r1], #0x04
912129198Scognet	strt	r7, [r1], #0x04
913129198Scognet.Lcopyout_bad3:
914236991Simp	subs	r2, r2, #0x10
915129198Scognet	bge	.Lcopyout_bad3_loop16
916129198Scognet
917236991Simp	adds	r2, r2, #0x10
918275418Sandrew	ldmfdeq	sp!, {r4-r7}
919137463Scognet	RETeq				/* Return now if done */
920129198Scognet	subs	r2, r2, #0x04
921129198Scognet	sublt	r0, r0, #0x01
922129198Scognet	blt	.Lcopyout_l4
923129198Scognet
924129198Scognet.Lcopyout_bad3_loop4:
925129198Scognet#ifdef __ARMEB__
926129198Scognet	mov	r4, ip, lsl #24
927129198Scognet#else
928129198Scognet	mov	r4, ip, lsr #24
929129198Scognet#endif
930129198Scognet	ldr	ip, [r0], #0x04
931129198Scognet	subs	r2, r2, #0x04
932129198Scognet#ifdef __ARMEB__
933129198Scognet	orr	r4, r4, ip, lsr #8
934129198Scognet#else
935129198Scognet	orr	r4, r4, ip, lsl #8
936129198Scognet#endif
937129198Scognet	strt	r4, [r1], #0x04
938129198Scognet	bge	.Lcopyout_bad3_loop4
939129198Scognet	sub	r0, r0, #0x01
940129198Scognet
941129198Scognet.Lcopyout_l4:
942129198Scognet	ldmfd	sp!, {r4-r7}
943129198Scognet	mov	r3, #0x00
944129198Scognet	adds	r2, r2, #0x04
945137463Scognet	RETeq
946129198Scognet.Lcopyout_l4_2:
947129198Scognet	rsbs	r2, r2, #0x03
948129198Scognet	addne	pc, pc, r2, lsl #3
949129198Scognet	nop
950129198Scognet	ldrb	ip, [r0], #0x01
951129198Scognet	strbt	ip, [r1], #0x01
952129198Scognet	ldrb	ip, [r0], #0x01
953129198Scognet	strbt	ip, [r1], #0x01
954129198Scognet	ldrb	ip, [r0]
955129198Scognet	strbt	ip, [r1]
956137463Scognet	RET
957248361SandrewEND(copyout)
958248361Sandrew
959