aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Martin <Dave.Martin@arm.com>2017-10-31 11:51:14 -0400
committerWill Deacon <will.deacon@arm.com>2017-11-03 11:24:19 -0400
commit2d2123bc7c7f843aa9db87720de159a049839862 (patch)
treecc8ad3cccc8d8156382edbf512c4cf1af1d27978
parent43d4da2c45b2f5d62f8a79ff7c6f95089bb24656 (diff)
arm64/sve: Add prctl controls for userspace vector length management
This patch adds two arm64-specific prctls, to permit userspace to control its vector length: * PR_SVE_SET_VL: set the thread's SVE vector length and vector length inheritance mode. * PR_SVE_GET_VL: get the same information. Although these prctls resemble instruction set features in the SVE architecture, they provide additional control: the vector length inheritance mode is Linux-specific and nothing to do with the architecture, and the architecture does not permit EL0 to set its own vector length directly. Both can be used in portable tools without requiring the use of SVE instructions. Signed-off-by: Dave Martin <Dave.Martin@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Alex Bennée <alex.bennee@linaro.org> [will: Fixed up prctl constants to avoid clash with PDEATHSIG] Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm64/include/asm/fpsimd.h14
-rw-r--r--arch/arm64/include/asm/processor.h4
-rw-r--r--arch/arm64/kernel/fpsimd.c50
-rw-r--r--include/uapi/linux/prctl.h4
-rw-r--r--kernel/sys.c12
5 files changed, 84 insertions, 0 deletions
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index d754e5a6949c..b868412c815c 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -17,6 +17,7 @@
17#define __ASM_FP_H 17#define __ASM_FP_H
18 18
19#include <asm/ptrace.h> 19#include <asm/ptrace.h>
20#include <asm/errno.h>
20 21
21#ifndef __ASSEMBLY__ 22#ifndef __ASSEMBLY__
22 23
@@ -98,6 +99,9 @@ extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
98extern int sve_set_vector_length(struct task_struct *task, 99extern int sve_set_vector_length(struct task_struct *task,
99 unsigned long vl, unsigned long flags); 100 unsigned long vl, unsigned long flags);
100 101
102extern int sve_set_current_vl(unsigned long arg);
103extern int sve_get_current_vl(void);
104
101/* 105/*
102 * Probing and setup functions. 106 * Probing and setup functions.
103 * Calls to these functions must be serialised with one another. 107 * Calls to these functions must be serialised with one another.
@@ -114,6 +118,16 @@ static inline void fpsimd_release_task(struct task_struct *task) { }
114static inline void sve_sync_to_fpsimd(struct task_struct *task) { } 118static inline void sve_sync_to_fpsimd(struct task_struct *task) { }
115static inline void sve_sync_from_fpsimd_zeropad(struct task_struct *task) { } 119static inline void sve_sync_from_fpsimd_zeropad(struct task_struct *task) { }
116 120
121static inline int sve_set_current_vl(unsigned long arg)
122{
123 return -EINVAL;
124}
125
126static inline int sve_get_current_vl(void)
127{
128 return -EINVAL;
129}
130
117static inline void sve_init_vq_map(void) { } 131static inline void sve_init_vq_map(void) { }
118static inline void sve_update_vq_map(void) { } 132static inline void sve_update_vq_map(void) { }
119static inline int sve_verify_vq_map(void) { return 0; } 133static inline int sve_verify_vq_map(void) { return 0; }
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index c6fddb005dc2..023cacb946c3 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -217,5 +217,9 @@ static inline void spin_lock_prefetch(const void *ptr)
217int cpu_enable_pan(void *__unused); 217int cpu_enable_pan(void *__unused);
218int cpu_enable_cache_maint_trap(void *__unused); 218int cpu_enable_cache_maint_trap(void *__unused);
219 219
220/* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */
221#define SVE_SET_VL(arg) sve_set_current_vl(arg)
222#define SVE_GET_VL() sve_get_current_vl()
223
220#endif /* __ASSEMBLY__ */ 224#endif /* __ASSEMBLY__ */
221#endif /* __ASM_PROCESSOR_H */ 225#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index b82d44693b9d..fd3cfdd7f9be 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -29,6 +29,7 @@
29#include <linux/irqflags.h> 29#include <linux/irqflags.h>
30#include <linux/init.h> 30#include <linux/init.h>
31#include <linux/percpu.h> 31#include <linux/percpu.h>
32#include <linux/prctl.h>
32#include <linux/preempt.h> 33#include <linux/preempt.h>
33#include <linux/prctl.h> 34#include <linux/prctl.h>
34#include <linux/ptrace.h> 35#include <linux/ptrace.h>
@@ -559,6 +560,55 @@ out:
559} 560}
560 561
561/* 562/*
563 * Encode the current vector length and flags for return.
564 * This is only required for prctl(): ptrace has separate fields
565 *
566 * flags are as for sve_set_vector_length().
567 */
568static int sve_prctl_status(unsigned long flags)
569{
570 int ret;
571
572 if (flags & PR_SVE_SET_VL_ONEXEC)
573 ret = current->thread.sve_vl_onexec;
574 else
575 ret = current->thread.sve_vl;
576
577 if (test_thread_flag(TIF_SVE_VL_INHERIT))
578 ret |= PR_SVE_VL_INHERIT;
579
580 return ret;
581}
582
583/* PR_SVE_SET_VL */
584int sve_set_current_vl(unsigned long arg)
585{
586 unsigned long vl, flags;
587 int ret;
588
589 vl = arg & PR_SVE_VL_LEN_MASK;
590 flags = arg & ~vl;
591
592 if (!system_supports_sve())
593 return -EINVAL;
594
595 ret = sve_set_vector_length(current, vl, flags);
596 if (ret)
597 return ret;
598
599 return sve_prctl_status(flags);
600}
601
602/* PR_SVE_GET_VL */
603int sve_get_current_vl(void)
604{
605 if (!system_supports_sve())
606 return -EINVAL;
607
608 return sve_prctl_status(0);
609}
610
611/*
562 * Bitmap for temporary storage of the per-CPU set of supported vector lengths 612 * Bitmap for temporary storage of the per-CPU set of supported vector lengths
563 * during secondary boot. 613 * during secondary boot.
564 */ 614 */
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 1b64901ca6b3..f60db5db6e8e 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -198,7 +198,11 @@ struct prctl_mm_map {
198# define PR_CAP_AMBIENT_CLEAR_ALL 4 198# define PR_CAP_AMBIENT_CLEAR_ALL 4
199 199
200/* arm64 Scalable Vector Extension controls */ 200/* arm64 Scalable Vector Extension controls */
201/* Flag values must be kept in sync with ptrace NT_ARM_SVE interface */
202#define PR_SVE_SET_VL 50 /* set task vector length */
201# define PR_SVE_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */ 203# define PR_SVE_SET_VL_ONEXEC (1 << 18) /* defer effect until exec */
204#define PR_SVE_GET_VL 51 /* get task vector length */
205/* Bits common to PR_SVE_SET_VL and PR_SVE_GET_VL */
202# define PR_SVE_VL_LEN_MASK 0xffff 206# define PR_SVE_VL_LEN_MASK 0xffff
203# define PR_SVE_VL_INHERIT (1 << 17) /* inherit across exec */ 207# define PR_SVE_VL_INHERIT (1 << 17) /* inherit across exec */
204 208
diff --git a/kernel/sys.c b/kernel/sys.c
index 9aebc2935013..c541916b38c6 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -110,6 +110,12 @@
110#ifndef SET_FP_MODE 110#ifndef SET_FP_MODE
111# define SET_FP_MODE(a,b) (-EINVAL) 111# define SET_FP_MODE(a,b) (-EINVAL)
112#endif 112#endif
113#ifndef SVE_SET_VL
114# define SVE_SET_VL(a) (-EINVAL)
115#endif
116#ifndef SVE_GET_VL
117# define SVE_GET_VL() (-EINVAL)
118#endif
113 119
114/* 120/*
115 * this is where the system-wide overflow UID and GID are defined, for 121 * this is where the system-wide overflow UID and GID are defined, for
@@ -2385,6 +2391,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
2385 case PR_GET_FP_MODE: 2391 case PR_GET_FP_MODE:
2386 error = GET_FP_MODE(me); 2392 error = GET_FP_MODE(me);
2387 break; 2393 break;
2394 case PR_SVE_SET_VL:
2395 error = SVE_SET_VL(arg2);
2396 break;
2397 case PR_SVE_GET_VL:
2398 error = SVE_GET_VL();
2399 break;
2388 default: 2400 default:
2389 error = -EINVAL; 2401 error = -EINVAL;
2390 break; 2402 break;