aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAnton Blanchard <anton@samba.org>2013-08-07 02:01:19 +1000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-26 16:52:45 -0700
commit7b900d1daf22341794f5fd7a0ec1fe97966b8590 (patch)
treeb00322cb97ffe9c3633b5246964d43bfbb9859ae /arch
parent162c7c77893520b95698d6a7d146295aab1397c2 (diff)
downloadkernel_samsung_smdk4412-7b900d1daf22341794f5fd7a0ec1fe97966b8590.zip
kernel_samsung_smdk4412-7b900d1daf22341794f5fd7a0ec1fe97966b8590.tar.gz
kernel_samsung_smdk4412-7b900d1daf22341794f5fd7a0ec1fe97966b8590.tar.bz2
powerpc: Handle unaligned ldbrx/stdbrx
commit 230aef7a6a23b6166bd4003bfff5af23c9bd381f upstream. 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> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch')
-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 8184ee9..3fcbae0 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -764,6 +764,16 @@ int fix_alignment(struct pt_regs *regs)
nb = aligninfo[instr].len;
flags = aligninfo[instr].flags;
+ /* ldbrx/stdbrx overlap lfs/stfs in the DSISR unfortunately */
+ if (IS_XFORM(instruction) && ((instruction >> 1) & 0x3ff) == 532) {
+ nb = 8;
+ flags = LD+SW;
+ } else if (IS_XFORM(instruction) &&
+ ((instruction >> 1) & 0x3ff) == 660) {
+ nb = 8;
+ flags = ST+SW;
+ }
+
/* Byteswap little endian loads and stores */
swiz = 0;
if (regs->msr & MSR_LE) {