Commit 6506b471 authored by Tom Musta's avatar Tom Musta Committed by Benjamin Herrenschmidt

powerpc: Fix Unaligned Loads and Stores

This patch modifies the unaligned access routines of the sstep.c
module so that it properly reverses the bytes of storage operands
in the little endian kernel kernel.   This is implemented by
breaking an unaligned little endian access into a combination of
single byte accesses plus an overal byte reversal operation.
Signed-off-by: default avatarTom Musta <tmusta@gmail.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 630c8a5f
...@@ -212,11 +212,19 @@ static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea, ...@@ -212,11 +212,19 @@ static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea,
{ {
int err; int err;
unsigned long x, b, c; unsigned long x, b, c;
#ifdef __LITTLE_ENDIAN__
int len = nb; /* save a copy of the length for byte reversal */
#endif
/* unaligned, do this in pieces */ /* unaligned, do this in pieces */
x = 0; x = 0;
for (; nb > 0; nb -= c) { for (; nb > 0; nb -= c) {
#ifdef __LITTLE_ENDIAN__
c = 1;
#endif
#ifdef __BIG_ENDIAN__
c = max_align(ea); c = max_align(ea);
#endif
if (c > nb) if (c > nb)
c = max_align(nb); c = max_align(nb);
err = read_mem_aligned(&b, ea, c); err = read_mem_aligned(&b, ea, c);
...@@ -225,7 +233,24 @@ static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea, ...@@ -225,7 +233,24 @@ static int __kprobes read_mem_unaligned(unsigned long *dest, unsigned long ea,
x = (x << (8 * c)) + b; x = (x << (8 * c)) + b;
ea += c; ea += c;
} }
#ifdef __LITTLE_ENDIAN__
switch (len) {
case 2:
*dest = byterev_2(x);
break;
case 4:
*dest = byterev_4(x);
break;
#ifdef __powerpc64__
case 8:
*dest = byterev_8(x);
break;
#endif
}
#endif
#ifdef __BIG_ENDIAN__
*dest = x; *dest = x;
#endif
return 0; return 0;
} }
...@@ -273,9 +298,29 @@ static int __kprobes write_mem_unaligned(unsigned long val, unsigned long ea, ...@@ -273,9 +298,29 @@ static int __kprobes write_mem_unaligned(unsigned long val, unsigned long ea,
int err; int err;
unsigned long c; unsigned long c;
#ifdef __LITTLE_ENDIAN__
switch (nb) {
case 2:
val = byterev_2(val);
break;
case 4:
val = byterev_4(val);
break;
#ifdef __powerpc64__
case 8:
val = byterev_8(val);
break;
#endif
}
#endif
/* unaligned or little-endian, do this in pieces */ /* unaligned or little-endian, do this in pieces */
for (; nb > 0; nb -= c) { for (; nb > 0; nb -= c) {
#ifdef __LITTLE_ENDIAN__
c = 1;
#endif
#ifdef __BIG_ENDIAN__
c = max_align(ea); c = max_align(ea);
#endif
if (c > nb) if (c > nb)
c = max_align(nb); c = max_align(nb);
err = write_mem_aligned(val >> (nb - c) * 8, ea, c); err = write_mem_aligned(val >> (nb - c) * 8, ea, c);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment