mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ben Hutchings <ben@decadent.org.uk>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: torvalds@linux-foundation.org, akpm@linux-foundation.org,
	alan@lxorguk.ukuu.org.uk,
	Russell King <rmk+kernel@arm.linux.org.uk>,
	Will Deacon <will.deacon@arm.com>
Subject: [ 51/70] ARM: Fix undefined instruction exception handling
Date: Tue, 07 Aug 2012 04:28:46 +0100	[thread overview]
Message-ID: <20120807032803.487273580@decadent.org.uk> (raw)
In-Reply-To: <20120807032755.803571133@decadent.org.uk>

3.2-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Russell King <rmk+kernel@arm.linux.org.uk>

commit 15ac49b65024f55c4371a53214879a9c77c4fbf9 upstream.

While trying to get a v3.5 kernel booted on the cubox, I noticed that
VFP does not work correctly with VFP bounce handling.  This is because
of the confusion over 16-bit vs 32-bit instructions, and where PC is
supposed to point to.

The rule is that FP handlers are entered with regs->ARM_pc pointing at
the _next_ instruction to be executed.  However, if the exception is
not handled, regs->ARM_pc points at the faulting instruction.

This is easy for ARM mode, because we know that the next instruction and
previous instructions are separated by four bytes.  This is not true of
Thumb2 though.

Since all FP instructions are 32-bit in Thumb2, it makes things easy.
We just need to select the appropriate adjustment.  Do this by moving
the adjustment out of do_undefinstr() into the assembly code, as only
the assembly code knows whether it's dealing with a 32-bit or 16-bit
instruction.

Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
 arch/arm/kernel/entry-armv.S |  111 +++++++++++++++++++++++++++---------------
 arch/arm/kernel/traps.c      |    8 ---
 arch/arm/vfp/entry.S         |   16 +++---
 arch/arm/vfp/vfphw.S         |   19 +++++---
 4 files changed, 92 insertions(+), 62 deletions(-)

--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -242,6 +242,19 @@ svc_preempt:
 	b	1b
 #endif
 
