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
38 __uint128_t vregs[32];38 __uint128_t vregs[32];
39 u32 fpsr;39 u32 fpsr;
40 u32 fpcr;40 u32 fpcr;
41 /*
42 * For ptrace compatibility, pad to next 128-bit
43 * boundary here if extending this struct.
44 */
41 };45 };
42 };46 };
43 /* the id of the last cpu to have restored this state */47 /* the id of the last cpu to have restored this state */
44 unsigned int cpu;48 unsigned int cpu;
45};49};
46 50
47
48#if defined(__KERNEL__) && defined(CONFIG_COMPAT)51#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
49/* Masks for extracting the FPSR and FPCR from the FPSCR */52/* Masks for extracting the FPSR and FPCR from the FPSCR */
50#define VFP_FPSCR_STAT_MASK 0xf800009f53#define VFP_FPSCR_STAT_MASK 0xf800009f
@@ -88,6 +91,10 @@ extern size_t sve_state_size(struct task_struct const *task); · 37 unmodified lines
88 91
89extern void sve_alloc(struct task_struct *task);92extern void sve_alloc(struct task_struct *task);
90extern void fpsimd_release_task(struct task_struct *task);93extern void fpsimd_release_task(struct task_struct *task);
94extern void fpsimd_sync_to_sve(struct task_struct *task);
95extern void sve_sync_to_fpsimd(struct task_struct *task);
96extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
97
91extern int sve_set_vector_length(struct task_struct *task,98extern int sve_set_vector_length(struct task_struct *task,
92 unsigned long vl, unsigned long flags);99 unsigned long vl, unsigned long flags);
93 100
@@ -104,6 +111,9 @@ extern void __init sve_setup(void); · 10 unmodified lines
104 111
105static inline void sve_alloc(struct task_struct *task) { }112static inline void sve_alloc(struct task_struct *task) { }
106static inline void fpsimd_release_task(struct task_struct *task) { }113static inline void fpsimd_release_task(struct task_struct *task) { }
114static inline void sve_sync_to_fpsimd(struct task_struct *task) { }
115static inline void sve_sync_from_fpsimd_zeropad(struct task_struct *task) { }
116
107static inline void sve_init_vq_map(void) { }117static inline void sve_init_vq_map(void) { }
108static inline void sve_update_vq_map(void) { }118static inline void sve_update_vq_map(void) { }
109static inline int sve_verify_vq_map(void) { return 0; }119static 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
22#include <linux/types.h>22#include <linux/types.h>
23 23
24#include <asm/hwcap.h>24#include <asm/hwcap.h>
25#include <asm/sigcontext.h>
25 26
26 27
27/*28/*
@@ -62,6 +63,8 @@ · 34 unmodified lines
62 63
63#ifndef __ASSEMBLY__64#ifndef __ASSEMBLY__
64 65
66#include <linux/prctl.h>
67
65/*68/*
66 * User structures for general purpose, floating point and debug registers.69 * User structures for general purpose, floating point and debug registers.
67 */70 */
@@ -89,6 +92,141 @@ struct user_hwdebug_state { · 21 unmodified lines
89 } dbg_regs[16];92 } dbg_regs[16];
90};93};
91 94
95/* SVE/FP/SIMD state (NT_ARM_SVE) */
96
97struct 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
92#endif /* __ASSEMBLY__ */230#endif /* __ASSEMBLY__ */
93 231
94#endif /* _UAPI__ASM_PTRACE_H */232#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
428 BUG_ON(!task->thread.sve_state);428 BUG_ON(!task->thread.sve_state);
429}429}
430 430
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 */
440void 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 */
454void 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 */
472void 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
431int sve_set_vector_length(struct task_struct *task,491int sve_set_vector_length(struct task_struct *task,
432 unsigned long vl, unsigned long flags)492 unsigned long vl, unsigned long flags)
433{493{
arch/arm64/kernel/ptrace.c+272−8
@@ -32,6 +32,7 @@ · 31 unmodified lines
32#include <linux/security.h>32#include <linux/security.h>
33#include <linux/init.h>33#include <linux/init.h>
34#include <linux/signal.h>34#include <linux/signal.h>
35#include <linux/string.h>
35#include <linux/uaccess.h>36#include <linux/uaccess.h>
36#include <linux/perf_event.h>37#include <linux/perf_event.h>
37#include <linux/hw_breakpoint.h>38#include <linux/hw_breakpoint.h>
@@ -40,6 +41,7 @@ · 2 unmodified lines
40#include <linux/elf.h>41#include <linux/elf.h>
41 42
42#include <asm/compat.h>43#include <asm/compat.h>
44#include <asm/cpufeature.h>
43#include <asm/debug-monitors.h>45#include <asm/debug-monitors.h>
44#include <asm/pgtable.h>46#include <asm/pgtable.h>
45#include <asm/stacktrace.h>47#include <asm/stacktrace.h>
@@ -618,17 +620,56 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset, · 572 unmodified lines
618/*620/*
619 * TODO: update fp accessors for lazy context switching (sync/flush hwstate)621 * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
620 */622 */
621static int fpr_get(struct task_struct *target, const struct user_regset *regset,623static int __fpr_get(struct task_struct *target,
622 unsigned int pos, unsigned int count,624 const struct user_regset *regset,
623 void *kbuf, void __user *ubuf)625 unsigned int pos, unsigned int count,
626 void *kbuf, void __user *ubuf, unsigned int start_pos)
624{627{
625 struct user_fpsimd_state *uregs;628 struct user_fpsimd_state *uregs;
629
630 sve_sync_to_fpsimd(target);
631
626 uregs = &target->thread.fpsimd_state.user_fpsimd;632 uregs = &target->thread.fpsimd_state.user_fpsimd;
627 633
634 return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
635 start_pos, start_pos + sizeof(*uregs));
636}
637
638static 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{
628 if (target == current)642 if (target == current)
629 fpsimd_preserve_current_state();643 fpsimd_preserve_current_state();
630 644
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
648static 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;
632}673}
633 674
634static int fpr_set(struct task_struct *target, const struct user_regset *regset,675static 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
636 const void *kbuf, const void __user *ubuf)677 const void *kbuf, const void __user *ubuf)
637{678{
638 int ret;679 int ret;
639 struct user_fpsimd_state newstate =
640 target->thread.fpsimd_state.user_fpsimd;
641 680
642 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);681 ret = __fpr_set(target, regset, pos, count, kbuf, ubuf, 0);
643 if (ret)682 if (ret)
644 return ret;683 return ret;
645 684
646 target->thread.fpsimd_state.user_fpsimd = newstate;685 sve_sync_from_fpsimd_zeropad(target);
647 fpsimd_flush_task_state(target);686 fpsimd_flush_task_state(target);
687
648 return ret;688 return ret;
649}689}
650 690
@@ -702,6 +742,215 @@ static int system_call_set(struct task_struct *target, · 51 unmodified lines
702 return ret;742 return ret;
703}743}
704 744
745#ifdef CONFIG_ARM64_SVE
746
747static 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
771static unsigned int sve_size_from_header(struct user_sve_header const *header)
772{
773 return ALIGN(header->size, SVE_VQ_BYTES);
774}
775
776static 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
788static 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
856static 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
947out:
948 fpsimd_flush_task_state(target);
949 return ret;
950}
951
952#endif /* CONFIG_ARM64_SVE */
953
705enum aarch64_regset {954enum aarch64_regset {
706 REGSET_GPR,955 REGSET_GPR,
707 REGSET_FPR,956 REGSET_FPR,
@@ -711,6 +960,9 @@ enum aarch64_regset { · 3 unmodified lines
711 REGSET_HW_WATCH,960 REGSET_HW_WATCH,
712#endif961#endif
713 REGSET_SYSTEM_CALL,962 REGSET_SYSTEM_CALL,
963#ifdef CONFIG_ARM64_SVE
964 REGSET_SVE,
965#endif
714};966};
715 967
716static const struct user_regset aarch64_regsets[] = {968static const struct user_regset aarch64_regsets[] = {
@@ -768,6 +1020,18 @@ static const struct user_regset aarch64_regsets[] = { · 51 unmodified lines
768 .get = system_call_get,1020 .get = system_call_get,
769 .set = system_call_set,1021 .set = system_call_set,
770 },1022 },
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
771};1035};
772 1036
773static const struct user_regset_view user_aarch64_view = {1037static 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
416#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */416#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
417#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */417#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
418#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */418#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
419#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension registers */
419#define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */420#define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */
420#define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */421#define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */
421#define NT_METAG_TLS 0x502 /* Metag TLS pointer */422#define NT_METAG_TLS 0x502 /* Metag TLS pointer */