Skip to content

Commit baa8515

Browse files
brooniewilldeacon
authored andcommitted
arm64/fpsimd: Track the saved FPSIMD state type separately to TIF_SVE
When we save the state for the floating point registers this can be done in the form visible through either the FPSIMD V registers or the SVE Z and P registers. At present we track which format is currently used based on TIF_SVE and the SME streaming mode state but particularly in the SVE case this limits our options for optimising things, especially around syscalls. Introduce a new enum which we place together with saved floating point state in both thread_struct and the KVM guest state which explicitly states which format is active and keep it up to date when we change it. At present we do not use this state except to verify that it has the expected value when loading the state, future patches will introduce functional changes. Signed-off-by: Mark Brown <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Reviewed-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 93ae6b0 commit baa8515

File tree

8 files changed

+74
-19
lines changed

8 files changed

+74
-19
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ extern void fpsimd_kvm_prepare(void);
6161
extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
6262
void *sve_state, unsigned int sve_vl,
6363
void *za_state, unsigned int sme_vl,
64-
u64 *svcr);
64+
u64 *svcr, enum fp_type *type);
6565

6666
extern void fpsimd_flush_task_state(struct task_struct *target);
6767
extern void fpsimd_save_and_flush_cpu_state(void);

arch/arm64/include/asm/kvm_host.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,18 @@ struct vcpu_reset_state {
306306
struct kvm_vcpu_arch {
307307
struct kvm_cpu_context ctxt;
308308

309-
/* Guest floating point state */
309+
/*
310+
* Guest floating point state
311+
*
312+
* The architecture has two main floating point extensions,
313+
* the original FPSIMD and SVE. These have overlapping
314+
* register views, with the FPSIMD V registers occupying the
315+
* low 128 bits of the SVE Z registers. When the core
316+
* floating point code saves the register state of a task it
317+
* records which view it saved in fp_type.
318+
*/
310319
void *sve_state;
320+
enum fp_type fp_type;
311321
unsigned int sve_max_vl;
312322
u64 svcr;
313323

arch/arm64/include/asm/processor.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ enum vec_type {
122122
ARM64_VEC_MAX,
123123
};
124124

125+
enum fp_type {
126+
FP_STATE_FPSIMD,
127+
FP_STATE_SVE,
128+
};
129+
125130
struct cpu_context {
126131
unsigned long x19;
127132
unsigned long x20;
@@ -152,6 +157,7 @@ struct thread_struct {
152157
struct user_fpsimd_state fpsimd_state;
153158
} uw;
154159

160+
enum fp_type fp_type; /* registers FPSIMD or SVE? */
155161
unsigned int fpsimd_cpu;
156162
void *sve_state; /* SVE registers, if any */
157163
void *za_state; /* ZA register, if any */

arch/arm64/kernel/fpsimd.c

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ struct fpsimd_last_state_struct {
125125
u64 *svcr;
126126
unsigned int sve_vl;
127127
unsigned int sme_vl;
128+
enum fp_type *fp_type;
128129
};
129130

130131
static DEFINE_PER_CPU(struct fpsimd_last_state_struct, fpsimd_last_state);
@@ -330,15 +331,6 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
330331
* The task can execute SVE instructions while in userspace without
331332
* trapping to the kernel.
332333
*
333-
* When stored, Z0-Z31 (incorporating Vn in bits[127:0] or the
334-
* corresponding Zn), P0-P15 and FFR are encoded in
335-
* task->thread.sve_state, formatted appropriately for vector
336-
* length task->thread.sve_vl or, if SVCR.SM is set,
337-
* task->thread.sme_vl.
338-
*
339-
* task->thread.sve_state must point to a valid buffer at least
340-
* sve_state_size(task) bytes in size.
341-
*
342334
* During any syscall, the kernel may optionally clear TIF_SVE and
343335
* discard the vector state except for the FPSIMD subset.
344336
*
@@ -348,7 +340,15 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
348340
* do_sve_acc() to be called, which does some preparation and then
349341
* sets TIF_SVE.
350342
*
351-
* When stored, FPSIMD registers V0-V31 are encoded in
343+
* During any syscall, the kernel may optionally clear TIF_SVE and
344+
* discard the vector state except for the FPSIMD subset.
345+
*
346+
* The data will be stored in one of two formats:
347+
*
348+
* * FPSIMD only - FP_STATE_FPSIMD:
349+
*
350+
* When the FPSIMD only state stored task->thread.fp_type is set to
351+
* FP_STATE_FPSIMD, the FPSIMD registers V0-V31 are encoded in
352352
* task->thread.uw.fpsimd_state; bits [max : 128] for each of Z0-Z31 are
353353
* logically zero but not stored anywhere; P0-P15 and FFR are not
354354
* stored and have unspecified values from userspace's point of
@@ -358,6 +358,19 @@ void task_set_vl_onexec(struct task_struct *task, enum vec_type type,
358358
* task->thread.sve_state does not need to be non-NULL, valid or any
359359
* particular size: it must not be dereferenced.
360360
*
361+
* * SVE state - FP_STATE_SVE:
362+
*
363+
* When the full SVE state is stored task->thread.fp_type is set to
364+
* FP_STATE_SVE and Z0-Z31 (incorporating Vn in bits[127:0] or the
365+
* corresponding Zn), P0-P15 and FFR are encoded in in
366+
* task->thread.sve_state, formatted appropriately for vector
367+
* length task->thread.sve_vl or, if SVCR.SM is set,
368+
* task->thread.sme_vl. The storage for the vector registers in
369+
* task->thread.uw.fpsimd_state should be ignored.
370+
*
371+
* task->thread.sve_state must point to a valid buffer at least
372+
* sve_state_size(task) bytes in size.
373+
*
361374
* * FPSR and FPCR are always stored in task->thread.uw.fpsimd_state
362375
* irrespective of whether TIF_SVE is clear or set, since these are
363376
* not vector length dependent.
@@ -404,12 +417,15 @@ static void task_fpsimd_load(void)
404417
}
405418
}
406419

407-
if (restore_sve_regs)
420+
if (restore_sve_regs) {
421+
WARN_ON_ONCE(current->thread.fp_type != FP_STATE_SVE);
408422
sve_load_state(sve_pffr(&current->thread),
409423
&current->thread.uw.fpsimd_state.fpsr,
410424
restore_ffr);
411-
else
425+
} else {
426+
WARN_ON_ONCE(current->thread.fp_type != FP_STATE_FPSIMD);
412427
fpsimd_load_state(&current->thread.uw.fpsimd_state);
428+
}
413429
}
414430

415431
/*
@@ -474,8 +490,10 @@ static void fpsimd_save(void)
474490
sve_save_state((char *)last->sve_state +
475491
sve_ffr_offset(vl),
476492
&last->st->fpsr, save_ffr);
493+
*last->fp_type = FP_STATE_SVE;
477494
} else {
478495
fpsimd_save_state(last->st);
496+
*last->fp_type = FP_STATE_FPSIMD;
479497
}
480498
}
481499

@@ -848,8 +866,10 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type,
848866

849867
fpsimd_flush_task_state(task);
850868
if (test_and_clear_tsk_thread_flag(task, TIF_SVE) ||
851-
thread_sm_enabled(&task->thread))
869+
thread_sm_enabled(&task->thread)) {
852870
sve_to_fpsimd(task);
871+
task->thread.fp_type = FP_STATE_FPSIMD;
872+
}
853873

854874
if (system_supports_sme() && type == ARM64_VEC_SME) {
855875
task->thread.svcr &= ~(SVCR_SM_MASK |
@@ -1368,6 +1388,7 @@ static void sve_init_regs(void)
13681388
fpsimd_bind_task_to_cpu();
13691389
} else {
13701390
fpsimd_to_sve(current);
1391+
current->thread.fp_type = FP_STATE_SVE;
13711392
}
13721393
}
13731394

@@ -1596,6 +1617,8 @@ void fpsimd_flush_thread(void)
15961617
current->thread.svcr = 0;
15971618
}
15981619

1620+
current->thread.fp_type = FP_STATE_FPSIMD;
1621+
15991622
put_cpu_fpsimd_context();
16001623
kfree(sve_state);
16011624
kfree(za_state);
@@ -1644,8 +1667,10 @@ void fpsimd_kvm_prepare(void)
16441667
*/
16451668
get_cpu_fpsimd_context();
16461669

1647-
if (test_and_clear_thread_flag(TIF_SVE))
1670+
if (test_and_clear_thread_flag(TIF_SVE)) {
16481671
sve_to_fpsimd(current);
1672+
current->thread.fp_type = FP_STATE_FPSIMD;
1673+
}
16491674

16501675
put_cpu_fpsimd_context();
16511676
}
@@ -1667,6 +1692,7 @@ static void fpsimd_bind_task_to_cpu(void)
16671692
last->sve_vl = task_get_sve_vl(current);
16681693
last->sme_vl = task_get_sme_vl(current);
16691694
last->svcr = &current->thread.svcr;
1695+
last->fp_type = &current->thread.fp_type;
16701696
current->thread.fpsimd_cpu = smp_processor_id();
16711697

