Skip to content

Commit cccb78c

Browse files
brooniectmarinas
authored andcommitted
arm64/sve: Rework SVE access trap to convert state in registers
When we enable SVE usage in userspace after taking a SVE access trap we need to ensure that the portions of the register state that are not shared with the FPSIMD registers are zeroed. Currently we do this by forcing the FPSIMD registers to be saved to the task struct and converting them there. This is wasteful in the common case where the task state is loaded into the registers and we will immediately return to userspace since we can initialise the SVE state directly in registers instead of accessing multiple copies of the register state in memory. Instead in that common case do the conversion in the registers and update the task metadata so that we can return to userspace without spilling the register state to memory unless there is some other reason to do so. Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20210312190313.24598-1-broonie@kernel.org Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 68f638a commit cccb78c

File tree

3 files changed

+23
-9
lines changed

3 files changed

+23
-9
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ extern void sve_flush_live(void);
7373
extern void sve_load_from_fpsimd_state(struct user_fpsimd_state const *state,
7474
unsigned long vq_minus_1);
7575
extern unsigned int sve_get_vl(void);
76+
extern void sve_set_vq(unsigned long vq_minus_1);
7677

7778
struct arm64_cpu_capabilities;
7879
extern void sve_kernel_enable(const struct arm64_cpu_capabilities *__unused);

arch/arm64/kernel/entry-fpsimd.S

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ SYM_FUNC_START(sve_get_vl)
4848
ret
4949
SYM_FUNC_END(sve_get_vl)
5050

51+
SYM_FUNC_START(sve_set_vq)
52+
sve_load_vq x0, x1, x2
53+
ret
54+
SYM_FUNC_END(sve_set_vq)
55+
5156
/*
5257
* Load SVE state from FPSIMD state.
5358
*

arch/arm64/kernel/fpsimd.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -926,9 +926,8 @@ void fpsimd_release_task(struct task_struct *dead_task)
926926
* Trapped SVE access
927927
*
928928
* Storage is allocated for the full SVE state, the current FPSIMD
929-
* register contents are migrated across, and TIF_SVE is set so that
930-
* the SVE access trap will be disabled the next time this task
931-
* reaches ret_to_user.
929+
* register contents are migrated across, and the access trap is
930+
* disabled.
932931
*
933932
* TIF_SVE should be clear on entry: otherwise, fpsimd_restore_current_state()
934933
* would have disabled the SVE access trap for userspace during
@@ -946,15 +945,24 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
946945

947946
get_cpu_fpsimd_context();
948947

949-
fpsimd_save();
950-
951-
/* Force ret_to_user to reload the registers: */
952-
fpsimd_flush_task_state(current);
953-
954-
fpsimd_to_sve(current);
955948
if (test_and_set_thread_flag(TIF_SVE))
956949
WARN_ON(1); /* SVE access shouldn't have trapped */
957950

951+
/*
952+
* Convert the FPSIMD state to SVE, zeroing all the state that
953+
* is not shared with FPSIMD. If (as is likely) the current
954+
* state is live in the registers then do this there and
955+
* update our metadata for the current task including
956+
* disabling the trap, otherwise update our in-memory copy.
957+
*/
958+
if (!test_thread_flag(TIF_FOREIGN_FPSTATE)) {
959+
sve_set_vq(sve_vq_from_vl(current->thread.sve_vl) - 1);
960+
sve_flush_live();
961+
fpsimd_bind_task_to_cpu();
962+
} else {
963+
fpsimd_to_sve(current);
964+
}
965+
958966
put_cpu_fpsimd_context();
959967
}
960968

0 commit comments

Comments
 (0)