aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Musta <tommusta@gmail.com>2013-10-18 13:07:10 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-10-30 01:01:17 -0400
commit075f6311af30b011eaa8e50341c06a9082a796a9 (patch)
treec555a6b3f274e1c2fa2107c69ccc12cb3f9f6ad5
parentdf015604cf5bb09f79c353926dd7e40d00d251a3 (diff)
powerpc: Fix Handler of Unaligned Load/Store Strings
The alignment handler is incorrect for unaligned string instructions in little endian mode. These instructions access data as arrays of bytes and thus are endian neutral. However, the routine also handles the load/store multiple instructions, which are NOT endian neutral. This patch toggles the byte swapping flag for the string instructions in little endian builds. This effectively disables the byte swapping logic. Signed-off-by: Tom Musta <tmusta@gmail.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/kernel/align.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 6e3f9772aaba..a3169a987b84 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -254,15 +254,20 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
254 * bottom 4 bytes of each register, and the loads clear the 254 * bottom 4 bytes of each register, and the loads clear the
255 * top 4 bytes of the affected register. 255 * top 4 bytes of the affected register.
256 */ 256 */
257#ifdef __BIG_ENDIAN__
257#ifdef CONFIG_PPC64 258#ifdef CONFIG_PPC64
258#define REG_BYTE(rp, i) *((u8 *)((rp) + ((i) >> 2)) + ((i) & 3) + 4) 259#define REG_BYTE(rp, i) *((u8 *)((rp) + ((i) >> 2)) + ((i) & 3) + 4)
259#else 260#else
260#define REG_BYTE(rp, i) *((u8 *)(rp) + (i)) 261#define REG_BYTE(rp, i) *((u8 *)(rp) + (i))
261#endif 262#endif
263#endif
264
265#ifdef __LITTLE_ENDIAN__
266#define REG_BYTE(rp, i) (*(((u8 *)((rp) + ((i)>>2)) + ((i)&3))))
267#endif
262 268
263#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz)) 269#define SWIZ_PTR(p) ((unsigned char __user *)((p) ^ swiz))
264 270
265#ifdef __BIG_ENDIAN__
266static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, 271static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
267 unsigned int reg, unsigned int nb, 272 unsigned int reg, unsigned int nb,
268 unsigned int flags, unsigned int instr, 273 unsigned int flags, unsigned int instr,
@@ -304,6 +309,15 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
304 nb0 = nb + reg * 4 - 128; 309 nb0 = nb + reg * 4 - 128;
305 nb = 128 - reg * 4; 310 nb = 128 - reg * 4;
306 } 311 }
312#ifdef __LITTLE_ENDIAN__
313 /*
314 * String instructions are endian neutral but the code
315 * below is not. Force byte swapping on so that the
316 * effects of swizzling are undone in the load/store
317 * loops below.
318 */
319 flags ^= SW;
320#endif
307 } else { 321 } else {
308 /* lwm, stmw */ 322 /* lwm, stmw */
309 nb = (32 - reg) * 4; 323 nb = (32 - reg) * 4;
@@ -364,6 +378,7 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
364 * Only POWER6 has these instructions, and it does true little-endian, 378 * Only POWER6 has these instructions, and it does true little-endian,
365 * so we don't need the address swizzling. 379 * so we don't need the address swizzling.
366 */ 380 */
381#ifdef __BIG_ENDIAN__
367static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, 382static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
368 unsigned int flags) 383 unsigned int flags)
369{ 384{
@@ -882,13 +897,9 @@ int fix_alignment(struct pt_regs *regs)
882 * function 897 * function
883 */ 898 */
884 if (flags & M) { 899 if (flags & M) {
885#ifdef __BIG_ENDIAN__
886 PPC_WARN_ALIGNMENT(multiple, regs); 900 PPC_WARN_ALIGNMENT(multiple, regs);
887 return emulate_multiple(regs, addr, reg, nb, 901 return emulate_multiple(regs, addr, reg, nb,
888 flags, instr, swiz); 902 flags, instr, swiz);
889#else
890 return -EFAULT;
891#endif
892 } 903 }
893 904
894 /* Verify the address of the operand */ 905 /* Verify the address of the operand */