Skip to content

Commit d4d5be9

Browse files
brooniewilldeacon
authored andcommitted
arm64/fpsimd: Ensure SME storage is allocated after SVE VL changes
When we reconfigure the SVE vector length we discard the backing storage for the SVE vectors and then reallocate on next SVE use, leaving the SME specific state alone. This means that we do not enable SME traps if they were already disabled. That means that userspace code can enter streaming mode without trapping, putting the task in a state where if we try to save the state of the task we will fault. Since the ABI does not specify that changing the SVE vector length disturbs SME state, and since SVE code may not be aware of SME code in the process, we shouldn't simply discard any ZA state. Instead immediately reallocate the storage for SVE, and disable SME if we change the SVE vector length while there is no SME state active. Disabling SME traps on SVE vector length changes would make the overall code more complex since we would have a state where we have valid SME state stored but might get a SME trap. Fixes: 9e4ab6c ("arm64/sme: Implement vector length configuration prctl()s") Reported-by: David Spickett <David.Spickett@arm.com> Signed-off-by: Mark Brown <broonie@kernel.org> Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230720-arm64-fix-sve-sme-vl-change-v2-1-8eea06b82d57@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
1 parent 71e06e1 commit d4d5be9

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

arch/arm64/kernel/fpsimd.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,8 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
847847
int vec_set_vector_length(struct task_struct *task, enum vec_type type,
848848
unsigned long vl, unsigned long flags)
849849
{
850+
bool free_sme = false;
851+
850852
if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT |
851853
PR_SVE_SET_VL_ONEXEC))
852854
return -EINVAL;
@@ -897,21 +899,36 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type,
897899
task->thread.fp_type = FP_STATE_FPSIMD;
898900
}
899901

900-
if (system_supports_sme() && type == ARM64_VEC_SME) {
901-
task->thread.svcr &= ~(SVCR_SM_MASK |
902-
SVCR_ZA_MASK);
903-
clear_thread_flag(TIF_SME);
902+
if (system_supports_sme()) {
903+
if (type == ARM64_VEC_SME ||
904+
!(task->thread.svcr & (SVCR_SM_MASK | SVCR_ZA_MASK))) {
905+
/*
906+
* We are changing the SME VL or weren't using
907+
* SME anyway, discard the state and force a
908+
* reallocation.
909+
*/
910+
task->thread.svcr &= ~(SVCR_SM_MASK |
911+
SVCR_ZA_MASK);
912+
clear_thread_flag(TIF_SME);
913+
free_sme = true;
914+
}
904915
}
905916

906917
if (task == current)
907918
put_cpu_fpsimd_context();
908919

909920
/*
910-
* Force reallocation of task SVE and SME state to the correct
911-
* size on next use:
921+
* Free the changed states if they are not in use, SME will be
922+
* reallocated to the correct size on next use and we just
923+
* allocate SVE now in case it is needed for use in streaming
924+
* mode.
912925
*/
913-
sve_free(task);
914-
if (system_supports_sme() && type == ARM64_VEC_SME)
926+
if (system_supports_sve()) {
927+
sve_free(task);
928+
sve_alloc(task, true);
929+
}
930+
931+
if (free_sme)
915932
sme_free(task);
916933

917934
task_set_vl(task, type, vl);

0 commit comments

Comments
 (0)