Skip to content

Commit 85ed24d

Browse files
brooniectmarinas
authored andcommitted
arm64/sme: Implement streaming SVE signal handling
When in streaming mode we have the same set of SVE registers as we do in regular SVE mode with the exception of FFR and the use of the SME vector length. Provide signal handling for these registers by taking one of the reserved words in the SVE signal context as a flags field and defining a flag which is set for streaming mode. When the flag is set the vector length is set to the streaming mode vector length and we save and restore streaming mode data. We support entering or leaving streaming mode based on the value of the flag but do not support changing the vector length, this is not currently supported SVE signal handling. We could instead allocate a separate record in the signal frame for the streaming mode SVE context but this inflates the size of the maximal signal frame required and adds complication when validating signal frames from userspace, especially given the current structure of the code. Any implementation of support for streaming mode vectors in signals will have some potential for causing issues for applications that attempt to handle SVE vectors in signals, use streaming mode but do not understand streaming mode in their signal handling code, it is hard to identify a case that is clearly better than any other - they all have cases where they could cause unexpected register corruption or faults. Signed-off-by: Mark Brown <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 40a8e87 commit 85ed24d

File tree

3 files changed

+53
-13
lines changed

3 files changed

+53
-13
lines changed

arch/arm64/include/asm/processor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ static inline unsigned int thread_get_sme_vl(struct thread_struct *thread)
190190
return thread_get_vl(thread, ARM64_VEC_SME);
191191
}
192192

