diff options
author | Ben Dooks <ben.dooks@codethink.co.uk> | 2013-07-19 12:12:05 -0400 |
---|---|---|
committer | Ben Dooks <ben.dooks@codethink.co.uk> | 2013-10-19 15:46:34 -0400 |
commit | a79a0cb1d35ec422dcf493cef1bebf9fdfcfdb9a (patch) | |
tree | 4e3dfddc2f910e07c9847cf68a97eeb9fe646851 /arch/arm/kernel | |
parent | 8592edf0dec8159fde379eb7e056eaddbbd697f2 (diff) |
ARM: traps: use <asm/opcodes.h> to get correct instruction order
The trap handler needs to take into account the endian configuration of
the system when loading instructions. Use <asm/opcodes.h> to provide the
necessary conversion functions.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/traps.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 8fcda140358d..caf96da27360 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <asm/unwind.h> | 34 | #include <asm/unwind.h> |
35 | #include <asm/tls.h> | 35 | #include <asm/tls.h> |
36 | #include <asm/system_misc.h> | 36 | #include <asm/system_misc.h> |
37 | #include <asm/opcodes.h> | ||
37 | 38 | ||
38 | static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; | 39 | static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" }; |
39 | 40 | ||
@@ -402,25 +403,28 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) | |||
402 | if (processor_mode(regs) == SVC_MODE) { | 403 | if (processor_mode(regs) == SVC_MODE) { |
403 | #ifdef CONFIG_THUMB2_KERNEL | 404 | #ifdef CONFIG_THUMB2_KERNEL |
404 | if (thumb_mode(regs)) { | 405 | if (thumb_mode(regs)) { |
405 | instr = ((u16 *)pc)[0]; | 406 | instr = __mem_to_opcode_thumb16(((u16 *)pc)[0]); |
406 | if (is_wide_instruction(instr)) { | 407 | if (is_wide_instruction(instr)) { |
407 | instr <<= 16; | 408 | u16 inst2; |
408 | instr |= ((u16 *)pc)[1]; | 409 | inst2 = __mem_to_opcode_thumb16(((u16 *)pc)[1]); |
410 | instr = __opcode_thumb32_compose(instr, inst2); | ||
409 | } | 411 | } |
410 | } else | 412 | } else |
411 | #endif | 413 | #endif |
412 | instr = *(u32 *) pc; | 414 | instr = __mem_to_opcode_arm(*(u32 *) pc); |
413 | } else if (thumb_mode(regs)) { | 415 | } else if (thumb_mode(regs)) { |
414 | if (get_user(instr, (u16 __user *)pc)) | 416 | if (get_user(instr, (u16 __user *)pc)) |
415 | goto die_sig; | 417 | goto die_sig; |
418 | instr = __mem_to_opcode_thumb16(instr); | ||
416 | if (is_wide_instruction(instr)) { | 419 | if (is_wide_instruction(instr)) { |
417 | unsigned int instr2; | 420 | unsigned int instr2; |
418 | if (get_user(instr2, (u16 __user *)pc+1)) | 421 | if (get_user(instr2, (u16 __user *)pc+1)) |
419 | goto die_sig; | 422 | goto die_sig; |
420 | instr <<= 16; | 423 | instr2 = __mem_to_opcode_thumb16(instr2); |
421 | instr |= instr2; | 424 | instr = __opcode_thumb32_compose(instr, instr2); |
422 | } | 425 | } |
423 | } else if (get_user(instr, (u32 __user *)pc)) { | 426 | } else if (get_user(instr, (u32 __user *)pc)) { |
427 | instr = __mem_to_opcode_arm(instr); | ||
424 | goto die_sig; | 428 | goto die_sig; |
425 | } | 429 | } |
426 | 430 | ||