Skip to content

Commit ee072cf

Browse files
brooniectmarinas
authored andcommitted
arm64/sme: Implement signal handling for ZT
Add a new signal context type for ZT which is present in the signal frame when ZA is enabled and ZT is supported by the system. In order to account for the possible addition of further ZT registers in the future we make the number of registers variable in the ABI, though currently the only possible number is 1. We could just use a bare list head for the context since the number of registers can be inferred from the size of the context but for usability and future extensibility we define a header with the number of registers and some reserved fields in it. Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20221208-arm64-sme2-v4-11-f2fa0aef982f@kernel.org Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
1 parent 95fcec7 commit ee072cf

File tree

3 files changed

+124
-3
lines changed

3 files changed

+124
-3
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,6 @@ extern unsigned int sme_get_vl(void);
361361
extern int sme_set_current_vl(unsigned long arg);
362362
extern int sme_get_current_vl(void);
363363

364-
/* Will move with signal support */
365-
#define ZT_SIG_REG_SIZE 512
366-
367364
/*
368365
* Return how many bytes of memory are required to store the full SME
369366
* specific state for task, given task's currently configured vector

arch/arm64/include/uapi/asm/sigcontext.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ struct za_context {
152152
__u16 __reserved[3];
153153
};
154154

155+
#define ZT_MAGIC 0x5a544e01
156+
157+
struct zt_context {
158+
struct _aarch64_ctx head;
159+
__u16 nregs;
160+
__u16 __reserved[3];
161+
};
162+
155163
#endif /* !__ASSEMBLY__ */
156164

157165
#include <asm/sve_context.h>
@@ -304,4 +312,15 @@ struct za_context {
304312
#define ZA_SIG_CONTEXT_SIZE(vq) \
305313
(ZA_SIG_REGS_OFFSET + ZA_SIG_REGS_SIZE(vq))
306314

315+
#define ZT_SIG_REG_SIZE 512
316+
317+
#define ZT_SIG_REG_BYTES (ZT_SIG_REG_SIZE / 8)
318+
319+
#define ZT_SIG_REGS_OFFSET sizeof(struct zt_context)
320+
321+
#define ZT_SIG_REGS_SIZE(n) (ZT_SIG_REG_BYTES * n)
322+
323+
#define ZT_SIG_CONTEXT_SIZE(n) \
324+
(sizeof(struct zt_context) + ZT_SIG_REGS_SIZE(n))
325+
307326
#endif /* _UAPI__ASM_SIGCONTEXT_H */

arch/arm64/kernel/signal.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ struct rt_sigframe_user_layout {
5757
unsigned long esr_offset;
5858
unsigned long sve_offset;
5959
unsigned long za_offset;
60+
unsigned long zt_offset;
6061
unsigned long extra_offset;
6162
unsigned long end_offset;
6263
};
@@ -221,6 +222,7 @@ struct user_ctxs {
221222
struct fpsimd_context __user *fpsimd;
222223
struct sve_context __user *sve;
223224
struct za_context __user *za;
225+
struct zt_context __user *zt;
224226
};
225227

226228
#ifdef CONFIG_ARM64_SVE
@@ -447,11 +449,81 @@ static int restore_za_context(struct user_ctxs *user)
447449

448450
return 0;
449451
}
452+
453+
static int preserve_zt_context(struct zt_context __user *ctx)
454+
{
455+
int err = 0;
456+
u16 reserved[ARRAY_SIZE(ctx->__reserved)];
457+
458+
if (WARN_ON(!thread_za_enabled(&current->thread)))
459+
return -EINVAL;
460+
461+
memset(reserved, 0, sizeof(reserved));
462+
463+
__put_user_error(ZT_MAGIC, &ctx->head.magic, err);
464+
__put_user_error(round_up(ZT_SIG_CONTEXT_SIZE(1), 16),
465+
&ctx->head.size, err);
466+
__put_user_error(1, &ctx->nregs, err);
467+
BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
468+
err |= __copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
469+
470+
/*
471+
* This assumes that the ZT state has already been saved to
472+
* the task struct by calling the function
473+
* fpsimd_signal_preserve_current_state().
474+
*/
475+
err |= __copy_to_user((char __user *)ctx + ZT_SIG_REGS_OFFSET,
476+
thread_zt_state(&current->thread),
477+
ZT_SIG_REGS_SIZE(1));
478+
479+
return err ? -EFAULT : 0;
480+
}
481+
482+
static int restore_zt_context(struct user_ctxs *user)
483+
{
484+
int err;
485+
struct zt_context zt;
486+
487+
/* ZA must be restored first for this check to be valid */
488+
if (!thread_za_enabled(&current->thread))
489+
return -EINVAL;
490+
491+
if (__copy_from_user(&zt, user->zt, sizeof(zt)))
492+
return -EFAULT;
493+
494+
if (zt.nregs != 1)
495+
return -EINVAL;
496+
497+
if (zt.head.size != ZT_SIG_CONTEXT_SIZE(zt.nregs))
498+
return -EINVAL;
499+
500+
/*
501+
* Careful: we are about __copy_from_user() directly into
502+
* thread.zt_state with preemption enabled, so protection is
503+
* needed to prevent a racing context switch from writing stale
504+
* registers back over the new data.
505+
*/
506+
507+
fpsimd_flush_task_state(current);
508+
/* From now, fpsimd_thread_switch() won't touch ZT in thread state */
509+
510+
err = __copy_from_user(thread_zt_state(&current->thread),
511+
(char __user const *)user->zt +
512+
ZT_SIG_REGS_OFFSET,
513+
ZT_SIG_REGS_SIZE(1));
514+
if (err)
515+
return -EFAULT;
516+
517+
return 0;
518+
}
519+
450520
#else /* ! CONFIG_ARM64_SME */
451521

