ARM: alignment: correctly decode instructions in BE8 mode.
authorBen Dooks <ben.dooks@codethink.co.uk>
Thu, 18 Jul 2013 20:10:56 +0000 (21:10 +0100)
committerBen Dooks <ben.dooks@codethink.co.uk>
Sat, 19 Oct 2013 19:46:34 +0000 (20:46 +0100)
If we are in BE8 mode, we must deal with the instruction stream being
in LE order when data is being loaded in BE order. Ensure the data is
swapped before processing to avoid thre following:

Change to using <asm/opcodes.h> to provide the necessary conversion
functions to change the byte ordering.

This stops the following warning messages from the kernel on a fault:

Unhandled fault: alignment exception (0x001) at 0xbfa09567
Alignment trap: not handling instruction 030091e8 at [<80333e8c>]

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
Reviewed-by: Dave Martin <Dave.Martin@arm.com>
Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
arch/arm/mm/alignment.c

index 6f4585b89078749e39383d1aee50f51040624a74..924036473b16f437019002b8afac36a2a41e4010 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/cp15.h>
 #include <asm/system_info.h>
 #include <asm/unaligned.h>
+#include <asm/opcodes.h>
 
 #include "fault.h"
 
@@ -762,21 +763,25 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (thumb_mode(regs)) {
                u16 *ptr = (u16 *)(instrptr & ~1);
                fault = probe_kernel_address(ptr, tinstr);
+               tinstr = __mem_to_opcode_thumb16(tinstr);
                if (!fault) {
                        if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
                            IS_T32(tinstr)) {
                                /* Thumb-2 32-bit */
                                u16 tinst2 = 0;
                                fault = probe_kernel_address(ptr + 1, tinst2);
-                               instr = (tinstr << 16) | tinst2;
+                               tinst2 = __mem_to_opcode_thumb16(tinst2);
+                               instr = __opcode_thumb32_compose(tinstr, tinst2);
                                thumb2_32b = 1;
                        } else {
                                isize = 2;
                                instr = thumb2arm(tinstr);
                        }
                }
-       } else
+       } else {
                fault = probe_kernel_address(instrptr, instr);
+               instr = __mem_to_opcode_arm(instr);
+       }
 
        if (fault) {
                type = TYPE_FAULT;