Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 299872
b: refs/heads/master
c: 2498814
h: refs/heads/master
v: v3
  • Loading branch information
Will Deacon authored and Russell King committed Apr 23, 2012
1 parent 283fc4a commit 4ddcd9d
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 52 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: ab4d536890853ab6675ede65db40e2c0980cb0ea
refs/heads/master: 2498814fcb3068f19b82b1519b4038721f61af43
7 changes: 7 additions & 0 deletions trunk/arch/arm/include/asm/thread_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ extern void iwmmxt_task_switch(struct thread_info *);
extern void vfp_sync_hwstate(struct thread_info *);
extern void vfp_flush_hwstate(struct thread_info *);

struct user_vfp;
struct user_vfp_exc;

extern int vfp_preserve_user_clear_hwstate(struct user_vfp __user *,
struct user_vfp_exc __user *);
extern int vfp_restore_user_hwstate(struct user_vfp __user *,
struct user_vfp_exc __user *);
#endif

/*
Expand Down
55 changes: 4 additions & 51 deletions trunk/arch/arm/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,44 +180,23 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)

static int preserve_vfp_context(struct vfp_sigframe __user *frame)
{
struct thread_info *thread = current_thread_info();
struct vfp_hard_struct *h = &thread->vfpstate.hard;
const unsigned long magic = VFP_MAGIC;
const unsigned long size = VFP_STORAGE_SIZE;
int err = 0;

vfp_sync_hwstate(thread);
__put_user_error(magic, &frame->magic, err);
__put_user_error(size, &frame->size, err);

/*
* Copy the floating point registers. There can be unused
* registers see asm/hwcap.h for details.
*/
err |= __copy_to_user(&frame->ufp.fpregs, &h->fpregs,
sizeof(h->fpregs));
/*
* Copy the status and control register.
*/
__put_user_error(h->fpscr, &frame->ufp.fpscr, err);

/*
* Copy the exception registers.
*/
__put_user_error(h->fpexc, &frame->ufp_exc.fpexc, err);
__put_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
__put_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);
if (err)
return -EFAULT;

return err ? -EFAULT : 0;
return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
}

static int restore_vfp_context(struct vfp_sigframe __user *frame)
{
struct thread_info *thread = current_thread_info();
struct vfp_hard_struct *h = &thread->vfpstate.hard;
unsigned long magic;
unsigned long size;
unsigned long fpexc;
int err = 0;

__get_user_error(magic, &frame->magic, err);
Expand All @@ -228,33 +207,7 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame)
if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
return -EINVAL;

vfp_flush_hwstate(thread);

/*
* Copy the floating point registers. There can be unused
* registers see asm/hwcap.h for details.
*/
err |= __copy_from_user(&h->fpregs, &frame->ufp.fpregs,
sizeof(h->fpregs));
/*
* Copy the status and control register.
*/
__get_user_error(h->fpscr, &frame->ufp.fpscr, err);

/*
* Sanitise and restore the exception registers.
*/
__get_user_error(fpexc, &frame->ufp_exc.fpexc, err);
/* Ensure the VFP is enabled. */
fpexc |= FPEXC_EN;
/* Ensure FPINST2 is invalid and the exception flag is cleared. */
fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
h->fpexc = fpexc;

__get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err);
__get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err);

return err ? -EFAULT : 0;
return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc);
}

#endif
Expand Down
79 changes: 79 additions & 0 deletions trunk/arch/arm/vfp/vfpmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/user.h>

#include <asm/cp15.h>
#include <asm/cputype.h>
Expand Down Expand Up @@ -528,6 +530,83 @@ void vfp_flush_hwstate(struct thread_info *thread)
put_cpu();
}

/*
* Save the current VFP state into the provided structures and prepare
* for entry into a new function (signal handler).
*/
int vfp_preserve_user_clear_hwstate(struct user_vfp __user *ufp,
struct user_vfp_exc __user *ufp_exc)
{
struct thread_info *thread = current_thread_info();
struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
int err = 0;

/* Ensure that the saved hwstate is up-to-date. */
vfp_sync_hwstate(thread);

/*
* Copy the floating point registers. There can be unused
* registers see asm/hwcap.h for details.
*/
err |= __copy_to_user(&ufp->fpregs, &hwstate->fpregs,
sizeof(hwstate->fpregs));
/*
* Copy the status and control register.
*/
__put_user_error(hwstate->fpscr, &ufp->fpscr, err);

/*
* Copy the exception registers.
*/
__put_user_error(hwstate->fpexc, &ufp_exc->fpexc, err);
__put_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
__put_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);

if (err)
return -EFAULT;
return 0;
}

/* Sanitise and restore the current VFP state from the provided structures. */
int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
struct user_vfp_exc __user *ufp_exc)
{
struct thread_info *thread = current_thread_info();
struct vfp_hard_struct *hwstate = &thread->vfpstate.hard;
unsigned long fpexc;
int err = 0;

vfp_flush_hwstate(thread);

/*
* Copy the floating point registers. There can be unused
* registers see asm/hwcap.h for details.
*/
err |= __copy_from_user(&hwstate->fpregs, &ufp->fpregs,
sizeof(hwstate->fpregs));
/*
* Copy the status and control register.
*/
__get_user_error(hwstate->fpscr, &ufp->fpscr, err);

/*
* Sanitise and restore the exception registers.
*/
__get_user_error(fpexc, &ufp_exc->fpexc, err);

/* Ensure the VFP is enabled. */
fpexc |= FPEXC_EN;

/* Ensure FPINST2 is invalid and the exception flag is cleared. */
fpexc &= ~(FPEXC_EX | FPEXC_FP2V);
hwstate->fpexc = fpexc;

__get_user_error(hwstate->fpinst, &ufp_exc->fpinst, err);
__get_user_error(hwstate->fpinst2, &ufp_exc->fpinst2, err);

return err ? -EFAULT : 0;
}

/*
* VFP hardware can lose all context when a CPU goes offline.
* As we will be running in SMP mode with CPU hotplug, we will save the
Expand Down

0 comments on commit 4ddcd9d

Please sign in to comment.