aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/align.c
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2013-08-06 12:01:19 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-08-13 21:50:20 -0400
commit230aef7a6a23b6166bd4003bfff5af23c9bd381f (patch)
treea7c3b41dc06504c87a7f952d2232a567b43fda5f /arch/powerpc/kernel/align.c
parent5b63fee1fe5d10c397d740ffef4d576a196ed72d (diff)
powerpc: Handle unaligned ldbrx/stdbrx
Normally when we haven't implemented an alignment handler for a load or store instruction the process will be terminated. The alignment handler uses the DSISR (or a pseudo one) to locate the right handler. Unfortunately ldbrx and stdbrx overlap lfs and stfs so we incorrectly think ldbrx is an lfs and stdbrx is an stfs. This bug is particularly nasty - instead of terminating the process we apply an incorrect fixup and continue on. With more and more overlapping instructions we should stop creating a pseudo DSISR and index using the instruction directly, but for now add a special case to catch ldbrx/stdbrx. Signed-off-by: Anton Blanchard <anton@samba.org> Cc: <stable@vger.kernel.org> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/align.c')
-rw-r--r--arch/powerpc/kernel/align.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index ee5b690a0bed..52e5758ea368 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -764,6 +764,16 @@ int fix_alignment(struct pt_regs *regs)
764 nb = aligninfo[instr].len; 764 nb = aligninfo[instr].len;
765 flags = aligninfo[instr].flags; 765 flags = aligninfo[instr].flags;
766 766
767 /* ldbrx/stdbrx overlap lfs/stfs in the DSISR unfortunately */
768 if (IS_XFORM(instruction) && ((instruction >> 1) & 0x3ff) == 532) {
769 nb = 8;
770 flags = LD+SW;
771 } else if (IS_XFORM(instruction) &&
772 ((instruction >> 1) & 0x3ff) == 660) {
773 nb = 8;
774 flags = ST+SW;
775 }
776
767 /* Byteswap little endian loads and stores */ 777 /* Byteswap little endian loads and stores */
768 swiz = 0; 778 swiz = 0;
769 if (regs->msr & MSR_LE) { 779 if (regs->msr & MSR_LE) {