aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-01-30 14:21:42 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-02-02 12:37:41 -0500
commit2af276dfb1722e97b190bd2e646b079a2aa674db (patch)
tree8fee4bc70d769d2d6bea25c627ff63716c3d0b20 /arch
parent97f1040982d7935716e9a45a26ccd5cc8fe92f8c (diff)
ARM: 7306/1: vfp: flush thread hwstate before restoring context from sigframe
Following execution of a signal handler, we currently restore the VFP context from the ucontext in the signal frame. This involves copying from the user stack into the current thread's vfp_hard_struct and then flushing the new data out to the hardware registers. This is problematic when using a preemptible kernel because we could be context switched whilst updating the vfp_hard_struct. If the current thread has made use of VFP since the last context switch, the VFP notifier will copy from the hardware registers into the vfp_hard_struct, overwriting any data that had been partially copied by the signal code. Disabling preemption across copy_from_user calls is a terrible idea, so instead we move the VFP thread flush *before* we update the vfp_hard_struct. Since the flushing is performed lazily, this has the effect of disabling VFP and clearing the CPU's VFP state pointer, therefore preventing the thread from being updated with stale data on the next context switch. Cc: stable <stable@vger.kernel.org> Tested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/kernel/signal.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 0340224cf73c..9e617bd4a146 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -227,6 +227,8 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
227 if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) 227 if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
228 return -EINVAL; 228 return -EINVAL;
229 229
230 vfp_flush_hwstate(thread);
231
230 /* 232 /*
231 * Copy the floating point registers. There can be unused 233 * Copy the floating point registers. There can be unused
232 * registers see asm/hwcap.h for details. 234 * registers see asm/hwcap.h for details.
@@ -251,9 +253,6 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
251 __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); 253 __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
252 __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); 254 __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
253 255
254 if (!err)
255 vfp_flush_hwstate(thread);
256
257 return err ? -EFAULT : 0; 256 return err ? -EFAULT : 0;
258} 257}
259 258