Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64/sme: Support disabling streaming mode via ptrace on SME only systems

Currently it is not possible to disable streaming mode via ptrace on SME
only systems, the interface for doing this is to write via NT_ARM_SVE but
such writes will be rejected on a system without SVE support. Enable this
functionality by allowing userspace to write SVE_PT_REGS_FPSIMD format data
via NT_ARM_SVE with the vector length set to 0 on SME only systems. Such
writes currently error since we require that a vector length is specified
which should minimise the risk that existing software is relying on current
behaviour.

Reads are not supported since I am not aware of any use case for this and
there is some risk that an existing userspace application may be confused if
it reads NT_ARM_SVE on a system without SVE. Existing kernels will return
FPSIMD formatted register state from NT_ARM_SVE if full SVE state is not
stored, for example if the task has not used SVE. Returning a vector length
of 0 would create a risk that software would try to do things like allocate
space for register state with zero sizes, while returning a vector length of
128 bits would look like SVE is supported. It seems safer to just not make
the changes to add read support.

It remains possible for userspace to detect a SME only system via the ptrace
interface only since reads of NT_ARM_SSVE and NT_ARM_ZA will succeed while
reads of NT_ARM_SVE will fail. Read/write access to the FPSIMD registers in
non-streaming mode is available via REGSET_FPR.

sve_set_common() already avoids allocating SVE storage when doing a FPSIMD
formatted write and allocating SME storage when doing a NT_ARM_SVE write so
we change the function to validate the new case and skip setting a vector
length for it.

The aim is to make a minimally invasive change, no operation that would
previously have succeeded will be affected, and we use a previously
defined interface in new circumstances rather than define completely new
ABI.

Signed-off-by: Mark Brown <broonie@kernel.org>
Reviewed-by: David Spickett <david.spickett@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Mark Brown and committed by
Catalin Marinas
472800cd 3a866087

+38 -7
+5
Documentation/arch/arm64/sve.rst
··· 402 402 streaming mode and any SETREGSET of NT_ARM_SSVE will enter streaming mode 403 403 if the target was not in streaming mode. 404 404 405 + * On systems that do not support SVE it is permitted to use SETREGSET to 406 + write SVE_PT_REGS_FPSIMD formatted data via NT_ARM_SVE, in this case the 407 + vector length should be specified as 0. This allows streaming mode to be 408 + disabled on systems with SME but not SVE. 409 + 405 410 * If any register data is provided along with SVE_PT_VL_ONEXEC then the 406 411 registers data will be interpreted with the current vector length, not 407 412 the vector length configured for use on exec.
+33 -7
arch/arm64/kernel/ptrace.c
··· 912 912 return -EINVAL; 913 913 914 914 /* 915 - * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are consumed by 916 - * vec_set_vector_length(), which will also validate them for us: 915 + * On systems without SVE we accept FPSIMD format writes with 916 + * a VL of 0 to allow exiting streaming mode, otherwise a VL 917 + * is required. 917 918 */ 918 - ret = vec_set_vector_length(target, type, header.vl, 919 - ((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16); 920 - if (ret) 921 - return ret; 919 + if (header.vl) { 920 + /* 921 + * If the system does not support SVE we can't 922 + * configure a SVE VL. 923 + */ 924 + if (!system_supports_sve() && type == ARM64_VEC_SVE) 925 + return -EINVAL; 926 + 927 + /* 928 + * Apart from SVE_PT_REGS_MASK, all SVE_PT_* flags are 929 + * consumed by vec_set_vector_length(), which will 930 + * also validate them for us: 931 + */ 932 + ret = vec_set_vector_length(target, type, header.vl, 933 + ((unsigned long)header.flags & ~SVE_PT_REGS_MASK) << 16); 934 + if (ret) 935 + return ret; 936 + } else { 937 + /* If the system supports SVE we require a VL. */ 938 + if (system_supports_sve()) 939 + return -EINVAL; 940 + 941 + /* 942 + * Only FPSIMD formatted data with no flags set is 943 + * supported. 944 + */ 945 + if (header.flags != SVE_PT_REGS_FPSIMD) 946 + return -EINVAL; 947 + } 922 948 923 949 /* Allocate SME storage if necessary, preserving any existing ZA/ZT state */ 924 950 if (type == ARM64_VEC_SME) { ··· 1042 1016 unsigned int pos, unsigned int count, 1043 1017 const void *kbuf, const void __user *ubuf) 1044 1018 { 1045 - if (!system_supports_sve()) 1019 + if (!system_supports_sve() && !system_supports_sme()) 1046 1020 return -EINVAL; 1047 1021 1048 1022 return sve_set_common(target, regset, pos, count, kbuf, ubuf,