| From 230aef7a6a23b6166bd4003bfff5af23c9bd381f Mon Sep 17 00:00:00 2001 |
| From: Anton Blanchard <anton@samba.org> |
| Date: Wed, 7 Aug 2013 02:01:19 +1000 |
| Subject: powerpc: Handle unaligned ldbrx/stdbrx |
| |
| From: Anton Blanchard <anton@samba.org> |
| |
| 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> |
| |
| --- |
| arch/powerpc/kernel/align.c | 10 ++++++++++ |
| 1 file changed, 10 insertions(+) |
| |
| --- 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) { |