193+
static inline unsigned int thread_get_cur_vl(struct thread_struct *thread)
194+
{
195+
if (system_supports_sme() && (thread->svcr & SYS_SVCR_EL0_SM_MASK))
196+
return thread_get_sme_vl(thread);
197+
else
198+
return thread_get_sve_vl(thread);
199+
}
200+
193201
unsigned int task_get_vl(const struct task_struct *task, enum vec_type type);
194202
void task_set_vl(struct task_struct *task, enum vec_type type,
195203
unsigned long vl);

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ struct extra_context {
134134
struct sve_context {
135135
struct _aarch64_ctx head;
136136
__u16 vl;
137-
__u16 __reserved[3];
137+
__u16 flags;
138+
__u16 __reserved[2];
138139
};
139140

141+
#define SVE_SIG_FLAG_SM 0x1 /* Context describes streaming mode */
142+
140143
#endif /* !__ASSEMBLY__ */
141144

142145
#include <asm/sve_context.h>
@@ -186,9 +189,16 @@ struct sve_context {
186189
* sve_context.vl must equal the thread's current vector length when
187190
* doing a sigreturn.
188191
*
192+
* On systems with support for SME the SVE register state may reflect either
193+
* streaming or non-streaming mode. In streaming mode the streaming mode
194+
* vector length will be used and the flag SVE_SIG_FLAG_SM will be set in
195+
* the flags field. It is permitted to enter or leave streaming mode in
196+
* a signal return, applications should take care to ensure that any difference
197+
* in vector length between the two modes is handled, including any resizing
198+
* and movement of context blocks.
189199
*
190-
* Note: for all these macros, the "vq" argument denotes the SVE
191-
* vector length in quadwords (i.e., units of 128 bits).
200+
* Note: for all these macros, the "vq" argument denotes the vector length
201+
* in quadwords (i.e., units of 128 bits).
192202
*
193203
* The correct way to obtain vq is to use sve_vq_from_vl(vl). The
194204
* result is valid if and only if sve_vl_valid(vl) is true. This is

arch/arm64/kernel/signal.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -226,18 +226,25 @@ static int preserve_sve_context(struct sve_context __user *ctx)
226226
{
227227
int err = 0;
228228
u16 reserved[ARRAY_SIZE(ctx->__reserved)];
229+
u16 flags = 0;
229230
unsigned int vl = task_get_sve_vl(current);
230231
unsigned int vq = 0;
231232

232-
if (test_thread_flag(TIF_SVE))
233+
if (thread_sm_enabled(&current->thread)) {
234+
vl = task_get_sme_vl(current);
233235
vq = sve_vq_from_vl(vl);
236+
flags |= SVE_SIG_FLAG_SM;
237+
} else if (test_thread_flag(TIF_SVE)) {
238+
vq = sve_vq_from_vl(vl);
239+
}
234240

235241
memset(reserved, 0, sizeof(reserved));
236242

237243
__put_user_error(SVE_MAGIC, &ctx->head.magic, err);
238244
__put_user_error(round_up(SVE_SIG_CONTEXT_SIZE(vq), 16),
239245
&ctx->head.size, err);
240246
__put_user_error(vl, &ctx->vl, err);
247+
__put_user_error(flags, &ctx->flags, err);
241248
BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
242249
err |= __copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
243250

@@ -258,18 +265,28 @@ static int preserve_sve_context(struct sve_context __user *ctx)
258265
static int restore_sve_fpsimd_context(struct user_ctxs *user)
259266
{
260267
int err;
261-
unsigned int vq;
268+
unsigned int vl, vq;
262269
struct user_fpsimd_state fpsimd;
263270
struct sve_context sve;
264271

265272
if (__copy_from_user(&sve, user->sve, sizeof(sve)))
266273
return -EFAULT;
267274

268-
if (sve.vl != task_get_sve_vl(current))
275+
if (sve.flags & SVE_SIG_FLAG_SM) {
276+
if (!system_supports_sme())
277+
return -EINVAL;
278+
279+
vl = task_get_sme_vl(current);
280+
} else {
281+
vl = task_get_sve_vl(current);
282+
}
283+
284+
if (sve.vl != vl)
269285
return -EINVAL;
270286

271287
if (sve.head.size <= sizeof(*user->sve)) {
272288
clear_thread_flag(TIF_SVE);
289+
current->thread.svcr &= ~SYS_SVCR_EL0_SM_MASK;
273290
goto fpsimd_only;
274291
}
275292

@@ -301,7 +318,10 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
301318
if (err)
302319
return -EFAULT;
303320

304-
set_thread_flag(TIF_SVE);
321+
if (sve.flags & SVE_SIG_FLAG_SM)
322+
current->thread.svcr |= SYS_SVCR_EL0_SM_MASK;
323+
else
324+
set_thread_flag(TIF_SVE);
305325

306326
fpsimd_only:
307327
/* copy the FP and status/control registers */
@@ -393,7 +413,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
393413
break;
394414

395415
case SVE_MAGIC:
396-
if (!system_supports_sve())
416+
if (!system_supports_sve() && !system_supports_sme())
397417
goto invalid;
398418

399419
if (user->sve)
@@ -594,11 +614,12 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
594614
if (system_supports_sve()) {
595615
unsigned int vq = 0;
596616

597-
if (add_all || test_thread_flag(TIF_SVE)) {
598-
int vl = sve_max_vl();
617+
if (add_all || test_thread_flag(TIF_SVE) ||
618+
thread_sm_enabled(&current->thread)) {
619+
int vl = max(sve_max_vl(), sme_max_vl());
599620

600621
if (!add_all)
601-
vl = task_get_sve_vl(current);
622+
vl = thread_get_cur_vl(&current->thread);
602623

603624
vq = sve_vq_from_vl(vl);
604625
}
@@ -649,8 +670,9 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
649670
__put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
650671
}
651672

652-
/* Scalable Vector Extension state, if present */
653-
if (system_supports_sve() && err == 0 && user->sve_offset) {
673+
/* Scalable Vector Extension state (including streaming), if present */
674+
if ((system_supports_sve() || system_supports_sme()) &&
675+
err == 0 && user->sve_offset) {
654676
struct sve_context __user *sve_ctx =
655677
apply_user_offset(user, user->sve_offset);
656678
err |= preserve_sve_context(sve_ctx);

0 commit comments

Comments
 (0)