diff options
author | Will Deacon <will.deacon@arm.com> | 2012-04-23 10:38:28 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-04-23 10:44:41 -0400 |
commit | 2498814fcb3068f19b82b1519b4038721f61af43 (patch) | |
tree | 6a3483bab350438a768b56bb56611d609b2396b4 /arch/arm/vfp | |
parent | ab4d536890853ab6675ede65db40e2c0980cb0ea (diff) |
ARM: 7399/1: vfp: move user vfp state save/restore code out of signal.c
The user VFP state must be preserved (subject to ucontext modifications)
across invocation of a signal handler and this is currently handled by
vfp_{preserve,restore}_context in signal.c
Since this code requires intimate low-level knowledge of the VFP state,
this patch moves it into vfpmodule.c.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 858748eaa144..05872d92fca2 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,83 @@ 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 | */ | ||
537 | int 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 | return 0; | ||
568 | } | ||
569 | |||
570 | /* Sanitise and restore the current VFP state from the provided structures. */ | ||
571 | int vfp_restore_user_hwstate(struct user_vfp __user *ufp, | ||
572 | struct user_vfp_exc __user *ufp_exc) | ||
573 | { | ||
574 | struct thread_info *thread = current_thread_info(); | ||
575 | struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; | ||
576 | unsigned long fpexc; | ||
577 | int err = 0; | ||
578 | |||
579 | vfp_flush_hwstate(thread); | ||
580 | |||
581 | /* | ||
582 | * Copy the floating point registers. There can be unused | ||
583 | * registers see asm/hwcap.h for details. | ||
584 | */ | ||
585 | err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs, | ||
586 | sizeof(hwstate->fpregs)); | ||
587 | /* | ||
588 | * Copy the status and control register. | ||
589 | */ | ||
590 | __get_user_error(hwstate->fpscr, &ufp->fpscr, err); | ||
591 | |||
592 | /* | ||
593 | * Sanitise and restore the exception registers. | ||
594 | */ | ||
595 | __get_user_error(fpexc, &ufp_exc->fpexc, err); | ||
596 | |||
597 | /* Ensure the VFP is enabled. */ | ||
598 | fpexc |= FPEXC_EN; | ||
599 | |||
600 | /* Ensure FPINST2 is invalid and the exception flag is cleared. */ | ||
601 | fpexc &= ~(FPEXC_EX | FPEXC_FP2V); | ||
602 | hwstate->fpexc = fpexc; | ||
603 | |||
604 | __get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err); | ||
605 | __get_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err); | ||
606 | |||
607 | return err ? -EFAULT : 0; | ||
608 | } | ||
609 | |||
610 | /* | ||
532 | * VFP hardware can lose all context when a CPU goes offline. | 611 | * 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 | 612 | * 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 | 613 | * hardware state at every thread switch. We clear our held state when |