From 592201a9f154cdd5db59304d1369e94d8b551803 Mon Sep 17 00:00:00 2001
From: Jon Medhurst <tixy@yxit.co.uk>
Date: Sat, 26 Mar 2011 19:19:07 +0000
Subject: ARM: Thumb-2: Support Thumb-2 in undefined instruction handler

This patch allows undef_hook's to be specified for 32-bit Thumb
instructions and also to be used for thumb kernel-side code.

32-bit Thumb instructions are specified in the form:
	((first_half << 16 ) | second_half)
which matches the layout used by the ARM ARM.

ptrace was handling 32-bit Thumb instructions by hooking the first
halfword and manually checking the second half. This method would be
broken by this patch so it is migrated to make use of the new Thumb-2
support.

Signed-off-by: Jon Medhurst <tixy@yxit.co.uk>
Acked-by: Nicolas Pitre <nicolas.pitre@linaro.org>
---
 arch/arm/kernel/traps.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

(limited to 'arch/arm/kernel/traps.c')

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 6807cb1e76dd..2d3436e9f71f 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -355,9 +355,24 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 	pc = (void __user *)instruction_pointer(regs);
 
 	if (processor_mode(regs) == SVC_MODE) {
-		instr = *(u32 *) pc;
+#ifdef CONFIG_THUMB2_KERNEL
+		if (thumb_mode(regs)) {
+			instr = ((u16 *)pc)[0];
+			if (is_wide_instruction(instr)) {
+				instr <<= 16;
+				instr |= ((u16 *)pc)[1];
+			}
+		} else
+#endif
+			instr = *(u32 *) pc;
 	} else if (thumb_mode(regs)) {
 		get_user(instr, (u16 __user *)pc);
+		if (is_wide_instruction(instr)) {
+			unsigned int instr2;
+			get_user(instr2, (u16 __user *)pc+1);
+			instr <<= 16;
+			instr |= instr2;
+		}
 	} else {
 		get_user(instr, (u32 __user *)pc);
 	}
-- 
cgit v1.2.2