Commit cc36b4a8 authored by Mark Brown's avatar Mark Brown Committed by yanhaitao
Browse files

arm64/sve: Generalise vector length configuration prctl() for SME

mainline inclusion
from mainline-v5.17-rc1
commit 30c43e73
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I8E73O
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=30c43e73b3fa2d75f5d4e72fea345380ba5eb21b



-------------------------------------------------

In preparation for adding SME support update the bulk of the implementation
for the vector length configuration prctl() calls to be independent of
vector type.

Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20211210184133.320748-3-broonie@kernel.org


Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarWang ShaoBo <bobo.shaobowang@huawei.com>
parent 376db135
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -52,8 +52,8 @@ extern void fpsimd_bind_state_to_cpu(struct user_fpsimd_state *state,
extern void fpsimd_flush_task_state(struct task_struct *target);
extern void fpsimd_save_and_flush_cpu_state(void);

/* Maximum VL that SVE VL-agnostic software can transparently support */
#define SVE_VL_ARCH_MAX 0x100
/* Maximum VL that SVE/SME VL-agnostic software can transparently support */
#define VL_ARCH_MAX 0x100

/* Offset of FFR in the SVE register dump */
static inline size_t sve_ffr_offset(int vl)
@@ -125,7 +125,7 @@ extern void fpsimd_sync_to_sve(struct task_struct *task);
extern void sve_sync_to_fpsimd(struct task_struct *task);
extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);

extern int sve_set_vector_length(struct task_struct *task,
extern int vec_set_vector_length(struct task_struct *task, enum vec_type type,
				 unsigned long vl, unsigned long flags);

extern int sve_set_current_vl(unsigned long arg);
+25 −22
Original line number Diff line number Diff line
@@ -630,7 +630,7 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
	__fpsimd_to_sve(sst, fst, vq);
}

