summaryrefslogtreecommitdiff
path: root/arch/x86
diff options
context:
space:
mode:
authorGraeme Russ <graeme.russ@gmail.com>2011-12-27 22:46:39 +1100
committerGraeme Russ <graeme.russ@gmail.com>2012-01-02 03:58:46 +1100
commitb2c2a038426f651c574a97a02563f78c2dceaa89 (patch)
tree4798a22f07e23c15f92e2f5608f337ed378c6668 /arch/x86
parentbfcc40bb09b05c90cc3b1496abb270eb8aa72134 (diff)
x86: Import glibc memcpy implementation
Taken from glibc version 2.14.90 -- Changes for v2: - None
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/string.h2
-rw-r--r--arch/x86/lib/string.c61
2 files changed, 62 insertions, 1 deletions
diff --git a/arch/x86/include/asm/string.h b/arch/x86/include/asm/string.h
index 3aa6c1131b..0ad612f627 100644
--- a/arch/x86/include/asm/string.h
+++ b/arch/x86/include/asm/string.h
@@ -14,7 +14,7 @@ extern char * strrchr(const char * s, int c);
#undef __HAVE_ARCH_STRCHR
extern char * strchr(const char * s, int c);
-#undef __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMCPY
extern void * memcpy(void *, const void *, __kernel_size_t);
#undef __HAVE_ARCH_MEMMOVE
diff --git a/arch/x86/lib/string.c b/arch/x86/lib/string.c
index f2ea7e4e33..1fde81b8b7 100644
--- a/arch/x86/lib/string.c
+++ b/arch/x86/lib/string.c
@@ -85,3 +85,64 @@ void *memset(void *dstpp, int c, size_t len)
return dstpp;
}
+
+#define OP_T_THRES 8
+#define OPSIZ (sizeof(op_t))
+
+#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \
+do { \
+ int __d0; \
+ asm volatile( \
+ /* Clear the direction flag, so copying goes forward. */ \
+ "cld\n" \
+ /* Copy bytes. */ \
+ "rep\n" \
+ "movsb" : \
+ "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \
+ "0" (dst_bp), "1" (src_bp), "2" (nbytes) : \
+ "memory"); \
+} while (0)
+
+#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \
+do { \
+ int __d0; \
+ asm volatile( \
+ /* Clear the direction flag, so copying goes forward. */ \
+ "cld\n" \
+ /* Copy longwords. */ \
+ "rep\n" \
+ "movsl" : \
+ "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \
+ "0" (dst_bp), "1" (src_bp), "2" ((nbytes) / 4) : \
+ "memory"); \
+ (nbytes_left) = (nbytes) % 4; \
+} while (0)
+
+void *memcpy(void *dstpp, const void *srcpp, size_t len)
+{
+ unsigned long int dstp = (long int)dstpp;
+ unsigned long int srcp = (long int)srcpp;
+
+ /* Copy from the beginning to the end. */
+
+ /* If there not too few bytes to copy, use word copy. */
+ if (len >= OP_T_THRES) {
+ /* Copy just a few bytes to make DSTP aligned. */
+ len -= (-dstp) % OPSIZ;
+ BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);
+
+ /* Copy from SRCP to DSTP taking advantage of the known
+ * alignment of DSTP. Number of bytes remaining is put
+ * in the third argument, i.e. in LEN. This number may
+ * vary from machine to machine.
+ */
+ WORD_COPY_FWD(dstp, srcp, len, len);
+
+ /* Fall out and copy the tail. */
+ }
+
+ /* There are just a few bytes to copy. Use byte memory operations. */
+ BYTE_COPY_FWD(dstp, srcp, len);
+
+ return dstpp;
+}