[PATCH] ARM: vfp: Fix up exception location in Thumb mode
Colin Cross
ccross at android.com
Fri Jan 14 14:23:39 EST 2011
On Fri, Jan 14, 2011 at 10:47 AM, Russell King - ARM Linux
<linux at arm.linux.org.uk> wrote:
> So... this incrementally on top of the previous patch (which I've
> reproduced below as there's a subtle comment change in there wrt IRQ
> state.)
>
> This means we have consistent state - both r2 and regs->ARM_pc always
> point to the next instruction to be executed in every case, which means
> its easy to understand and remember while reading through the code.
>
> diff -u b/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> --- b/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -499,10 +499,11 @@
> blo __und_usr_unknown
> 3: ldrht r0, [r4]
> add r2, r2, #2 @ r2 is PC + 2, make it PC + 4
> - orr r0, r0, r5, lsl #16
> + str r2, [sp, #S_PC] @ it's a 2x16bit instr, update
> + orr r0, r0, r5, lsl #16 @ regs->ARM_pc
> @
> @ r0 = the two 16-bit Thumb instructions which caused the exception
> - @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc+2)
> + @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc)
> @ r4 = PC value for the first 16-bit Thumb instruction
> @
> #else
>
> 8<-x-x-
>
> diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
> index 2b46fea..5876eec 100644
> --- a/arch/arm/kernel/entry-armv.S
> +++ b/arch/arm/kernel/entry-armv.S
> @@ -461,27 +461,35 @@ ENDPROC(__irq_usr)
> .align 5
> __und_usr:
> usr_entry
> -
> - @
> - @ 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)
> + @
> + @ r2 = regs->ARM_pc, which is either 2 or 4 bytes ahead of the
> + @ faulting instruction depending on Thumb mode.
> + @ r3 = regs->ARM_cpsr
> + @
> tst r3, #PSR_T_BIT @ Thumb mode?
> - itet eq @ explicit IT needed for the 1f label
> + itttt 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]
> #ifdef CONFIG_CPU_ENDIAN_BE8
> reveq r0, r0 @ little endian instruction
> #endif
> + @
> + @ 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
> + @
> beq call_fpe
> +
> @ Thumb instruction
> #if __LINUX_ARM_ARCH__ >= 7
> + sub r4, r2, #2 @ Thumb instr at LR - 2
> 2:
> ARM( ldrht r5, [r4], #2 )
> THUMB( ldrht r5, [r4] )
> @@ -492,18 +500,19 @@ __und_usr:
> 3: ldrht r0, [r4]
> add r2, r2, #2 @ r2 is PC + 2, make it PC + 4
> orr r0, r0, r5, lsl #16
> + @
> + @ r0 = the two 16-bit Thumb instructions which caused the exception
> + @ r2 = PC value for the following Thumb instruction (:= regs->ARM_pc+2)
> + @ r4 = PC value for the first 16-bit Thumb instruction
> + @
> #else
> b __und_usr_unknown
> #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
> @@ -534,11 +543,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
> diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
> index ee57640..eeb9250 100644
> --- a/arch/arm/kernel/traps.c
> +++ b/arch/arm/kernel/traps.c
> @@ -347,9 +347,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
> 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.
> + * According to the ARM ARM, the PC is 2 or 4 bytes ahead
> + * depending on Thumb mode. Correct this offset so that
> + * regs->ARM_pc points at the faulting instruction.
> */
> regs->ARM_pc -= correction;
>
> diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
> index 4fa9903..2bf6089 100644
> --- a/arch/arm/vfp/entry.S
> +++ b/arch/arm/vfp/entry.S
> @@ -19,6 +19,15 @@
> #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
> diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
> index 9897dcf..7292921 100644
> --- 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
I tested copying r2 to regs->ARM_pc like this patch does, and it fixes
my test case. Could this second patch go first so it can be applied
to stable?
More information about the linux-arm-kernel
mailing list