16721698
/*
@@ -1690,7 +1716,8 @@ static void fpsimd_bind_task_to_cpu(void)
16901716

16911717
void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
16921718
unsigned int sve_vl, void *za_state,
1693-
unsigned int sme_vl, u64 *svcr)
1719+
unsigned int sme_vl, u64 *svcr,
1720+
enum fp_type *type)
16941721
{
16951722
struct fpsimd_last_state_struct *last =
16961723
this_cpu_ptr(&fpsimd_last_state);
@@ -1704,6 +1731,7 @@ void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *st, void *sve_state,
17041731
last->za_state = za_state;
17051732
last->sve_vl = sve_vl;
17061733
last->sme_vl = sme_vl;
1734+
last->fp_type = type;
17071735
}
17081736

17091737
/*

arch/arm64/kernel/process.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
331331
clear_tsk_thread_flag(dst, TIF_SME);
332332
}
333333

334+
dst->thread.fp_type = FP_STATE_FPSIMD;
335+
334336
/* clear any pending asynchronous tag fault raised by the parent */
335337
clear_tsk_thread_flag(dst, TIF_MTE_ASYNC_FAULT);
336338

arch/arm64/kernel/ptrace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ static int sve_set_common(struct task_struct *target,
909909
clear_tsk_thread_flag(target, TIF_SVE);
910910
if (type == ARM64_VEC_SME)
911911
fpsimd_force_sync_to_sve(target);
912+
target->thread.fp_type = FP_STATE_FPSIMD;
912913
goto out;
913914
}
914915

