summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-01-23 13:56:04 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-01-23 13:56:04 -0800
commite85d3e9d581eb6047a2a79f088b1934e30d81a9b (patch)
treeed1a3d803158ad09551059c5cf6b2d666fbfd2dd /arch
parent6d064432376627ff76f86e16b3fbc13c38e860c2 (diff)
parente2f8216ca2d8e61a23cb6ec355616339667e0ba6 (diff)
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 fixes from Catalin Marinas: - A set of fixes for FPSIMD/SVE/SME state management (around signal handling and ptrace) where a task can be placed in an invalid state - __nocfi added to swsusp_arch_resume() to avoid a data abort on resuming from hibernate * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: Set __nocfi on swsusp_arch_resume() arm64/fpsimd: signal: Fix restoration of SVE context arm64/fpsimd: signal: Allocate SSVE storage when restoring ZA arm64/fpsimd: ptrace: Fix SVE writes on !SME systems
Diffstat (limited to 'arch')
-rw-r--r--arch/arm64/kernel/hibernate.c2
-rw-r--r--arch/arm64/kernel/ptrace.c26
-rw-r--r--arch/arm64/kernel/signal.c26
3 files changed, 33 insertions, 21 deletions
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index 18749e9a6c2d..9717568518ba 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -402,7 +402,7 @@ int swsusp_arch_suspend(void)
* Memory allocated by get_safe_page() will be dealt with by the hibernate code,
* we don't need to free it here.
*/
-int swsusp_arch_resume(void)
+int __nocfi swsusp_arch_resume(void)
{
int rc;
void *zero_page;
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index b9bdd83fbbca..6c5ff6807d4c 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -968,20 +968,18 @@ static int sve_set_common(struct task_struct *target,
vq = sve_vq_from_vl(task_get_vl(target, type));
/* Enter/exit streaming mode */
- if (system_supports_sme()) {
- switch (type) {
- case ARM64_VEC_SVE:
- target->thread.svcr &= ~SVCR_SM_MASK;
- set_tsk_thread_flag(target, TIF_SVE);
- break;
- case ARM64_VEC_SME:
- target->thread.svcr |= SVCR_SM_MASK;
- set_tsk_thread_flag(target, TIF_SME);
- break;
- default:
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
+ switch (type) {
+ case ARM64_VEC_SVE:
+ target->thread.svcr &= ~SVCR_SM_MASK;
+ set_tsk_thread_flag(target, TIF_SVE);
+ break;
+ case ARM64_VEC_SME:
+ target->thread.svcr |= SVCR_SM_MASK;
+ set_tsk_thread_flag(target, TIF_SME);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
}
/* Always zero V regs, FPSR, and FPCR */
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 1110eeb21f57..08ffc5a5aea4 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -449,12 +449,28 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
if (user->sve_size < SVE_SIG_CONTEXT_SIZE(vq))
return -EINVAL;
+ if (sm) {
+ sme_alloc(current, false);
+ if (!current->thread.sme_state)
+ return -ENOMEM;
+ }
+
sve_alloc(current, true);
if (!current->thread.sve_state) {
clear_thread_flag(TIF_SVE);
return -ENOMEM;
}
+ if (sm) {
+ current->thread.svcr |= SVCR_SM_MASK;
+ set_thread_flag(TIF_SME);
+ } else {
+ current->thread.svcr &= ~SVCR_SM_MASK;
+ set_thread_flag(TIF_SVE);
+ }
+
+ current->thread.fp_type = FP_STATE_SVE;
+
err = __copy_from_user(current->thread.sve_state,
(char __user const *)user->sve +
SVE_SIG_REGS_OFFSET,
@@ -462,12 +478,6 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
if (err)
return -EFAULT;
- if (flags & SVE_SIG_FLAG_SM)
- current->thread.svcr |= SVCR_SM_MASK;
- else
- set_thread_flag(TIF_SVE);
- current->thread.fp_type = FP_STATE_SVE;
-
err = read_fpsimd_context(&fpsimd, user);
if (err)
return err;
@@ -576,6 +586,10 @@ static int restore_za_context(struct user_ctxs *user)
if (user->za_size < ZA_SIG_CONTEXT_SIZE(vq))
return -EINVAL;
+ sve_alloc(current, false);
+ if (!current->thread.sve_state)
+ return -ENOMEM;
+
sme_alloc(current, true);
if (!current->thread.sme_state) {
current->thread.svcr &= ~SVCR_ZA_MASK;