Commit c51f9269 authored by Ard Biesheuvel's avatar Ard Biesheuvel

arm64: add abstractions for FPSIMD state manipulation

There are two tacit assumptions in the FPSIMD handling code that will no longer
hold after the next patch that optimizes away some FPSIMD state restores:
. the FPSIMD registers of this CPU contain the userland FPSIMD state of
  task 'current';
. when switching to a task, its FPSIMD state will always be restored from
  memory.

This patch adds the following functions to abstract away from straight FPSIMD
register file saves and restores:
- fpsimd_preserve_current_state -> ensure current's FPSIMD state is saved
- fpsimd_update_current_state -> replace current's FPSIMD state

Where necessary, the signal handling and fork code are updated to use the above
wrappers instead of poking into the FPSIMD registers directly.
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
parent 0567f5fa
...@@ -58,6 +58,9 @@ extern void fpsimd_load_state(struct fpsimd_state *state); ...@@ -58,6 +58,9 @@ extern void fpsimd_load_state(struct fpsimd_state *state);
extern void fpsimd_thread_switch(struct task_struct *next); extern void fpsimd_thread_switch(struct task_struct *next);
extern void fpsimd_flush_thread(void); extern void fpsimd_flush_thread(void);
extern void fpsimd_preserve_current_state(void);
extern void fpsimd_update_current_state(struct fpsimd_state *state);
#endif #endif
#endif #endif
...@@ -87,6 +87,26 @@ void fpsimd_flush_thread(void) ...@@ -87,6 +87,26 @@ void fpsimd_flush_thread(void)
preempt_enable(); preempt_enable();
} }
/*
* Save the userland FPSIMD state of 'current' to memory
*/
void fpsimd_preserve_current_state(void)
{
preempt_disable();
fpsimd_save_state(&current->thread.fpsimd_state);
preempt_enable();
}
/*
* Load an updated userland FPSIMD state for 'current' from memory
*/
void fpsimd_update_current_state(struct fpsimd_state *state)
{
preempt_disable();
fpsimd_load_state(state);
preempt_enable();
}
#ifdef CONFIG_KERNEL_MODE_NEON #ifdef CONFIG_KERNEL_MODE_NEON
/* /*
......
...@@ -205,7 +205,7 @@ void release_thread(struct task_struct *dead_task) ...@@ -205,7 +205,7 @@ void release_thread(struct task_struct *dead_task)
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{ {
fpsimd_save_state(&current->thread.fpsimd_state); fpsimd_preserve_current_state();
*dst = *src; *dst = *src;
return 0; return 0;
} }
......
...@@ -51,7 +51,7 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx) ...@@ -51,7 +51,7 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
int err; int err;
/* dump the hardware registers to the fpsimd_state structure */ /* dump the hardware registers to the fpsimd_state structure */
fpsimd_save_state(fpsimd); fpsimd_preserve_current_state();
/* copy the FP and status/control registers */ /* copy the FP and status/control registers */
err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs)); err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
...@@ -86,11 +86,8 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx) ...@@ -86,11 +86,8 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
__get_user_error(fpsimd.fpcr, &ctx->fpcr, err); __get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
/* load the hardware registers from the fpsimd_state structure */ /* load the hardware registers from the fpsimd_state structure */
if (!err) { if (!err)
preempt_disable(); fpsimd_update_current_state(&fpsimd);
fpsimd_load_state(&fpsimd);
preempt_enable();
}
return err ? -EFAULT : 0; return err ? -EFAULT : 0;
} }
......
...@@ -219,7 +219,7 @@ static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame) ...@@ -219,7 +219,7 @@ static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
* Note that this also saves V16-31, which aren't visible * Note that this also saves V16-31, which aren't visible
* in AArch32. * in AArch32.
*/ */
fpsimd_save_state(fpsimd); fpsimd_preserve_current_state();
/* Place structure header on the stack */ /* Place structure header on the stack */
__put_user_error(magic, &frame->magic, err); __put_user_error(magic, &frame->magic, err);
...@@ -282,11 +282,8 @@ static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame) ...@@ -282,11 +282,8 @@ static int compat_restore_vfp_context(struct compat_vfp_sigframe __user *frame)
* We don't need to touch the exception register, so * We don't need to touch the exception register, so
* reload the hardware state. * reload the hardware state.
*/ */
if (!err) { if (!err)
preempt_disable(); fpsimd_update_current_state(&fpsimd);
fpsimd_load_state(&fpsimd);
preempt_enable();
}
return err ? -EFAULT : 0; return err ? -EFAULT : 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment