Skip to content

Commit e12310a

Browse files
brooniectmarinas
authored andcommitted
arm64/sme: Implement ptrace support for streaming mode SVE registers
The streaming mode SVE registers are represented using the same data structures as for SVE but since the vector lengths supported and in use may not be the same as SVE we represent them with a new type NT_ARM_SSVE. Unfortunately we only have a single 16 bit reserved field available in the header so there is no space to fit the current and maximum vector length for both standard and streaming SVE mode without redefining the structure in a way the creates a complicatd and fragile ABI. Since FFR is not present in streaming mode it is read and written as zero. Setting NT_ARM_SSVE registers will put the task into streaming mode, similarly setting NT_ARM_SVE registers will exit it. Reads that do not correspond to the current mode of the task will return the header with no register data. For compatibility reasons on write setting no flag for the register type will be interpreted as setting SVE registers, though users can provide no register data as an alternative mechanism for doing so. 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 3978221 commit e12310a

File tree

5 files changed

+201
-59
lines changed

5 files changed

+201
-59
lines changed

arch/arm64/include/asm/fpsimd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ struct vl_info {
144144
extern void sve_alloc(struct task_struct *task);
145145
extern void fpsimd_release_task(struct task_struct *task);
146146
extern void fpsimd_sync_to_sve(struct task_struct *task);
147+
extern void fpsimd_force_sync_to_sve(struct task_struct *task);
147148
extern void sve_sync_to_fpsimd(struct task_struct *task);
148149
extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
149150

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ struct user_hwdebug_state {
109109
} dbg_regs[16];
110110
};
111111

112-
/* SVE/FP/SIMD state (NT_ARM_SVE) */
112+
/* SVE/FP/SIMD state (NT_ARM_SVE & NT_ARM_SSVE) */
113113

114114
struct user_sve_header {
115115
__u32 size; /* total meaningful regset content in bytes */
@@ -220,6 +220,7 @@ struct user_sve_header {
220220
(SVE_PT_SVE_PREG_OFFSET(vq, __SVE_NUM_PREGS) - \
221221
SVE_PT_SVE_PREGS_OFFSET(vq))
222222

223+
/* For streaming mode SVE (SSVE) FFR must be read and written as zero */
223224
#define SVE_PT_SVE_FFR_OFFSET(vq) \
224225
(SVE_PT_REGS_OFFSET + __SVE_FFR_OFFSET(vq))
225226

@@ -240,10 +241,12 @@ struct user_sve_header {
240241
- SVE_PT_SVE_OFFSET + (__SVE_VQ_BYTES - 1)) \
241242
/ __SVE_VQ_BYTES * __SVE_VQ_BYTES)
242243

243-
#define SVE_PT_SIZE(vq, flags) \
244-
(((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? \
245-
SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \
246-
: SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags))
244+
#define SVE_PT_SIZE(vq, flags) \
245+
(((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? \
246+
SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \
247+
: ((((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD ? \
248+
SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags) \
249+
: SVE_PT_REGS_OFFSET)))
247250

248251
/* pointer authentication masks (NT_ARM_PAC_MASK) */
249252

arch/arm64/kernel/fpsimd.c

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ static void fpsimd_to_sve(struct task_struct *task)
643643
if (!system_supports_sve())
644644
return;
645645

646-
vq = sve_vq_from_vl(task_get_sve_vl(task));
646+
vq = sve_vq_from_vl(thread_get_cur_vl(&task->thread));
647647
__fpsimd_to_sve(sst, fst, vq);
648648
}
649649

@@ -660,7 +660,7 @@ static void fpsimd_to_sve(struct task_struct *task)
660660
*/
661661
static void sve_to_fpsimd(struct task_struct *task)
662662
{
663-
unsigned int vq;
663+
unsigned int vq, vl;
664664
void const *sst = task->thread.sve_state;
665665
struct user_fpsimd_state *fst = &task->thread.uw.fpsimd_state;
666666
unsigned int i;
@@ -669,7 +669,8 @@ static void sve_to_fpsimd(struct task_struct *task)
669669
if (!system_supports_sve())
670670
return;
671671

672-
vq = sve_vq_from_vl(task_get_sve_vl(task));
672+
vl = thread_get_cur_vl(&task->thread);
673+
vq = sve_vq_from_vl(vl);
673674
for (i = 0; i < SVE_NUM_ZREGS; ++i) {
674675
p = (__uint128_t const *)ZREG(sst, vq, i);
675676
fst->vregs[i] = arm64_le128_to_cpu(*p);
@@ -717,6 +718,19 @@ void sve_alloc(struct task_struct *task)
717718
}
718719

719720

721+
/*
722+
* Force the FPSIMD state shared with SVE to be updated in the SVE state
723+
* even if the SVE state is the current active state.
724+
*
725+
* This should only be called by ptrace. task must be non-runnable.
726+
* task->thread.sve_state must point to at least sve_state_size(task)
727+
* bytes of allocated kernel memory.
728+
*/
729+
void fpsimd_force_sync_to_sve(struct task_struct *task)
730+
{
731+
fpsimd_to_sve(task);
732+
}
733+
720734
/*
721735
* Ensure that task->thread.sve_state is up to date with respect to
722736
* the user task, irrespective of when SVE is in use or not.
@@ -727,7 +741,8 @@ void sve_alloc(struct task_struct *task)
727741
*/
728742
void fpsimd_sync_to_sve(struct task_struct *task)
729743
{
730-
if (!test_tsk_thread_flag(task, TIF_SVE))
744+
if (!test_tsk_thread_flag(task, TIF_SVE) &&
745+
!thread_sm_enabled(&task->thread))
731746
fpsimd_to_sve(task);
732747
}
733748

@@ -741,7 +756,8 @@ void fpsimd_sync_to_sve(struct task_struct *task)
741756
*/
742757
void sve_sync_to_fpsimd(struct task_struct *task)
743758
{
744-
if (test_tsk_thread_flag(task, TIF_SVE))
759+
if (test_tsk_thread_flag(task, TIF_SVE) ||
760+
thread_sm_enabled(&task->thread))
745761
sve_to_fpsimd(task);
746762
}
747763

@@ -766,7 +782,7 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
766782
if (!test_tsk_thread_flag(task, TIF_SVE))
767783
return;
768784

769-
vq = sve_vq_from_vl(task_get_sve_vl(task));
785+
vq = sve_vq_from_vl(thread_get_cur_vl(&task->thread));
770786

771787
memset(sst, 0, SVE_SIG_REGS_SIZE(vq));
772788
__fpsimd_to_sve(sst, fst, vq);
@@ -810,8 +826,7 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type,
810826
/*
811827
* To ensure the FPSIMD bits of the SVE vector registers are preserved,
812828
* write any live register state back to task_struct, and convert to a
813-
* regular FPSIMD thread. Since the vector length can only be changed
814-
* with a syscall we can't be in streaming mode while reconfiguring.
829+
* regular FPSIMD thread.
815830
*/
816831
if (task == current) {
817832
get_cpu_fpsimd_context();

0 commit comments

Comments
 (0)