mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-19 19:50:58 -04:00
68000 has different alignment needs to 68020+. memcpy() checks if the destination is aligned and does a smaller copy to fix the alignment and then critically for 68000 it checks if the source is still unaligned and if it is reverts to smaller copies. memmove() does not currently do the second part and malfunctions if one of the pointers is aligned and the other isn't. This is apparently getting triggered by printk. If I put breakpoints into the new checks added by this commit the first hit looks like this: memmove (n=205, src=0x2f3971 <printk_shared_pbufs+205>, dest=0x2f3980 <printk_shared_pbufs+220>) at arch/m68k/lib/memmove.c:82 Signed-off-by: Daniel Palmer <daniel@thingy.jp> Signed-off-by: Greg Ungerer <gerg@kernel.org>
122 lines
2.1 KiB
C
122 lines
2.1 KiB
C
/*
|
|
* This file is subject to the terms and conditions of the GNU General Public
|
|
* License. See the file COPYING in the main directory of this archive
|
|
* for more details.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/string.h>
|
|
|
|
void *memmove(void *dest, const void *src, size_t n)
|
|
{
|
|
void *xdest = dest;
|
|
size_t temp;
|
|
|
|
if (!n)
|
|
return xdest;
|
|
|
|
if (dest < src) {
|
|
if ((long)dest & 1) {
|
|
char *cdest = dest;
|
|
const char *csrc = src;
|
|
*cdest++ = *csrc++;
|
|
dest = cdest;
|
|
src = csrc;
|
|
n--;
|
|
}
|
|
#if defined(CONFIG_M68000)
|
|
if ((long)src & 1) {
|
|
char *cdest = dest;
|
|
const char *csrc = src;
|
|
for (; n; n--)
|
|
*cdest++ = *csrc++;
|
|
return xdest;
|
|
}
|
|
#endif
|
|
if (n > 2 && (long)dest & 2) {
|
|
short *sdest = dest;
|
|
const short *ssrc = src;
|
|
*sdest++ = *ssrc++;
|
|
dest = sdest;
|
|
src = ssrc;
|
|
n -= 2;
|
|
}
|
|
temp = n >> 2;
|
|
if (temp) {
|
|
long *ldest = dest;
|
|
const long *lsrc = src;
|
|
temp--;
|
|
do
|
|
*ldest++ = *lsrc++;
|
|
while (temp--);
|
|
dest = ldest;
|
|
src = lsrc;
|
|
}
|
|
if (n & 2) {
|
|
short *sdest = dest;
|
|
const short *ssrc = src;
|
|
*sdest++ = *ssrc++;
|
|
dest = sdest;
|
|
src = ssrc;
|
|
}
|
|
if (n & 1) {
|
|
char *cdest = dest;
|
|
const char *csrc = src;
|
|
*cdest = *csrc;
|
|
}
|
|
} else {
|
|
dest = (char *)dest + n;
|
|
src = (const char *)src + n;
|
|
if ((long)dest & 1) {
|
|
char *cdest = dest;
|
|
const char *csrc = src;
|
|
*--cdest = *--csrc;
|
|
dest = cdest;
|
|
src = csrc;
|
|
n--;
|
|
}
|
|
#if defined(CONFIG_M68000)
|
|
if ((long)src & 1) {
|
|
char *cdest = dest;
|
|
const char *csrc = src;
|
|
for (; n; n--)
|
|
*--cdest = *--csrc;
|
|
return xdest;
|
|
}
|
|
#endif
|
|
if (n > 2 && (long)dest & 2) {
|
|
short *sdest = dest;
|
|
const short *ssrc = src;
|
|
*--sdest = *--ssrc;
|
|
dest = sdest;
|
|
src = ssrc;
|
|
n -= 2;
|
|
}
|
|
temp = n >> 2;
|
|
if (temp) {
|
|
long *ldest = dest;
|
|
const long *lsrc = src;
|
|
temp--;
|
|
do
|
|
*--ldest = *--lsrc;
|
|
while (temp--);
|
|
dest = ldest;
|
|
src = lsrc;
|
|
}
|
|
if (n & 2) {
|
|
short *sdest = dest;
|
|
const short *ssrc = src;
|
|
*--sdest = *--ssrc;
|
|
dest = sdest;
|
|
src = ssrc;
|
|
}
|
|
if (n & 1) {
|
|
char *cdest = dest;
|
|
const char *csrc = src;
|
|
*--cdest = *--csrc;
|
|
}
|
|
}
|
|
return xdest;
|
|
}
|
|
EXPORT_SYMBOL(memmove);
|