aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfpmodule.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 858748eaa144..bc683b8219b5 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -17,6 +17,8 @@
17#include <linux/sched.h> 17#include <linux/sched.h>
18#include <linux/smp.h> 18#include <linux/smp.h>
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/uaccess.h>
21#include <linux/user.h>
20 22
21#include <asm/cp15.h> 23#include <asm/cp15.h>
22#include <asm/cputype.h> 24#include <asm/cputype.h>
@@ -529,6 +531,103 @@ void vfp_flush_hwstate(struct thread_info *thread)
529} 531}
530 532
531/* 533/*
534 * Save the current VFP state into the provided structures and prepare
535 * for entry into a new function (signal handler).
536 */
537int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
538 struct user_vfp_exc __user *ufp_exc)
539{
540 struct thread_info *thread = current_thread_info();
541 struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
542 int err = 0;
543
544 /* Ensure that the saved hwstate is up-to-date. */
545 vfp_sync_hwstate(thread);
546
547 /*
548 * Copy the floating point registers. There can be unused
549 * registers see asm/hwcap.h for details.
550 */
551 err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
552 sizeof(hwstate->fpregs));
553 /*
554 * Copy the status and control register.
555 */
556 __put_user_error(hwstate->fpscr, &ufp->fpscr, err);
557
558 /*
559 * Copy the exception registers.
560 */
561 __put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
562 __put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
563 __put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);
564
565 if (err)
566 return -EFAULT;
567
568 /* Ensure that VFP is disabled. */
569 vfp_flush_hwstate(thread);
570
571 /*
572 * As per the PCS, clear the length and stride bits for function
573 * entry.
574 */
575 hwstate->fpscr &= ~(FPSCR_LENGTH_MASK | FPSCR_STRIDE_MASK);
576
577 /*
578 * Disable VFP in the hwstate so that we can detect if it gets
579 * used.
580 */
581 hwstate->fpexc &= ~FPEXC_EN;
582 return 0;
583}
584
585/* Sanitise and restore the current VFP state from the provided structures. */
586int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
587 struct user_vfp_exc __user *ufp_exc)
588{
589 struct thread_info *thread = current_thread_info();
590 struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
591 unsigned long fpexc;
592 int err = 0;
593
594 /*
595 * If VFP has been used, then disable it to avoid corrupting
596 * the new thread state.
597 */
598 if (hwstate->fpexc & FPEXC_EN)
599 vfp_flush_hwstate(thread);
600
601 /*
602 * Copy the floating point registers. There can be unused
603 * registers see asm/hwcap.h for details.
604 */
605 err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs,
606 sizeof(hwstate->fpregs));
607 /*
608 * Copy the status and control register.
609 */
610 __get_user_error(hwstate->fpscr, &ufp->fpscr, err);
611
612 /*
613 * Sanitise and restore the exception registers.
614 */
615 __get_user_error(fpexc, &ufp_exc->fpexc, err);
616
617 /* Ensure the VFP is enabled. */
618 fpexc |= FPEXC_EN;
619
620 /* Ensure FPINST2 is invalid and the exception flag is cleared. */
621 fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
622 hwstate->fpexc = fpexc;
623
624 __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
625 __get_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);
626
627 return err ? -EFAULT : 0;
628}
629
630/*
532 * VFP hardware can lose all context when a CPU goes offline. 631 * VFP hardware can lose all context when a CPU goes offline.
533 * As we will be running in SMP mode with CPU hotplug, we will save the 632 * As we will be running in SMP mode with CPU hotplug, we will save the
534 * hardware state at every thread switch. We clear our held state when 633 * hardware state at every thread switch. We clear our held state when