xref: /openbmc/linux/arch/mips/lib/memcpy.S (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
11da177e4SLinus Torvalds/*
21da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
31da177e4SLinus Torvalds * License.  See the file "COPYING" in the main directory of this archive
41da177e4SLinus Torvalds * for more details.
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Unified implementation of memcpy, memmove and the __copy_user backend.
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Copyright (C) 1998, 99, 2000, 01, 2002 Ralf Baechle (ralf@gnu.org)
91da177e4SLinus Torvalds * Copyright (C) 1999, 2000, 01, 2002 Silicon Graphics, Inc.
101da177e4SLinus Torvalds * Copyright (C) 2002 Broadcom, Inc.
111da177e4SLinus Torvalds *   memcpy/copy_user author: Mark Vandevoorde
12619b6e18SMaciej W. Rozycki * Copyright (C) 2007  Maciej W. Rozycki
135bc05971SMarkos Chandras * Copyright (C) 2014 Imagination Technologies Ltd.
141da177e4SLinus Torvalds *
151da177e4SLinus Torvalds * Mnemonic names for arguments to memcpy/__copy_user
161da177e4SLinus Torvalds */
17e5adb877SRalf Baechle
18e5adb877SRalf Baechle/*
19e5adb877SRalf Baechle * Hack to resolve longstanding prefetch issue
20e5adb877SRalf Baechle *
21e5adb877SRalf Baechle * Prefetching may be fatal on some systems if we're prefetching beyond the
22e5adb877SRalf Baechle * end of memory on some systems.  It's also a seriously bad idea on non
23e5adb877SRalf Baechle * dma-coherent systems.
24e5adb877SRalf Baechle */
25634286f1SRalf Baechle#ifdef CONFIG_DMA_NONCOHERENT
26e5adb877SRalf Baechle#undef CONFIG_CPU_HAS_PREFETCH
27e5adb877SRalf Baechle#endif
28e5adb877SRalf Baechle#ifdef CONFIG_MIPS_MALTA
29e5adb877SRalf Baechle#undef CONFIG_CPU_HAS_PREFETCH
30e5adb877SRalf Baechle#endif
313daf281fSLeonid Yegoshin#ifdef CONFIG_CPU_MIPSR6
323daf281fSLeonid Yegoshin#undef CONFIG_CPU_HAS_PREFETCH
333daf281fSLeonid Yegoshin#endif
34e5adb877SRalf Baechle
35*9259e15bSMasahiro Yamada#include <linux/export.h>
361da177e4SLinus Torvalds#include <asm/asm.h>
37048eb582SSam Ravnborg#include <asm/asm-offsets.h>
381da177e4SLinus Torvalds#include <asm/regdef.h>
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds#define dst a0
411da177e4SLinus Torvalds#define src a1
421da177e4SLinus Torvalds#define len a2
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds/*
451da177e4SLinus Torvalds * Spec
461da177e4SLinus Torvalds *
471da177e4SLinus Torvalds * memcpy copies len bytes from src to dst and sets v0 to dst.
481da177e4SLinus Torvalds * It assumes that
491da177e4SLinus Torvalds *   - src and dst don't overlap
501da177e4SLinus Torvalds *   - src is readable
511da177e4SLinus Torvalds *   - dst is writable
521da177e4SLinus Torvalds * memcpy uses the standard calling convention
531da177e4SLinus Torvalds *
541da177e4SLinus Torvalds * __copy_user copies up to len bytes from src to dst and sets a2 (len) to
551da177e4SLinus Torvalds * the number of uncopied bytes due to an exception caused by a read or write.
561da177e4SLinus Torvalds * __copy_user assumes that src and dst don't overlap, and that the call is
571da177e4SLinus Torvalds * implementing one of the following:
581da177e4SLinus Torvalds *   copy_to_user
591da177e4SLinus Torvalds *     - src is readable  (no exceptions when reading src)
601da177e4SLinus Torvalds *   copy_from_user
611da177e4SLinus Torvalds *     - dst is writable  (no exceptions when writing dst)
621da177e4SLinus Torvalds * __copy_user uses a non-standard calling convention; see
631da177e4SLinus Torvalds * include/asm-mips/uaccess.h
641da177e4SLinus Torvalds *
651da177e4SLinus Torvalds * When an exception happens on a load, the handler must
661da177e4SLinus Torvalds # ensure that all of the destination buffer is overwritten to prevent
671da177e4SLinus Torvalds * leaking information to user mode programs.
681da177e4SLinus Torvalds */
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds/*
711da177e4SLinus Torvalds * Implementation
721da177e4SLinus Torvalds */
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds/*
751da177e4SLinus Torvalds * The exception handler for loads requires that:
761da177e4SLinus Torvalds *  1- AT contain the address of the byte just past the end of the source
771da177e4SLinus Torvalds *     of the copy,
781da177e4SLinus Torvalds *  2- src_entry <= src < AT, and
791da177e4SLinus Torvalds *  3- (dst - src) == (dst_entry - src_entry),
801da177e4SLinus Torvalds * The _entry suffix denotes values when __copy_user was called.
811da177e4SLinus Torvalds *
821da177e4SLinus Torvalds * (1) is set up up by uaccess.h and maintained by not writing AT in copy_user
831da177e4SLinus Torvalds * (2) is met by incrementing src by the number of bytes copied
841da177e4SLinus Torvalds * (3) is met by not doing loads between a pair of increments of dst and src
851da177e4SLinus Torvalds *
861da177e4SLinus Torvalds * The exception handlers for stores adjust len (if necessary) and return.
871da177e4SLinus Torvalds * These handlers do not need to overwrite any data.
881da177e4SLinus Torvalds *
891da177e4SLinus Torvalds * For __rmemcpy and memmove an exception is always a kernel bug, therefore
901da177e4SLinus Torvalds * they're not protected.
911da177e4SLinus Torvalds */
921da177e4SLinus Torvalds
935bc05971SMarkos Chandras/* Instruction type */
945bc05971SMarkos Chandras#define LD_INSN 1
955bc05971SMarkos Chandras#define ST_INSN 2
96bda4d986SMarkos Chandras/* Pretech type */
97bda4d986SMarkos Chandras#define SRC_PREFETCH 1
98bda4d986SMarkos Chandras#define DST_PREFETCH 2
99cf62a8b8SMarkos Chandras#define LEGACY_MODE 1
100cf62a8b8SMarkos Chandras#define EVA_MODE    2
101cf62a8b8SMarkos Chandras#define USEROP   1
102cf62a8b8SMarkos Chandras#define KERNELOP 2
1035bc05971SMarkos Chandras
1045bc05971SMarkos Chandras/*
1055bc05971SMarkos Chandras * Wrapper to add an entry in the exception table
1065bc05971SMarkos Chandras * in case the insn causes a memory exception.
1075bc05971SMarkos Chandras * Arguments:
1085bc05971SMarkos Chandras * insn    : Load/store instruction
1095bc05971SMarkos Chandras * type    : Instruction type
1105bc05971SMarkos Chandras * reg     : Register
1115bc05971SMarkos Chandras * addr    : Address
1125bc05971SMarkos Chandras * handler : Exception handler
1135bc05971SMarkos Chandras */
114cf62a8b8SMarkos Chandras
1155bc05971SMarkos Chandras#define EXC(insn, type, reg, addr, handler)			\
116cf62a8b8SMarkos Chandras	.if \mode == LEGACY_MODE;				\
1175bc05971SMarkos Chandras9:		insn reg, addr;					\
1181da177e4SLinus Torvalds		.section __ex_table,"a";			\
119fa62f39dSThomas Bogendoerfer		PTR_WD	9b, handler;				\
120cf62a8b8SMarkos Chandras		.previous;					\
121cd26cb41SMarkos Chandras	/* This is assembled in EVA mode */			\
122cd26cb41SMarkos Chandras	.else;							\
123cd26cb41SMarkos Chandras		/* If loading from user or storing to user */	\
124cd26cb41SMarkos Chandras		.if ((\from == USEROP) && (type == LD_INSN)) || \
125cd26cb41SMarkos Chandras		    ((\to == USEROP) && (type == ST_INSN));	\
126cd26cb41SMarkos Chandras9:			__BUILD_EVA_INSN(insn##e, reg, addr);	\
127cd26cb41SMarkos Chandras			.section __ex_table,"a";		\
128fa62f39dSThomas Bogendoerfer			PTR_WD	9b, handler;			\
129cd26cb41SMarkos Chandras			.previous;				\
130cd26cb41SMarkos Chandras		.else;						\
131cd26cb41SMarkos Chandras			/*					\
132cd26cb41SMarkos Chandras			 *  Still in EVA, but no need for	\
133cd26cb41SMarkos Chandras			 * exception handler or EVA insn	\
134cd26cb41SMarkos Chandras			 */					\
135cd26cb41SMarkos Chandras			insn reg, addr;				\
136cd26cb41SMarkos Chandras		.endif;						\
137cf62a8b8SMarkos Chandras	.endif
138cd26cb41SMarkos Chandras
1391da177e4SLinus Torvalds/*
1401da177e4SLinus Torvalds * Only on the 64-bit kernel we can made use of 64-bit registers.
1411da177e4SLinus Torvalds */
142875d43e7SRalf Baechle#ifdef CONFIG_64BIT
1431da177e4SLinus Torvalds#define USE_DOUBLE
1441da177e4SLinus Torvalds#endif
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds#ifdef USE_DOUBLE
1471da177e4SLinus Torvalds
1485bc05971SMarkos Chandras#define LOADK ld /* No exception */
1495bc05971SMarkos Chandras#define LOAD(reg, addr, handler)	EXC(ld, LD_INSN, reg, addr, handler)
1505bc05971SMarkos Chandras#define LOADL(reg, addr, handler)	EXC(ldl, LD_INSN, reg, addr, handler)
1515bc05971SMarkos Chandras#define LOADR(reg, addr, handler)	EXC(ldr, LD_INSN, reg, addr, handler)
1525bc05971SMarkos Chandras#define STOREL(reg, addr, handler)	EXC(sdl, ST_INSN, reg, addr, handler)
1535bc05971SMarkos Chandras#define STORER(reg, addr, handler)	EXC(sdr, ST_INSN, reg, addr, handler)
1545bc05971SMarkos Chandras#define STORE(reg, addr, handler)	EXC(sd, ST_INSN, reg, addr, handler)
1551da177e4SLinus Torvalds#define ADD    daddu
1561da177e4SLinus Torvalds#define SUB    dsubu
1571da177e4SLinus Torvalds#define SRL    dsrl
1581da177e4SLinus Torvalds#define SRA    dsra
1591da177e4SLinus Torvalds#define SLL    dsll
1601da177e4SLinus Torvalds#define SLLV   dsllv
1611da177e4SLinus Torvalds#define SRLV   dsrlv
1621da177e4SLinus Torvalds#define NBYTES 8
1631da177e4SLinus Torvalds#define LOG_NBYTES 3
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds/*
1661da177e4SLinus Torvalds * As we are sharing code base with the mips32 tree (which use the o32 ABI
1671da177e4SLinus Torvalds * register definitions). We need to redefine the register definitions from
1681da177e4SLinus Torvalds * the n64 ABI register naming to the o32 ABI register naming.
1691da177e4SLinus Torvalds */
1701da177e4SLinus Torvalds#undef t0
1711da177e4SLinus Torvalds#undef t1
1721da177e4SLinus Torvalds#undef t2
1731da177e4SLinus Torvalds#undef t3
1741da177e4SLinus Torvalds#define t0	$8
1751da177e4SLinus Torvalds#define t1	$9
1761da177e4SLinus Torvalds#define t2	$10
1771da177e4SLinus Torvalds#define t3	$11
1781da177e4SLinus Torvalds#define t4	$12
1791da177e4SLinus Torvalds#define t5	$13
1801da177e4SLinus Torvalds#define t6	$14
1811da177e4SLinus Torvalds#define t7	$15
1821da177e4SLinus Torvalds
1831da177e4SLinus Torvalds#else
1841da177e4SLinus Torvalds
1855bc05971SMarkos Chandras#define LOADK lw /* No exception */
1865bc05971SMarkos Chandras#define LOAD(reg, addr, handler)	EXC(lw, LD_INSN, reg, addr, handler)
1875bc05971SMarkos Chandras#define LOADL(reg, addr, handler)	EXC(lwl, LD_INSN, reg, addr, handler)
1885bc05971SMarkos Chandras#define LOADR(reg, addr, handler)	EXC(lwr, LD_INSN, reg, addr, handler)
1895bc05971SMarkos Chandras#define STOREL(reg, addr, handler)	EXC(swl, ST_INSN, reg, addr, handler)
1905bc05971SMarkos Chandras#define STORER(reg, addr, handler)	EXC(swr, ST_INSN, reg, addr, handler)
1915bc05971SMarkos Chandras#define STORE(reg, addr, handler)	EXC(sw, ST_INSN, reg, addr, handler)
1921da177e4SLinus Torvalds#define ADD    addu
1931da177e4SLinus Torvalds#define SUB    subu
1941da177e4SLinus Torvalds#define SRL    srl
1951da177e4SLinus Torvalds#define SLL    sll
1961da177e4SLinus Torvalds#define SRA    sra
1971da177e4SLinus Torvalds#define SLLV   sllv
1981da177e4SLinus Torvalds#define SRLV   srlv
1991da177e4SLinus Torvalds#define NBYTES 4
2001da177e4SLinus Torvalds#define LOG_NBYTES 2
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds#endif /* USE_DOUBLE */
2031da177e4SLinus Torvalds
2045bc05971SMarkos Chandras#define LOADB(reg, addr, handler)	EXC(lb, LD_INSN, reg, addr, handler)
2055bc05971SMarkos Chandras#define STOREB(reg, addr, handler)	EXC(sb, ST_INSN, reg, addr, handler)
2065bc05971SMarkos Chandras
2071d6fb222SPaul Burton#ifdef CONFIG_CPU_HAS_PREFETCH
208cf62a8b8SMarkos Chandras# define _PREF(hint, addr, type)					\
209cf62a8b8SMarkos Chandras	.if \mode == LEGACY_MODE;					\
2101d6fb222SPaul Burton		kernel_pref(hint, addr);				\
211cd26cb41SMarkos Chandras	.else;								\
212cd26cb41SMarkos Chandras		.if ((\from == USEROP) && (type == SRC_PREFETCH)) ||	\
213cd26cb41SMarkos Chandras		    ((\to == USEROP) && (type == DST_PREFETCH));	\
214cd26cb41SMarkos Chandras			/*						\
215cd26cb41SMarkos Chandras			 * PREFE has only 9 bits for the offset		\
216cd26cb41SMarkos Chandras			 * compared to PREF which has 16, so it may	\
217cd26cb41SMarkos Chandras			 * need to use the $at register but this	\
218cd26cb41SMarkos Chandras			 * register should remain intact because it's	\
219cd26cb41SMarkos Chandras			 * used later on. Therefore use $v1.		\
220cd26cb41SMarkos Chandras			 */						\
221cd26cb41SMarkos Chandras			.set at=v1;					\
2221d6fb222SPaul Burton			user_pref(hint, addr);				\
223cd26cb41SMarkos Chandras			.set noat;					\
224cd26cb41SMarkos Chandras		.else;							\
2251d6fb222SPaul Burton			kernel_pref(hint, addr);			\
226cd26cb41SMarkos Chandras		.endif;							\
227cf62a8b8SMarkos Chandras	.endif
2281d6fb222SPaul Burton#else
2291d6fb222SPaul Burton# define _PREF(hint, addr, type)
2301d6fb222SPaul Burton#endif
231bda4d986SMarkos Chandras
232bda4d986SMarkos Chandras#define PREFS(hint, addr) _PREF(hint, addr, SRC_PREFETCH)
233bda4d986SMarkos Chandras#define PREFD(hint, addr) _PREF(hint, addr, DST_PREFETCH)
234bda4d986SMarkos Chandras
2351da177e4SLinus Torvalds#ifdef CONFIG_CPU_LITTLE_ENDIAN
2361da177e4SLinus Torvalds#define LDFIRST LOADR
2371da177e4SLinus Torvalds#define LDREST	LOADL
2381da177e4SLinus Torvalds#define STFIRST STORER
2391da177e4SLinus Torvalds#define STREST	STOREL
2401da177e4SLinus Torvalds#define SHIFT_DISCARD SLLV
2411da177e4SLinus Torvalds#else
2421da177e4SLinus Torvalds#define LDFIRST LOADL
2431da177e4SLinus Torvalds#define LDREST	LOADR
2441da177e4SLinus Torvalds#define STFIRST STOREL
2451da177e4SLinus Torvalds#define STREST	STORER
2461da177e4SLinus Torvalds#define SHIFT_DISCARD SRLV
2471da177e4SLinus Torvalds#endif
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds#define FIRST(unit) ((unit)*NBYTES)
2501da177e4SLinus Torvalds#define REST(unit)  (FIRST(unit)+NBYTES-1)
2511da177e4SLinus Torvalds#define UNIT(unit)  FIRST(unit)
2521da177e4SLinus Torvalds
2531da177e4SLinus Torvalds#define ADDRMASK (NBYTES-1)
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds	.text
2561da177e4SLinus Torvalds	.set	noreorder
257619b6e18SMaciej W. Rozycki#ifndef CONFIG_CPU_DADDI_WORKAROUNDS
2581da177e4SLinus Torvalds	.set	noat
259619b6e18SMaciej W. Rozycki#else
260619b6e18SMaciej W. Rozycki	.set	at=v1
261619b6e18SMaciej W. Rozycki#endif
2621da177e4SLinus Torvalds
263cf62a8b8SMarkos Chandras	.align	5
264bb0757ebSDavid Daney
265bb0757ebSDavid Daney	/*
266cf62a8b8SMarkos Chandras	 * Macro to build the __copy_user common code
267209b8778SAndrea Gelmini	 * Arguments:
268cf62a8b8SMarkos Chandras	 * mode : LEGACY_MODE or EVA_MODE
269cf62a8b8SMarkos Chandras	 * from : Source operand. USEROP or KERNELOP
270cf62a8b8SMarkos Chandras	 * to   : Destination operand. USEROP or KERNELOP
2711da177e4SLinus Torvalds	 */
272cf62a8b8SMarkos Chandras	.macro __BUILD_COPY_USER mode, from, to
273cf62a8b8SMarkos Chandras
274cf62a8b8SMarkos Chandras	/* initialize __memcpy if this the first time we execute this macro */
275cf62a8b8SMarkos Chandras	.ifnotdef __memcpy
276cf62a8b8SMarkos Chandras	.set __memcpy, 1
277cf62a8b8SMarkos Chandras	.hidden __memcpy /* make sure it does not leak */
278cf62a8b8SMarkos Chandras	.endif
279cf62a8b8SMarkos Chandras
2801da177e4SLinus Torvalds	/*
2811da177e4SLinus Torvalds	 * Note: dst & src may be unaligned, len may be 0
2821da177e4SLinus Torvalds	 * Temps
2831da177e4SLinus Torvalds	 */
2841da177e4SLinus Torvalds#define rem t8
2851da177e4SLinus Torvalds
286930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
2871da177e4SLinus Torvalds	/*
2881da177e4SLinus Torvalds	 * The "issue break"s below are very approximate.
2891da177e4SLinus Torvalds	 * Issue delays for dcache fills will perturb the schedule, as will
2901da177e4SLinus Torvalds	 * load queue full replay traps, etc.
2911da177e4SLinus Torvalds	 *
2921da177e4SLinus Torvalds	 * If len < NBYTES use byte operations.
2931da177e4SLinus Torvalds	 */
294bda4d986SMarkos Chandras	PREFS(	0, 0(src) )
295bda4d986SMarkos Chandras	PREFD(	1, 0(dst) )
2961da177e4SLinus Torvalds	sltu	t2, len, NBYTES
2971da177e4SLinus Torvalds	and	t1, dst, ADDRMASK
298bda4d986SMarkos Chandras	PREFS(	0, 1*32(src) )
299bda4d986SMarkos Chandras	PREFD(	1, 1*32(dst) )
300cf62a8b8SMarkos Chandras	bnez	t2, .Lcopy_bytes_checklen\@
3011da177e4SLinus Torvalds	 and	t0, src, ADDRMASK
302bda4d986SMarkos Chandras	PREFS(	0, 2*32(src) )
303bda4d986SMarkos Chandras	PREFD(	1, 2*32(dst) )
30418d84e2eSAlexander Lobakin#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
305cf62a8b8SMarkos Chandras	bnez	t1, .Ldst_unaligned\@
3061da177e4SLinus Torvalds	 nop
307cf62a8b8SMarkos Chandras	bnez	t0, .Lsrc_unaligned_dst_aligned\@
30818d84e2eSAlexander Lobakin#else /* CONFIG_CPU_NO_LOAD_STORE_LR */
309b0ce4bd5SLeonid Yegoshin	or	t0, t0, t1
310b0ce4bd5SLeonid Yegoshin	bnez	t0, .Lcopy_unaligned_bytes\@
31118d84e2eSAlexander Lobakin#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
3121da177e4SLinus Torvalds	/*
3131da177e4SLinus Torvalds	 * use delay slot for fall-through
3141da177e4SLinus Torvalds	 * src and dst are aligned; need to compute rem
3151da177e4SLinus Torvalds	 */
316cf62a8b8SMarkos Chandras.Lboth_aligned\@:
3171da177e4SLinus Torvalds	 SRL	t0, len, LOG_NBYTES+3	 # +3 for 8 units/iter
318cf62a8b8SMarkos Chandras	beqz	t0, .Lcleanup_both_aligned\@ # len < 8*NBYTES
3191da177e4SLinus Torvalds	 and	rem, len, (8*NBYTES-1)	 # rem = len % (8*NBYTES)
320bda4d986SMarkos Chandras	PREFS(	0, 3*32(src) )
321bda4d986SMarkos Chandras	PREFD(	1, 3*32(dst) )
3221da177e4SLinus Torvalds	.align	4
3231da177e4SLinus Torvalds1:
324930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
325cf62a8b8SMarkos Chandras	LOAD(t0, UNIT(0)(src), .Ll_exc\@)
326cf62a8b8SMarkos Chandras	LOAD(t1, UNIT(1)(src), .Ll_exc_copy\@)
327cf62a8b8SMarkos Chandras	LOAD(t2, UNIT(2)(src), .Ll_exc_copy\@)
328cf62a8b8SMarkos Chandras	LOAD(t3, UNIT(3)(src), .Ll_exc_copy\@)
3291da177e4SLinus Torvalds	SUB	len, len, 8*NBYTES
330cf62a8b8SMarkos Chandras	LOAD(t4, UNIT(4)(src), .Ll_exc_copy\@)
331cf62a8b8SMarkos Chandras	LOAD(t7, UNIT(5)(src), .Ll_exc_copy\@)
332cf62a8b8SMarkos Chandras	STORE(t0, UNIT(0)(dst),	.Ls_exc_p8u\@)
333cf62a8b8SMarkos Chandras	STORE(t1, UNIT(1)(dst),	.Ls_exc_p7u\@)
334cf62a8b8SMarkos Chandras	LOAD(t0, UNIT(6)(src), .Ll_exc_copy\@)
335cf62a8b8SMarkos Chandras	LOAD(t1, UNIT(7)(src), .Ll_exc_copy\@)
3361da177e4SLinus Torvalds	ADD	src, src, 8*NBYTES
3371da177e4SLinus Torvalds	ADD	dst, dst, 8*NBYTES
338cf62a8b8SMarkos Chandras	STORE(t2, UNIT(-6)(dst), .Ls_exc_p6u\@)
339cf62a8b8SMarkos Chandras	STORE(t3, UNIT(-5)(dst), .Ls_exc_p5u\@)
340cf62a8b8SMarkos Chandras	STORE(t4, UNIT(-4)(dst), .Ls_exc_p4u\@)
341cf62a8b8SMarkos Chandras	STORE(t7, UNIT(-3)(dst), .Ls_exc_p3u\@)
342cf62a8b8SMarkos Chandras	STORE(t0, UNIT(-2)(dst), .Ls_exc_p2u\@)
343cf62a8b8SMarkos Chandras	STORE(t1, UNIT(-1)(dst), .Ls_exc_p1u\@)
344bda4d986SMarkos Chandras	PREFS(	0, 8*32(src) )
345bda4d986SMarkos Chandras	PREFD(	1, 8*32(dst) )
3461da177e4SLinus Torvalds	bne	len, rem, 1b
3471da177e4SLinus Torvalds	 nop
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds	/*
3501da177e4SLinus Torvalds	 * len == rem == the number of bytes left to copy < 8*NBYTES
3511da177e4SLinus Torvalds	 */
352cf62a8b8SMarkos Chandras.Lcleanup_both_aligned\@:
353cf62a8b8SMarkos Chandras	beqz	len, .Ldone\@
3541da177e4SLinus Torvalds	 sltu	t0, len, 4*NBYTES
355cf62a8b8SMarkos Chandras	bnez	t0, .Lless_than_4units\@
3561da177e4SLinus Torvalds	 and	rem, len, (NBYTES-1)	# rem = len % NBYTES
3571da177e4SLinus Torvalds	/*
3581da177e4SLinus Torvalds	 * len >= 4*NBYTES
3591da177e4SLinus Torvalds	 */
360cf62a8b8SMarkos Chandras	LOAD( t0, UNIT(0)(src),	.Ll_exc\@)
361cf62a8b8SMarkos Chandras	LOAD( t1, UNIT(1)(src),	.Ll_exc_copy\@)
362cf62a8b8SMarkos Chandras	LOAD( t2, UNIT(2)(src),	.Ll_exc_copy\@)
363cf62a8b8SMarkos Chandras	LOAD( t3, UNIT(3)(src),	.Ll_exc_copy\@)
3641da177e4SLinus Torvalds	SUB	len, len, 4*NBYTES
3651da177e4SLinus Torvalds	ADD	src, src, 4*NBYTES
366930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
367cf62a8b8SMarkos Chandras	STORE(t0, UNIT(0)(dst),	.Ls_exc_p4u\@)
368cf62a8b8SMarkos Chandras	STORE(t1, UNIT(1)(dst),	.Ls_exc_p3u\@)
369cf62a8b8SMarkos Chandras	STORE(t2, UNIT(2)(dst),	.Ls_exc_p2u\@)
370cf62a8b8SMarkos Chandras	STORE(t3, UNIT(3)(dst),	.Ls_exc_p1u\@)
371619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
3721da177e4SLinus Torvalds	ADD	dst, dst, 4*NBYTES
373cf62a8b8SMarkos Chandras	beqz	len, .Ldone\@
374619b6e18SMaciej W. Rozycki	.set	noreorder
375cf62a8b8SMarkos Chandras.Lless_than_4units\@:
3761da177e4SLinus Torvalds	/*
3771da177e4SLinus Torvalds	 * rem = len % NBYTES
3781da177e4SLinus Torvalds	 */
379cf62a8b8SMarkos Chandras	beq	rem, len, .Lcopy_bytes\@
3801da177e4SLinus Torvalds	 nop
3811da177e4SLinus Torvalds1:
382930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
383cf62a8b8SMarkos Chandras	LOAD(t0, 0(src), .Ll_exc\@)
3841da177e4SLinus Torvalds	ADD	src, src, NBYTES
3851da177e4SLinus Torvalds	SUB	len, len, NBYTES
386cf62a8b8SMarkos Chandras	STORE(t0, 0(dst), .Ls_exc_p1u\@)
387619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
3881da177e4SLinus Torvalds	ADD	dst, dst, NBYTES
389619b6e18SMaciej W. Rozycki	bne	rem, len, 1b
390619b6e18SMaciej W. Rozycki	.set	noreorder
3911da177e4SLinus Torvalds
39218d84e2eSAlexander Lobakin#ifndef CONFIG_CPU_NO_LOAD_STORE_LR
3931da177e4SLinus Torvalds	/*
3941da177e4SLinus Torvalds	 * src and dst are aligned, need to copy rem bytes (rem < NBYTES)
3951da177e4SLinus Torvalds	 * A loop would do only a byte at a time with possible branch
3961da177e4SLinus Torvalds	 * mispredicts.	 Can't do an explicit LOAD dst,mask,or,STORE
3971da177e4SLinus Torvalds	 * because can't assume read-access to dst.  Instead, use
3981da177e4SLinus Torvalds	 * STREST dst, which doesn't require read access to dst.
3991da177e4SLinus Torvalds	 *
4001da177e4SLinus Torvalds	 * This code should perform better than a simple loop on modern,
4011da177e4SLinus Torvalds	 * wide-issue mips processors because the code has fewer branches and
4021da177e4SLinus Torvalds	 * more instruction-level parallelism.
4031da177e4SLinus Torvalds	 */
4041da177e4SLinus Torvalds#define bits t2
405cf62a8b8SMarkos Chandras	beqz	len, .Ldone\@
4061da177e4SLinus Torvalds	 ADD	t1, dst, len	# t1 is just past last byte of dst
4071da177e4SLinus Torvalds	li	bits, 8*NBYTES
4081da177e4SLinus Torvalds	SLL	rem, len, 3	# rem = number of bits to keep
409cf62a8b8SMarkos Chandras	LOAD(t0, 0(src), .Ll_exc\@)
4101da177e4SLinus Torvalds	SUB	bits, bits, rem # bits = number of bits to discard
4111da177e4SLinus Torvalds	SHIFT_DISCARD t0, t0, bits
412cf62a8b8SMarkos Chandras	STREST(t0, -1(t1), .Ls_exc\@)
4131da177e4SLinus Torvalds	jr	ra
4141da177e4SLinus Torvalds	 move	len, zero
415cf62a8b8SMarkos Chandras.Ldst_unaligned\@:
4161da177e4SLinus Torvalds	/*
4171da177e4SLinus Torvalds	 * dst is unaligned
4181da177e4SLinus Torvalds	 * t0 = src & ADDRMASK
4191da177e4SLinus Torvalds	 * t1 = dst & ADDRMASK; T1 > 0
4201da177e4SLinus Torvalds	 * len >= NBYTES
4211da177e4SLinus Torvalds	 *
4221da177e4SLinus Torvalds	 * Copy enough bytes to align dst
4231da177e4SLinus Torvalds	 * Set match = (src and dst have same alignment)
4241da177e4SLinus Torvalds	 */
4251da177e4SLinus Torvalds#define match rem
426cf62a8b8SMarkos Chandras	LDFIRST(t3, FIRST(0)(src), .Ll_exc\@)
4271da177e4SLinus Torvalds	ADD	t2, zero, NBYTES
428cf62a8b8SMarkos Chandras	LDREST(t3, REST(0)(src), .Ll_exc_copy\@)
4291da177e4SLinus Torvalds	SUB	t2, t2, t1	# t2 = number of bytes copied
4301da177e4SLinus Torvalds	xor	match, t0, t1
431930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
432cf62a8b8SMarkos Chandras	STFIRST(t3, FIRST(0)(dst), .Ls_exc\@)
433cf62a8b8SMarkos Chandras	beq	len, t2, .Ldone\@
4341da177e4SLinus Torvalds	 SUB	len, len, t2
4351da177e4SLinus Torvalds	ADD	dst, dst, t2
436cf62a8b8SMarkos Chandras	beqz	match, .Lboth_aligned\@
4371da177e4SLinus Torvalds	 ADD	src, src, t2
4381da177e4SLinus Torvalds
439cf62a8b8SMarkos Chandras.Lsrc_unaligned_dst_aligned\@:
4401da177e4SLinus Torvalds	SRL	t0, len, LOG_NBYTES+2	 # +2 for 4 units/iter
441bda4d986SMarkos Chandras	PREFS(	0, 3*32(src) )
442cf62a8b8SMarkos Chandras	beqz	t0, .Lcleanup_src_unaligned\@
4431da177e4SLinus Torvalds	 and	rem, len, (4*NBYTES-1)	 # rem = len % 4*NBYTES
444bda4d986SMarkos Chandras	PREFD(	1, 3*32(dst) )
4451da177e4SLinus Torvalds1:
4461da177e4SLinus Torvalds/*
4471da177e4SLinus Torvalds * Avoid consecutive LD*'s to the same register since some mips
4481da177e4SLinus Torvalds * implementations can't issue them in the same cycle.
4491da177e4SLinus Torvalds * It's OK to load FIRST(N+1) before REST(N) because the two addresses
4501da177e4SLinus Torvalds * are to the same unit (unless src is aligned, but it's not).
4511da177e4SLinus Torvalds */
452930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
453cf62a8b8SMarkos Chandras	LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
454cf62a8b8SMarkos Chandras	LDFIRST(t1, FIRST(1)(src), .Ll_exc_copy\@)
4551da177e4SLinus Torvalds	SUB	len, len, 4*NBYTES
456cf62a8b8SMarkos Chandras	LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
457cf62a8b8SMarkos Chandras	LDREST(t1, REST(1)(src), .Ll_exc_copy\@)
458cf62a8b8SMarkos Chandras	LDFIRST(t2, FIRST(2)(src), .Ll_exc_copy\@)
459cf62a8b8SMarkos Chandras	LDFIRST(t3, FIRST(3)(src), .Ll_exc_copy\@)
460cf62a8b8SMarkos Chandras	LDREST(t2, REST(2)(src), .Ll_exc_copy\@)
461cf62a8b8SMarkos Chandras	LDREST(t3, REST(3)(src), .Ll_exc_copy\@)
462bda4d986SMarkos Chandras	PREFS(	0, 9*32(src) )		# 0 is PREF_LOAD  (not streamed)
4631da177e4SLinus Torvalds	ADD	src, src, 4*NBYTES
4641da177e4SLinus Torvalds#ifdef CONFIG_CPU_SB1
4651da177e4SLinus Torvalds	nop				# improves slotting
4661da177e4SLinus Torvalds#endif
467cf62a8b8SMarkos Chandras	STORE(t0, UNIT(0)(dst),	.Ls_exc_p4u\@)
468cf62a8b8SMarkos Chandras	STORE(t1, UNIT(1)(dst),	.Ls_exc_p3u\@)
469cf62a8b8SMarkos Chandras	STORE(t2, UNIT(2)(dst),	.Ls_exc_p2u\@)
470cf62a8b8SMarkos Chandras	STORE(t3, UNIT(3)(dst),	.Ls_exc_p1u\@)
471bda4d986SMarkos Chandras	PREFD(	1, 9*32(dst) )		# 1 is PREF_STORE (not streamed)
472619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
4731da177e4SLinus Torvalds	ADD	dst, dst, 4*NBYTES
474619b6e18SMaciej W. Rozycki	bne	len, rem, 1b
475619b6e18SMaciej W. Rozycki	.set	noreorder
4761da177e4SLinus Torvalds
477cf62a8b8SMarkos Chandras.Lcleanup_src_unaligned\@:
478cf62a8b8SMarkos Chandras	beqz	len, .Ldone\@
4791da177e4SLinus Torvalds	 and	rem, len, NBYTES-1  # rem = len % NBYTES
480cf62a8b8SMarkos Chandras	beq	rem, len, .Lcopy_bytes\@
4811da177e4SLinus Torvalds	 nop
4821da177e4SLinus Torvalds1:
483930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
484cf62a8b8SMarkos Chandras	LDFIRST(t0, FIRST(0)(src), .Ll_exc\@)
485cf62a8b8SMarkos Chandras	LDREST(t0, REST(0)(src), .Ll_exc_copy\@)
4861da177e4SLinus Torvalds	ADD	src, src, NBYTES
4871da177e4SLinus Torvalds	SUB	len, len, NBYTES
488cf62a8b8SMarkos Chandras	STORE(t0, 0(dst), .Ls_exc_p1u\@)
489619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
4901da177e4SLinus Torvalds	ADD	dst, dst, NBYTES
491619b6e18SMaciej W. Rozycki	bne	len, rem, 1b
492619b6e18SMaciej W. Rozycki	.set	noreorder
4931da177e4SLinus Torvalds
49418d84e2eSAlexander Lobakin#endif /* !CONFIG_CPU_NO_LOAD_STORE_LR */
495cf62a8b8SMarkos Chandras.Lcopy_bytes_checklen\@:
496cf62a8b8SMarkos Chandras	beqz	len, .Ldone\@
4971da177e4SLinus Torvalds	 nop
498cf62a8b8SMarkos Chandras.Lcopy_bytes\@:
4991da177e4SLinus Torvalds	/* 0 < len < NBYTES  */
500930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
5011da177e4SLinus Torvalds#define COPY_BYTE(N)			\
502cf62a8b8SMarkos Chandras	LOADB(t0, N(src), .Ll_exc\@);	\
5031da177e4SLinus Torvalds	SUB	len, len, 1;		\
504cf62a8b8SMarkos Chandras	beqz	len, .Ldone\@;		\
505cf62a8b8SMarkos Chandras	STOREB(t0, N(dst), .Ls_exc_p1\@)
5061da177e4SLinus Torvalds
5071da177e4SLinus Torvalds	COPY_BYTE(0)
5081da177e4SLinus Torvalds	COPY_BYTE(1)
5091da177e4SLinus Torvalds#ifdef USE_DOUBLE
5101da177e4SLinus Torvalds	COPY_BYTE(2)
5111da177e4SLinus Torvalds	COPY_BYTE(3)
5121da177e4SLinus Torvalds	COPY_BYTE(4)
5131da177e4SLinus Torvalds	COPY_BYTE(5)
5141da177e4SLinus Torvalds#endif
515cf62a8b8SMarkos Chandras	LOADB(t0, NBYTES-2(src), .Ll_exc\@)
5161da177e4SLinus Torvalds	SUB	len, len, 1
5171da177e4SLinus Torvalds	jr	ra
518cf62a8b8SMarkos Chandras	STOREB(t0, NBYTES-2(dst), .Ls_exc_p1\@)
519cf62a8b8SMarkos Chandras.Ldone\@:
5201da177e4SLinus Torvalds	jr	ra
52151b1029dSMarkos Chandras	 nop
522b0ce4bd5SLeonid Yegoshin
52318d84e2eSAlexander Lobakin#ifdef CONFIG_CPU_NO_LOAD_STORE_LR
524b0ce4bd5SLeonid Yegoshin.Lcopy_unaligned_bytes\@:
525b0ce4bd5SLeonid Yegoshin1:
526b0ce4bd5SLeonid Yegoshin	COPY_BYTE(0)
527b0ce4bd5SLeonid Yegoshin	COPY_BYTE(1)
528b0ce4bd5SLeonid Yegoshin	COPY_BYTE(2)
529b0ce4bd5SLeonid Yegoshin	COPY_BYTE(3)
530b0ce4bd5SLeonid Yegoshin	COPY_BYTE(4)
531b0ce4bd5SLeonid Yegoshin	COPY_BYTE(5)
532b0ce4bd5SLeonid Yegoshin	COPY_BYTE(6)
533b0ce4bd5SLeonid Yegoshin	COPY_BYTE(7)
534b0ce4bd5SLeonid Yegoshin	ADD	src, src, 8
535b0ce4bd5SLeonid Yegoshin	b	1b
536b0ce4bd5SLeonid Yegoshin	 ADD	dst, dst, 8
53718d84e2eSAlexander Lobakin#endif /* CONFIG_CPU_NO_LOAD_STORE_LR */
538cf62a8b8SMarkos Chandras	.if __memcpy == 1
5391da177e4SLinus Torvalds	END(memcpy)
540cf62a8b8SMarkos Chandras	.set __memcpy, 0
541cf62a8b8SMarkos Chandras	.hidden __memcpy
542cf62a8b8SMarkos Chandras	.endif
5431da177e4SLinus Torvalds
544cf62a8b8SMarkos Chandras.Ll_exc_copy\@:
5451da177e4SLinus Torvalds	/*
5461da177e4SLinus Torvalds	 * Copy bytes from src until faulting load address (or until a
5471da177e4SLinus Torvalds	 * lb faults)
5481da177e4SLinus Torvalds	 *
5491da177e4SLinus Torvalds	 * When reached by a faulting LDFIRST/LDREST, THREAD_BUADDR($28)
5501da177e4SLinus Torvalds	 * may be more than a byte beyond the last address.
5511da177e4SLinus Torvalds	 * Hence, the lb below may get an exception.
5521da177e4SLinus Torvalds	 *
5531da177e4SLinus Torvalds	 * Assumes src < THREAD_BUADDR($28)
5541da177e4SLinus Torvalds	 */
5555bc05971SMarkos Chandras	LOADK	t0, TI_TASK($28)
5561da177e4SLinus Torvalds	 nop
5575bc05971SMarkos Chandras	LOADK	t0, THREAD_BUADDR(t0)
5581da177e4SLinus Torvalds1:
559cf62a8b8SMarkos Chandras	LOADB(t1, 0(src), .Ll_exc\@)
5601da177e4SLinus Torvalds	ADD	src, src, 1
5611da177e4SLinus Torvalds	sb	t1, 0(dst)	# can't fault -- we're copy_from_user
562619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
5631da177e4SLinus Torvalds	ADD	dst, dst, 1
564619b6e18SMaciej W. Rozycki	bne	src, t0, 1b
565619b6e18SMaciej W. Rozycki	.set	noreorder
566cf62a8b8SMarkos Chandras.Ll_exc\@:
5675bc05971SMarkos Chandras	LOADK	t0, TI_TASK($28)
5681da177e4SLinus Torvalds	 nop
5695bc05971SMarkos Chandras	LOADK	t0, THREAD_BUADDR(t0)	# t0 is just past last good address
5701da177e4SLinus Torvalds	 nop
5711da177e4SLinus Torvalds	SUB	len, AT, t0		# len number of uncopied bytes
5721da177e4SLinus Torvalds	jr	ra
5731da177e4SLinus Torvalds	 nop
5741da177e4SLinus Torvalds
5751da177e4SLinus Torvalds#define SEXC(n)							\
576619b6e18SMaciej W. Rozycki	.set	reorder;			/* DADDI_WAR */ \
577cf62a8b8SMarkos Chandras.Ls_exc_p ## n ## u\@:						\
578619b6e18SMaciej W. Rozycki	ADD	len, len, n*NBYTES;				\
5791da177e4SLinus Torvalds	jr	ra;						\
580619b6e18SMaciej W. Rozycki	.set	noreorder
5811da177e4SLinus Torvalds
5821da177e4SLinus TorvaldsSEXC(8)
5831da177e4SLinus TorvaldsSEXC(7)
5841da177e4SLinus TorvaldsSEXC(6)
5851da177e4SLinus TorvaldsSEXC(5)
5861da177e4SLinus TorvaldsSEXC(4)
5871da177e4SLinus TorvaldsSEXC(3)
5881da177e4SLinus TorvaldsSEXC(2)
5891da177e4SLinus TorvaldsSEXC(1)
5901da177e4SLinus Torvalds
591cf62a8b8SMarkos Chandras.Ls_exc_p1\@:
592619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
5931da177e4SLinus Torvalds	ADD	len, len, 1
594619b6e18SMaciej W. Rozycki	jr	ra
595619b6e18SMaciej W. Rozycki	.set	noreorder
596cf62a8b8SMarkos Chandras.Ls_exc\@:
5971da177e4SLinus Torvalds	jr	ra
5981da177e4SLinus Torvalds	 nop
599cf62a8b8SMarkos Chandras	.endm
6001da177e4SLinus Torvalds
60178bdbbacSMasahiro Yamada#ifndef CONFIG_HAVE_PLAT_MEMCPY
6021da177e4SLinus Torvalds	.align	5
6031da177e4SLinus TorvaldsLEAF(memmove)
604576a2f0cSPaul BurtonEXPORT_SYMBOL(memmove)
6051da177e4SLinus Torvalds	ADD	t0, a0, a2
6061da177e4SLinus Torvalds	ADD	t1, a1, a2
6071da177e4SLinus Torvalds	sltu	t0, a1, t0			# dst + len <= src -> memcpy
6081da177e4SLinus Torvalds	sltu	t1, a0, t1			# dst >= src + len -> memcpy
6091da177e4SLinus Torvalds	and	t0, t1
610c5ec1983SRalf Baechle	beqz	t0, .L__memcpy
6111da177e4SLinus Torvalds	 move	v0, a0				/* return value */
612c5ec1983SRalf Baechle	beqz	a2, .Lr_out
6131da177e4SLinus Torvalds	END(memmove)
6141da177e4SLinus Torvalds
6151da177e4SLinus Torvalds	/* fall through to __rmemcpy */
6161da177e4SLinus TorvaldsLEAF(__rmemcpy)					/* a0=dst a1=src a2=len */
6171da177e4SLinus Torvalds	 sltu	t0, a1, a0
618c5ec1983SRalf Baechle	beqz	t0, .Lr_end_bytes_up		# src >= dst
6191da177e4SLinus Torvalds	 nop
6201da177e4SLinus Torvalds	ADD	a0, a2				# dst = dst + len
6211da177e4SLinus Torvalds	ADD	a1, a2				# src = src + len
6221da177e4SLinus Torvalds
623c5ec1983SRalf Baechle.Lr_end_bytes:
624930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
6251da177e4SLinus Torvalds	lb	t0, -1(a1)
6261da177e4SLinus Torvalds	SUB	a2, a2, 0x1
6271da177e4SLinus Torvalds	sb	t0, -1(a0)
6281da177e4SLinus Torvalds	SUB	a1, a1, 0x1
629619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
6301da177e4SLinus Torvalds	SUB	a0, a0, 0x1
631c5ec1983SRalf Baechle	bnez	a2, .Lr_end_bytes
632619b6e18SMaciej W. Rozycki	.set	noreorder
6331da177e4SLinus Torvalds
634c5ec1983SRalf Baechle.Lr_out:
6351da177e4SLinus Torvalds	jr	ra
6361da177e4SLinus Torvalds	 move	a2, zero
6371da177e4SLinus Torvalds
638c5ec1983SRalf Baechle.Lr_end_bytes_up:
639930bff88SThomas Bogendoerfer	R10KCBARRIER(0(ra))
6401da177e4SLinus Torvalds	lb	t0, (a1)
6411da177e4SLinus Torvalds	SUB	a2, a2, 0x1
6421da177e4SLinus Torvalds	sb	t0, (a0)
6431da177e4SLinus Torvalds	ADD	a1, a1, 0x1
644619b6e18SMaciej W. Rozycki	.set	reorder				/* DADDI_WAR */
6451da177e4SLinus Torvalds	ADD	a0, a0, 0x1
646c5ec1983SRalf Baechle	bnez	a2, .Lr_end_bytes_up
647619b6e18SMaciej W. Rozycki	.set	noreorder
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds	jr	ra
6501da177e4SLinus Torvalds	 move	a2, zero
6511da177e4SLinus Torvalds	END(__rmemcpy)
652cf62a8b8SMarkos Chandras
653cf62a8b8SMarkos Chandras/*
654cf62a8b8SMarkos Chandras * A combined memcpy/__copy_user
655cf62a8b8SMarkos Chandras * __copy_user sets len to 0 for success; else to an upper bound of
656cf62a8b8SMarkos Chandras * the number of uncopied bytes.
657cf62a8b8SMarkos Chandras * memcpy sets v0 to dst.
658cf62a8b8SMarkos Chandras */
659cf62a8b8SMarkos Chandras	.align	5
660cf62a8b8SMarkos ChandrasLEAF(memcpy)					/* a0=dst a1=src a2=len */
661576a2f0cSPaul BurtonEXPORT_SYMBOL(memcpy)
662cf62a8b8SMarkos Chandras	move	v0, dst				/* return value */
663cf62a8b8SMarkos Chandras.L__memcpy:
66404324f44SThomas Bogendoerfer#ifndef CONFIG_EVA
66504324f44SThomas BogendoerferFEXPORT(__raw_copy_from_user)
66604324f44SThomas BogendoerferEXPORT_SYMBOL(__raw_copy_from_user)
66704324f44SThomas BogendoerferFEXPORT(__raw_copy_to_user)
66804324f44SThomas BogendoerferEXPORT_SYMBOL(__raw_copy_to_user)
66904324f44SThomas Bogendoerfer#endif
670cf62a8b8SMarkos Chandras	/* Legacy Mode, user <-> user */
671cf62a8b8SMarkos Chandras	__BUILD_COPY_USER LEGACY_MODE USEROP USEROP
672cd26cb41SMarkos Chandras
67378bdbbacSMasahiro Yamada#endif
67478bdbbacSMasahiro Yamada
675cd26cb41SMarkos Chandras#ifdef CONFIG_EVA
676cd26cb41SMarkos Chandras
677cd26cb41SMarkos Chandras/*
678cd26cb41SMarkos Chandras * For EVA we need distinct symbols for reading and writing to user space.
679cd26cb41SMarkos Chandras * This is because we need to use specific EVA instructions to perform the
680cd26cb41SMarkos Chandras * virtual <-> physical translation when a virtual address is actually in user
681cd26cb41SMarkos Chandras * space
682cd26cb41SMarkos Chandras */
683cd26cb41SMarkos Chandras
684cd26cb41SMarkos Chandras/*
685cd26cb41SMarkos Chandras * __copy_from_user (EVA)
686cd26cb41SMarkos Chandras */
687cd26cb41SMarkos Chandras
68804324f44SThomas BogendoerferLEAF(__raw_copy_from_user)
68904324f44SThomas BogendoerferEXPORT_SYMBOL(__raw_copy_from_user)
690cd26cb41SMarkos Chandras	__BUILD_COPY_USER EVA_MODE USEROP KERNELOP
69104324f44SThomas BogendoerferEND(__raw_copy_from_user)
692cd26cb41SMarkos Chandras
693cd26cb41SMarkos Chandras
694cd26cb41SMarkos Chandras
695cd26cb41SMarkos Chandras/*
696cd26cb41SMarkos Chandras * __copy_to_user (EVA)
697cd26cb41SMarkos Chandras */
698cd26cb41SMarkos Chandras
69904324f44SThomas BogendoerferLEAF(__raw_copy_to_user)
70004324f44SThomas BogendoerferEXPORT_SYMBOL(__raw_copy_to_user)
701cd26cb41SMarkos Chandras__BUILD_COPY_USER EVA_MODE KERNELOP USEROP
70204324f44SThomas BogendoerferEND(__raw_copy_to_user)
703cd26cb41SMarkos Chandras
704cd26cb41SMarkos Chandras#endif
705