@@ -931,6 +932,7 @@ static int sve_set_common(struct task_struct *target,
931932
if (!target->thread.sve_state) {
932933
ret = -ENOMEM;
933934
clear_tsk_thread_flag(target, TIF_SVE);
935+
target->thread.fp_type = FP_STATE_FPSIMD;
934936
goto out;
935937
}
936938

@@ -942,6 +944,7 @@ static int sve_set_common(struct task_struct *target,
942944
*/
943945
fpsimd_sync_to_sve(target);
944946
set_tsk_thread_flag(target, TIF_SVE);
947+
target->thread.fp_type = FP_STATE_SVE;
945948

946949
BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
947950
start = SVE_PT_SVE_OFFSET;

arch/arm64/kernel/signal.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
207207
__get_user_error(fpsimd.fpcr, &ctx->fpcr, err);
208208

209209
clear_thread_flag(TIF_SVE);
210+
current->thread.fp_type = FP_STATE_FPSIMD;
210211

211212
/* load the hardware registers from the fpsimd_state structure */
212213
if (!err)
@@ -292,6 +293,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
292293
if (sve.head.size <= sizeof(*user->sve)) {
293294
clear_thread_flag(TIF_SVE);
294295
current->thread.svcr &= ~SVCR_SM_MASK;
296+
current->thread.fp_type = FP_STATE_FPSIMD;
295297
goto fpsimd_only;
296298
}
297299

@@ -327,6 +329,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user)
327329
current->thread.svcr |= SVCR_SM_MASK;
328330
else
329331
set_thread_flag(TIF_SVE);
332+
current->thread.fp_type = FP_STATE_SVE;
330333

331334
fpsimd_only:
332335
/* copy the FP and status/control registers */
@@ -932,9 +935,11 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
932935
* FPSIMD register state - flush the saved FPSIMD
933936
* register state in case it gets loaded.
934937
*/
935-
if (current->thread.svcr & SVCR_SM_MASK)
938+
if (current->thread.svcr & SVCR_SM_MASK) {
936939
memset(&current->thread.uw.fpsimd_state, 0,
937940
sizeof(current->thread.uw.fpsimd_state));
941+
current->thread.fp_type = FP_STATE_FPSIMD;
942+
}
938943

939944
current->thread.svcr &= ~(SVCR_ZA_MASK |
940945
SVCR_SM_MASK);

arch/arm64/kvm/fpsimd.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
140140
fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.fp_regs,
141141
vcpu->arch.sve_state,
142142
vcpu->arch.sve_max_vl,
143-
NULL, 0, &vcpu->arch.svcr);
143+
NULL, 0, &vcpu->arch.svcr,
144+
&vcpu->arch.fp_type);
144145

145146
clear_thread_flag(TIF_FOREIGN_FPSTATE);
146147
update_thread_flag(TIF_SVE, vcpu_has_sve(vcpu));

0 commit comments

Comments
 (0)