[PATCH] ARM: vfp: Fix up exception location in Thumb mode

Colin Cross ccross at android.com
Fri Jan 14 14:51:38 EST 2011


On Fri, Jan 14, 2011 at 11:23 AM, Colin Cross <ccross at android.com> wrote:
> 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?
>

Also, both patches together Tested-by: Colin Cross <ccross at android.com>



More information about the linux-arm-kernel mailing list