15ac49b650
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. Cc: <stable@vger.kernel.org> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
71 lines
1.7 KiB
ArmAsm
71 lines
1.7 KiB
ArmAsm
/*
|
|
* linux/arch/arm/vfp/entry.S
|
|
*
|
|
* Copyright (C) 2004 ARM Limited.
|
|
* Written by Deep Blue Solutions Limited.
|
|
*
|
|
* 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.
|
|
*/
|
|
#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
|
|
add r11, r4, #1 @ increment it
|
|
str r11, [r10, #TI_PREEMPT]
|
|
#endif
|
|
enable_irq
|
|
ldr r4, .LCvfp
|
|
ldr r11, [r10, #TI_CPU] @ CPU number
|
|
add r10, r10, #TI_VFPSTATE @ r10 = workspace
|
|
ldr pc, [r4] @ call VFP entry point
|
|
ENDPROC(do_vfp)
|
|
|
|
ENTRY(vfp_null_entry)
|
|
#ifdef CONFIG_PREEMPT
|
|
get_thread_info r10
|
|
ldr r4, [r10, #TI_PREEMPT] @ get preempt count
|
|
sub r11, r4, #1 @ decrement it
|
|
str r11, [r10, #TI_PREEMPT]
|
|
#endif
|
|
mov pc, lr
|
|
ENDPROC(vfp_null_entry)
|
|
|
|
.align 2
|
|
.LCvfp:
|
|
.word vfp_vector
|
|
|
|
@ This code is called if the VFP does not exist. It needs to flag the
|
|
@ failure to the VFP initialisation code.
|
|
|
|
__INIT
|
|
ENTRY(vfp_testing_entry)
|
|
#ifdef CONFIG_PREEMPT
|
|
get_thread_info r10
|
|
ldr r4, [r10, #TI_PREEMPT] @ get preempt count
|
|
sub r11, r4, #1 @ decrement it
|
|
str r11, [r10, #TI_PREEMPT]
|
|
#endif
|
|
ldr r0, VFP_arch_address
|
|
str r5, [r0] @ known non-zero value
|
|
mov pc, r9 @ we have handled the fault
|
|
ENDPROC(vfp_testing_entry)
|
|
|
|
.align 2
|
|
VFP_arch_address:
|
|
.word VFP_arch
|
|
|
|
__FINIT
|