int sve_set_vector_length(struct task_struct *task,
int vec_set_vector_length(struct task_struct *task, enum vec_type type,
			  unsigned long vl, unsigned long flags)
{
	if (flags & ~(unsigned long)(PR_SVE_VL_INHERIT |
@@ -641,33 +641,35 @@ int sve_set_vector_length(struct task_struct *task,
		return -EINVAL;

	/*
	 * Clamp to the maximum vector length that VL-agnostic SVE code can
	 * work with.  A flag may be assigned in the future to allow setting
	 * of larger vector lengths without confusing older software.
	 * Clamp to the maximum vector length that VL-agnostic code
	 * can work with.  A flag may be assigned in the future to
	 * allow setting of larger vector lengths without confusing
	 * older software.
	 */
	if (vl > SVE_VL_ARCH_MAX)
		vl = SVE_VL_ARCH_MAX;
	if (vl > VL_ARCH_MAX)
		vl = VL_ARCH_MAX;

	vl = find_supported_vector_length(ARM64_VEC_SVE, vl);
	vl = find_supported_vector_length(type, vl);

	if (flags & (PR_SVE_VL_INHERIT |
		     PR_SVE_SET_VL_ONEXEC))
		task_set_sve_vl_onexec(task, vl);
		task_set_vl_onexec(task, type, vl);
	else
		/* Reset VL to system default on next exec: */
		task_set_sve_vl_onexec(task, 0);
		task_set_vl_onexec(task, type, 0);

	/* Only actually set the VL if not deferred: */
	if (flags & PR_SVE_SET_VL_ONEXEC)
		goto out;

	if (vl == task_get_sve_vl(task))
	if (vl == task_get_vl(task, type))
		goto out;

	/*
	 * To ensure the FPSIMD bits of the SVE vector registers are preserved,
	 * write any live register state back to task_struct, and convert to a
	 * non-SVE thread.
	 * regular FPSIMD thread.  Since the vector length can only be changed
	 * with a syscall we can't be in streaming mode while reconfiguring.
	 */
	if (task == current) {
		get_cpu_fpsimd_context();
@@ -688,10 +690,10 @@ int sve_set_vector_length(struct task_struct *task,
	 */
	sve_free(task);

	task_set_sve_vl(task, vl);
	task_set_vl(task, type, vl);

out:
	update_tsk_thread_flag(task, TIF_SVE_VL_INHERIT,
	update_tsk_thread_flag(task, vec_vl_inherit_flag(type),
			       flags & PR_SVE_VL_INHERIT);

	return 0;
@@ -699,20 +701,21 @@ int sve_set_vector_length(struct task_struct *task,

/*
 * Encode the current vector length and flags for return.
 * This is only required for prctl(): ptrace has separate fields
 * This is only required for prctl(): ptrace has separate fields.
 * SVE and SME use the same bits for _ONEXEC and _INHERIT.
 *
 * flags are as for sve_set_vector_length().
 * flags are as for vec_set_vector_length().
 */
static int sve_prctl_status(unsigned long flags)
static int vec_prctl_status(enum vec_type type, unsigned long flags)
{
	int ret;

	if (flags & PR_SVE_SET_VL_ONEXEC)
		ret = task_get_sve_vl_onexec(current);
		ret = task_get_vl_onexec(current, type);
	else
		ret = task_get_sve_vl(current);
		ret = task_get_vl(current, type);

	if (test_thread_flag(TIF_SVE_VL_INHERIT))
	if (test_thread_flag(vec_vl_inherit_flag(type)))
		ret |= PR_SVE_VL_INHERIT;

	return ret;
@@ -730,11 +733,11 @@ int sve_set_current_vl(unsigned long arg)
	if (!system_supports_sve() || is_compat_task())
		return -EINVAL;

	ret = sve_set_vector_length(current, vl, flags);
	ret = vec_set_vector_length(current, ARM64_VEC_SVE, vl, flags);
	if (ret)
		return ret;

	return sve_prctl_status(flags);
	return vec_prctl_status(ARM64_VEC_SVE, flags);
}

/* PR_SVE_GET_VL */
@@ -743,7 +746,7 @@ int sve_get_current_vl(void)
	if (!system_supports_sve() || is_compat_task())
		return -EINVAL;

	return sve_prctl_status(0);
	return vec_prctl_status(ARM64_VEC_SVE, 0);
}

static void vec_probe_vqs(struct vl_info *info,
+2 −2
Original line number Diff line number Diff line
@@ -813,9 +813,9 @@ static int sve_set(struct task_struct *target,

	/*
	 * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by
	 * sve_set_vector_length(), which will also validate them for us:
	 * vec_set_vector_length(), which will also validate them for us:
	 */
	ret = sve_set_vector_length(target, header.vl,
	ret = vec_set_vector_length(target, ARM64_VEC_SVE, header.vl,
		((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16);
	if (ret)
		goto out;
+4 −4
Original line number Diff line number Diff line
@@ -105,10 +105,10 @@ int kvm_arm_init_sve(void)
		 * The get_sve_reg()/set_sve_reg() ioctl interface will need
		 * to be extended with multiple register slice support in
		 * order to support vector lengths greater than
		 * SVE_VL_ARCH_MAX:
		 * VL_ARCH_MAX:
		 */
		if (WARN_ON(kvm_sve_max_vl > SVE_VL_ARCH_MAX))
			kvm_sve_max_vl = SVE_VL_ARCH_MAX;
		if (WARN_ON(kvm_sve_max_vl > VL_ARCH_MAX))
			kvm_sve_max_vl = VL_ARCH_MAX;

		/*
		 * Don't even try to make use of vector lengths that
@@ -160,7 +160,7 @@ static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu)
	 * set_sve_vls().  Double-check here just to be sure:
	 */
	if (WARN_ON(!sve_vl_valid(vl) || vl > sve_max_virtualisable_vl() ||
		    vl > SVE_VL_ARCH_MAX))
		    vl > VL_ARCH_MAX))
		return -EIO;

	buf = kzalloc(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), GFP_KERNEL);