coreboot/lib/mem.c
Peter Stuge 9d7f9f93cf 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
2007-03-01 01:09:45 +00:00

132 lines
3.6 KiB
C

/*
* 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
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA
*/
/* Memory routines with some optimizations. */
#include <arch/types.h>
/**
* 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)
{
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)
{
memcpy_helper(dest, src, len, dest > src && dest < (src + len));
}
void memset(void *v, unsigned char a, int len)
{
unsigned char *cp = v;
while(len--)
*cp++ = a;
}
/* did you ever notice that the memcmp web page does not specify
* a signed or unsigned compare? It matters ... oh well, we assumed unsigned
*/
int memcmp(const void *s1, const void *s2, int len)
{
const unsigned char *d = (const unsigned char *)s1;
const unsigned char *s = (const unsigned char *)s2;
while (len--){
if (*d < *s)
return -1;
if (*d > *s)
return 1;
d++, s++;
}
return 0;
}