+__und_fault:
+	@ Correct the PC such that it is pointing at the instruction
+	@ which caused the fault.  If the faulting instruction was ARM
+	@ the PC will be pointing at the next instruction, and have to
+	@ subtract 4.  Otherwise, it is Thumb, and the PC will be
+	@ pointing at the second half of the Thumb instruction.  We
+	@ have to subtract 2.
+	ldr	r2, [r0, #S_PC]
+	sub	r2, r2, r1
+	str	r2, [r0, #S_PC]
+	b	do_undefinstr
+ENDPROC(__und_fault)
+
 	.align	5
 __und_svc:
 #ifdef CONFIG_KPROBES
@@ -259,25 +272,32 @@ __und_svc:
 	@
 	@  r0 - instruction
 	@
-#ifndef	CONFIG_THUMB2_KERNEL
+#ifndef CONFIG_THUMB2_KERNEL
 	ldr	r0, [r4, #-4]
 #else
+	mov	r1, #2
 	ldrh	r0, [r4, #-2]			@ Thumb instruction at LR - 2
 	cmp	r0, #0xe800			@ 32-bit instruction if xx >= 0
-	ldrhhs	r9, [r4]			@ bottom 16 bits
-	orrhs	r0, r9, r0, lsl #16
+	blo	__und_svc_fault
+	ldrh	r9, [r4]			@ bottom 16 bits
+	add	r4, r4, #2
+	str	r4, [sp, #S_PC]
+	orr	r0, r9, r0, lsl #16
 #endif
-	adr	r9, BSYM(1f)
+	adr	r9, BSYM(__und_svc_finish)
 	mov	r2, r4
 	bl	call_fpe
 
+	mov	r1, #4				@ PC correction to apply
+__und_svc_fault:
 	mov	r0, sp				@ struct pt_regs *regs
-	bl	do_undefinstr
+	bl	__und_fault
 
 	@
 	@ IRQs off again before pulling preserved data off the stack
 	@
-1:	disable_irq_notrace
+__und_svc_finish:
+	disable_irq_notrace
 
 	@
 	@ restore SPSR and restart the instruction
@@ -421,25 +441,33 @@ __und_usr:
 	mov	r2, r4
 	mov	r3, r5
 
+	@ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the
+	@      faulting instruction depending on Thumb mode.
+	@ r3 = regs->ARM_cpsr
 	@
-	@ fall through to the emulation code, which returns using r9 if
-	@ it has emulated the instruction, or the more conventional lr
-	@ if we are to treat this as a real undefined instruction
-	@
-	@  r0 - instruction
+	@ The emulation code returns using r9 if it has emulated the
+	@ instruction, or the more conventional lr if we are to treat
+	@ this as a real undefined instruction
 	@
 	adr	r9, BSYM(ret_from_exception)
-	adr	lr, BSYM(__und_usr_unknown)
+
 	tst	r3, #PSR_T_BIT			@ Thumb mode?
-	itet	eq				@ explicit IT needed for the 1f label
-	subeq	r4, r2, #4			@ ARM instr at LR - 4
-	subne	r4, r2, #2			@ Thumb instr at LR - 2
-1:	ldreqt	r0, [r4]
+	bne	__und_usr_thumb
+	sub	r4, r2, #4			@ ARM instr at LR - 4
+1:	ldrt	r0, [r4]
 #ifdef CONFIG_CPU_ENDIAN_BE8
-	reveq	r0, r0				@ little endian instruction
+	rev	r0, r0				@ little endian instruction
 #endif
-	beq	call_fpe
+	@ r0 = 32-bit ARM instruction which caused the exception
+	@ r2 = PC value for the following instruction (:= regs->ARM_pc)
+	@ r4 = PC value for the faulting instruction
+	@ lr = 32-bit undefined instruction function
+	adr	lr, BSYM(__und_usr_fault_32)
+	b	call_fpe
+
+__und_usr_thumb:
 	@ Thumb instruction
+	sub	r4, r2, #2			@ First half of thumb instr at LR - 2
 #if CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7
 /*
  * Thumb-2 instruction handling.  Note that because pre-v6 and >= v6 platforms
@@ -453,7 +481,7 @@ __und_usr:
 	ldr	r5, .LCcpu_architecture
 	ldr	r5, [r5]
 	cmp	r5, #CPU_ARCH_ARMv7
-	blo	__und_usr_unknown
+	blo	__und_usr_fault_16		@ 16bit undefined instruction
 /*
  * The following code won't get run unless the running CPU really is v7, so
  * coding round the lack of ldrht on older arches is pointless.  Temporarily
@@ -461,15 +489,18 @@ __und_usr:
  */
 	.arch	armv6t2
 #endif
-2:
- ARM(	ldrht	r5, [r4], #2	)
- THUMB(	ldrht	r5, [r4]	)
- THUMB(	add	r4, r4, #2	)
+2:	ldrht	r5, [r4]
 	cmp	r5, #0xe800			@ 32bit instruction if xx != 0
-	blo	__und_usr_unknown
-3:	ldrht	r0, [r4]
+	blo	__und_usr_fault_16		@ 16bit undefined instruction
+3:	ldrht	r0, [r2]
 	add	r2, r2, #2			@ r2 is PC + 2, make it PC + 4
+	str	r2, [sp, #S_PC]			@ it's a 2x16bit instr, update
 	orr	r0, r0, r5, lsl #16
+	adr	lr, BSYM(__und_usr_fault_32)
+	@ r0 = the two 16-bit Thumb instructions which caused the exception
+	@ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
+	@ r4 = PC value for the first 16-bit Thumb instruction
+	@ lr = 32bit undefined instruction function
 
 #if __LINUX_ARM_ARCH__ < 7
 /* If the target arch was overridden, change it back: */
@@ -480,17 +511,13 @@ __und_usr:
 #endif
 #endif /* __LINUX_ARM_ARCH__ < 7 */
 #else /* !(CONFIG_ARM_THUMB && __LINUX_ARM_ARCH__ >= 6 && CONFIG_CPU_V7) */
-	b	__und_usr_unknown
+	b	__und_usr_fault_16
 #endif
- UNWIND(.fnend		)
+ UNWIND(.fnend)
 ENDPROC(__und_usr)
 
-	@
-	@ fallthrough to call_fpe
-	@
-
 /*
- * The out of line fixup for the ldrt above.
+ * The out of line fixup for the ldrt instructions above.
  */
 	.pushsection .fixup, "ax"
 4:	mov	pc, r9
@@ -521,11 +548,12 @@ ENDPROC(__und_usr)
  * NEON handler code.
  *
  * Emulators may wish to make use of the following registers:
- *  r0  = instruction opcode.
- *  r2  = PC+4
+ *  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
+ *  r2  = PC value to resume execution after successful emulation
  *  r9  = normal "successful" return address
- *  r10 = this threads thread_info structure.
+ *  r10 = this threads thread_info structure
  *  lr  = unrecognised instruction return address
+ * IRQs disabled, FIQs enabled.
  */
 	@
 	@ Fall-through from Thumb-2 __und_usr
@@ -660,12 +688,17 @@ ENTRY(no_fp)
 	mov	pc, lr
 ENDPROC(no_fp)
 
-__und_usr_unknown:
-	enable_irq
+__und_usr_fault_32:
+	mov	r1, #4
+	b	1f
+__und_usr_fault_16:
+	mov	r1, #2
+1:	enable_irq
 	mov	r0, sp
 	adr	lr, BSYM(ret_from_exception)
-	b	do_undefinstr
-ENDPROC(__und_usr_unknown)
+	b	__und_fault
+ENDPROC(__und_usr_fault_32)
+ENDPROC(__und_usr_fault_16)
 
 	.align	5
 __pabt_usr:
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -362,18 +362,10 @@ static int call_undef_hook(struct pt_reg
 
 asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
 {
-	unsigned int correction = thumb_mode(regs) ? 2 : 4;
 	unsigned int instr;
 	siginfo_t info;
 	void __user *pc;
 
-	/*
-	 * According to the ARM ARM, PC is 2 or 4 bytes ahead,
-	 * depending whether we're in Thumb mode or not.
-	 * Correct this offset.
-	 */
-	regs->ARM_pc -= correction;
-
 	pc = (void __user *)instruction_pointer(regs);
 
 	if (processor_mode(regs) == SVC_MODE) {
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -7,18 +7,20 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- *
- * Basic entry code, called from the kernel's undefined instruction trap.
- *  r0  = faulted instruction
- *  r5  = faulted PC+4
- *  r9  = successful return
- *  r10 = thread_info structure
- *  lr  = failure return
  */
 #include <asm/thread_info.h>
 #include <asm/vfpmacros.h>
 #include "../kernel/entry-header.S"
 
+@ VFP entry point.
+@
+@  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
+@  r2  = PC value to resume execution after successful emulation
+@  r9  = normal "successful" return address
+@  r10 = this threads thread_info structure
+@  lr  = unrecognised instruction return address
+@  IRQs disabled.
+@
 ENTRY(do_vfp)
 #ifdef CONFIG_PREEMPT
 	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -61,13 +61,13 @@
 
 @ VFP hardware support entry point.
 @
-@  r0  = faulted instruction
-@  r2  = faulted PC+4
-@  r9  = successful return
+@  r0  = instruction opcode (32-bit ARM or two 16-bit Thumb)
+@  r2  = PC value to resume execution after successful emulation
+@  r9  = normal "successful" return address
 @  r10 = vfp_state union
 @  r11 = CPU number
-@  lr  = failure return
-
+@  lr  = unrecognised instruction return address
+@  IRQs enabled.
 ENTRY(vfp_support_entry)
 	DBGSTR3	"instr %08x pc %08x state %p", r0, r2, r10
 
@@ -161,9 +161,12 @@ vfp_hw_state_valid:
 					@ exception before retrying branch
 					@ out before setting an FPEXC that
 					@ stops us reading stuff
-	VFPFMXR	FPEXC, r1		@ restore FPEXC last
-	sub	r2, r2, #4
-	str	r2, [sp, #S_PC]		@ retry the instruction
+	VFPFMXR	FPEXC, r1		@ Restore FPEXC last
+	sub	r2, r2, #4		@ Retry current instruction - if Thumb
+	str	r2, [sp, #S_PC]		@ mode it's two 16-bit instructions,
+					@ else it's one 32-bit instruction, so
+					@ always subtract 4 from the following
+					@ instruction address.
 #ifdef CONFIG_PREEMPT
 	get_thread_info	r10
 	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count



  parent reply	other threads:[~2012-08-07  3:48 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-07  3:27 [ 00/70] 3.2.27-stable review Ben Hutchings
2012-08-07  3:27 ` [ 01/70] sched: Fix race in task_group() Ben Hutchings
2012-08-07  3:27 ` [ 02/70] floppy: Cleanup disk->queue before caling put_disk() if add_disk() was never called Ben Hutchings
2012-08-07 22:49   ` Herton Ronaldo Krzesinski
2012-08-08  0:40     ` Ben Hutchings
2012-08-08 13:02       ` Herton Ronaldo Krzesinski
2012-08-07  3:27 ` [ 03/70] xen: mark local pages as FOREIGN in the m2p_override Ben Hutchings
2012-08-07  3:27 ` [ 04/70] [media] lirc_sir: make device registration work Ben Hutchings
2012-08-07  3:28 ` [ 05/70] stable: update references to older 2.6 versions for 3.x Ben Hutchings
2012-08-07  3:28 ` [ 06/70] ALSA: hda - add dock support for Thinkpad X230 Tablet Ben Hutchings
2012-08-07  3:28 ` [ 07/70] cfg80211: fix interface combinations check for ADHOC(IBSS) Ben Hutchings
2012-08-07  3:28 ` [ 08/70] m68k: Correct the Atari ALLOWINT definition Ben Hutchings
2012-08-07  3:28 ` [ 09/70] [media] ene_ir: Fix driver initialisation Ben Hutchings
2012-08-07  3:28 ` [ 10/70] nfsd4: our filesystems are normally case sensitive Ben Hutchings
2012-08-07  3:28 ` [ 11/70] random: Use arch_get_random_int instead of cycle counter if avail Ben Hutchings
2012-08-07  3:28 ` [ 12/70] random: Use arch-specific RNG to initialize the entropy store Ben Hutchings
2012-08-07  3:28 ` [ 13/70] random: Adjust the number of loops when initializing Ben Hutchings
2012-08-07  3:28 ` [ 14/70] random: make add_interrupt_randomness() do something sane Ben Hutchings
2012-08-07  3:28 ` [ 15/70] random: use lockless techniques in the interrupt path Ben Hutchings
2012-08-07  3:28 ` [ 16/70] random: create add_device_randomness() interface Ben Hutchings
2012-08-07  3:28 ` [ 17/70] usb: feed USB device information to the /dev/random driver Ben Hutchings
2012-08-07  3:28 ` [ 18/70] net: feed /dev/random with the MAC address when registering a device Ben Hutchings
2012-08-07  3:28 ` [ 19/70] random: use the arch-specific rng in xfer_secondary_pool Ben Hutchings
2012-08-07  3:28 ` [ 20/70] random: add new get_random_bytes_arch() function Ben Hutchings
2012-08-07  3:28 ` [ 21/70] rtc: wm831x: Feed the write counter into device_add_randomness() Ben Hutchings
2012-08-07  3:28 ` [ 22/70] mfd: wm831x: Feed the device UUID " Ben Hutchings
2012-08-07  3:28 ` [ 23/70] ASoC: wm8994: Ensure there are enough BCLKs for four channels Ben Hutchings
2012-08-07  3:28 ` [ 24/70] futex: Test for pi_mutex on fault in futex_wait_requeue_pi() Ben Hutchings
2012-08-07  3:28 ` [ 25/70] futex: Fix bug in WARN_ON for NULL q.pi_state Ben Hutchings
2012-08-07  3:28 ` [ 26/70] futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi() Ben Hutchings
2012-08-07  3:28 ` [ 27/70] video/smscufx: fix line counting in fb_write Ben Hutchings
2012-08-07  3:28 ` [ 28/70] Input: synaptics - handle out of bounds values from the hardware Ben Hutchings
2012-08-07  3:28 ` [ 29/70] ALSA: hda - Fix invalid D3 of headphone DAC on VT202x codecs Ben Hutchings
2012-08-07  3:28 ` [ 30/70] ALSA: mpu401: Fix missing initialization of irq field Ben Hutchings
2012-08-07  3:28 ` [ 31/70] x86, nops: Missing break resulting in incorrect selection on Intel Ben Hutchings
2012-08-07  3:28 ` [ 32/70] s390/mm: downgrade page table after fork of a 31 bit process Ben Hutchings
2012-08-07  3:28 ` [ 33/70] [IA64] Redefine ATOMIC_INIT and ATOMIC64_INIT to drop the casts Ben Hutchings
2012-08-07  3:28 ` [ 34/70] dm thin: reduce endio_hook pool size Ben Hutchings
2012-08-07  3:28 ` [ 35/70] dm thin: fix memory leak in process_prepared_mapping error paths Ben Hutchings
2012-08-07  3:28 ` [ 36/70] random: mix in architectural randomness in extract_buf() Ben Hutchings
2012-08-07  3:28 ` [ 37/70] asus-wmi: use ASUS_WMI_METHODID_DSTS2 as default DSTS ID Ben Hutchings
2012-08-07  3:28 ` [ 38/70] virtio-blk: Use block layer provided spinlock Ben Hutchings
2012-08-07  3:28 ` [ 39/70] s390/mm: fix fault handling for page table walk case Ben Hutchings
2012-08-07  3:28 ` [ 40/70] nfs: skip commit in releasepage if were freeing memory for fs-related reasons Ben Hutchings
2012-08-07  3:28 ` [ 41/70] md/raid1: dont abort a resync on the first badblock Ben Hutchings
2012-08-07  3:28 ` [ 42/70] pcdp: use early_ioremap/early_iounmap to access pcdp table Ben Hutchings
2012-08-07  3:28 ` [ 43/70] lib/vsprintf.c: kptr_restrict: fix pK-error in SysRq show-all-timers(Q) Ben Hutchings
2012-08-07  3:28 ` [ 44/70] nilfs2: fix deadlock issue between chcp and thaw ioctls Ben Hutchings
2012-08-07  3:28 ` [ 45/70] SUNRPC: return negative value in case rpcbind client creation error Ben Hutchings
2012-08-07  3:28 ` [ 46/70] ARM: 7466/1: disable interrupt before spinning endlessly Ben Hutchings
2012-08-07  3:28 ` [ 47/70] ARM: 7467/1: mutex: use generic xchg-based implementation for ARMv6+ Ben Hutchings
2012-08-07  3:28 ` [ 48/70] ARM: 7476/1: vfp: only clear vfp state for current cpu in vfp_pm_suspend Ben Hutchings
2012-08-07  3:28 ` [ 49/70] ARM: 7477/1: vfp: Always save VFP state in vfp_pm_suspend on UP Ben Hutchings
2012-08-07  3:28 ` [ 50/70] ARM: 7478/1: errata: extend workaround for erratum #720789 Ben Hutchings
2012-08-07  3:28 ` Ben Hutchings [this message]
2012-08-07  3:28 ` [ 52/70] USB: echi-dbgp: increase the controller wait time to come out of halt Ben Hutchings
2012-08-07  3:28 ` [ 53/70] ASoC: wm8962: Allow VMID time to fully ramp Ben Hutchings
2012-08-07  3:28 ` [ 54/70] mm/page_alloc.c: remove pageblock_default_order() Ben Hutchings
2012-08-07  3:28 ` [ 55/70] mm: setup pageblock_order before its used by sparsemem Ben Hutchings
2012-08-07  3:28 ` [ 56/70] mm: mmu_notifier: fix freed page still mapped in secondary MMU Ben Hutchings
2012-08-07  3:28 ` [ 57/70] mm: hugetlbfs: close race during teardown of hugetlbfs shared page tables Ben Hutchings
2012-08-07  3:28 ` [ 58/70] ALSA: snd-usb: fix clock source validity index Ben Hutchings
2012-08-07  3:28 ` [ 59/70] ALSA: hda - Support dock on Lenovo Thinkpad T530 with ALC269VC Ben Hutchings
2012-08-07  3:28 ` [ 60/70] ore: Fix out-of-bounds access in _ios_obj() Ben Hutchings
2012-08-07  3:28 ` [ 61/70] m68k: Make sys_atomic_cmpxchg_32 work on classic m68k Ben Hutchings
2012-08-07  3:28 ` [ 62/70] drm/i915: prefer wide & slow to fast & narrow in DP configs Ben Hutchings
2012-08-07  3:28 ` [ 63/70] rt2x00: Add support for BUFFALO WLI-UC-GNM2 to rt2800usb Ben Hutchings
2012-08-07  3:28 ` [ 64/70] drop_monitor: fix sleeping in invalid context warning Ben Hutchings
2012-08-07  3:29 ` [ 65/70] drop_monitor: Make updating data->skb smp safe Ben Hutchings
2012-08-07  3:29 ` [ 66/70] drop_monitor: prevent init path from scheduling on the wrong cpu Ben Hutchings
2012-08-07  3:29 ` [ 67/70] drop_monitor: dont sleep in atomic context Ben Hutchings
2012-08-07  3:29 ` [ 68/70] pch_uart: Fix missing break for 16 byte fifo Ben Hutchings
2012-08-07  3:29 ` [ 69/70] pch_uart: Fix rx error interrupt setting issue Ben Hutchings
2012-08-07  3:29 ` [ 70/70] pch_uart: Fix parity " Ben Hutchings
2012-08-07  3:49 ` [ 00/70] 3.2.27-stable review Ben Hutchings

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120807032803.487273580@decadent.org.uk \
    --to=ben@decadent.org.uk \
    --cc=akpm@linux-foundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rmk+kernel@arm.linux.org.uk \
    --cc=stable@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=will.deacon@arm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®