diff options
author | Peter Stuge <peter@stuge.se> | 2007-03-01 01:09:45 +0000 |
---|---|---|
committer | Peter Stuge <peter@stuge.se> | 2007-03-01 01:09:45 +0000 |
commit | 9d7f9f93cf632337797d5a1f055fef1eb2310012 (patch) | |
tree | 9fdbc94ed86fdbc04a9513262ba974839b069a56 /lib | |
parent | bf544534fee1fb4b72dd49fc24c2c42e447090e7 (diff) | |
download | coreboot-9d7f9f93cf632337797d5a1f055fef1eb2310012.tar.gz coreboot-9d7f9f93cf632337797d5a1f055fef1eb2310012.tar.bz2 coreboot-9d7f9f93cf632337797d5a1f055fef1eb2310012.zip |
Add a static memcpy_helper() that optimizes copy using unsigned long when
both dest and src are long aligned or have the same offset from being long
aligned.
memcpy() and memmove() use the helper, memmove() will properly handle dest
and src overlapping.
Update comments to reflect the code changes.
Signed-off-by: Peter Stuge <peter@stuge.se>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>
git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@162 f3766cd6-281f-0410-b1cd-43a5c92072e9
Diffstat (limited to 'lib')
-rw-r--r-- | lib/mem.c | 85 |
1 files changed, 75 insertions, 10 deletions
diff --git a/lib/mem.c b/lib/mem.c index f182efd6566e..5228082a5b5b 100644 --- a/lib/mem.c +++ b/lib/mem.c @@ -2,6 +2,7 @@ * This file is part of the LinuxBIOS project. * * Copyright (C) 2007 Ronald G. Minnich <rminnich@gmail.com> + * Copyright (C) 2007 Peter Stuge <peter@stuge.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,27 +18,91 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA */ -/* Simple memory routines that have no optimizations for anything. */ +/* Memory routines with some optimizations. */ #include <arch/types.h> -/* this one is pretty stupid. Won't handle overlaps, it's not efficient, etc. */ +/** + * memcpy() and memmove() helper that uses unsigned long copying when dest and + * src are both unsigned long aligned, or offset by the same amount from being + * unsigned long aligned. + * + * Copies data one byte at a time until both dest and src are aligned to + * sizeof(unsigned long) or until no data is left. + * + * Copies data one unsigned long at a time until fewer than + * sizeof(unsigned long) bytes remain. + * + * Finally, or if dest and src have different alignment, copies any remaining + * data one byte at a time. + * + * @param dest Memory area to copy to. + * @param src Memory area to copy from. + * @param len Number of bytes to copy. + * @param backwards Start at the end, used by memmove() when dest > src. + */ +static void memcpy_helper(void *dest, const void *src, int len, int backwards) { + u8 *d = dest; + const u8 *s = src; + unsigned long *ld; + const unsigned long *ls; + u8 longmask = sizeof(unsigned long) - 1; + u8 longlen = sizeof(unsigned long); + + if (d == s || !len) + return; + + if (backwards) { + d += len; + s += len; + if (((unsigned long)d & longmask) == ((unsigned long)s & longmask)) { + while (((unsigned long)d & longmask || (unsigned long)s & longmask) && len) { + *--d = *--s; + len--; + } + ld = (unsigned long *)d; + ls = (const unsigned long *)s; + while (len >= longlen) { + *--ld = *--ls; + len -= longlen; + } + d = (u8 *)ld; + s = (const u8 *)ls; + } + while (len--) + *--d = *--s; + } else { + if (((unsigned long)d & longmask) == ((unsigned long)s & longmask)) { + while (((unsigned long)d & longmask || (unsigned long)s & longmask) && len) { + *d++ = *s++; + len--; + } + ld = (unsigned long *)d; + ls = (const unsigned long *)s; + while (len >= longlen) { + *ld++ = *ls++; + len -= longlen; + } + d = (u8 *)ld; + s = (const u8 *)ls; + } + while (len--) + *d++ = *s++; + } +} + +/* Won't handle overlaps. */ /* Please don't be silly and inline these. Inlines are not as wonderful as people think */ void memcpy(void *dest, const void *src, int len) { - unsigned char *d = dest; - const unsigned char *s = src; - while (len--) - *d++ = *s++; + memcpy_helper(dest, src, len, 0); } +/* Handles overlapping memory. */ /* seperate function in case we decide to use the built-in -- not sure yet. */ void memmove(void *dest, const void *src, int len) { - unsigned char *d = dest; - const unsigned char *s = src; - while (len--) - *d++ = *s++; + memcpy_helper(dest, src, len, dest > src && dest < (src + len)); } void memset(void *v, unsigned char a, int len) |