libpayload: Support unaligned pointer for memcpy, memmove and memcmp

The memcpy(), memmove() and memcmp() functions use word by word
operations regardless of the pointer alignment.  Depending on the
platform, this could lead to a crash.

This patch makes the memcpy(), memmove() or memcmp() operate byte per
byte if they are supplied with unaligned pointers.

Change-Id: I0b668739b7b58d47266f10f2dff2dc9cbf38577e
Signed-off-by: Jeremy Compostella <jeremy.compostella@intel.com>
Reviewed-on: https://review.coreboot.org/20535
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Nico Huber <nico.h@gmx.de>
Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
Jeremy Compostella 2017-07-11 14:08:37 -07:00 committed by Julius Werner
parent 4dc9fb026c
commit 5b8987ae46
1 changed files with 23 additions and 9 deletions

View File

@ -66,13 +66,17 @@ static void *default_memcpy(void *dst, const void *src, size_t n)
size_t i;
void *ret = dst;
for(i = 0; i < n / sizeof(unsigned long); i++)
if (IS_ALIGNED((uintptr_t)dst, sizeof(unsigned long)) &&
IS_ALIGNED((uintptr_t)src, sizeof(unsigned long))) {
for (i = 0; i < n / sizeof(unsigned long); i++)
((unsigned long *)dst)[i] = ((unsigned long *)src)[i];
src += i * sizeof(unsigned long);
dst += i * sizeof(unsigned long);
n -= i * sizeof(unsigned long);
}
for(i = 0; i < n % sizeof(unsigned long); i++)
for (i = 0; i < n; i++)
((u8 *)dst)[i] = ((u8 *)src)[i];
return ret;
@ -89,6 +93,13 @@ static void *default_memmove(void *dst, const void *src, size_t n)
if (src > dst)
return memcpy(dst, src, n);
if (!IS_ALIGNED((uintptr_t)dst, sizeof(unsigned long)) ||
!IS_ALIGNED((uintptr_t)src, sizeof(unsigned long))) {
for (i = n - 1; i >= 0; i--)
((u8 *)dst)[i] = ((u8 *)src)[i];
return dst;
}
offs = n - (n % sizeof(unsigned long));
for (i = (n % sizeof(unsigned long)) - 1; i >= 0; i--)
@ -116,10 +127,13 @@ void *memmove(void *dst, const void *src, size_t n)
static int default_memcmp(const void *s1, const void *s2, size_t n)
{
size_t i;
size_t i = 0;
const unsigned long *w1 = s1, *w2 = s2;
for (i = 0; i < n / sizeof(unsigned long); i++)
if (((unsigned long *)s1)[i] != ((unsigned long *)s2)[i])
if (IS_ALIGNED((uintptr_t)s1, sizeof(unsigned long)) &&
IS_ALIGNED((uintptr_t)s2, sizeof(unsigned long)))
for (; i < n / sizeof(unsigned long); i++)
if (w1[i] != w2[i])
break; /* fall through to find differing byte */
for (i *= sizeof(unsigned long); i < n; i++)