Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Ard Biesheuvel <ard.biesheuvel@linaro.org>

+30 -13
+3
arch/arm64/include/asm/fpsimd.h
··· 58 58 extern void fpsimd_thread_switch(struct task_struct *next); 59 59 extern void fpsimd_flush_thread(void); 60 60 61 + extern void fpsimd_preserve_current_state(void); 62 + extern void fpsimd_update_current_state(struct fpsimd_state *state); 63 + 61 64 #endif 62 65 63 66 #endif
+20
arch/arm64/kernel/fpsimd.c
··· 87 87 preempt_enable(); 88 88 } 89 89 90 + /* 91 + * Save the userland FPSIMD state of 'current' to memory 92 + */ 93 + void fpsimd_preserve_current_state(void) 94 + { 95 + preempt_disable(); 96 + fpsimd_save_state(&current->thread.fpsimd_state); 97 + preempt_enable(); 98 + } 99 + 100 + /* 101 + * Load an updated userland FPSIMD state for 'current' from memory 102 + */ 103 + void fpsimd_update_current_state(struct fpsimd_state *state) 104 + { 105 + preempt_disable(); 106 + fpsimd_load_state(state); 107 + preempt_enable(); 108 + } 109 + 90 110 #ifdef CONFIG_KERNEL_MODE_NEON 91 111 92 112 /*
+1 -1
arch/arm64/kernel/process.c
··· 205 205 206 206 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) 207 207 { 208 - fpsimd_save_state(&current->thread.fpsimd_state); 208 + fpsimd_preserve_current_state(); 209 209 *dst = *src; 210 210 return 0; 211 211 }
+3 -6
arch/arm64/kernel/signal.c
··· 51 51 int err; 52 52 53 53 /* dump the hardware registers to the fpsimd_state structure */ 54 - fpsimd_save_state(fpsimd); 54 + fpsimd_preserve_current_state(); 55 55 56 56 /* copy the FP and status/control registers */ 57 57 err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs)); ··· 86 86 __get_user_error(fpsimd.fpcr, &ctx->fpcr, err); 87 87 88 88 /* load the hardware registers from the fpsimd_state structure */ 89 - if (!err) { 90 - preempt_disable(); 91 - fpsimd_load_state(&fpsimd); 92 - preempt_enable(); 93 - } 89 + if (!err) 90 + fpsimd_update_current_state(&fpsimd); 94 91 95 92 return err ? -EFAULT : 0; 96 93 }
+3 -6
arch/arm64/kernel/signal32.c
··· 219 219 * Note that this also saves V16-31, which aren't visible 220 220 * in AArch32. 221 221 */ 222 - fpsimd_save_state(fpsimd); 222 + fpsimd_preserve_current_state(); 223 223 224 224 /* Place structure header on the stack */ 225 225 __put_user_error(magic, &frame->magic, err); ··· 282 282 * We don't need to touch the exception register, so 283 283 * reload the hardware state. 284 284 */ 285 - if (!err) { 286 - preempt_disable(); 287 - fpsimd_load_state(&fpsimd); 288 - preempt_enable(); 289 - } 285 + if (!err) 286 + fpsimd_update_current_state(&fpsimd); 290 287 291 288 return err ? -EFAULT : 0; 292 289 }