History

arm64/sve: ptrace and ELF coredump support

This patch defines and implements a new regset NT_ARM_SVE, which describes a thread's SVE register state. This allows a debugger to manipulate the SVE state, as well as being included in ELF coredumps for post-mortem debugging. Because the regset size and layout are dependent on the thread's current vector length, it is not possible to define a C struct to describe the regset contents as is done for existing regsets. Instead, and for the same reasons, NT_ARM_SVE is based on the freeform variable-layout approach used for the SVE signal frame. Additionally, to reduce debug overhead when debugging threads that might or might not have live SVE register state, NT_ARM_SVE may be presented in one of two different formats: the old struct user_fpsimd_state format is embedded for describing the state of a thread with no live SVE state, whereas a new variable-layout structure is embedded for describing live SVE state. This avoids a debugger needing to poll NT_PRFPREG in addition to NT_ARM_SVE, and allows existing userspace code to handle the non-SVE case without too much modification. For this to work, NT_ARM_SVE is defined with a fixed-format header of type struct user_sve_header, which the recipient can use to figure out the content, size and layout of the reset of the regset. Accessor macros are defined to allow the vector-length-dependent parts of the regset to be manipulated.

Dave Martin committed 9 years ago

Commit 43d4da21 parent fdfa9765 files · +482 −9Browse files

Unified · Split

5 files
  1. arch/arm64/include/asm/fpsimd.h +11 −1
  2. arch/arm64/include/uapi/asm/ptrace.h +138 −0
  3. arch/arm64/kernel/fpsimd.c +60 −0
  4. arch/arm64/kernel/ptrace.c +272 −8
  5. include/uapi/linux/elf.h +1 −0
