/* Extracted from GLIBC memcpy.c and memcopy.h, which is:1Copyright (C) 1991, 1992, 1993, 1997, 2004 Free Software Foundation, Inc.2This file is part of the GNU C Library.3Contributed by Torbjorn Granlund ([email protected]).45The GNU C Library is free software; you can redistribute it and/or6modify it under the terms of the GNU Lesser General Public7License as published by the Free Software Foundation; either8version 2.1 of the License, or (at your option) any later version.910The GNU C Library is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU13Lesser General Public License for more details.1415You should have received a copy of the GNU Lesser General Public16License along with the GNU C Library; if not, see17<http://www.gnu.org/licenses/>. */1819#include <linux/types.h>2021/* Type to use for aligned memory operations.22This should normally be the biggest type supported by a single load23and store. */24#define op_t unsigned long int25#define OPSIZ (sizeof(op_t))2627/* Optimal type for storing bytes in registers. */28#define reg_char char2930#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))3132/* Copy exactly NBYTES bytes from SRC_BP to DST_BP,33without any assumptions about alignment of the pointers. */34#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \35do { \36size_t __nbytes = (nbytes); \37while (__nbytes > 0) { \38unsigned char __x = ((unsigned char *) src_bp)[0]; \39src_bp += 1; \40__nbytes -= 1; \41((unsigned char *) dst_bp)[0] = __x; \42dst_bp += 1; \43} \44} while (0)4546/* Copy *up to* NBYTES bytes from SRC_BP to DST_BP, with47the assumption that DST_BP is aligned on an OPSIZ multiple. If48not all bytes could be easily copied, store remaining number of bytes49in NBYTES_LEFT, otherwise store 0. */50/* extern void _wordcopy_fwd_aligned __P ((long int, long int, size_t)); */51/* extern void _wordcopy_fwd_dest_aligned __P ((long int, long int, size_t)); */52#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \53do { \54if (src_bp % OPSIZ == 0) \55_wordcopy_fwd_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);\56else \57_wordcopy_fwd_dest_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);\58src_bp += (nbytes) & -OPSIZ; \59dst_bp += (nbytes) & -OPSIZ; \60(nbytes_left) = (nbytes) % OPSIZ; \61} while (0)626364/* Threshold value for when to enter the unrolled loops. */65#define OP_T_THRES 166667/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to68block beginning at DSTP with LEN `op_t' words (not LEN bytes!).69Both SRCP and DSTP should be aligned for memory operations on `op_t's. */70/* stream-lined (read x8 + write x8) */71static void _wordcopy_fwd_aligned(long int dstp, long int srcp, size_t len)72{73while (len > 7) {74register op_t a0, a1, a2, a3, a4, a5, a6, a7;7576a0 = ((op_t *) srcp)[0];77a1 = ((op_t *) srcp)[1];78a2 = ((op_t *) srcp)[2];79a3 = ((op_t *) srcp)[3];80a4 = ((op_t *) srcp)[4];81a5 = ((op_t *) srcp)[5];82a6 = ((op_t *) srcp)[6];83a7 = ((op_t *) srcp)[7];84((op_t *) dstp)[0] = a0;85((op_t *) dstp)[1] = a1;86((op_t *) dstp)[2] = a2;87((op_t *) dstp)[3] = a3;88((op_t *) dstp)[4] = a4;89((op_t *) dstp)[5] = a5;90((op_t *) dstp)[6] = a6;91((op_t *) dstp)[7] = a7;9293srcp += 8 * OPSIZ;94dstp += 8 * OPSIZ;95len -= 8;96}97while (len > 0) {98*(op_t *)dstp = *(op_t *)srcp;99100srcp += OPSIZ;101dstp += OPSIZ;102len -= 1;103}104}105106/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to107block beginning at DSTP with LEN `op_t' words (not LEN bytes!).108DSTP should be aligned for memory operations on `op_t's, but SRCP must109*not* be aligned. */110/* stream-lined (read x4 + write x4) */111static void _wordcopy_fwd_dest_aligned(long int dstp, long int srcp,112size_t len)113{114op_t ap;115int sh_1, sh_2;116117/* Calculate how to shift a word read at the memory operation118aligned srcp to make it aligned for copy. */119120sh_1 = 8 * (srcp % OPSIZ);121sh_2 = 8 * OPSIZ - sh_1;122123/* Make SRCP aligned by rounding it down to the beginning of the `op_t'124it points in the middle of. */125srcp &= -OPSIZ;126ap = ((op_t *) srcp)[0];127srcp += OPSIZ;128129while (len > 3) {130op_t a0, a1, a2, a3;131132a0 = ((op_t *) srcp)[0];133a1 = ((op_t *) srcp)[1];134a2 = ((op_t *) srcp)[2];135a3 = ((op_t *) srcp)[3];136((op_t *) dstp)[0] = MERGE(ap, sh_1, a0, sh_2);137((op_t *) dstp)[1] = MERGE(a0, sh_1, a1, sh_2);138((op_t *) dstp)[2] = MERGE(a1, sh_1, a2, sh_2);139((op_t *) dstp)[3] = MERGE(a2, sh_1, a3, sh_2);140141ap = a3;142srcp += 4 * OPSIZ;143dstp += 4 * OPSIZ;144len -= 4;145}146while (len > 0) {147register op_t a0;148149a0 = ((op_t *) srcp)[0];150((op_t *) dstp)[0] = MERGE(ap, sh_1, a0, sh_2);151152ap = a0;153srcp += OPSIZ;154dstp += OPSIZ;155len -= 1;156}157}158159void *memcpy(void *dstpp, const void *srcpp, size_t len)160{161unsigned long int dstp = (long int) dstpp;162unsigned long int srcp = (long int) srcpp;163164/* Copy from the beginning to the end. */165166/* If there not too few bytes to copy, use word copy. */167if (len >= OP_T_THRES) {168/* Copy just a few bytes to make DSTP aligned. */169len -= (-dstp) % OPSIZ;170BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);171172/* Copy whole pages from SRCP to DSTP by virtual address173manipulation, as much as possible. */174175/* PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); */176177/* Copy from SRCP to DSTP taking advantage of the known178alignment of DSTP. Number of bytes remaining is put in the179third argument, i.e. in LEN. This number may vary from180machine to machine. */181182WORD_COPY_FWD(dstp, srcp, len, len);183184/* Fall out and copy the tail. */185}186187/* There are just a few bytes to copy. Use byte memory operations. */188BYTE_COPY_FWD(dstp, srcp, len);189190return dstpp;191}192193void *memcpyb(void *dstpp, const void *srcpp, unsigned len)194{195unsigned long int dstp = (long int) dstpp;196unsigned long int srcp = (long int) srcpp;197198BYTE_COPY_FWD(dstp, srcp, len);199200return dstpp;201}202203204