summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Dooks <ben.dooks@codethink.co.uk>2013-07-18 21:10:56 +0100
committerBen Dooks <ben.dooks@codethink.co.uk>2013-09-03 17:36:44 +0100
commitf28733c12df6b6b4d89ef72fdbfd84797ca9ad60 (patch)
tree338bc57de3f3194a2e415d9e0b73b1ad9badbd8a
parent5b32b6b041461c5234ca8a176b10b0a138ebcb59 (diff)
downloadlinux-f28733c12df6b6b4d89ef72fdbfd84797ca9ad60.tar.gz
ARM: alignment: correctly decode instructions in BE8 mode.
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>
-rw-r--r--arch/arm/mm/alignment.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index 6f4585b89078..924036473b16 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -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;