452522
/* Turn any non-optimised out attempts to use these into a link error: */
453523
extern int preserve_za_context(void __user *ctx);
454524
extern int restore_za_context(struct user_ctxs *user);
525+
extern int preserve_zt_context(void __user *ctx);
526+
extern int restore_zt_context(struct user_ctxs *user);
455527

456528
#endif /* ! CONFIG_ARM64_SME */
457529

@@ -469,6 +541,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
469541
user->fpsimd = NULL;
470542
user->sve = NULL;
471543
user->za = NULL;
544+
user->zt = NULL;
472545

473546
if (!IS_ALIGNED((unsigned long)base, 16))
474547
goto invalid;
@@ -547,6 +620,19 @@ static int parse_user_sigframe(struct user_ctxs *user,
547620
user->za = (struct za_context __user *)head;
548621
break;
549622

623+
case ZT_MAGIC:
624+
if (!system_supports_sme2())
625+
goto invalid;
626+
627+
if (user->zt)
628+
goto invalid;
629+
630+
if (size < sizeof(*user->zt))
631+
goto invalid;
632+
633+
user->zt = (struct zt_context __user *)head;
634+
break;
635+
550636
case EXTRA_MAGIC:
551637
if (have_extra_context)
552638
goto invalid;
@@ -669,6 +755,9 @@ static int restore_sigframe(struct pt_regs *regs,
669755
if (err == 0 && system_supports_sme() && user.za)
670756
err = restore_za_context(&user);
671757

758+
if (err == 0 && system_supports_sme2() && user.zt)
759+
err = restore_zt_context(&user);
760+
672761
return err;
673762
}
674763

@@ -769,6 +858,15 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
769858
return err;
770859
}
771860

861+
if (system_supports_sme2()) {
862+
if (add_all || thread_za_enabled(&current->thread)) {
863+
err = sigframe_alloc(user, &user->zt_offset,
864+
ZT_SIG_CONTEXT_SIZE(1));
865+
if (err)
866+
return err;
867+
}
868+
}
869+
772870
return sigframe_alloc_end(user);
773871
}
774872

@@ -824,6 +922,13 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
824922
err |= preserve_za_context(za_ctx);
825923
}
826924

925+
/* ZT state if present */
926+
if (system_supports_sme2() && err == 0 && user->zt_offset) {
927+
struct zt_context __user *zt_ctx =
928+
apply_user_offset(user, user->zt_offset);
929+
err |= preserve_zt_context(zt_ctx);
930+
}
931+
827932
if (err == 0 && user->extra_offset) {
828933
char __user *sfp = (char __user *)user->sigframe;
829934
char __user *userp =

0 commit comments

Comments
 (0)