162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file COPYING in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/string.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_civoid *memcpy(void *to, const void *from, size_t n)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	void *xto = to;
1362306a36Sopenharmony_ci	size_t temp;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	if (!n)
1662306a36Sopenharmony_ci		return xto;
1762306a36Sopenharmony_ci	if ((long)to & 1) {
1862306a36Sopenharmony_ci		char *cto = to;
1962306a36Sopenharmony_ci		const char *cfrom = from;
2062306a36Sopenharmony_ci		*cto++ = *cfrom++;
2162306a36Sopenharmony_ci		to = cto;
2262306a36Sopenharmony_ci		from = cfrom;
2362306a36Sopenharmony_ci		n--;
2462306a36Sopenharmony_ci	}
2562306a36Sopenharmony_ci#if defined(CONFIG_M68000)
2662306a36Sopenharmony_ci	if ((long)from & 1) {
2762306a36Sopenharmony_ci		char *cto = to;
2862306a36Sopenharmony_ci		const char *cfrom = from;
2962306a36Sopenharmony_ci		for (; n; n--)
3062306a36Sopenharmony_ci			*cto++ = *cfrom++;
3162306a36Sopenharmony_ci		return xto;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci#endif
3462306a36Sopenharmony_ci	if (n > 2 && (long)to & 2) {
3562306a36Sopenharmony_ci		short *sto = to;
3662306a36Sopenharmony_ci		const short *sfrom = from;
3762306a36Sopenharmony_ci		*sto++ = *sfrom++;
3862306a36Sopenharmony_ci		to = sto;
3962306a36Sopenharmony_ci		from = sfrom;
4062306a36Sopenharmony_ci		n -= 2;
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci	temp = n >> 2;
4362306a36Sopenharmony_ci	if (temp) {
4462306a36Sopenharmony_ci		long *lto = to;
4562306a36Sopenharmony_ci		const long *lfrom = from;
4662306a36Sopenharmony_ci#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
4762306a36Sopenharmony_ci		for (; temp; temp--)
4862306a36Sopenharmony_ci			*lto++ = *lfrom++;
4962306a36Sopenharmony_ci#else
5062306a36Sopenharmony_ci		size_t temp1;
5162306a36Sopenharmony_ci		asm volatile (
5262306a36Sopenharmony_ci			"	movel %2,%3\n"
5362306a36Sopenharmony_ci			"	andw  #7,%3\n"
5462306a36Sopenharmony_ci			"	lsrl  #3,%2\n"
5562306a36Sopenharmony_ci			"	negw  %3\n"
5662306a36Sopenharmony_ci			"	jmp   %%pc@(1f,%3:w:2)\n"
5762306a36Sopenharmony_ci			"4:	movel %0@+,%1@+\n"
5862306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
5962306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
6062306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
6162306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
6262306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
6362306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
6462306a36Sopenharmony_ci			"	movel %0@+,%1@+\n"
6562306a36Sopenharmony_ci			"1:	dbra  %2,4b\n"
6662306a36Sopenharmony_ci			"	clrw  %2\n"
6762306a36Sopenharmony_ci			"	subql #1,%2\n"
6862306a36Sopenharmony_ci			"	jpl   4b"
6962306a36Sopenharmony_ci			: "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
7062306a36Sopenharmony_ci			: "0" (lfrom), "1" (lto), "2" (temp));
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci		to = lto;
7362306a36Sopenharmony_ci		from = lfrom;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci	if (n & 2) {
7662306a36Sopenharmony_ci		short *sto = to;
7762306a36Sopenharmony_ci		const short *sfrom = from;
7862306a36Sopenharmony_ci		*sto++ = *sfrom++;
7962306a36Sopenharmony_ci		to = sto;
8062306a36Sopenharmony_ci		from = sfrom;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci	if (n & 1) {
8362306a36Sopenharmony_ci		char *cto = to;
8462306a36Sopenharmony_ci		const char *cfrom = from;
8562306a36Sopenharmony_ci		*cto = *cfrom;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	return xto;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ciEXPORT_SYMBOL(memcpy);
90