From patchwork Sat Jul 9 10:56:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tixy X-Patchwork-Id: 959332 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p69BDZxZ001385 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Sat, 9 Jul 2011 11:14:02 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QfVPA-00040V-GV; Sat, 09 Jul 2011 11:09:02 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QfVP7-0007Rz-Gj; Sat, 09 Jul 2011 11:08:57 +0000 Received: from smarthost01.mail.zen.net.uk ([212.23.3.140]) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QfVEP-0004Ka-2Y for linux-arm-kernel@lists.infradead.org; Sat, 09 Jul 2011 10:58:10 +0000 Received: from [82.69.122.217] (helo=plug1) by smarthost01.mail.zen.net.uk with esmtpsa (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.63) (envelope-from ) id 1QfVEL-0005Yu-9F for linux-arm-kernel@lists.infradead.org; Sat, 09 Jul 2011 10:57:49 +0000 Received: from [192.168.2.20] (helo=computer2) by plug1 with esmtp (Exim 4.72) (envelope-from ) id 1QfVEK-0003gO-Ov for linux-arm-kernel@lists.infradead.org; Sat, 09 Jul 2011 11:57:48 +0100 Received: from tixy by computer2 with local (Exim 4.72) (envelope-from ) id 1QfVEK-0005TB-Lp for linux-arm-kernel@lists.infradead.org; Sat, 09 Jul 2011 11:57:48 +0100 From: Tixy To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 02/51] ARM: Thumb-2: Support Thumb-2 in undefined instruction handler Date: Sat, 9 Jul 2011 11:56:49 +0100 Message-Id: <1310209058-20980-3-git-send-email-tixy@yxit.co.uk> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1310209058-20980-1-git-send-email-tixy@yxit.co.uk> References: <1310209058-20980-1-git-send-email-tixy@yxit.co.uk> X-Originating-Smarthost01-IP: [82.69.122.217] X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110709_065753_606762_B252F4CD X-CRM114-Status: GOOD ( 19.18 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.23.3.140 listed in list.dnswl.org] X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Sat, 09 Jul 2011 11:14:02 +0000 (UTC) From: Jon Medhurst 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 Acked-by: Nicolas Pitre --- arch/arm/include/asm/ptrace.h | 8 ++++++++ arch/arm/kernel/ptrace.c | 28 +++------------------------- arch/arm/kernel/traps.c | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 312d108..d484871 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -200,6 +200,14 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define PREDICATE_ALWAYS 0xe0000000 /* + * True if instr is a 32-bit thumb instruction. This works if instr + * is the first or only half-word of a thumb instruction. It also works + * when instr holds all 32-bits of a wide thumb instruction if stored + * in the form (first_half<<16)|(second_half) + */ +#define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800) + +/* * kprobe-based event tracer support */ #include diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 9726006..897ade0 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = { .fn = break_trap, }; -static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr) -{ - unsigned int instr2; - void __user *pc; - - /* Check the second half of the instruction. */ - pc = (void __user *)(instruction_pointer(regs) + 2); - - if (processor_mode(regs) == SVC_MODE) { - instr2 = *(u16 *) pc; - } else { - get_user(instr2, (u16 __user *)pc); - } - - if (instr2 == 0xa000) { - ptrace_break(current, regs); - return 0; - } else { - return 1; - } -} - static struct undef_hook thumb2_break_hook = { - .instr_mask = 0xffff, - .instr_val = 0xf7f0, + .instr_mask = 0xffffffff, + .instr_val = 0xf7f0a000, .cpsr_mask = PSR_T_BIT, .cpsr_val = PSR_T_BIT, - .fn = thumb2_break_trap, + .fn = break_trap, }; static int __init ptrace_break_init(void) diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6807cb1..2d3436e 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); }