arch/arm64/include/asm/fpsimd.h+11−1
@@ -38,13 +38,16 @@ struct fpsimd_state { · 37 unmodified lines
3838 __uint128_t vregs[32];
3939 u32 fpsr;
4040 u32 fpcr;
41+ /*
42+ * For ptrace compatibility, pad to next 128-bit
43+ * boundary here if extending this struct.
44+ */
4145 };
4246 };
4347 /* the id of the last cpu to have restored this state */
4448 unsigned int cpu;
4549 };
4650
47−
4851 #if defined(__KERNEL__) && defined(CONFIG_COMPAT)
4952 /* Masks for extracting the FPSR and FPCR from the FPSCR */
5053 #define VFP_FPSCR_STAT_MASK 0xf800009f
@@ -88,6 +91,10 @@ extern size_t sve_state_size(struct task_struct const *task); · 37 unmodified lines
8891
8992 extern void sve_alloc(struct task_struct *task);
9093 extern void fpsimd_release_task(struct task_struct *task);
94+extern void fpsimd_sync_to_sve(struct task_struct *task);
95+extern void sve_sync_to_fpsimd(struct task_struct *task);
96+extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
97+
9198 extern int sve_set_vector_length(struct task_struct *task,
9299 unsigned long vl, unsigned long flags);
93100
@@ -104,6 +111,9 @@ extern void __init sve_setup(void); · 10 unmodified lines
104111
105112 static inline void sve_alloc(struct task_struct *task) { }
106113 static inline void fpsimd_release_task(struct task_struct *task) { }
114+static inline void sve_sync_to_fpsimd(struct task_struct *task) { }
115+static inline void sve_sync_from_fpsimd_zeropad(struct task_struct *task) { }
116+
107117 static inline void sve_init_vq_map(void) { }
108118 static inline void sve_update_vq_map(void) { }
109119 static inline int sve_verify_vq_map(void) { return 0; }
arch/arm64/include/uapi/asm/ptrace.h+138−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include <linux/types.h>
2323
2424 #include <asm/hwcap.h>
25+#include <asm/sigcontext.h>
2526
2627
2728 /*
@@ -62,6 +63,8 @@ · 34 unmodified lines
6263
6364 #ifndef __ASSEMBLY__
6465
66+#include <linux/prctl.h>
67+
6568 /*
6669 * User structures for general purpose, floating point and debug registers.
6770 */
@@ -89,6 +92,141 @@ struct user_hwdebug_state { · 21 unmodified lines
8992 } dbg_regs[16];
9093 };
9194
95+/* SVE/FP/SIMD state (NT_ARM_SVE) */
96+
97+struct user_sve_header {
98+ __u32 size; /* total meaningful regset content in bytes */
99+ __u32 max_size; /* maxmium possible size for this thread */
100+ __u16 vl; /* current vector length */
101+ __u16 max_vl; /* maximum possible vector length */
102+ __u16 flags;
103+ __u16 __reserved;
104+};
105+
106+/* Definitions for user_sve_header.flags: */
107+#define SVE_PT_REGS_MASK (1 << 0)
108+
109+#define SVE_PT_REGS_FPSIMD 0
110+#define SVE_PT_REGS_SVE SVE_PT_REGS_MASK
111+
112+/*
113+ * Common SVE_PT_* flags:
114+ * These must be kept in sync with prctl interface in <linux/ptrace.h>
115+ */
116+#define SVE_PT_VL_INHERIT (PR_SVE_VL_INHERIT >> 16)
117+#define SVE_PT_VL_ONEXEC (PR_SVE_SET_VL_ONEXEC >> 16)
118+
119+
120+/*
121+ * The remainder of the SVE state follows struct user_sve_header. The
122+ * total size of the SVE state (including header) depends on the
123+ * metadata in the header: SVE_PT_SIZE(vq, flags) gives the total size
124+ * of the state in bytes, including the header.
125+ *
126+ * Refer to <asm/sigcontext.h> for details of how to pass the correct
127+ * "vq" argument to these macros.
128+ */
129+
130+/* Offset from the start of struct user_sve_header to the register data */
131+#define SVE_PT_REGS_OFFSET \
132+ ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \
133+ / SVE_VQ_BYTES * SVE_VQ_BYTES)
134+
135+/*
136+ * The register data content and layout depends on the value of the
137+ * flags field.
138+ */
139+
140+/*
141+ * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD case:
142+ *
143+ * The payload starts at offset SVE_PT_FPSIMD_OFFSET, and is of type
144+ * struct user_fpsimd_state. Additional data might be appended in the
145+ * future: use SVE_PT_FPSIMD_SIZE(vq, flags) to compute the total size.
146+ * SVE_PT_FPSIMD_SIZE(vq, flags) will never be less than
147+ * sizeof(struct user_fpsimd_state).
148+ */
149+
150+#define SVE_PT_FPSIMD_OFFSET SVE_PT_REGS_OFFSET
151+
152+#define SVE_PT_FPSIMD_SIZE(vq, flags) (sizeof(struct user_fpsimd_state))
153+
154+/*
155+ * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE case:
156+ *
157+ * The payload starts at offset SVE_PT_SVE_OFFSET, and is of size
158+ * SVE_PT_SVE_SIZE(vq, flags).
159+ *
160+ * Additional macros describe the contents and layout of the payload.
161+ * For each, SVE_PT_SVE_x_OFFSET(args) is the start offset relative to
162+ * the start of struct user_sve_header, and SVE_PT_SVE_x_SIZE(args) is
163+ * the size in bytes:
164+ *
165+ * x type description
166+ * - ---- -----------
167+ * ZREGS \
168+ * ZREG |
169+ * PREGS | refer to <asm/sigcontext.h>
170+ * PREG |
171+ * FFR /
172+ *
173+ * FPSR uint32_t FPSR
174+ * FPCR uint32_t FPCR
175+ *
176+ * Additional data might be appended in the future.
177+ */
178+
179+#define SVE_PT_SVE_ZREG_SIZE(vq) SVE_SIG_ZREG_SIZE(vq)
180+#define SVE_PT_SVE_PREG_SIZE(vq) SVE_SIG_PREG_SIZE(vq)
181+#define SVE_PT_SVE_FFR_SIZE(vq) SVE_SIG_FFR_SIZE(vq)
182+#define SVE_PT_SVE_FPSR_SIZE sizeof(__u32)
183+#define SVE_PT_SVE_FPCR_SIZE sizeof(__u32)
184+
185+#define __SVE_SIG_TO_PT(offset) \
186+ ((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET)
187+
188+#define SVE_PT_SVE_OFFSET SVE_PT_REGS_OFFSET
189+
190+#define SVE_PT_SVE_ZREGS_OFFSET \
191+ __SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET)
192+#define SVE_PT_SVE_ZREG_OFFSET(vq, n) \
193+ __SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n))
194+#define SVE_PT_SVE_ZREGS_SIZE(vq) \
195+ (SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
196+
197+#define SVE_PT_SVE_PREGS_OFFSET(vq) \
198+ __SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq))
199+#define SVE_PT_SVE_PREG_OFFSET(vq, n) \
200+ __SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n))
201+#define SVE_PT_SVE_PREGS_SIZE(vq) \
202+ (SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \
203+ SVE_PT_SVE_PREGS_OFFSET(vq))
204+
205+#define SVE_PT_SVE_FFR_OFFSET(vq) \
206+ __SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq))
207+
208+#define SVE_PT_SVE_FPSR_OFFSET(vq) \
209+ ((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + \
210+ (SVE_VQ_BYTES - 1)) \
211+ / SVE_VQ_BYTES * SVE_VQ_BYTES)
212+#define SVE_PT_SVE_FPCR_OFFSET(vq) \
213+ (SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE)
214+
215+/*
216+ * Any future extension appended after FPCR must be aligned to the next
217+ * 128-bit boundary.
218+ */
219+
220+#define SVE_PT_SVE_SIZE(vq, flags) \
221+ ((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE \
222+ - SVE_PT_SVE_OFFSET + (SVE_VQ_BYTES - 1)) \
223+ / SVE_VQ_BYTES * SVE_VQ_BYTES)
224+
225+#define SVE_PT_SIZE(vq, flags) \
226+ (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? \
227+ SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags) \
228+ : SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags))
229+
92230 #endif /* __ASSEMBLY__ */
93231
94232 #endif /* _UAPI__ASM_PTRACE_H */
arch/arm64/kernel/fpsimd.c+60−0
@@ -428,6 +428,66 @@ void sve_alloc(struct task_struct *task) · 427 unmodified lines
428428 BUG_ON(!task->thread.sve_state);
429429 }
430430
431+
432+/*
433+ * Ensure that task->thread.sve_state is up to date with respect to
434+ * the user task, irrespective of when SVE is in use or not.
435+ *
436+ * This should only be called by ptrace. task must be non-runnable.
437+ * task->thread.sve_state must point to at least sve_state_size(task)
438+ * bytes of allocated kernel memory.
439+ */
440+void fpsimd_sync_to_sve(struct task_struct *task)
441+{
442+ if (!test_tsk_thread_flag(task, TIF_SVE))
443+ fpsimd_to_sve(task);
444+}
445+
446+/*
447+ * Ensure that task->thread.fpsimd_state is up to date with respect to
448+ * the user task, irrespective of whether SVE is in use or not.
449+ *
450+ * This should only be called by ptrace. task must be non-runnable.
451+ * task->thread.sve_state must point to at least sve_state_size(task)
452+ * bytes of allocated kernel memory.
453+ */
454+void sve_sync_to_fpsimd(struct task_struct *task)
455+{
456+ if (test_tsk_thread_flag(task, TIF_SVE))
457+ sve_to_fpsimd(task);
458+}
459+
460+/*
461+ * Ensure that task->thread.sve_state is up to date with respect to
462+ * the task->thread.fpsimd_state.
463+ *
464+ * This should only be called by ptrace to merge new FPSIMD register
465+ * values into a task for which SVE is currently active.
466+ * task must be non-runnable.
467+ * task->thread.sve_state must point to at least sve_state_size(task)
468+ * bytes of allocated kernel memory.
469+ * task->thread.fpsimd_state must already have been initialised with
470+ * the new FPSIMD register values to be merged in.
471+ */
472+void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
473+{
474+ unsigned int vq;
475+ void *sst = task->thread.sve_state;
476+ struct fpsimd_state const *fst = &task->thread.fpsimd_state;
477+ unsigned int i;
478+
479+ if (!test_tsk_thread_flag(task, TIF_SVE))
480+ return;
481+
482+ vq = sve_vq_from_vl(task->thread.sve_vl);
483+
484+ memset(sst, 0, SVE_SIG_REGS_SIZE(vq));
485+
486+ for (i = 0; i < 32; ++i)
487+ memcpy(ZREG(sst, vq, i), &fst->vregs[i],
488+ sizeof(fst->vregs[i]));
489+}
490+
431491 int sve_set_vector_length(struct task_struct *task,
432492 unsigned long vl, unsigned long flags)
433493 {
arch/arm64/kernel/ptrace.c+272−8
@@ -32,6 +32,7 @@ · 31 unmodified lines
3232 #include <linux/security.h>
3333 #include <linux/init.h>
3434 #include <linux/signal.h>
35+#include <linux/string.h>
3536 #include <linux/uaccess.h>
3637 #include <linux/perf_event.h>
3738 #include <linux/hw_breakpoint.h>
@@ -40,6 +41,7 @@ · 2 unmodified lines
4041 #include <linux/elf.h>
4142
4243 #include <asm/compat.h>
44+#include <asm/cpufeature.h>
4345 #include <asm/debug-monitors.h>
4446 #include <asm/pgtable.h>
4547 #include <asm/stacktrace.h>
@@ -618,17 +620,56 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, · 572 unmodified lines
618620 /*
619621 * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
620622 */
621−static int fpr_get(struct task_struct *target, const struct user_regset *regset,
622− unsigned int pos, unsigned int count,
623− void *kbuf, void __user *ubuf)
623+static int __fpr_get(struct task_struct *target,
624+ const struct user_regset *regset,
625+ unsigned int pos, unsigned int count,
626+ void *kbuf, void __user *ubuf, unsigned int start_pos)
624627 {
625628 struct user_fpsimd_state *uregs;
629+
630+ sve_sync_to_fpsimd(target);
631+
626632 uregs = &target->thread.fpsimd_state.user_fpsimd;
627633
634+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
635+ start_pos, start_pos + sizeof(*uregs));
636+}
637+
638+static int fpr_get(struct task_struct *target, const struct user_regset *regset,
639+ unsigned int pos, unsigned int count,
640+ void *kbuf, void __user *ubuf)
641+{
628642 if (target == current)
629643 fpsimd_preserve_current_state();
630644
631− return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
645+ return __fpr_get(target, regset, pos, count, kbuf, ubuf, 0);
646+}
647+
648+static int __fpr_set(struct task_struct *target,
649+ const struct user_regset *regset,
650+ unsigned int pos, unsigned int count,
651+ const void *kbuf, const void __user *ubuf,
652+ unsigned int start_pos)
653+{
654+ int ret;
655+ struct user_fpsimd_state newstate;
656+
657+ /*
658+ * Ensure target->thread.fpsimd_state is up to date, so that a
659+ * short copyin can't resurrect stale data.
660+ */
661+ sve_sync_to_fpsimd(target);
662+
663+ newstate = target->thread.fpsimd_state.user_fpsimd;
664+
665+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate,
666+ start_pos, start_pos + sizeof(newstate));
667+ if (ret)
668+ return ret;
669+
670+ target->thread.fpsimd_state.user_fpsimd = newstate;
671+
672+ return ret;
632673 }
633674
634675 static int fpr_set(struct task_struct *target, const struct user_regset *regset,
@@ -636,15 +677,14 @@ static int fpr_set(struct task_struct *target, const struct user_regset *regset, · 1 unmodified line
636677 const void *kbuf, const void __user *ubuf)
637678 {
638679 int ret;
639− struct user_fpsimd_state newstate =
640− target->thread.fpsimd_state.user_fpsimd;
641680
642− ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
681+ ret = __fpr_set(target, regset, pos, count, kbuf, ubuf, 0);
643682 if (ret)
644683 return ret;
645684
646− target->thread.fpsimd_state.user_fpsimd = newstate;
685+ sve_sync_from_fpsimd_zeropad(target);
647686 fpsimd_flush_task_state(target);
687+
648688 return ret;
649689 }
650690
@@ -702,6 +742,215 @@ static int system_call_set(struct task_struct *target, · 51 unmodified lines
702742 return ret;
703743 }
704744
745+#ifdef CONFIG_ARM64_SVE
746+
747+static void sve_init_header_from_task(struct user_sve_header *header,
748+ struct task_struct *target)
749+{
750+ unsigned int vq;
751+
752+ memset(header, 0, sizeof(*header));
753+
754+ header->flags = test_tsk_thread_flag(target, TIF_SVE) ?
755+ SVE_PT_REGS_SVE : SVE_PT_REGS_FPSIMD;
756+ if (test_tsk_thread_flag(target, TIF_SVE_VL_INHERIT))
757+ header->flags |= SVE_PT_VL_INHERIT;
758+
759+ header->vl = target->thread.sve_vl;
760+ vq = sve_vq_from_vl(header->vl);
761+
762+ header->max_vl = sve_max_vl;
763+ if (WARN_ON(!sve_vl_valid(sve_max_vl)))
764+ header->max_vl = header->vl;
765+
766+ header->size = SVE_PT_SIZE(vq, header->flags);
767+ header->max_size = SVE_PT_SIZE(sve_vq_from_vl(header->max_vl),
768+ SVE_PT_REGS_SVE);
769+}
770+
771+static unsigned int sve_size_from_header(struct user_sve_header const *header)
772+{
773+ return ALIGN(header->size, SVE_VQ_BYTES);
774+}
775+
776+static unsigned int sve_get_size(struct task_struct *target,
777+ const struct user_regset *regset)
778+{
779+ struct user_sve_header header;
780+
781+ if (!system_supports_sve())
782+ return 0;
783+
784+ sve_init_header_from_task(&header, target);
785+ return sve_size_from_header(&header);
786+}
787+
788+static int sve_get(struct task_struct *target,
789+ const struct user_regset *regset,
790+ unsigned int pos, unsigned int count,
791+ void *kbuf, void __user *ubuf)
792+{
793+ int ret;
794+ struct user_sve_header header;
795+ unsigned int vq;
796+ unsigned long start, end;
797+
798+ if (!system_supports_sve())
799+ return -EINVAL;
800+
801+ /* Header */
802+ sve_init_header_from_task(&header, target);
803+ vq = sve_vq_from_vl(header.vl);
804+
805+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header,
806+ 0, sizeof(header));
807+ if (ret)
808+ return ret;
809+
810+ if (target == current)
811+ fpsimd_preserve_current_state();
812+
813+ /* Registers: FPSIMD-only case */
814+
815+ BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
816+ if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
817+ return __fpr_get(target, regset, pos, count, kbuf, ubuf,
818+ SVE_PT_FPSIMD_OFFSET);
819+
820+ /* Otherwise: full SVE case */
821+
822+ BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
823+ start = SVE_PT_SVE_OFFSET;
824+ end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
825+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
826+ target->thread.sve_state,
827+ start, end);
828+ if (ret)
829+ return ret;
830+
831+ start = end;
832+ end = SVE_PT_SVE_FPSR_OFFSET(vq);
833+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
834+ start, end);
835+ if (ret)
836+ return ret;
837+
838+ /*
839+ * Copy fpsr, and fpcr which must follow contiguously in
840+ * struct fpsimd_state:
841+ */
842+ start = end;
843+ end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
844+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
845+ &target->thread.fpsimd_state.fpsr,
846+ start, end);
847+ if (ret)
848+ return ret;
849+
850+ start = end;
851+ end = sve_size_from_header(&header);
852+ return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
853+ start, end);
854+}
855+
856+static int sve_set(struct task_struct *target,
857+ const struct user_regset *regset,
858+ unsigned int pos, unsigned int count,
859+ const void *kbuf, const void __user *ubuf)
860+{
861+ int ret;
862+ struct user_sve_header header;
863+ unsigned int vq;
864+ unsigned long start, end;
865+
866+ if (!system_supports_sve())
867+ return -EINVAL;
868+
869+ /* Header */
870+ if (count < sizeof(header))
871+ return -EINVAL;
872+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &header,
873+ 0, sizeof(header));
874+ if (ret)
875+ goto out;
876+
877+ /*
878+ * Apart from PT_SVE_REGS_MASK, all PT_SVE_* flags are consumed by
879+ * sve_set_vector_length(), which will also validate them for us:
880+ */
881+ ret = sve_set_vector_length(target, header.vl,
882+ ((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16);
883+ if (ret)
884+ goto out;
885+
886+ /* Actual VL set may be less than the user asked for: */
887+ vq = sve_vq_from_vl(target->thread.sve_vl);
888+
889+ /* Registers: FPSIMD-only case */
890+
891+ BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
892+ if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) {
893+ ret = __fpr_set(target, regset, pos, count, kbuf, ubuf,
894+ SVE_PT_FPSIMD_OFFSET);
895+ clear_tsk_thread_flag(target, TIF_SVE);
896+ goto out;
897+ }
898+
899+ /* Otherwise: full SVE case */
900+
901+ /*
902+ * If setting a different VL from the requested VL and there is
903+ * register data, the data layout will be wrong: don't even
904+ * try to set the registers in this case.
905+ */
906+ if (count && vq != sve_vq_from_vl(header.vl)) {
907+ ret = -EIO;
908+ goto out;
909+ }
910+
911+ sve_alloc(target);
912+
913+ /*
914+ * Ensure target->thread.sve_state is up to date with target's
915+ * FPSIMD regs, so that a short copyin leaves trailing registers
916+ * unmodified.
917+ */
918+ fpsimd_sync_to_sve(target);
919+ set_tsk_thread_flag(target, TIF_SVE);
920+
921+ BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
922+ start = SVE_PT_SVE_OFFSET;
923+ end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
924+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
925+ target->thread.sve_state,
926+ start, end);
927+ if (ret)
928+ goto out;
929+
930+ start = end;
931+ end = SVE_PT_SVE_FPSR_OFFSET(vq);
932+ ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
933+ start, end);
934+ if (ret)
935+ goto out;
936+
937+ /*
938+ * Copy fpsr, and fpcr which must follow contiguously in
939+ * struct fpsimd_state:
940+ */
941+ start = end;
942+ end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
943+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
944+ &target->thread.fpsimd_state.fpsr,
945+ start, end);
946+
947+out:
948+ fpsimd_flush_task_state(target);
949+ return ret;
950+}
951+
952+#endif /* CONFIG_ARM64_SVE */
953+
705954 enum aarch64_regset {
706955 REGSET_GPR,
707956 REGSET_FPR,
@@ -711,6 +960,9 @@ enum aarch64_regset { · 3 unmodified lines
711960 REGSET_HW_WATCH,
712961 #endif
713962 REGSET_SYSTEM_CALL,
963+#ifdef CONFIG_ARM64_SVE
964+ REGSET_SVE,
965+#endif
714966 };
715967
716968 static const struct user_regset aarch64_regsets[] = {
@@ -768,6 +1020,18 @@ static const struct user_regset aarch64_regsets[] = { · 51 unmodified lines
7681020 .get = system_call_get,
7691021 .set = system_call_set,
7701022 },
1023+#ifdef CONFIG_ARM64_SVE
1024+ [REGSET_SVE] = { /* Scalable Vector Extension */
1025+ .core_note_type = NT_ARM_SVE,
1026+ .n = DIV_ROUND_UP(SVE_PT_SIZE(SVE_VQ_MAX, SVE_PT_REGS_SVE),
1027+ SVE_VQ_BYTES),
1028+ .size = SVE_VQ_BYTES,
1029+ .align = SVE_VQ_BYTES,
1030+ .get = sve_get,
1031+ .set = sve_set,
1032+ .get_size = sve_get_size,
1033+ },
1034+#endif
7711035 };
7721036
7731037 static const struct user_regset_view user_aarch64_view = {
include/uapi/linux/elf.h+1−0
@@ -416,6 +416,7 @@ typedef struct elf64_shdr { · 415 unmodified lines
416416 #define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
417417 #define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
418418 #define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
419+#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */
419420 #define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */
420421 #define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */
421422 #define NT_METAG_TLS 0x502 /* Metag TLS pointer */