aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-05-15 10:51:54 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-05-17 09:48:56 -0400
commit56cb248428ead13a6b423ed3f3cf9e4aa01244b1 (patch)
treebd1ab001b446712e5741220d80ce8c877b9e6482
parent1a3abcf41f13666d4ed241c8cc7f48bd38e7b543 (diff)
ARM: 7419/1: vfp: fix VFP flushing regression on sigreturn path
Commit ff9a184c ("ARM: 7400/1: vfp: clear fpscr length and stride bits on entry to sig handler") flushes the VFP state prior to entering a signal handler so that a VFP operation inside the handler will trap and force a restore of ABI-compliant registers. Reflushing and disabling VFP on the sigreturn path is predicated on the saved thread state indicating that VFP was used by the handler -- however for SMP platforms this is only set on context-switch, making the check unreliable and causing VFP register corruption in userspace since the register values are not necessarily those restored from the sigframe. This patch unconditionally flushes the VFP state after a signal handler. Since we already perform the flush before the handler and the flushing itself happens lazily, the redundant flush when VFP is not used by the handler is essentially a nop. Reported-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Jon Medhurst <tixy@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/vfp/vfpmodule.c14
1 files changed, 2 insertions, 12 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index c5767b5a4318..b0197b2c857d 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -577,12 +577,6 @@ int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
577 * entry. 577 * entry.
578 */ 578 */
579 hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK); 579 hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
580
581 /*
582 * Disable VFP in the hwstate so that we can detect if it gets
583 * used.
584 */
585 hwstate->fpexc &= ~FPEXC_EN;
586 return 0; 580 return 0;
587} 581}
588 582
@@ -595,12 +589,8 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
595 unsigned long fpexc; 589 unsigned long fpexc;
596 int err = 0; 590 int err = 0;
597 591
598 /* 592 /* Disable VFP to avoid corrupting the new thread state. */
599 * If VFP has been used, then disable it to avoid corrupting 593 vfp_flush_hwstate(thread);
600 * the new thread state.
601 */
602 if (hwstate->fpexc & FPEXC_EN)
603 vfp_flush_hwstate(thread);
604 594
605 /* 595 /*
606 * Copy the floating point registers. There can be unused 596 * Copy the floating point registers. There can be unused